Update DFU translations and ignore local sdk workspace
This commit is contained in:
parent
5e387c24f5
commit
5350017085
3
.gitignore
vendored
3
.gitignore
vendored
@ -74,3 +74,6 @@ yarn-error.log
|
|||||||
!.yarn/releases
|
!.yarn/releases
|
||||||
!.yarn/sdks
|
!.yarn/sdks
|
||||||
!.yarn/versions
|
!.yarn/versions
|
||||||
|
|
||||||
|
# Local SDK workspace
|
||||||
|
sdk/
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
DfuProgressEvent,
|
DfuProgressEvent,
|
||||||
DfuStateEvent,
|
DfuStateEvent,
|
||||||
} from "@systemic-games/react-native-nordic-nrf5-dfu";
|
} from "@systemic-games/react-native-nordic-nrf5-dfu";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
import MyStatusbar from "./component/MyStatusbar";
|
import MyStatusbar from "./component/MyStatusbar";
|
||||||
import MyHeader from "./component/MyHeader";
|
import MyHeader from "./component/MyHeader";
|
||||||
|
|
||||||
@ -66,39 +67,40 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
name,
|
name,
|
||||||
firmware: deviceFirmware,
|
firmware: deviceFirmware,
|
||||||
} = route.params;
|
} = route.params;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [progress, setProgress] = useState(0);
|
const [progress, setProgress] = useState(0);
|
||||||
const [state, setState] = useState("准备中...");
|
const [state, setState] = useState(t("dfu.preparing"));
|
||||||
const [error, setError] = useState<string>();
|
const [error, setError] = useState<string>();
|
||||||
const [latestVersion, setLatestVersion] = useState("读取中...");
|
const [latestVersion, setLatestVersion] = useState(t("dfu.reading"));
|
||||||
const [isDfuRunning, setIsDfuRunning] = useState(false);
|
const [isDfuRunning, setIsDfuRunning] = useState(false);
|
||||||
const startedRef = useRef(false);
|
const startedRef = useRef(false);
|
||||||
|
|
||||||
const mapDfuStateToChinese = (s: string): string => {
|
const mapDfuStateToLabel = (s: string): string => {
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case "connecting":
|
case "connecting":
|
||||||
return "连接中…";
|
return t("dfu.stateConnecting");
|
||||||
case "starting":
|
case "starting":
|
||||||
return "初始化中…";
|
return t("dfu.stateStarting");
|
||||||
case "enablingDfuMode":
|
case "enablingDfuMode":
|
||||||
return "启用 DFU 模式…";
|
return t("dfu.stateEnablingDfuMode");
|
||||||
case "uploading":
|
case "uploading":
|
||||||
return "上传固件中…";
|
return t("dfu.stateUploading");
|
||||||
case "validating":
|
case "validating":
|
||||||
return "校验固件…";
|
return t("dfu.stateValidating");
|
||||||
case "disconnecting":
|
case "disconnecting":
|
||||||
return "断开连接…";
|
return t("dfu.stateDisconnecting");
|
||||||
case "completed":
|
case "completed":
|
||||||
return "升级完成";
|
return t("dfu.stateCompleted");
|
||||||
case "aborted":
|
case "aborted":
|
||||||
return "已取消";
|
return t("dfu.stateAborted");
|
||||||
case "failed":
|
case "failed":
|
||||||
case "dfu_failed":
|
case "dfu_failed":
|
||||||
return "升级失败";
|
return t("dfu.stateFailed");
|
||||||
case "initializing":
|
case "initializing":
|
||||||
return "启动中…";
|
return t("dfu.stateInitializing");
|
||||||
case "errored":
|
case "errored":
|
||||||
return "升级出错!";
|
return t("dfu.stateErrored");
|
||||||
default:
|
default:
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@ -108,11 +110,11 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
const unsubscribe = navigation.addListener("beforeRemove", (e) => {
|
const unsubscribe = navigation.addListener("beforeRemove", (e) => {
|
||||||
if (!isDfuRunning) return;
|
if (!isDfuRunning) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
Alert.alert("请稍候", "正在升级,请勿返回或关闭应用!");
|
Alert.alert(t("dfu.pleaseWait"), t("dfu.doNotReturn"));
|
||||||
});
|
});
|
||||||
|
|
||||||
return unsubscribe;
|
return unsubscribe;
|
||||||
}, [navigation, isDfuRunning]);
|
}, [navigation, isDfuRunning, t]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
trace("screen mounted", {
|
trace("screen mounted", {
|
||||||
@ -163,7 +165,7 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!safeDeviceId) {
|
if (!safeDeviceId) {
|
||||||
throw new Error("无法生成 DFU 目标设备 ID");
|
throw new Error(t("dfu.invalidTargetDeviceId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentFw = parseFirmwareVersion(firmwareText);
|
const currentFw = parseFirmwareVersion(firmwareText);
|
||||||
@ -178,7 +180,9 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
trace("manifest fetch response", { status: manifestResp.status });
|
trace("manifest fetch response", { status: manifestResp.status });
|
||||||
|
|
||||||
if (!manifestResp.ok) {
|
if (!manifestResp.ok) {
|
||||||
throw new Error(`manifest 下载失败,HTTP ${manifestResp.status}`);
|
throw new Error(
|
||||||
|
t("dfu.manifestDownloadFailed", { status: manifestResp.status })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const manifestText = await manifestResp.text();
|
const manifestText = await manifestResp.text();
|
||||||
@ -192,7 +196,11 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
try {
|
try {
|
||||||
manifest = JSON.parse(manifestText) as { devices: DeviceInfo[] };
|
manifest = JSON.parse(manifestText) as { devices: DeviceInfo[] };
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error("manifest 不是合法 JSON: " + manifestText.slice(0, 200));
|
throw new Error(
|
||||||
|
t("dfu.manifestInvalidJson", {
|
||||||
|
preview: manifestText.slice(0, 200),
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const deviceInfo = manifest.devices.find(
|
const deviceInfo = manifest.devices.find(
|
||||||
@ -204,9 +212,9 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
if (!deviceInfo) {
|
if (!deviceInfo) {
|
||||||
setIsDfuRunning(false);
|
setIsDfuRunning(false);
|
||||||
Alert.alert(
|
Alert.alert(
|
||||||
"无法升级",
|
t("dfu.cannotUpgrade"),
|
||||||
`未找到 hardware=${currentFw.hardware} 的固件`,
|
t("dfu.hardwareNotFound", { hardware: currentFw.hardware }),
|
||||||
[{ text: "确认", onPress: () => navigation.goBack() }]
|
[{ text: t("dfu.confirm"), onPress: () => navigation.goBack() }]
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -218,14 +226,17 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
|
|
||||||
if (latestFw.hardware !== currentFw.hardware) {
|
if (latestFw.hardware !== currentFw.hardware) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`服务器固件硬件号不匹配:当前 ${currentFw.hardware},服务器 ${latestFw.hardware}`
|
t("dfu.hardwareMismatch", {
|
||||||
|
current: currentFw.hardware,
|
||||||
|
latest: latestFw.hardware,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (latestFw.iteration <= currentFw.iteration) {
|
if (latestFw.iteration <= currentFw.iteration) {
|
||||||
setIsDfuRunning(false);
|
setIsDfuRunning(false);
|
||||||
Alert.alert("无需升级", "已是最新固件,无需升级", [
|
Alert.alert(t("dfu.noNeedUpgrade"), t("dfu.alreadyLatest"), [
|
||||||
{ text: "确认", onPress: () => navigation.goBack() },
|
{ text: t("dfu.confirm"), onPress: () => navigation.goBack() },
|
||||||
]);
|
]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -258,14 +269,18 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
trace("firmware download result", downloadResult);
|
trace("firmware download result", downloadResult);
|
||||||
|
|
||||||
if (downloadResult.statusCode !== 200) {
|
if (downloadResult.statusCode !== 200) {
|
||||||
throw new Error(`固件包下载失败,HTTP ${downloadResult.statusCode}`);
|
throw new Error(
|
||||||
|
t("dfu.firmwareDownloadFailed", {
|
||||||
|
status: downloadResult.statusCode,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileExists = await RNFS.exists(localPath);
|
const fileExists = await RNFS.exists(localPath);
|
||||||
trace("firmware exists check", { fileExists });
|
trace("firmware exists check", { fileExists });
|
||||||
|
|
||||||
if (!fileExists) {
|
if (!fileExists) {
|
||||||
throw new Error(`固件包下载后文件不存在: ${localPath}`);
|
throw new Error(t("dfu.firmwareFileMissing", { path: localPath }));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileStat = await RNFS.stat(localPath);
|
const fileStat = await RNFS.stat(localPath);
|
||||||
@ -273,7 +288,9 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
trace("firmware stat", fileStat);
|
trace("firmware stat", fileStat);
|
||||||
|
|
||||||
if (!Number.isFinite(fileSize) || fileSize <= 0) {
|
if (!Number.isFinite(fileSize) || fileSize <= 0) {
|
||||||
throw new Error(`固件包文件无效,大小为 ${fileStat.size}`);
|
throw new Error(
|
||||||
|
t("dfu.firmwareFileInvalid", { size: String(fileStat.size) })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dfuFilePath = "file://" + localPath;
|
const dfuFilePath = "file://" + localPath;
|
||||||
@ -310,9 +327,9 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
|
|
||||||
trace("startDfu resolved successfully");
|
trace("startDfu resolved successfully");
|
||||||
setIsDfuRunning(false);
|
setIsDfuRunning(false);
|
||||||
Alert.alert("升级成功", "升级成功,请重连设备", [
|
Alert.alert(t("dfu.upgradeSuccess"), t("dfu.upgradeSuccessMessage"), [
|
||||||
{
|
{
|
||||||
text: "确认",
|
text: t("dfu.confirm"),
|
||||||
onPress: () => {
|
onPress: () => {
|
||||||
navigation.reset({
|
navigation.reset({
|
||||||
index: 0,
|
index: 0,
|
||||||
@ -329,21 +346,21 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
error: err,
|
error: err,
|
||||||
});
|
});
|
||||||
setIsDfuRunning(false);
|
setIsDfuRunning(false);
|
||||||
setError(err?.message || "DFU失败");
|
setError(err?.message || t("dfu.dfuFailed"));
|
||||||
Alert.alert("升级失败", err?.message || "DFU失败", [
|
Alert.alert(t("dfu.upgradeFailed"), err?.message || t("dfu.dfuFailed"), [
|
||||||
{ text: "确认", onPress: () => navigation.goBack() },
|
{ text: t("dfu.confirm"), onPress: () => navigation.goBack() },
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
runDfu();
|
runDfu();
|
||||||
}, [deviceId, name, deviceFirmware, navigation]);
|
}, [deviceId, name, deviceFirmware, navigation, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<MyStatusbar backgroundColor="#FFFFFF" dark />
|
<MyStatusbar backgroundColor="#FFFFFF" dark />
|
||||||
<MyHeader
|
<MyHeader
|
||||||
title="固件升级"
|
title={t("dfu.title")}
|
||||||
textColor="#333"
|
textColor="#333"
|
||||||
backgroundColor="#FFFFFF"
|
backgroundColor="#FFFFFF"
|
||||||
navigation={navigation}
|
navigation={navigation}
|
||||||
@ -351,20 +368,26 @@ export default function DfuScreen({ route, navigation }: Props) {
|
|||||||
|
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<Text style={styles.titleText}>蓝牙名称: {name || "--"}</Text>
|
<Text style={styles.titleText}>
|
||||||
</View>
|
{t("dfu.bluetoothName")}: {name || "--"}
|
||||||
|
</Text>
|
||||||
<View style={styles.row}>
|
|
||||||
<Text style={styles.normalText}>最新版本: {latestVersion}</Text>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.row}>
|
|
||||||
<Text style={styles.normalText}>当前版本: {deviceFirmware || "--"}</Text>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.row}>
|
<View style={styles.row}>
|
||||||
<Text style={styles.normalText}>
|
<Text style={styles.normalText}>
|
||||||
升级状态: {mapDfuStateToChinese(state)}
|
{t("dfu.latestVersion")}: {latestVersion}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text style={styles.normalText}>
|
||||||
|
{t("dfu.currentVersion")}: {deviceFirmware || "--"}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View style={styles.row}>
|
||||||
|
<Text style={styles.normalText}>
|
||||||
|
{t("dfu.upgradeStatus")}: {mapDfuStateToLabel(state)}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
|||||||
@ -217,24 +217,34 @@ export default function InfoScreen({ route, navigation }: Props) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const readBatteryCharacteristic = async () => {
|
const readBatteryCharacteristic = async () => {
|
||||||
for (let attempt = 0; attempt < 3; attempt += 1) {
|
let lastValidBattery: number | null = null;
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
||||||
try {
|
try {
|
||||||
const bytes = await readCharacteristicWithRetry("180f", "2a19", 1);
|
const bytes = await readCharacteristicWithRetry("180f", "2a19", 1);
|
||||||
const batteryValue = bytes[0];
|
const batteryValue = bytes[0];
|
||||||
|
|
||||||
if (Number.isInteger(batteryValue) && batteryValue >= 0 && batteryValue <= 100) {
|
if (
|
||||||
return `${batteryValue}%`;
|
Number.isInteger(batteryValue) &&
|
||||||
|
batteryValue >= 0 &&
|
||||||
|
batteryValue <= 100
|
||||||
|
) {
|
||||||
|
if (lastValidBattery !== null && lastValidBattery === batteryValue) {
|
||||||
|
return `${batteryValue}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastValidBattery = batteryValue;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Continue retrying with a short gap below.
|
// Continue retrying with a short gap below.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attempt < 2) {
|
if (attempt < 3) {
|
||||||
await sleep(180);
|
await sleep(220);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "未知";
|
return lastValidBattery !== null ? `${lastValidBattery}%` : "未知";
|
||||||
};
|
};
|
||||||
|
|
||||||
const subscribePowerDataIfNeeded = async () => {
|
const subscribePowerDataIfNeeded = async () => {
|
||||||
|
|||||||
@ -189,9 +189,16 @@
|
|||||||
"doNotReturn": "Updating in progress, do not go back or close the app!",
|
"doNotReturn": "Updating in progress, do not go back or close the app!",
|
||||||
|
|
||||||
"cannotUpgrade": "Cannot Update",
|
"cannotUpgrade": "Cannot Update",
|
||||||
"hardwareNotFound": "Firmware not found for hardware version {hardware}",
|
"hardwareNotFound": "Firmware not found for hardware version {{hardware}}",
|
||||||
"noNeedUpgrade": "No Update Needed",
|
"noNeedUpgrade": "No Update Needed",
|
||||||
"alreadyLatest": "Already the latest firmware, no update needed",
|
"alreadyLatest": "Already the latest firmware, no update needed",
|
||||||
|
"invalidTargetDeviceId": "Unable to generate DFU target device ID",
|
||||||
|
"manifestDownloadFailed": "Manifest download failed, HTTP {{status}}",
|
||||||
|
"manifestInvalidJson": "Manifest is not valid JSON: {{preview}}",
|
||||||
|
"hardwareMismatch": "Firmware hardware mismatch: current {{current}}, server {{latest}}",
|
||||||
|
"firmwareDownloadFailed": "Firmware package download failed, HTTP {{status}}",
|
||||||
|
"firmwareFileMissing": "Firmware package file not found after download: {{path}}",
|
||||||
|
"firmwareFileInvalid": "Firmware package file is invalid, size {{size}}",
|
||||||
|
|
||||||
"upgradeSuccess": "Update Successful",
|
"upgradeSuccess": "Update Successful",
|
||||||
"upgradeSuccessMessage": "Update successful, please reconnect the device",
|
"upgradeSuccessMessage": "Update successful, please reconnect the device",
|
||||||
|
|||||||
@ -189,9 +189,16 @@
|
|||||||
"doNotReturn": "正在升级,请勿返回或关闭应用!",
|
"doNotReturn": "正在升级,请勿返回或关闭应用!",
|
||||||
|
|
||||||
"cannotUpgrade": "无法升级",
|
"cannotUpgrade": "无法升级",
|
||||||
"hardwareNotFound": "未找到硬件版本 {hardware} 的固件",
|
"hardwareNotFound": "未找到硬件版本 {{hardware}} 的固件",
|
||||||
"noNeedUpgrade": "无需升级",
|
"noNeedUpgrade": "无需升级",
|
||||||
"alreadyLatest": "已是最新固件,无需升级",
|
"alreadyLatest": "已是最新固件,无需升级",
|
||||||
|
"invalidTargetDeviceId": "无法生成 DFU 目标设备 ID",
|
||||||
|
"manifestDownloadFailed": "manifest 下载失败,HTTP {{status}}",
|
||||||
|
"manifestInvalidJson": "manifest 不是合法 JSON: {{preview}}",
|
||||||
|
"hardwareMismatch": "服务器固件硬件号不匹配:当前 {{current}},服务器 {{latest}}",
|
||||||
|
"firmwareDownloadFailed": "固件包下载失败,HTTP {{status}}",
|
||||||
|
"firmwareFileMissing": "固件包下载后文件不存在: {{path}}",
|
||||||
|
"firmwareFileInvalid": "固件包文件无效,大小为 {{size}}",
|
||||||
|
|
||||||
"upgradeSuccess": "升级成功",
|
"upgradeSuccess": "升级成功",
|
||||||
"upgradeSuccessMessage": "升级成功,请重连设备",
|
"upgradeSuccessMessage": "升级成功,请重连设备",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user