@onekeyfe/hd-core 1.2.0-alpha.106 → 1.2.0-alpha.107
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/DeviceCommands.test.ts +28 -100
- package/__tests__/device-lifecycle-events.test.ts +2 -113
- package/__tests__/device-pool-state.test.ts +0 -25
- package/__tests__/deviceSettings.test.ts +1 -0
- package/__tests__/deviceUploadNft.test.ts +4 -33
- package/__tests__/get-device-state.test.ts +13 -52
- package/__tests__/logBlockEvent.test.ts +1 -13
- package/__tests__/protocol-v2.test.ts +121 -758
- package/__tests__/refresh-device-state.test.ts +1 -3
- package/__tests__/search-devices.test.ts +38 -32
- package/dist/api/FirmwareUpdateV4.d.ts +3 -10
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/UploadPortfolio.d.ts +1 -1
- package/dist/api/UploadPortfolio.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +3 -2
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts +3 -2
- package/dist/api/protocol-v2/DeviceUploadWallpaper.d.ts.map +1 -1
- package/dist/api/ton/TonSignMessage.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +2 -7
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/index.d.ts +16 -12
- package/dist/index.js +201 -446
- package/dist/protocols/protocol-v2/features.d.ts +1 -9
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/index.d.ts +2 -2
- package/dist/protocols/protocol-v2/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +1 -1
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts.map +1 -1
- package/dist/utils/pro2Nft.d.ts +0 -7
- package/dist/utils/pro2Nft.d.ts.map +1 -1
- package/package.json +4 -6
- package/src/api/FirmwareUpdateV4.ts +174 -312
- package/src/api/SearchDevices.ts +2 -2
- package/src/api/UploadPortfolio.ts +2 -9
- package/src/api/protocol-v2/DeviceUploadNft.ts +8 -56
- package/src/api/protocol-v2/DeviceUploadWallpaper.ts +18 -37
- package/src/api/ton/TonSignMessage.ts +3 -5
- package/src/core/index.ts +2 -6
- package/src/device/Device.ts +31 -53
- package/src/device/DeviceCommands.ts +14 -4
- package/src/device/DevicePool.ts +2 -6
- package/src/events/logBlockEvent.ts +1 -14
- package/src/protocols/protocol-v2/features.ts +2 -19
- package/src/protocols/protocol-v2/index.ts +0 -2
- package/src/types/api/protocolV2.ts +1 -1
- package/src/types/device.ts +2 -1
- package/src/utils/deviceSettings.ts +1 -1
- package/src/utils/pro2Nft.ts +8 -31
- package/__tests__/base64Data.test.ts +0 -70
- package/__tests__/firmware-update/firmware-update-v4-install-poll.test.ts +0 -145
- package/__tests__/resourceBase64Boundary.test.ts +0 -48
- package/__tests__/ton-sign-message.test.ts +0 -84
- package/dist/api/helpers/base64Data.d.ts +0 -16
- package/dist/api/helpers/base64Data.d.ts.map +0 -1
- package/src/api/helpers/base64Data.ts +0 -85
|
@@ -28,7 +28,6 @@ import { DevicePool } from '../device/DevicePool';
|
|
|
28
28
|
import {
|
|
29
29
|
PROTOCOL_V2_VERSIONS_DEVICE_INFO_REQUEST,
|
|
30
30
|
ProtocolV2FirmwareTargetType,
|
|
31
|
-
isLegacyProtocolV2ProtocolInfo,
|
|
32
31
|
} from '../protocols/protocol-v2';
|
|
33
32
|
import { requestProtocolV2DeviceInfo } from '../protocols/protocol-v2/features';
|
|
34
33
|
import {
|
|
@@ -244,7 +243,15 @@ type JSZipSizedEntry = JSZip.JSZipObject & {
|
|
|
244
243
|
};
|
|
245
244
|
};
|
|
246
245
|
|
|
247
|
-
type
|
|
246
|
+
type ProtocolV2ExecutionPhaseKind =
|
|
247
|
+
| 'resource-sync'
|
|
248
|
+
| 'bootloader-install'
|
|
249
|
+
| 'bootloader-verify'
|
|
250
|
+
| 'component-install'
|
|
251
|
+
| 'final-verify';
|
|
252
|
+
|
|
253
|
+
type ProtocolV2ExecutionPhase = {
|
|
254
|
+
kind: ProtocolV2ExecutionPhaseKind;
|
|
248
255
|
installSources: ProtocolV2InstallSource[];
|
|
249
256
|
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
250
257
|
};
|
|
@@ -377,19 +384,6 @@ const isProtocolV2ReconnectProbeError = (error: unknown) => {
|
|
|
377
384
|
);
|
|
378
385
|
};
|
|
379
386
|
|
|
380
|
-
const isProtocolV2BleTransportReleasedError = (error: unknown) => {
|
|
381
|
-
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
382
|
-
const compactMessage = message.replace(/\s+/gu, '');
|
|
383
|
-
return (
|
|
384
|
-
message.includes('react native ble transport released') ||
|
|
385
|
-
message.includes('bledevicedisconnected') ||
|
|
386
|
-
message.includes('bleconnectederror') ||
|
|
387
|
-
(compactMessage.includes('rxerrorerror6') &&
|
|
388
|
-
(compactMessage.includes('multiplatformbleadapter') ||
|
|
389
|
-
compactMessage.includes('multipalformebleadapter')))
|
|
390
|
-
);
|
|
391
|
-
};
|
|
392
|
-
|
|
393
387
|
const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
|
|
394
388
|
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
395
389
|
return (
|
|
@@ -399,13 +393,6 @@ const isProtocolV2FirmwareStatusEndpointUnavailable = (error: unknown) => {
|
|
|
399
393
|
);
|
|
400
394
|
};
|
|
401
395
|
|
|
402
|
-
const isProtocolV2FirmwareUpdateEndpointUnavailable = (error: unknown) => {
|
|
403
|
-
const message = getProtocolV2UnknownErrorText(error).toLowerCase();
|
|
404
|
-
return (
|
|
405
|
-
message.includes('handler not registered') || message.includes('message handler not found')
|
|
406
|
-
);
|
|
407
|
-
};
|
|
408
|
-
|
|
409
396
|
const isProtocolV2TerminalInstallStatusError = (error: unknown) =>
|
|
410
397
|
error instanceof HardwareError &&
|
|
411
398
|
(error.errorCode === HardwareErrorCode.FirmwareError ||
|
|
@@ -600,8 +587,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
600
587
|
|
|
601
588
|
private protocolV2ExecutionInLoader = false;
|
|
602
589
|
|
|
603
|
-
private protocolV2LegacyDirectUpdate = false;
|
|
604
|
-
|
|
605
590
|
private protocolV2BootResourceStagingSafe = false;
|
|
606
591
|
|
|
607
592
|
private protocolV2CompletedTargetVersions = new Map<number, number>();
|
|
@@ -610,12 +595,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
610
595
|
|
|
611
596
|
private protocolV2FinalStatusVerified = false;
|
|
612
597
|
|
|
613
|
-
private protocolV2InstallAckReceived = false;
|
|
614
|
-
|
|
615
|
-
private protocolV2InstallBaselineVersions = new Map<number, string>();
|
|
616
|
-
|
|
617
|
-
private protocolV2LastRuntimeProbeFeatures?: Features;
|
|
618
|
-
|
|
619
598
|
init() {
|
|
620
599
|
this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.NOT_INITIALIZE];
|
|
621
600
|
this.requireDeviceMode = [];
|
|
@@ -834,9 +813,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
834
813
|
private async runProtocolV2() {
|
|
835
814
|
await this.captureProtocolV2PhysicalIdentity();
|
|
836
815
|
const deviceFeatures = await this.getProtocolV2DeviceFeatures();
|
|
837
|
-
this.protocolV2InstallBaselineVersions =
|
|
838
|
-
this.getProtocolV2ObservableTargetVersions(deviceFeatures);
|
|
839
|
-
this.protocolV2LastRuntimeProbeFeatures = undefined;
|
|
840
816
|
const currentDeviceType = this.device.getCurrentDeviceType();
|
|
841
817
|
const capabilityDeviceType =
|
|
842
818
|
currentDeviceType === EDeviceType.Pro2 || currentDeviceType === EDeviceType.Neo
|
|
@@ -850,7 +826,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
850
826
|
const deviceFirmwareType = getFirmwareType(deviceFeatures);
|
|
851
827
|
const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
|
|
852
828
|
this.validateExpectedTargetVersions();
|
|
853
|
-
const wantsResources = !!this.params.targetsToUpdate?.includes('resource');
|
|
854
829
|
|
|
855
830
|
if (
|
|
856
831
|
!this.params.preparedPlan &&
|
|
@@ -874,11 +849,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
874
849
|
if (this.params.preparedPlan || hasPreparedComponentArtifacts) {
|
|
875
850
|
return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
|
|
876
851
|
}
|
|
852
|
+
const wantsResources = !!this.params.targetsToUpdate?.includes('resource');
|
|
877
853
|
|
|
878
854
|
let fwBinaryMap: ProtocolV2TargetBinary[] = [];
|
|
879
855
|
let bootloaderBinary: ArrayBuffer | null = null;
|
|
880
856
|
let installItems: ProtocolV2InstallItem[] | undefined;
|
|
881
|
-
let resourceMemoryHost: FirmwareUpdateV4MemoryHost | undefined;
|
|
882
857
|
try {
|
|
883
858
|
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
884
859
|
fwBinaryMap = this.collectExplicitTargetBinaries();
|
|
@@ -891,9 +866,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
891
866
|
const needsRemoteFirmware = this.params.targetsToUpdate?.length
|
|
892
867
|
? missingFirmwareTargets.length > 0
|
|
893
868
|
: explicitInstallItems.length === 0;
|
|
894
|
-
|
|
869
|
+
if (wantsResources) {
|
|
870
|
+
throw ERRORS.TypedError(
|
|
871
|
+
HardwareErrorCode.RuntimeError,
|
|
872
|
+
'Protocol V2 resource archive must be provided through a local or external PreparedPlan',
|
|
873
|
+
{
|
|
874
|
+
firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
|
|
875
|
+
}
|
|
876
|
+
);
|
|
877
|
+
}
|
|
895
878
|
if (
|
|
896
|
-
|
|
879
|
+
needsRemoteFirmware &&
|
|
897
880
|
(this.params.artifactReader ||
|
|
898
881
|
DataManager.getSettings('firmwareManifestMode') === 'external-only')
|
|
899
882
|
) {
|
|
@@ -905,13 +888,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
905
888
|
}
|
|
906
889
|
);
|
|
907
890
|
}
|
|
908
|
-
if (
|
|
891
|
+
if (needsRemoteFirmware) {
|
|
909
892
|
// Remote updates must use a freshly fetched config before any reboot or file write.
|
|
910
|
-
await DataManager.forceReloadData(
|
|
911
|
-
requireResources: wantsResources,
|
|
912
|
-
resourceDeviceType:
|
|
913
|
-
capabilityDeviceType === EDeviceType.Neo ? EDeviceType.Neo : EDeviceType.Pro2,
|
|
914
|
-
});
|
|
893
|
+
await DataManager.forceReloadData();
|
|
915
894
|
}
|
|
916
895
|
if (needsRemoteFirmware) {
|
|
917
896
|
const remoteBinaries = await this.prepareRemoteProtocolV2Binaries(
|
|
@@ -934,19 +913,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
934
913
|
targetId: item.targetId,
|
|
935
914
|
}));
|
|
936
915
|
}
|
|
937
|
-
if (wantsResources) {
|
|
938
|
-
this.params.resourceArchiveBinary = await this.downloadRemoteProtocolV2ResourceArchive(
|
|
939
|
-
deviceFeatures
|
|
940
|
-
);
|
|
941
|
-
resourceMemoryHost = await this.prepareProtocolV2LocalMemoryHost({
|
|
942
|
-
features: deviceFeatures,
|
|
943
|
-
firmwareType,
|
|
944
|
-
availableInstallItems: installItems ?? explicitInstallItems,
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
916
|
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
948
917
|
} catch (err) {
|
|
949
|
-
resourceMemoryHost?.release();
|
|
950
918
|
if (
|
|
951
919
|
typeof err === 'object' &&
|
|
952
920
|
err !== null &&
|
|
@@ -961,14 +929,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
961
929
|
throw normalizeFirmwarePreparationError(err);
|
|
962
930
|
}
|
|
963
931
|
|
|
964
|
-
if (resourceMemoryHost) {
|
|
965
|
-
try {
|
|
966
|
-
return await this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType, false);
|
|
967
|
-
} finally {
|
|
968
|
-
resourceMemoryHost.release();
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
|
-
|
|
972
932
|
if (!bootloaderBinary && fwBinaryMap.length === 0 && !installItems?.length) {
|
|
973
933
|
throw ERRORS.TypedError(
|
|
974
934
|
HardwareErrorCode.FirmwareUpdateDownloadFailed,
|
|
@@ -1122,15 +1082,14 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1122
1082
|
private async prepareProtocolV2LocalMemoryHost({
|
|
1123
1083
|
features,
|
|
1124
1084
|
firmwareType,
|
|
1125
|
-
availableInstallItems = this.buildProtocolV2InstallItems({
|
|
1126
|
-
bootloaderBinary: this.prepareBootloaderBinary(),
|
|
1127
|
-
fwBinaryMap: this.collectExplicitTargetBinaries(),
|
|
1128
|
-
}),
|
|
1129
1085
|
}: {
|
|
1130
1086
|
features: Features;
|
|
1131
1087
|
firmwareType: EFirmwareType;
|
|
1132
|
-
availableInstallItems?: ProtocolV2InstallItem[];
|
|
1133
1088
|
}): Promise<FirmwareUpdateV4MemoryHost> {
|
|
1089
|
+
const availableInstallItems = this.buildProtocolV2InstallItems({
|
|
1090
|
+
bootloaderBinary: this.prepareBootloaderBinary(),
|
|
1091
|
+
fwBinaryMap: this.collectExplicitTargetBinaries(),
|
|
1092
|
+
});
|
|
1134
1093
|
const requestedComponentTargets = new Set(
|
|
1135
1094
|
(this.params.targetsToUpdate ?? []).filter(
|
|
1136
1095
|
(target): target is Exclude<FirmwareUpdateV4Target, 'resource' | 'boot_resources'> =>
|
|
@@ -1558,15 +1517,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1558
1517
|
return sources;
|
|
1559
1518
|
}
|
|
1560
1519
|
|
|
1561
|
-
private async runProtocolV2PreparedArtifacts(
|
|
1562
|
-
features: Features,
|
|
1563
|
-
firmwareType: EFirmwareType,
|
|
1564
|
-
announceDownload = true
|
|
1565
|
-
) {
|
|
1520
|
+
private async runProtocolV2PreparedArtifacts(features: Features, firmwareType: EFirmwareType) {
|
|
1566
1521
|
try {
|
|
1567
|
-
|
|
1568
|
-
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
1569
|
-
}
|
|
1522
|
+
this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
|
|
1570
1523
|
const installSources = await this.prepareProtocolV2InstallSources(firmwareType, features);
|
|
1571
1524
|
const resourceSources = await this.prepareProtocolV2ResourceSources();
|
|
1572
1525
|
if (installSources.length === 0 && resourceSources.length === 0) {
|
|
@@ -1575,9 +1528,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1575
1528
|
'No firmware to update'
|
|
1576
1529
|
);
|
|
1577
1530
|
}
|
|
1578
|
-
|
|
1579
|
-
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
1580
|
-
}
|
|
1531
|
+
this.postTipMessage(FirmwareUpdateTipMessage.FinishDownloadFirmware);
|
|
1581
1532
|
|
|
1582
1533
|
return await this.executeProtocolV2SourceUpdate({
|
|
1583
1534
|
installSources,
|
|
@@ -1931,44 +1882,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
1931
1882
|
};
|
|
1932
1883
|
}
|
|
1933
1884
|
|
|
1934
|
-
private async downloadRemoteProtocolV2ResourceArchive(features: Features): Promise<ArrayBuffer> {
|
|
1935
|
-
const deviceType = getDeviceType(features);
|
|
1936
|
-
if (deviceType !== EDeviceType.Pro2 && deviceType !== EDeviceType.Neo) {
|
|
1937
|
-
throw ERRORS.TypedError(
|
|
1938
|
-
HardwareErrorCode.RuntimeError,
|
|
1939
|
-
'Protocol V2 resource archive requires a Pro2 or Neo device'
|
|
1940
|
-
);
|
|
1941
|
-
}
|
|
1942
|
-
const source = DataManager.getProtocolV2ResourceSource(deviceType);
|
|
1943
|
-
const expectedSha256 = normalizeProtocolV2Hex(source?.archiveSha256);
|
|
1944
|
-
if (
|
|
1945
|
-
!source?.archiveUrl ||
|
|
1946
|
-
!Number.isSafeInteger(source.archiveSize) ||
|
|
1947
|
-
source.archiveSize <= 0 ||
|
|
1948
|
-
source.archiveSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES ||
|
|
1949
|
-
!expectedSha256 ||
|
|
1950
|
-
!/^[0-9a-f]{64}$/u.test(expectedSha256)
|
|
1951
|
-
) {
|
|
1952
|
-
throw ERRORS.TypedError(
|
|
1953
|
-
HardwareErrorCode.RuntimeError,
|
|
1954
|
-
'Protocol V2 resource archive integrity metadata is invalid',
|
|
1955
|
-
{ firmwareUpdateCode: 'FirmwarePlanInvalid' }
|
|
1956
|
-
);
|
|
1957
|
-
}
|
|
1958
|
-
const { binary } = await getSysResourceBinary(source.archiveUrl);
|
|
1959
|
-
if (
|
|
1960
|
-
binary.byteLength !== source.archiveSize ||
|
|
1961
|
-
bytesToHex(sha256(new Uint8Array(binary))) !== expectedSha256
|
|
1962
|
-
) {
|
|
1963
|
-
throw ERRORS.TypedError(
|
|
1964
|
-
HardwareErrorCode.RuntimeError,
|
|
1965
|
-
'Protocol V2 resource archive does not match the remote config',
|
|
1966
|
-
{ firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
|
|
1967
|
-
);
|
|
1968
|
-
}
|
|
1969
|
-
return binary;
|
|
1970
|
-
}
|
|
1971
|
-
|
|
1972
1885
|
private async prepareRemoteProtocolV2Binaries(
|
|
1973
1886
|
firmwareType: EFirmwareType,
|
|
1974
1887
|
features: Features,
|
|
@@ -2154,12 +2067,21 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2154
2067
|
return this.device.features?.mode === 'romloader';
|
|
2155
2068
|
}
|
|
2156
2069
|
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2070
|
+
async enterProtocolV2BootloaderMode() {
|
|
2071
|
+
// romloader is the first update environment and forwards targets to bootloader.
|
|
2072
|
+
// It rejects DeviceRebootType.Bootloader, so reuse the current connection.
|
|
2073
|
+
if (this.isProtocolV2RomloaderMode()) {
|
|
2074
|
+
Log.debug('Protocol V2 device is in romloader mode; start firmware update directly');
|
|
2075
|
+
this.protocolV2ExecutionInLoader = true;
|
|
2076
|
+
return false;
|
|
2077
|
+
}
|
|
2078
|
+
if (this.isProtocolV2BootloaderMode()) {
|
|
2079
|
+
Log.debug('Protocol V2 device is already in bootloader mode, skip reboot');
|
|
2080
|
+
this.protocolV2ExecutionInLoader = true;
|
|
2081
|
+
this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
2082
|
+
return false;
|
|
2083
|
+
}
|
|
2161
2084
|
|
|
2162
|
-
private async rebootProtocolV2ToBootloader() {
|
|
2163
2085
|
try {
|
|
2164
2086
|
this.postTipMessage(FirmwareUpdateTipMessage.AutoRebootToBootloader);
|
|
2165
2087
|
await this.protocolV2Reboot(DeviceRebootType.Bootloader);
|
|
@@ -2177,27 +2099,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2177
2099
|
}
|
|
2178
2100
|
}
|
|
2179
2101
|
|
|
2180
|
-
async enterProtocolV2BootloaderMode() {
|
|
2181
|
-
this.protocolV2LegacyDirectUpdate = false;
|
|
2182
|
-
// romloader is the first update environment and forwards targets to bootloader.
|
|
2183
|
-
// It rejects DeviceRebootType.Bootloader, so reuse the current connection.
|
|
2184
|
-
if (this.isProtocolV2RomloaderMode()) {
|
|
2185
|
-
Log.debug('Protocol V2 device is in romloader mode; start firmware update directly');
|
|
2186
|
-
this.protocolV2LegacyDirectUpdate = this.isLegacyProtocolV2Runtime();
|
|
2187
|
-
this.protocolV2ExecutionInLoader = true;
|
|
2188
|
-
return false;
|
|
2189
|
-
}
|
|
2190
|
-
if (this.isProtocolV2BootloaderMode()) {
|
|
2191
|
-
Log.debug('Protocol V2 device is already in bootloader mode, skip reboot');
|
|
2192
|
-
this.protocolV2LegacyDirectUpdate = this.isLegacyProtocolV2Runtime();
|
|
2193
|
-
this.protocolV2ExecutionInLoader = true;
|
|
2194
|
-
this.postTipMessage(FirmwareUpdateTipMessage.GoToBootloaderSuccess);
|
|
2195
|
-
return false;
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
|
-
return this.rebootProtocolV2ToBootloader();
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
2102
|
private async waitForProtocolV2BootloaderMode(
|
|
2202
2103
|
timeout = PROTOCOL_V2_BOOTLOADER_RECONNECT_TIMEOUT,
|
|
2203
2104
|
retryInterval = 1000
|
|
@@ -2282,7 +2183,68 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2282
2183
|
return entries;
|
|
2283
2184
|
}
|
|
2284
2185
|
|
|
2285
|
-
private
|
|
2186
|
+
private buildProtocolV2ExecutionPhases({
|
|
2187
|
+
installSources,
|
|
2188
|
+
resourceSources,
|
|
2189
|
+
}: {
|
|
2190
|
+
installSources: ProtocolV2InstallSource[];
|
|
2191
|
+
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
2192
|
+
}): ProtocolV2ExecutionPhase[] {
|
|
2193
|
+
const phases: ProtocolV2ExecutionPhase[] = [];
|
|
2194
|
+
const bootResourceSources = resourceSources.filter(source =>
|
|
2195
|
+
isProtocolV2BootResourcePackagePath(source.devicePath)
|
|
2196
|
+
);
|
|
2197
|
+
const remainingResourceSources = resourceSources.filter(
|
|
2198
|
+
source => !isProtocolV2BootResourcePackagePath(source.devicePath)
|
|
2199
|
+
);
|
|
2200
|
+
// A previous interrupted run may have left a promotable staging file. Replace
|
|
2201
|
+
// it with the current approved package before any firmware-triggered reboot.
|
|
2202
|
+
if (bootResourceSources.length > 0) {
|
|
2203
|
+
phases.push({
|
|
2204
|
+
kind: 'resource-sync',
|
|
2205
|
+
installSources: [],
|
|
2206
|
+
resourceSources: bootResourceSources,
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
const bootloaderSources = installSources.filter(source => source.kind === 'bootloader');
|
|
2210
|
+
if (bootloaderSources.length > 0) {
|
|
2211
|
+
phases.push(
|
|
2212
|
+
{
|
|
2213
|
+
kind: 'bootloader-install',
|
|
2214
|
+
installSources: bootloaderSources,
|
|
2215
|
+
resourceSources: [],
|
|
2216
|
+
},
|
|
2217
|
+
{
|
|
2218
|
+
kind: 'bootloader-verify',
|
|
2219
|
+
installSources: [],
|
|
2220
|
+
resourceSources: [],
|
|
2221
|
+
}
|
|
2222
|
+
);
|
|
2223
|
+
}
|
|
2224
|
+
if (remainingResourceSources.length > 0) {
|
|
2225
|
+
phases.push({
|
|
2226
|
+
kind: 'resource-sync',
|
|
2227
|
+
installSources: [],
|
|
2228
|
+
resourceSources: remainingResourceSources,
|
|
2229
|
+
});
|
|
2230
|
+
}
|
|
2231
|
+
const componentSources = installSources.filter(source => source.kind !== 'bootloader');
|
|
2232
|
+
if (componentSources.length > 0) {
|
|
2233
|
+
phases.push({
|
|
2234
|
+
kind: 'component-install',
|
|
2235
|
+
installSources: componentSources,
|
|
2236
|
+
resourceSources: [],
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
phases.push({
|
|
2240
|
+
kind: 'final-verify',
|
|
2241
|
+
installSources: [],
|
|
2242
|
+
resourceSources: [],
|
|
2243
|
+
});
|
|
2244
|
+
return phases;
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
private async executeProtocolV2Phases({
|
|
2286
2248
|
installSources,
|
|
2287
2249
|
resourceSources,
|
|
2288
2250
|
}: {
|
|
@@ -2290,22 +2252,38 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2290
2252
|
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
2291
2253
|
}) {
|
|
2292
2254
|
this.protocolV2BootResourceStagingSafe = false;
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2255
|
+
const phases = this.buildProtocolV2ExecutionPhases({
|
|
2256
|
+
installSources,
|
|
2257
|
+
resourceSources,
|
|
2258
|
+
});
|
|
2259
|
+
for (const phase of phases) {
|
|
2260
|
+
if (phase.kind === 'final-verify') {
|
|
2261
|
+
return this.completeProtocolV2FinalVerification();
|
|
2262
|
+
}
|
|
2263
|
+
if (phase.kind === 'resource-sync') {
|
|
2264
|
+
await this.enterProtocolV2BootloaderMode();
|
|
2265
|
+
if (
|
|
2266
|
+
!phase.resourceSources.some(source =>
|
|
2267
|
+
isProtocolV2BootResourcePackagePath(source.devicePath)
|
|
2268
|
+
)
|
|
2269
|
+
) {
|
|
2270
|
+
await this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
2271
|
+
}
|
|
2272
|
+
await this.executeProtocolV2TransferPhase(phase);
|
|
2273
|
+
} else if (phase.kind === 'bootloader-install' || phase.kind === 'component-install') {
|
|
2274
|
+
await this.enterProtocolV2BootloaderMode();
|
|
2275
|
+
await this.ensureProtocolV2BootResourceStagingIsEmpty();
|
|
2276
|
+
await this.executeProtocolV2TransferPhase(phase);
|
|
2277
|
+
await this.exitProtocolV2BootloaderToNormal();
|
|
2278
|
+
} else if (phase.kind === 'bootloader-verify') {
|
|
2279
|
+
await this.waitForProtocolV2FinalFeatures();
|
|
2280
|
+
this.assertExpectedProtocolV2Versions(['boot']);
|
|
2281
|
+
}
|
|
2307
2282
|
}
|
|
2308
|
-
|
|
2283
|
+
throw ERRORS.TypedError(
|
|
2284
|
+
HardwareErrorCode.RuntimeError,
|
|
2285
|
+
'Protocol V2 execution has no final verification phase'
|
|
2286
|
+
);
|
|
2309
2287
|
}
|
|
2310
2288
|
|
|
2311
2289
|
private async ensureProtocolV2BootResourceStagingIsEmpty() {
|
|
@@ -2337,6 +2315,19 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2337
2315
|
this.protocolV2BootResourceStagingSafe = true;
|
|
2338
2316
|
}
|
|
2339
2317
|
|
|
2318
|
+
private async executeProtocolV2SourceUpdate({
|
|
2319
|
+
installSources,
|
|
2320
|
+
resourceSources,
|
|
2321
|
+
}: {
|
|
2322
|
+
installSources: ProtocolV2InstallSource[];
|
|
2323
|
+
resourceSources: ProtocolV2ResourceBundleSource[];
|
|
2324
|
+
}) {
|
|
2325
|
+
return this.executeProtocolV2Phases({
|
|
2326
|
+
installSources,
|
|
2327
|
+
resourceSources,
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2330
|
+
|
|
2340
2331
|
private async executeProtocolV2Update({
|
|
2341
2332
|
fwBinaryMap,
|
|
2342
2333
|
bootloaderBinary,
|
|
@@ -2361,7 +2352,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2361
2352
|
kind: item.kind,
|
|
2362
2353
|
}))
|
|
2363
2354
|
);
|
|
2364
|
-
return await this.
|
|
2355
|
+
return await this.executeProtocolV2Phases({
|
|
2365
2356
|
installSources,
|
|
2366
2357
|
resourceSources: [],
|
|
2367
2358
|
});
|
|
@@ -2373,7 +2364,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2373
2364
|
private async executeProtocolV2TransferPhase({
|
|
2374
2365
|
installSources,
|
|
2375
2366
|
resourceSources,
|
|
2376
|
-
}:
|
|
2367
|
+
}: ProtocolV2ExecutionPhase) {
|
|
2377
2368
|
let totalSize = installSources.reduce((total, item) => total + item.source.size, 0);
|
|
2378
2369
|
const resourcesToSync: ProtocolV2ResourceBundleSource[] = [];
|
|
2379
2370
|
for (const resource of resourceSources) {
|
|
@@ -2646,47 +2637,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2646
2637
|
return Array.from(expectedTargetIds).filter(targetId => !reportedTargetIds.has(targetId));
|
|
2647
2638
|
}
|
|
2648
2639
|
|
|
2649
|
-
private getProtocolV2ObservableTargetVersions(features: Features) {
|
|
2650
|
-
const versions = new Map<number, string>();
|
|
2651
|
-
versions.set(
|
|
2652
|
-
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER,
|
|
2653
|
-
getDeviceBootloaderVersion(features).join('.')
|
|
2654
|
-
);
|
|
2655
|
-
const applicationVersion = getDeviceFirmwareVersion(features).join('.');
|
|
2656
|
-
versions.set(ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, applicationVersion);
|
|
2657
|
-
versions.set(ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P2, applicationVersion);
|
|
2658
|
-
versions.set(
|
|
2659
|
-
ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_COPROCESSOR,
|
|
2660
|
-
getDeviceBLEFirmwareVersion(features).join('.')
|
|
2661
|
-
);
|
|
2662
|
-
const secureElementVersions: Array<[number, string | null | undefined]> = [
|
|
2663
|
-
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE01, features.se01Version],
|
|
2664
|
-
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE02, features.se02Version],
|
|
2665
|
-
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, features.se03Version],
|
|
2666
|
-
[ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, features.se04Version],
|
|
2667
|
-
];
|
|
2668
|
-
secureElementVersions.forEach(([targetId, version]) => {
|
|
2669
|
-
if (version) versions.set(targetId, version);
|
|
2670
|
-
});
|
|
2671
|
-
return versions;
|
|
2672
|
-
}
|
|
2673
|
-
|
|
2674
|
-
private hasProtocolV2InstallVersionChanged(expectedTargetIds: Set<number>) {
|
|
2675
|
-
if (!this.protocolV2LastRuntimeProbeFeatures) return false;
|
|
2676
|
-
const currentVersions = this.getProtocolV2ObservableTargetVersions(
|
|
2677
|
-
this.protocolV2LastRuntimeProbeFeatures
|
|
2678
|
-
);
|
|
2679
|
-
return Array.from(expectedTargetIds).some(targetId => {
|
|
2680
|
-
const previousVersion = this.protocolV2InstallBaselineVersions.get(targetId);
|
|
2681
|
-
const currentVersion = currentVersions.get(targetId);
|
|
2682
|
-
return (
|
|
2683
|
-
previousVersion !== undefined &&
|
|
2684
|
-
currentVersion !== undefined &&
|
|
2685
|
-
previousVersion !== currentVersion
|
|
2686
|
-
);
|
|
2687
|
-
});
|
|
2688
|
-
}
|
|
2689
|
-
|
|
2690
2640
|
private async waitForProtocolV2FirmwareUpdateComplete(
|
|
2691
2641
|
targets: Array<{ target_id: number; path: string }>
|
|
2692
2642
|
) {
|
|
@@ -2699,17 +2649,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2699
2649
|
let deviceInfo: ProtocolV2DeviceInfo | undefined;
|
|
2700
2650
|
let missingTargetStatusSince: number | undefined;
|
|
2701
2651
|
let missingTargetStatusKey: string | undefined;
|
|
2702
|
-
let normalModeWithoutInstallEvidenceSince: number | undefined;
|
|
2703
|
-
let installEvidenceObserved = this.protocolV2InstallAckReceived;
|
|
2704
2652
|
const resetMissingTargetStatusGrace = () => {
|
|
2705
2653
|
missingTargetStatusSince = undefined;
|
|
2706
2654
|
missingTargetStatusKey = undefined;
|
|
2707
2655
|
};
|
|
2708
2656
|
|
|
2709
2657
|
while (Date.now() - startTime < PROTOCOL_V2_INSTALL_TIMEOUT) {
|
|
2710
|
-
// A transport release caused by an explicit workflow cancellation must not
|
|
2711
|
-
// be mistaken for the expected device reboot during installation.
|
|
2712
|
-
this.throwIfAborted();
|
|
2713
2658
|
try {
|
|
2714
2659
|
if (shouldReconnect) {
|
|
2715
2660
|
await this.reconnectProtocolV2Device();
|
|
@@ -2732,33 +2677,21 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2732
2677
|
);
|
|
2733
2678
|
const statusTargets = (statusResponse.message.records ??
|
|
2734
2679
|
[]) as ProtocolV2FirmwareUpdateStatusTarget[];
|
|
2735
|
-
if (
|
|
2736
|
-
statusTargets.some(target => {
|
|
2737
|
-
const targetId = normalizeProtocolV2TargetId(target.target_id);
|
|
2738
|
-
return targetId !== undefined && expectedTargetIds.has(targetId);
|
|
2739
|
-
})
|
|
2740
|
-
) {
|
|
2741
|
-
installEvidenceObserved = true;
|
|
2742
|
-
normalModeWithoutInstallEvidenceSince = undefined;
|
|
2743
|
-
}
|
|
2744
2680
|
if (this.assertProtocolV2TargetStatus(statusTargets, expectedTargetIds, expectedPaths)) {
|
|
2745
2681
|
this.protocolV2FinalStatusVerified = true;
|
|
2746
2682
|
return;
|
|
2747
2683
|
}
|
|
2748
2684
|
|
|
2749
|
-
if (
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
this.postProgressMessage(100, 'installingFirmware');
|
|
2760
|
-
return;
|
|
2761
|
-
}
|
|
2685
|
+
if (
|
|
2686
|
+
statusTargets.length === 0 &&
|
|
2687
|
+
currentDeviceInfo &&
|
|
2688
|
+
(await this.probeProtocolV2NormalMode(currentDeviceInfo))
|
|
2689
|
+
) {
|
|
2690
|
+
Log.log(
|
|
2691
|
+
'[FirmwareUpdateV4] empty firmware status after confirmed App reboot; update complete'
|
|
2692
|
+
);
|
|
2693
|
+
this.postProgressMessage(100, 'installingFirmware');
|
|
2694
|
+
return;
|
|
2762
2695
|
}
|
|
2763
2696
|
|
|
2764
2697
|
const missingTargetIds = this.getProtocolV2MissingTargetIds(
|
|
@@ -2808,39 +2741,16 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2808
2741
|
'Protocol V2 device identity is unavailable during install polling'
|
|
2809
2742
|
);
|
|
2810
2743
|
}
|
|
2811
|
-
|
|
2812
|
-
if (
|
|
2813
|
-
isNormalMode &&
|
|
2814
|
-
(installEvidenceObserved ||
|
|
2815
|
-
this.hasProtocolV2InstallVersionChanged(expectedTargetIds))
|
|
2816
|
-
) {
|
|
2744
|
+
if (await this.probeProtocolV2NormalMode(currentDeviceInfo)) {
|
|
2817
2745
|
Log.log(
|
|
2818
2746
|
'[FirmwareUpdateV4] firmware status endpoint unavailable after confirmed App reboot'
|
|
2819
2747
|
);
|
|
2820
2748
|
this.postProgressMessage(100, 'installingFirmware');
|
|
2821
2749
|
return;
|
|
2822
2750
|
}
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
if (
|
|
2827
|
-
now - normalModeWithoutInstallEvidenceSince >=
|
|
2828
|
-
PROTOCOL_V2_MISSING_TARGET_STATUS_GRACE_TIMEOUT
|
|
2829
|
-
) {
|
|
2830
|
-
throw ERRORS.TypedError(
|
|
2831
|
-
HardwareErrorCode.FirmwareError,
|
|
2832
|
-
'Protocol V2 device returned to normal mode without install ACK, target status, or version change'
|
|
2833
|
-
);
|
|
2834
|
-
}
|
|
2835
|
-
lastError = new Error(
|
|
2836
|
-
'Protocol V2 device is in normal mode but installation is not yet confirmed'
|
|
2837
|
-
);
|
|
2838
|
-
} else {
|
|
2839
|
-
normalModeWithoutInstallEvidenceSince = undefined;
|
|
2840
|
-
lastError = new Error(
|
|
2841
|
-
'Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode'
|
|
2842
|
-
);
|
|
2843
|
-
}
|
|
2751
|
+
lastError = new Error(
|
|
2752
|
+
'Protocol V2 firmware status endpoint is unavailable while the device remains in loader mode'
|
|
2753
|
+
);
|
|
2844
2754
|
} else {
|
|
2845
2755
|
shouldReconnect = true;
|
|
2846
2756
|
deviceInfo = undefined;
|
|
@@ -2901,7 +2811,6 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
2901
2811
|
deviceInfo,
|
|
2902
2812
|
PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT
|
|
2903
2813
|
);
|
|
2904
|
-
this.protocolV2LastRuntimeProbeFeatures = features;
|
|
2905
2814
|
return features.mode === 'normal' && !features.bootloaderMode;
|
|
2906
2815
|
}
|
|
2907
2816
|
|
|
@@ -3134,62 +3043,15 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
|
|
|
3134
3043
|
}: {
|
|
3135
3044
|
targets: Array<{ target_id: number; path: string }>;
|
|
3136
3045
|
}) {
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
{ timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT }
|
|
3147
|
-
);
|
|
3148
|
-
let response: ProtocolV2FirmwareUpdateStartResponse | undefined;
|
|
3149
|
-
try {
|
|
3150
|
-
response = await startUpdate();
|
|
3151
|
-
this.protocolV2InstallAckReceived = true;
|
|
3152
|
-
} catch (error) {
|
|
3153
|
-
if (this.isBleReconnect() && isProtocolV2BleTransportReleasedError(error)) {
|
|
3154
|
-
this.throwIfAborted();
|
|
3155
|
-
// Installation can reboot the device before the Success response reaches
|
|
3156
|
-
// the host. The request has side effects, so do not replay it; reconnect
|
|
3157
|
-
// and let status polling determine whether installation was accepted.
|
|
3158
|
-
Log.log(
|
|
3159
|
-
'[FirmwareUpdateV4] install request interrupted by device reboot; continue status polling: ',
|
|
3160
|
-
error
|
|
3161
|
-
);
|
|
3162
|
-
} else if (
|
|
3163
|
-
this.protocolV2LegacyDirectUpdate &&
|
|
3164
|
-
isProtocolV2FirmwareUpdateEndpointUnavailable(error)
|
|
3165
|
-
) {
|
|
3166
|
-
// Both legacy loaders register this request. A missing handler therefore identifies
|
|
3167
|
-
// a legacy App before dispatch, so it is safe to reboot and retry the unhandled request.
|
|
3168
|
-
this.protocolV2LegacyDirectUpdate = false;
|
|
3169
|
-
Log.debug(
|
|
3170
|
-
'[FirmwareUpdateV4] legacy App does not expose DeviceFirmwareUpdateRequest; rebooting to bootloader'
|
|
3171
|
-
);
|
|
3172
|
-
await this.rebootProtocolV2ToBootloader();
|
|
3173
|
-
try {
|
|
3174
|
-
response = await startUpdate();
|
|
3175
|
-
this.protocolV2InstallAckReceived = true;
|
|
3176
|
-
} catch (retryError) {
|
|
3177
|
-
if (!(this.isBleReconnect() && isProtocolV2BleTransportReleasedError(retryError))) {
|
|
3178
|
-
throw retryError;
|
|
3179
|
-
}
|
|
3180
|
-
this.throwIfAborted();
|
|
3181
|
-
Log.log(
|
|
3182
|
-
'[FirmwareUpdateV4] install request interrupted after legacy reboot; continue status polling: ',
|
|
3183
|
-
retryError
|
|
3184
|
-
);
|
|
3185
|
-
}
|
|
3186
|
-
} else {
|
|
3187
|
-
throw error;
|
|
3188
|
-
}
|
|
3189
|
-
}
|
|
3190
|
-
this.protocolV2LegacyDirectUpdate = false;
|
|
3191
|
-
// A Success ACK or an install-time disconnect both end confirmation. In the
|
|
3192
|
-
// latter case only status polling may establish the final outcome.
|
|
3046
|
+
const commands = this.device.getCommands();
|
|
3047
|
+
const response: ProtocolV2FirmwareUpdateStartResponse = await commands.typedCall(
|
|
3048
|
+
'DeviceFirmwareUpdateRequest',
|
|
3049
|
+
'Success',
|
|
3050
|
+
{ targets },
|
|
3051
|
+
{ timeoutMs: PROTOCOL_V2_START_UPDATE_TIMEOUT }
|
|
3052
|
+
);
|
|
3053
|
+
// Success acknowledges that the device accepted installation. End confirmation
|
|
3054
|
+
// and begin status polling only after receiving this ACK.
|
|
3193
3055
|
this.postTipMessage(FirmwareUpdateTipMessage.FirmwareUpdating);
|
|
3194
3056
|
this.postProgressMessage(0, 'installingFirmware');
|
|
3195
3057
|
return response;
|