@onekeyfe/hd-core 1.2.0-alpha.54 → 1.2.0-alpha.56
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__/AllNetworkGetAddressBase.tracing.test.ts +231 -0
- package/__tests__/DeviceCommands.test.ts +45 -0
- package/__tests__/DeviceEventRegistration.test.ts +6 -0
- package/__tests__/check-all-firmware-release-protocol-v2.test.ts +198 -3
- package/__tests__/connectSettings.test.ts +5 -47
- package/__tests__/device-lifecycle-events.test.ts +105 -3
- package/__tests__/device-state-contract.test.ts +1 -0
- package/__tests__/device-state-mapper.test.ts +1 -1
- package/__tests__/deviceSettings.test.ts +1 -1
- package/__tests__/deviceUploadNft.test.ts +293 -0
- package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
- package/__tests__/get-device-state.test.ts +132 -12
- package/__tests__/homescreen.test.ts +41 -1
- package/__tests__/kaspaSignTransaction.test.ts +3 -26
- package/__tests__/logBlockEvent.test.ts +1 -1
- package/__tests__/method-protocol-support.test.ts +19 -0
- package/__tests__/open-wallet-session.test.ts +568 -37
- package/__tests__/pro2Nft.test.ts +108 -0
- package/__tests__/protocol-binding.test.ts +89 -0
- package/__tests__/protocol-v2-resources.test.ts +286 -0
- package/__tests__/protocol-v2-ui-lifecycle.test.ts +91 -0
- package/__tests__/protocol-v2-unlock-policy.test.ts +201 -35
- package/__tests__/protocol-v2.test.ts +1353 -1011
- package/__tests__/protocolV2FileWrite.test.ts +39 -0
- package/__tests__/protocolV2UiInteraction.test.ts +63 -0
- package/__tests__/public-pro2-api-boundary.test.ts +1 -0
- package/__tests__/search-devices.test.ts +12 -3
- package/__tests__/uiProgressThrottle.test.ts +74 -0
- package/__tests__/uiPromiseRegistry.test.ts +86 -0
- package/dist/api/BaseMethod.d.ts +3 -1
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
- package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
- package/dist/api/DetectDeviceConnectProtocol.d.ts +7 -0
- package/dist/api/DetectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/api/FirmwareUpdate.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV2.d.ts +0 -11
- package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV3.d.ts +3 -7
- package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
- package/dist/api/FirmwareUpdateV4.d.ts +11 -25
- package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
- package/dist/api/GetPassphraseState.d.ts.map +1 -1
- package/dist/api/OpenWalletSession.d.ts.map +1 -1
- package/dist/api/SearchDevices.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
- package/dist/api/device/DeviceUnlock.d.ts +2 -2
- package/dist/api/device/DeviceUnlock.d.ts.map +1 -1
- package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
- package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -9
- package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
- package/dist/api/firmware/getBinary.d.ts +0 -7
- package/dist/api/firmware/getBinary.d.ts.map +1 -1
- package/dist/api/firmware/updateBootloader.d.ts +0 -2
- package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
- package/dist/api/firmware/uploadFirmware.d.ts +1 -9
- package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
- package/dist/api/helpers/protocolV2FileWrite.d.ts +2 -0
- package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/kaspa/KaspaSignTransaction.d.ts.map +1 -1
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts +31 -0
- package/dist/api/protocol-v2/DeviceUploadNft.d.ts.map +1 -0
- package/dist/api/protocol-v2/ProtocolInfoRequest.d.ts.map +1 -1
- package/dist/api/protocol-v2/helpers.d.ts.map +1 -1
- package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
- package/dist/core/deviceEventRegistration.d.ts +2 -0
- package/dist/core/deviceEventRegistration.d.ts.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/uiPromiseRegistry.d.ts +4 -0
- package/dist/core/uiPromiseRegistry.d.ts.map +1 -0
- package/dist/data-manager/DataManager.d.ts +4 -2
- package/dist/data-manager/DataManager.d.ts.map +1 -1
- package/dist/data-manager/connectSettings.d.ts.map +1 -1
- package/dist/device/Device.d.ts +29 -6
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/device/DeviceCommands.d.ts +4 -4
- package/dist/device/DeviceCommands.d.ts.map +1 -1
- package/dist/device/DevicePool.d.ts.map +1 -1
- package/dist/events/device.d.ts +4 -0
- package/dist/events/device.d.ts.map +1 -1
- package/dist/events/logBlockEvent.d.ts.map +1 -1
- package/dist/events/ui-promise.d.ts +4 -2
- package/dist/events/ui-promise.d.ts.map +1 -1
- package/dist/events/ui-request.d.ts +31 -2
- package/dist/events/ui-request.d.ts.map +1 -1
- package/dist/events/ui-response.d.ts +10 -2
- package/dist/events/ui-response.d.ts.map +1 -1
- package/dist/index.d.ts +214 -231
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2634 -3530
- package/dist/inject.d.ts +6 -1
- package/dist/inject.d.ts.map +1 -1
- package/dist/lowLevelInject.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/features.d.ts +0 -4
- package/dist/protocols/protocol-v2/features.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/resources.d.ts +30 -0
- package/dist/protocols/protocol-v2/resources.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/uiInteraction.d.ts +7 -4
- package/dist/protocols/protocol-v2/uiInteraction.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts +1 -3
- package/dist/protocols/protocol-v2/unlockPolicy.d.ts.map +1 -1
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts +22 -0
- package/dist/protocols/protocol-v2/unlockPolicyRunner.d.ts.map +1 -0
- package/dist/protocols/protocol-v2/walletSession.d.ts +6 -1
- package/dist/protocols/protocol-v2/walletSession.d.ts.map +1 -1
- package/dist/topLevelInject.d.ts.map +1 -1
- package/dist/types/api/checkAllFirmwareRelease.d.ts +2 -4
- package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
- package/dist/types/api/detectDeviceConnectProtocol.d.ts +4 -0
- package/dist/types/api/detectDeviceConnectProtocol.d.ts.map +1 -0
- package/dist/types/api/deviceUnlock.d.ts +5 -1
- package/dist/types/api/deviceUnlock.d.ts.map +1 -1
- package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
- package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
- package/dist/types/api/export.d.ts +2 -4
- package/dist/types/api/export.d.ts.map +1 -1
- package/dist/types/api/firmwareUpdate.d.ts +2 -70
- package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +7 -10
- package/dist/types/api/index.d.ts.map +1 -1
- package/dist/types/api/protocolV2.d.ts +3 -0
- package/dist/types/api/protocolV2.d.ts.map +1 -1
- package/dist/types/device.d.ts.map +1 -1
- package/dist/types/params.d.ts +1 -0
- package/dist/types/params.d.ts.map +1 -1
- package/dist/types/settings.d.ts +22 -13
- package/dist/types/settings.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
- package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
- package/dist/utils/deviceFeaturesUtils.d.ts +4 -0
- package/dist/utils/deviceFeaturesUtils.d.ts.map +1 -1
- package/dist/utils/homescreen.d.ts +4 -0
- package/dist/utils/homescreen.d.ts.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/patch.d.ts +1 -1
- package/dist/utils/patch.d.ts.map +1 -1
- package/dist/utils/pro2Nft.d.ts +31 -0
- package/dist/utils/pro2Nft.d.ts.map +1 -0
- package/dist/utils/pro2Wallpaper.d.ts +10 -0
- package/dist/utils/pro2Wallpaper.d.ts.map +1 -1
- package/dist/utils/uiProgressThrottle.d.ts +3 -0
- package/dist/utils/uiProgressThrottle.d.ts.map +1 -0
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +8 -10
- package/src/api/CheckAllFirmwareRelease.ts +54 -57
- package/src/api/DetectDeviceConnectProtocol.ts +18 -0
- package/src/api/FirmwareUpdate.ts +7 -15
- package/src/api/FirmwareUpdateV2.ts +126 -316
- package/src/api/FirmwareUpdateV3.ts +63 -265
- package/src/api/FirmwareUpdateV4.ts +584 -975
- package/src/api/GetPassphraseState.ts +7 -1
- package/src/api/OpenWalletSession.ts +70 -17
- package/src/api/SearchDevices.ts +3 -1
- package/src/api/allnetwork/AllNetworkGetAddress.ts +21 -21
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +34 -11
- package/src/api/device/DeviceUnlock.ts +8 -3
- package/src/api/device/DeviceUpdateBootloader.ts +6 -122
- package/src/api/firmware/FirmwareUpdateBaseMethod.ts +16 -83
- package/src/api/firmware/updateBootloader.ts +4 -19
- package/src/api/firmware/uploadFirmware.ts +39 -144
- package/src/api/helpers/protocolV2FileWrite.ts +27 -7
- package/src/api/index.ts +2 -0
- package/src/api/kaspa/KaspaSignTransaction.ts +1 -12
- package/src/api/protocol-v2/DeviceUploadNft.ts +189 -0
- package/src/api/protocol-v2/ProtocolInfoRequest.ts +3 -1
- package/src/api/protocol-v2/helpers.ts +1 -0
- package/src/core/deviceEventRegistration.ts +4 -0
- package/src/core/index.ts +167 -83
- package/src/core/uiPromiseRegistry.ts +41 -0
- package/src/data/messages/messages-protocol-v2.json +25 -0
- package/src/data-manager/DataManager.ts +71 -39
- package/src/data-manager/connectSettings.ts +0 -11
- package/src/device/Device.ts +259 -43
- package/src/device/DeviceCommands.ts +7 -1
- package/src/device/DevicePool.ts +7 -2
- package/src/events/device.ts +4 -0
- package/src/events/logBlockEvent.ts +1 -0
- package/src/events/ui-promise.ts +4 -2
- package/src/events/ui-request.ts +36 -2
- package/src/events/ui-response.ts +12 -2
- package/src/index.ts +0 -5
- package/src/inject.ts +60 -24
- package/src/lowLevelInject.ts +7 -8
- package/src/protocols/protocol-v2/features.ts +10 -7
- package/src/protocols/protocol-v2/firmware.ts +2 -0
- package/src/protocols/protocol-v2/resources.ts +359 -0
- package/src/protocols/protocol-v2/uiInteraction.ts +46 -6
- package/src/protocols/protocol-v2/unlockPolicy.ts +1 -105
- package/src/protocols/protocol-v2/unlockPolicyRunner.ts +118 -0
- package/src/protocols/protocol-v2/walletSession.ts +214 -36
- package/src/topLevelInject.ts +7 -8
- package/src/types/api/checkAllFirmwareRelease.ts +2 -4
- package/src/types/api/detectDeviceConnectProtocol.ts +6 -0
- package/src/types/api/deviceUnlock.ts +12 -1
- package/src/types/api/deviceUpdateBootloader.ts +0 -6
- package/src/types/api/export.ts +1 -18
- package/src/types/api/firmwareUpdate.ts +3 -76
- package/src/types/api/index.ts +13 -14
- package/src/types/api/protocolV2.ts +13 -0
- package/src/types/device.ts +3 -0
- package/src/types/params.ts +7 -1
- package/src/types/settings.ts +42 -13
- package/src/utils/deviceFeaturesCompat.ts +0 -6
- package/src/utils/deviceFeaturesUtils.ts +8 -0
- package/src/utils/homescreen.ts +32 -6
- package/src/utils/index.ts +6 -1
- package/src/utils/pro2Nft.ts +142 -0
- package/src/utils/pro2Wallpaper.ts +35 -8
- package/src/utils/uiProgressThrottle.ts +63 -0
- package/__tests__/device-initialize-timeout.test.ts +0 -56
- package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
- package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
- package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
- package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
- package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
- package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
- package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -294
- package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
- package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -213
- package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -58
- package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
- package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
- package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
- package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
- package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
- package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
- package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
- package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
- package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/dist/api/firmware/progressThrottle.d.ts +0 -3
- package/dist/api/firmware/progressThrottle.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/lockedError.d.ts +0 -2
- package/dist/protocols/protocol-v2/lockedError.d.ts.map +0 -1
- package/dist/protocols/protocol-v2/unlockRetry.d.ts +0 -10
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
- package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
- package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
- package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
- package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
- package/src/api/firmware/FirmwareHostBinding.ts +0 -100
- package/src/api/firmware/FirmwarePreparationError.ts +0 -12
- package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
- package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
- package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -415
- package/src/api/firmware/progressThrottle.ts +0 -44
- package/src/protocols/protocol-v2/lockedError.ts +0 -10
- package/src/protocols/protocol-v2/unlockRetry.ts +0 -109
- package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
- package/src/types/api/firmwareUpdatePlan.ts +0 -38
- package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
|
@@ -13,8 +13,6 @@ import { DeviceModelToTypes } from '../../types';
|
|
|
13
13
|
import { DataManager } from '../../data-manager';
|
|
14
14
|
import { BaseMethod } from '../BaseMethod';
|
|
15
15
|
import { DEVICE } from '../../events';
|
|
16
|
-
import { createFirmwareProgressThrottle } from './progressThrottle';
|
|
17
|
-
import { writeFirmwareByteSource } from './FirmwareArtifactSource';
|
|
18
16
|
|
|
19
17
|
import type {
|
|
20
18
|
IFirmwareUpdateProgressType,
|
|
@@ -25,22 +23,11 @@ import type { RebootType } from '@onekeyfe/hd-transport';
|
|
|
25
23
|
import type { Deferred } from '@onekeyfe/hd-shared';
|
|
26
24
|
import type { KnownDevice } from '../../types';
|
|
27
25
|
import type { TypedResponseMessage } from '../../device/DeviceCommands';
|
|
28
|
-
import type { FirmwareByteSource } from './FirmwareArtifactSource';
|
|
29
26
|
|
|
30
27
|
const Log = getLogger(LoggerNames.Method);
|
|
31
28
|
const SESSION_ERROR = 'session not found';
|
|
32
29
|
const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
|
|
33
30
|
|
|
34
|
-
/**
|
|
35
|
-
* Response timeout for each Initialize probe while polling a rebooting device over BLE.
|
|
36
|
-
* Overlap safety comes from the poll's in-flight guard, not from this value. Keep it
|
|
37
|
-
* well below the 30s reboot budget so several attempts fit: a probe written into the
|
|
38
|
-
* dying pre-reboot connection is never answered, and its timeout tears that stale link
|
|
39
|
-
* down so the next tick reconnects fresh. Raise it only if a device model is proven to
|
|
40
|
-
* answer bootloader Initialize slower than this on a fresh connection.
|
|
41
|
-
*/
|
|
42
|
-
export const BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS = 5000;
|
|
43
|
-
|
|
44
31
|
const isDeviceDisconnectedError = (error: unknown) => {
|
|
45
32
|
const message = error instanceof Error ? error.message : String(error ?? '');
|
|
46
33
|
return (
|
|
@@ -53,8 +40,6 @@ const isDeviceDisconnectedError = (error: unknown) => {
|
|
|
53
40
|
export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
54
41
|
checkPromise: Deferred<any> | null = null;
|
|
55
42
|
|
|
56
|
-
private shouldPostFirmwareProgress = createFirmwareProgressThrottle();
|
|
57
|
-
|
|
58
43
|
init(): void {}
|
|
59
44
|
|
|
60
45
|
run(): Promise<any> {
|
|
@@ -98,10 +83,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
98
83
|
* @param progress Post the percentage of the progress
|
|
99
84
|
*/
|
|
100
85
|
postProgressMessage = (progress: number, progressType: IFirmwareUpdateProgressType) => {
|
|
101
|
-
if (!this.shouldPostFirmwareProgress(progress, progressType)) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
86
|
this.postMessage(
|
|
106
87
|
createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
|
|
107
88
|
device: this.device.toMessageObject() as KnownDevice,
|
|
@@ -151,10 +132,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
151
132
|
this.checkPromise = createDeferred();
|
|
152
133
|
const env = DataManager.getSettings('env');
|
|
153
134
|
const isBleReconnect = connectId && DataManager.isBleConnect(env);
|
|
154
|
-
// Tracks the in-flight BLE probe so interval ticks never overlap: a superseded
|
|
155
|
-
// Initialize left pending on the V1 transport is exactly what later times out
|
|
156
|
-
// and used to tear down the connection mid-firmware-upload.
|
|
157
|
-
let bleProbeInFlight = false;
|
|
158
135
|
|
|
159
136
|
Log.log('FirmwareUpdateBaseMethod [checkDeviceToBootloader] isBleReconnect: ', isBleReconnect);
|
|
160
137
|
|
|
@@ -210,18 +187,14 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
210
187
|
}
|
|
211
188
|
|
|
212
189
|
if (isBleReconnect) {
|
|
213
|
-
if (bleProbeInFlight) return;
|
|
214
|
-
bleProbeInFlight = true;
|
|
215
190
|
try {
|
|
216
191
|
await this.device.deviceConnector?.acquire(
|
|
217
192
|
this.device.originalDescriptor.id,
|
|
218
193
|
null,
|
|
219
|
-
true
|
|
194
|
+
true,
|
|
195
|
+
this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
|
|
220
196
|
);
|
|
221
|
-
|
|
222
|
-
// frees the slot for the next tick instead of hanging into the
|
|
223
|
-
// 30s reboot budget.
|
|
224
|
-
await this.device.initialize({ timeoutMs: BOOTLOADER_POLL_INITIALIZE_TIMEOUT_MS });
|
|
197
|
+
await this.device.initialize();
|
|
225
198
|
if (this.device.isBootloader()) {
|
|
226
199
|
clearInterval(intervalTimer);
|
|
227
200
|
this.checkPromise?.resolve(true);
|
|
@@ -229,8 +202,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
229
202
|
} catch (e) {
|
|
230
203
|
// ignore error because of device is not connected
|
|
231
204
|
Log.log('catch Bluetooth error when device is restarting: ', e);
|
|
232
|
-
} finally {
|
|
233
|
-
bleProbeInFlight = false;
|
|
234
205
|
}
|
|
235
206
|
} else {
|
|
236
207
|
await this._checkDeviceInBootloaderMode(connectId, intervalTimer, timeoutTimer);
|
|
@@ -255,7 +226,9 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
255
226
|
) {
|
|
256
227
|
const deviceDiff = await this.device.deviceConnector?.enumerate();
|
|
257
228
|
const devicesDescriptor = deviceDiff?.descriptors ?? [];
|
|
258
|
-
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId
|
|
229
|
+
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, connectId, {
|
|
230
|
+
connectProtocol: this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
|
|
231
|
+
});
|
|
259
232
|
|
|
260
233
|
if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
|
|
261
234
|
// should update current device from cache
|
|
@@ -410,54 +383,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
410
383
|
return totalSize !== undefined ? (processedSize ?? 0) + payload.byteLength : 0;
|
|
411
384
|
}
|
|
412
385
|
|
|
413
|
-
async emmcCommonUpdateProcessFromSource({
|
|
414
|
-
source,
|
|
415
|
-
filePath,
|
|
416
|
-
processedSize,
|
|
417
|
-
totalSize,
|
|
418
|
-
}: {
|
|
419
|
-
source: FirmwareByteSource;
|
|
420
|
-
filePath: string;
|
|
421
|
-
processedSize?: number;
|
|
422
|
-
totalSize?: number;
|
|
423
|
-
}) {
|
|
424
|
-
if (!filePath.startsWith('0:')) {
|
|
425
|
-
throw new Error('filePath must start with 0:');
|
|
426
|
-
}
|
|
427
|
-
const env = DataManager.getSettings('env');
|
|
428
|
-
const chunkSize = 1024 * (DataManager.isBleConnect(env) ? 16 : 128);
|
|
429
|
-
|
|
430
|
-
await writeFirmwareByteSource({
|
|
431
|
-
source,
|
|
432
|
-
chunkSize,
|
|
433
|
-
write: async ({ data, sourceOffset, length, first }) => {
|
|
434
|
-
const progress =
|
|
435
|
-
totalSize !== undefined && processedSize !== undefined
|
|
436
|
-
? Math.min(Math.ceil(((processedSize + sourceOffset + length) / totalSize) * 100), 99)
|
|
437
|
-
: Math.min(Math.ceil(((sourceOffset + length) / source.size) * 100), 99);
|
|
438
|
-
const writeRes = await this.emmcFileWriteWithRetry(
|
|
439
|
-
filePath,
|
|
440
|
-
length,
|
|
441
|
-
sourceOffset,
|
|
442
|
-
data,
|
|
443
|
-
first,
|
|
444
|
-
progress
|
|
445
|
-
);
|
|
446
|
-
if (!writeRes) {
|
|
447
|
-
throw ERRORS.TypedError(
|
|
448
|
-
HardwareErrorCode.EmmcFileWriteFirmwareError,
|
|
449
|
-
'transfer data error'
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
const processedBytes = Number(writeRes.message.processed_byte);
|
|
453
|
-
this.postProgressMessage(progress, 'transferData');
|
|
454
|
-
return Number.isFinite(processedBytes) ? processedBytes : length;
|
|
455
|
-
},
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
return totalSize !== undefined ? (processedSize ?? 0) + source.size : 0;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
386
|
async emmcFileWriteWithRetry(
|
|
462
387
|
filePath: string,
|
|
463
388
|
chunkLength: number,
|
|
@@ -512,7 +437,12 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
512
437
|
const env = DataManager.getSettings('env');
|
|
513
438
|
if (DataManager.isBleConnect(env)) {
|
|
514
439
|
await wait(3000);
|
|
515
|
-
await this.device.deviceConnector?.acquire(
|
|
440
|
+
await this.device.deviceConnector?.acquire(
|
|
441
|
+
this.device.originalDescriptor.id,
|
|
442
|
+
null,
|
|
443
|
+
true,
|
|
444
|
+
this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType
|
|
445
|
+
);
|
|
516
446
|
await this.device.initialize();
|
|
517
447
|
} else if (
|
|
518
448
|
error?.message?.indexOf(SESSION_ERROR) > -1 ||
|
|
@@ -520,7 +450,10 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
|
|
|
520
450
|
) {
|
|
521
451
|
const deviceDiff = await this.device.deviceConnector?.enumerate();
|
|
522
452
|
const devicesDescriptor = deviceDiff?.descriptors ?? [];
|
|
523
|
-
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined
|
|
453
|
+
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
|
|
454
|
+
connectProtocol:
|
|
455
|
+
this.payload.connectProtocol ?? this.device.originalDescriptor.protocolType,
|
|
456
|
+
});
|
|
524
457
|
if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
|
|
525
458
|
this.device.updateFromCache(deviceList[0]);
|
|
526
459
|
await this.device.acquire();
|
|
@@ -8,7 +8,6 @@ import { shouldUpdateBootloaderForClassicAndMini } from './bootloaderHelper';
|
|
|
8
8
|
|
|
9
9
|
import type { Features } from '../../types';
|
|
10
10
|
import type { EFirmwareType } from '@onekeyfe/hd-shared';
|
|
11
|
-
import type { FirmwareByteSource } from './FirmwareArtifactSource';
|
|
12
11
|
|
|
13
12
|
export function checkNeedUpdateBootForTouch(features: Features, firmwareType: EFirmwareType) {
|
|
14
13
|
const deviceType = getDeviceType(features);
|
|
@@ -63,7 +62,8 @@ export function checkNeedUpdateBootForClassicAndMini({
|
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
const INIT_DATA_CHUNK_SIZE = 16 * 1024;
|
|
66
|
-
|
|
65
|
+
export function checkBootloaderLength(data: ArrayBuffer) {
|
|
66
|
+
const chunk = new Uint8Array(data.slice(0, Math.min(INIT_DATA_CHUNK_SIZE, data.byteLength)));
|
|
67
67
|
const buffer = ByteBuffer.wrap(chunk, undefined, undefined, true);
|
|
68
68
|
buffer.LE();
|
|
69
69
|
// byte 'O', 'K', 'T', 'B'
|
|
@@ -77,21 +77,6 @@ const readBootloaderLength = (chunk: Uint8Array) => {
|
|
|
77
77
|
buffer.readUint32();
|
|
78
78
|
// codelen
|
|
79
79
|
const codelen = buffer.readUint32();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
export function checkBootloaderLength(data: ArrayBuffer) {
|
|
84
|
-
if (data.byteLength < 16) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
const chunk = new Uint8Array(data.slice(0, Math.min(INIT_DATA_CHUNK_SIZE, data.byteLength)));
|
|
88
|
-
return readBootloaderLength(chunk) === data.byteLength;
|
|
80
|
+
const bootloaderLength = hdrlen + codelen;
|
|
81
|
+
return bootloaderLength === data.byteLength;
|
|
89
82
|
}
|
|
90
|
-
|
|
91
|
-
export const checkBootloaderSourceLength = async (source: FirmwareByteSource) => {
|
|
92
|
-
if (source.size < 16) {
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
const chunk = new Uint8Array(await source.readAt(0, Math.min(INIT_DATA_CHUNK_SIZE, source.size)));
|
|
96
|
-
return readBootloaderLength(chunk) === source.size;
|
|
97
|
-
};
|
|
@@ -10,7 +10,6 @@ import { bytesToHex } from '../helpers/hexUtils';
|
|
|
10
10
|
import { DataManager } from '../../data-manager';
|
|
11
11
|
import { DevicePool } from '../../device/DevicePool';
|
|
12
12
|
import { buildProtocolV1FeaturesPayload } from '../../deviceProfile';
|
|
13
|
-
import { openFirmwareByteSource, readFirmwareByteSourceFully } from './FirmwareArtifactSource';
|
|
14
13
|
|
|
15
14
|
import type { KnownDevice } from '../../types';
|
|
16
15
|
import type { TypedCall, TypedResponseMessage } from '../../device/DeviceCommands';
|
|
@@ -18,7 +17,6 @@ import type { PROTO } from '../../constants';
|
|
|
18
17
|
import type { CoreMessage, IFirmwareUpdateProgressType } from '../../events';
|
|
19
18
|
import type { Success } from '@onekeyfe/hd-transport';
|
|
20
19
|
import type { Device } from '../../device/Device';
|
|
21
|
-
import type { FirmwareByteSource } from './FirmwareArtifactSource';
|
|
22
20
|
|
|
23
21
|
const NEW_BOOT_UPRATE_FIRMWARE_VERSION = '2.4.5';
|
|
24
22
|
const SESSION_ERROR = 'session not found';
|
|
@@ -90,20 +88,17 @@ export const waitBleInstall = async (updateType: string) => {
|
|
|
90
88
|
}
|
|
91
89
|
};
|
|
92
90
|
|
|
93
|
-
const
|
|
94
|
-
if (payload instanceof ArrayBuffer) {
|
|
95
|
-
return payload;
|
|
96
|
-
}
|
|
97
|
-
return new Uint8Array(payload.buffer, payload.byteOffset, payload.byteLength).slice().buffer;
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
export const uploadFirmwareFromSource = async (
|
|
91
|
+
export const uploadFirmware = async (
|
|
101
92
|
updateType: 'firmware' | 'ble',
|
|
102
93
|
typedCall: TypedCall,
|
|
103
94
|
postMessage: (message: CoreMessage) => void,
|
|
104
95
|
device: Device,
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
{
|
|
97
|
+
payload,
|
|
98
|
+
rebootOnSuccess,
|
|
99
|
+
}: PROTO.FirmwareUpload & {
|
|
100
|
+
rebootOnSuccess?: boolean;
|
|
101
|
+
},
|
|
107
102
|
isUpdateBootloader?: boolean
|
|
108
103
|
) => {
|
|
109
104
|
const deviceType = device.getCurrentDeviceType();
|
|
@@ -124,20 +119,20 @@ export const uploadFirmwareFromSource = async (
|
|
|
124
119
|
if (supportUpgradeFileHeader) {
|
|
125
120
|
// Extract and validate firmware header (first 1KB)
|
|
126
121
|
const HEADER_SIZE = 1024;
|
|
127
|
-
if (
|
|
122
|
+
if (payload.byteLength < HEADER_SIZE) {
|
|
128
123
|
throw ERRORS.TypedError(
|
|
129
124
|
HardwareErrorCode.RuntimeError,
|
|
130
|
-
`firmware payload too small: ${
|
|
125
|
+
`firmware payload too small: ${payload.byteLength} bytes, expected at least ${HEADER_SIZE} bytes`
|
|
131
126
|
);
|
|
132
127
|
}
|
|
133
128
|
|
|
134
129
|
Log.debug('Uploading firmware header:', {
|
|
135
130
|
size: HEADER_SIZE,
|
|
136
|
-
totalSize:
|
|
131
|
+
totalSize: payload.byteLength,
|
|
137
132
|
});
|
|
138
133
|
postProgressTip(device, 'UploadingFirmwareHeader', postMessage);
|
|
139
134
|
|
|
140
|
-
const header = new Uint8Array(
|
|
135
|
+
const header = new Uint8Array(payload.slice(0, HEADER_SIZE));
|
|
141
136
|
|
|
142
137
|
try {
|
|
143
138
|
const headerRes = await typedCall('UpgradeFileHeader', 'Success', {
|
|
@@ -174,9 +169,6 @@ export const uploadFirmwareFromSource = async (
|
|
|
174
169
|
postProgressMessage(device, 0, 'installingFirmware', postMessage);
|
|
175
170
|
let updateResponse: TypedResponseMessage<'Success'>;
|
|
176
171
|
try {
|
|
177
|
-
// Classic/Mini bootloaders accept one protobuf payload and do not expose
|
|
178
|
-
// a request-range protocol. Other device families remain fully streamed.
|
|
179
|
-
const payload = await readFirmwareByteSourceFully(source);
|
|
180
172
|
updateResponse = await typedCall('FirmwareUpload', 'Success', {
|
|
181
173
|
payload,
|
|
182
174
|
});
|
|
@@ -208,7 +200,9 @@ export const uploadFirmwareFromSource = async (
|
|
|
208
200
|
updateType,
|
|
209
201
|
postMessage,
|
|
210
202
|
device,
|
|
211
|
-
|
|
203
|
+
{
|
|
204
|
+
payload,
|
|
205
|
+
},
|
|
212
206
|
rebootOnSuccess
|
|
213
207
|
);
|
|
214
208
|
return response.message;
|
|
@@ -217,7 +211,7 @@ export const uploadFirmwareFromSource = async (
|
|
|
217
211
|
|
|
218
212
|
postConfirmationMessage(device);
|
|
219
213
|
postProgressTip(device, 'ConfirmOnDevice', postMessage);
|
|
220
|
-
const length =
|
|
214
|
+
const length = payload.byteLength;
|
|
221
215
|
|
|
222
216
|
let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
|
|
223
217
|
postProgressTip(device, 'FirmwareEraseSuccess', postMessage);
|
|
@@ -226,7 +220,7 @@ export const uploadFirmwareFromSource = async (
|
|
|
226
220
|
const start = response.message.offset!;
|
|
227
221
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
228
222
|
const end = response.message.offset! + response.message.length!;
|
|
229
|
-
const chunk =
|
|
223
|
+
const chunk = payload.slice(start, end);
|
|
230
224
|
|
|
231
225
|
if (start > 0) {
|
|
232
226
|
postProgressMessage(
|
|
@@ -255,45 +249,11 @@ export const uploadFirmwareFromSource = async (
|
|
|
255
249
|
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'uploadFirmware: unknown device model');
|
|
256
250
|
};
|
|
257
251
|
|
|
258
|
-
export const uploadFirmware = async (
|
|
259
|
-
updateType: 'firmware' | 'ble',
|
|
260
|
-
typedCall: TypedCall,
|
|
261
|
-
postMessage: (message: CoreMessage) => void,
|
|
262
|
-
device: Device,
|
|
263
|
-
{
|
|
264
|
-
payload,
|
|
265
|
-
rebootOnSuccess,
|
|
266
|
-
}: PROTO.FirmwareUpload & {
|
|
267
|
-
rebootOnSuccess?: boolean;
|
|
268
|
-
},
|
|
269
|
-
isUpdateBootloader?: boolean
|
|
270
|
-
) => {
|
|
271
|
-
const source = await openFirmwareByteSource({
|
|
272
|
-
binary: toArrayBuffer(payload),
|
|
273
|
-
});
|
|
274
|
-
if (!source) {
|
|
275
|
-
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'firmware payload is empty');
|
|
276
|
-
}
|
|
277
|
-
try {
|
|
278
|
-
return await uploadFirmwareFromSource(
|
|
279
|
-
updateType,
|
|
280
|
-
typedCall,
|
|
281
|
-
postMessage,
|
|
282
|
-
device,
|
|
283
|
-
source,
|
|
284
|
-
rebootOnSuccess,
|
|
285
|
-
isUpdateBootloader
|
|
286
|
-
);
|
|
287
|
-
} finally {
|
|
288
|
-
await source.close();
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
|
|
292
252
|
const newTouchUpdateProcess = async (
|
|
293
253
|
updateType: 'firmware' | 'ble',
|
|
294
254
|
postMessage: (message: CoreMessage) => void,
|
|
295
255
|
device: Device,
|
|
296
|
-
|
|
256
|
+
{ payload }: PROTO.FirmwareUpload,
|
|
297
257
|
rebootOnSuccess = true
|
|
298
258
|
) => {
|
|
299
259
|
let typedCall = device.getCommands().typedCall.bind(device.getCommands());
|
|
@@ -303,13 +263,13 @@ const newTouchUpdateProcess = async (
|
|
|
303
263
|
const env = DataManager.getSettings('env');
|
|
304
264
|
const perPackageSize = DataManager.isBleConnect(env) ? 16 : 128;
|
|
305
265
|
const chunkSize = 1024 * perPackageSize;
|
|
306
|
-
const totalChunks = Math.ceil(
|
|
266
|
+
const totalChunks = Math.ceil(payload.byteLength / chunkSize);
|
|
307
267
|
let offset = 0;
|
|
308
268
|
for (let i = 0; i < totalChunks; i++) {
|
|
309
269
|
const chunkStart = i * chunkSize;
|
|
310
|
-
const chunkEnd = Math.min(chunkStart + chunkSize,
|
|
270
|
+
const chunkEnd = Math.min(chunkStart + chunkSize, payload.byteLength);
|
|
311
271
|
const chunkLength = chunkEnd - chunkStart;
|
|
312
|
-
const chunk =
|
|
272
|
+
const chunk = payload.slice(chunkStart, chunkEnd);
|
|
313
273
|
const overwrite = i === 0;
|
|
314
274
|
const progress = Math.round(((i + 1) / totalChunks) * 100);
|
|
315
275
|
const writeRes = await emmcFileWriteWithRetry(
|
|
@@ -362,7 +322,12 @@ const newTouchUpdateProcess = async (
|
|
|
362
322
|
try {
|
|
363
323
|
if (isBleReconnect) {
|
|
364
324
|
try {
|
|
365
|
-
await device.deviceConnector?.acquire(
|
|
325
|
+
await device.deviceConnector?.acquire(
|
|
326
|
+
device.originalDescriptor.id,
|
|
327
|
+
null,
|
|
328
|
+
true,
|
|
329
|
+
device.originalDescriptor.protocolType
|
|
330
|
+
);
|
|
366
331
|
const typedCall = device.getCommands().typedCall.bind(device.getCommands());
|
|
367
332
|
await Promise.race([
|
|
368
333
|
typedCall('Initialize', 'Features', {}),
|
|
@@ -381,7 +346,8 @@ const newTouchUpdateProcess = async (
|
|
|
381
346
|
const devicesDescriptor = deviceDiff?.descriptors ?? [];
|
|
382
347
|
const { deviceList } = await DevicePool.getDevices(
|
|
383
348
|
devicesDescriptor,
|
|
384
|
-
device.originalDescriptor.id
|
|
349
|
+
device.originalDescriptor.id,
|
|
350
|
+
{ connectProtocol: device.originalDescriptor.protocolType }
|
|
385
351
|
);
|
|
386
352
|
if (deviceList.length === 1) {
|
|
387
353
|
device.updateFromCache(deviceList[0]);
|
|
@@ -456,7 +422,12 @@ const emmcFileWriteWithRetry = async (
|
|
|
456
422
|
const env = DataManager.getSettings('env');
|
|
457
423
|
if (DataManager.isBleConnect(env)) {
|
|
458
424
|
await wait(3000);
|
|
459
|
-
await device.deviceConnector?.acquire(
|
|
425
|
+
await device.deviceConnector?.acquire(
|
|
426
|
+
device.originalDescriptor.id,
|
|
427
|
+
null,
|
|
428
|
+
true,
|
|
429
|
+
device.originalDescriptor.protocolType
|
|
430
|
+
);
|
|
460
431
|
await device.initialize();
|
|
461
432
|
} else if (
|
|
462
433
|
error?.message?.indexOf(SESSION_ERROR) > -1 ||
|
|
@@ -464,7 +435,9 @@ const emmcFileWriteWithRetry = async (
|
|
|
464
435
|
) {
|
|
465
436
|
const deviceDiff = await device.deviceConnector?.enumerate();
|
|
466
437
|
const devicesDescriptor = deviceDiff?.descriptors ?? [];
|
|
467
|
-
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined
|
|
438
|
+
const { deviceList } = await DevicePool.getDevices(devicesDescriptor, undefined, {
|
|
439
|
+
connectProtocol: device.originalDescriptor.protocolType,
|
|
440
|
+
});
|
|
468
441
|
if (deviceList.length === 1 && deviceList[0]?.isBootloader()) {
|
|
469
442
|
device.updateFromCache(deviceList[0]);
|
|
470
443
|
await device.acquire();
|
|
@@ -530,67 +503,6 @@ export const updateResource = async (
|
|
|
530
503
|
return processResourceRequest(typedCall, res, data);
|
|
531
504
|
};
|
|
532
505
|
|
|
533
|
-
export const updateResourceFromSource = async (
|
|
534
|
-
typedCall: TypedCall,
|
|
535
|
-
fileName: string,
|
|
536
|
-
source: FirmwareByteSource,
|
|
537
|
-
onConfirmAfter?: () => void
|
|
538
|
-
) => {
|
|
539
|
-
const initialLength = Math.min(INIT_DATA_CHUNK_SIZE, source.size);
|
|
540
|
-
const initialChunk = new Uint8Array(await source.readAt(0, initialLength));
|
|
541
|
-
let response = await typedCall('ResourceUpdate', ['ResourceRequest', 'Success'], {
|
|
542
|
-
file_name: fileName,
|
|
543
|
-
data_length: source.size,
|
|
544
|
-
initial_data_chunk: bytesToHex(initialChunk),
|
|
545
|
-
hash: bytesToHex(blake2s(initialChunk)),
|
|
546
|
-
});
|
|
547
|
-
onConfirmAfter?.();
|
|
548
|
-
|
|
549
|
-
while (response.type !== 'Success') {
|
|
550
|
-
const { offset, data_length: dataLength } = response.message;
|
|
551
|
-
if (
|
|
552
|
-
!Number.isSafeInteger(offset) ||
|
|
553
|
-
offset === undefined ||
|
|
554
|
-
offset < 0 ||
|
|
555
|
-
!Number.isSafeInteger(dataLength) ||
|
|
556
|
-
dataLength === undefined ||
|
|
557
|
-
dataLength <= 0 ||
|
|
558
|
-
offset + dataLength > source.size
|
|
559
|
-
) {
|
|
560
|
-
throw ERRORS.TypedError(
|
|
561
|
-
HardwareErrorCode.RuntimeError,
|
|
562
|
-
'Device requested an invalid firmware resource range'
|
|
563
|
-
);
|
|
564
|
-
}
|
|
565
|
-
const chunk = new Uint8Array(await source.readAt(offset, dataLength));
|
|
566
|
-
response = await typedCall('ResourceAck', ['ResourceRequest', 'Success'], {
|
|
567
|
-
data_chunk: bytesToHex(chunk),
|
|
568
|
-
hash: bytesToHex(blake2s(chunk)),
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
return response.message;
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
export const updateResourcesFromSources = async (
|
|
575
|
-
typedCall: TypedCall,
|
|
576
|
-
postMessage: (message: CoreMessage) => void,
|
|
577
|
-
device: Device,
|
|
578
|
-
entries: ReadonlyArray<{ entryName: string; source: FirmwareByteSource }>
|
|
579
|
-
) => {
|
|
580
|
-
postProgressTip(device, 'UpdateSysResource', postMessage);
|
|
581
|
-
for (const [index, entry] of entries.entries()) {
|
|
582
|
-
await updateResourceFromSource(typedCall, entry.entryName, entry.source);
|
|
583
|
-
postProgressMessage(
|
|
584
|
-
device,
|
|
585
|
-
Math.floor(((index + 1) / entries.length) * 100),
|
|
586
|
-
'installingFirmware',
|
|
587
|
-
postMessage
|
|
588
|
-
);
|
|
589
|
-
}
|
|
590
|
-
postProgressTip(device, 'UpdateSysResourceSuccess', postMessage);
|
|
591
|
-
return true;
|
|
592
|
-
};
|
|
593
|
-
|
|
594
506
|
export const updateResources = async (
|
|
595
507
|
typedCall: TypedCall,
|
|
596
508
|
postMessage: (message: CoreMessage) => void,
|
|
@@ -625,28 +537,11 @@ export const updateBootloader = async (
|
|
|
625
537
|
typedCall: TypedCall,
|
|
626
538
|
postMessage: (message: CoreMessage) => void,
|
|
627
539
|
device: Device,
|
|
628
|
-
|
|
629
|
-
) => {
|
|
630
|
-
const source = await openFirmwareByteSource({ binary: data });
|
|
631
|
-
if (!source) {
|
|
632
|
-
throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'bootloader payload is empty');
|
|
633
|
-
}
|
|
634
|
-
try {
|
|
635
|
-
return await updateBootloaderFromSource(typedCall, postMessage, device, source);
|
|
636
|
-
} finally {
|
|
637
|
-
await source.close();
|
|
638
|
-
}
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
export const updateBootloaderFromSource = async (
|
|
642
|
-
typedCall: TypedCall,
|
|
643
|
-
postMessage: (message: CoreMessage) => void,
|
|
644
|
-
device: Device,
|
|
645
|
-
source: FirmwareByteSource
|
|
540
|
+
source: ArrayBuffer
|
|
646
541
|
) => {
|
|
647
542
|
postProgressTip(device, 'UpdateBootloader', postMessage);
|
|
648
543
|
postProgressMessage(device, Math.floor(0), 'installingFirmware', postMessage);
|
|
649
|
-
await
|
|
544
|
+
await updateResource(typedCall, 'bootloader.bin', source, () => {
|
|
650
545
|
postProcessingMessage('resource', postMessage);
|
|
651
546
|
});
|
|
652
547
|
postProgressMessage(device, Math.floor(100), 'installingFirmware', postMessage);
|
|
@@ -31,19 +31,22 @@ export type ProtocolV2FileWriteOptions = {
|
|
|
31
31
|
uiPercentage?: number;
|
|
32
32
|
timeoutMs?: number;
|
|
33
33
|
maxChunkRetries?: number;
|
|
34
|
+
paceMs?: number;
|
|
34
35
|
throwIfAborted?: () => void;
|
|
35
36
|
onProgress?: (progress: ProtocolV2FileWriteProgress) => void;
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
const MIN_FILE_CHUNK_SIZE = 64;
|
|
40
|
+
const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
|
|
39
41
|
|
|
40
|
-
function
|
|
42
|
+
export function isProtocolV2ResponseTimeout(error: unknown) {
|
|
41
43
|
if (!error || typeof error !== 'object') return false;
|
|
42
|
-
const candidate = error as { errorCode?: number; code?: number; message?: string };
|
|
44
|
+
const candidate = error as { errorCode?: number; code?: number | string; message?: string };
|
|
43
45
|
const code = candidate.errorCode ?? candidate.code;
|
|
44
46
|
return (
|
|
45
47
|
code === HardwareErrorCode.BleTimeoutError ||
|
|
46
|
-
|
|
48
|
+
code === 'response-timeout' ||
|
|
49
|
+
/(?:BLE|Lowlevel|Protocol V2) response timeout/i.test(candidate.message ?? '')
|
|
47
50
|
);
|
|
48
51
|
}
|
|
49
52
|
|
|
@@ -119,6 +122,9 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
119
122
|
let chunks = 0;
|
|
120
123
|
let lastMessage: Record<string, unknown> | undefined;
|
|
121
124
|
const startTime = Date.now();
|
|
125
|
+
let rateWindowStartedAt = startTime;
|
|
126
|
+
let rateWindowStartedBytes = 0;
|
|
127
|
+
let rateBytesPerSecond: number | undefined;
|
|
122
128
|
|
|
123
129
|
while (written < dataLength) {
|
|
124
130
|
options.throwIfAborted?.();
|
|
@@ -147,7 +153,7 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
147
153
|
);
|
|
148
154
|
isWritePending = false;
|
|
149
155
|
} catch (error) {
|
|
150
|
-
if (retryCount >= maxChunkRetries || !
|
|
156
|
+
if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
|
|
151
157
|
retryCount += 1;
|
|
152
158
|
options.throwIfAborted?.();
|
|
153
159
|
}
|
|
@@ -176,16 +182,30 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
|
|
|
176
182
|
written =
|
|
177
183
|
rawProcessedByte === undefined ? written + chunk.byteLength : processedByte - startOffset;
|
|
178
184
|
chunks += 1;
|
|
179
|
-
const
|
|
185
|
+
const now = Date.now();
|
|
186
|
+
const elapsedMs = now - startTime;
|
|
180
187
|
const transferredBytes = Math.min(written, dataLength);
|
|
188
|
+
const rateWindowElapsedMs = now - rateWindowStartedAt;
|
|
189
|
+
if (rateWindowElapsedMs >= FILE_TRANSFER_RATE_WINDOW_MS) {
|
|
190
|
+
const rateWindowBytes = Math.max(transferredBytes - rateWindowStartedBytes, 0);
|
|
191
|
+
rateBytesPerSecond = Math.round((rateWindowBytes / rateWindowElapsedMs) * 1000);
|
|
192
|
+
rateWindowStartedAt = now;
|
|
193
|
+
rateWindowStartedBytes = transferredBytes;
|
|
194
|
+
} else if (rateBytesPerSecond === undefined && elapsedMs > 0) {
|
|
195
|
+
rateBytesPerSecond = Math.round((transferredBytes / elapsedMs) * 1000);
|
|
196
|
+
}
|
|
181
197
|
options.onProgress?.({
|
|
182
198
|
progress: getConfirmedProgress(startOffset + written, totalSize, written, dataLength),
|
|
183
199
|
transferredBytes,
|
|
184
200
|
totalBytes: dataLength,
|
|
185
|
-
rateBytesPerSecond
|
|
186
|
-
elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
|
|
201
|
+
rateBytesPerSecond,
|
|
187
202
|
elapsedMs,
|
|
188
203
|
});
|
|
204
|
+
if (options.paceMs && options.paceMs > 0) {
|
|
205
|
+
await new Promise(resolve => {
|
|
206
|
+
setTimeout(resolve, options.paceMs);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
189
209
|
}
|
|
190
210
|
|
|
191
211
|
return {
|
package/src/api/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { default as testProtocolV2Ping } from './protocol-v2/Ping';
|
|
|
3
3
|
export { default as preInitialize } from './device/PreInitialize';
|
|
4
4
|
|
|
5
5
|
export { default as searchDevices } from './SearchDevices';
|
|
6
|
+
export { default as detectDeviceConnectProtocol } from './DetectDeviceConnectProtocol';
|
|
6
7
|
export { default as getFeatures } from './GetFeatures';
|
|
7
8
|
export { default as getDeviceState } from './GetDeviceState';
|
|
8
9
|
export { default as getOnekeyFeatures } from './GetOnekeyFeatures';
|
|
@@ -49,6 +50,7 @@ export { default as promptWebDeviceAccess } from './PromptWebDeviceAccess';
|
|
|
49
50
|
export { default as deviceReboot } from './protocol-v2/DeviceReboot';
|
|
50
51
|
export { default as deviceGetOnboardingStatus } from './protocol-v2/DeviceGetOnboardingStatus';
|
|
51
52
|
export { default as deviceUploadWallpaper } from './protocol-v2/DeviceUploadWallpaper';
|
|
53
|
+
export { default as deviceUploadNft } from './protocol-v2/DeviceUploadNft';
|
|
52
54
|
export { default as uploadPortfolio } from './UploadPortfolio';
|
|
53
55
|
|
|
54
56
|
export { default as cipherKeyValue } from './CipherKeyValue';
|
|
@@ -506,18 +506,7 @@ export default class KaspaSignTransaction extends BaseMethod<KaspaSignTransactio
|
|
|
506
506
|
'KaspaSignTransaction: device firmware uses the streaming protocol; every output requires address or addressN'
|
|
507
507
|
);
|
|
508
508
|
}
|
|
509
|
-
|
|
510
|
-
return await this.signTxStream(typedCall, response);
|
|
511
|
-
} catch (error) {
|
|
512
|
-
// Device rejected our refTxs; the caller decides whether to sign without them.
|
|
513
|
-
if (
|
|
514
|
-
error instanceof HardwareError &&
|
|
515
|
-
String(error.message).toLowerCase().includes('previous transaction id mismatch')
|
|
516
|
-
) {
|
|
517
|
-
throw ERRORS.TypedError(HardwareErrorCode.KaspaPrevTxIdMismatch, String(error.message));
|
|
518
|
-
}
|
|
519
|
-
throw error;
|
|
520
|
-
}
|
|
509
|
+
return this.signTxStream(typedCall, response);
|
|
521
510
|
}
|
|
522
511
|
|
|
523
512
|
// Legacy answer to a streaming-only packet: no prehash material exists.
|