@onekeyfe/hd-core 1.1.26 → 1.1.27-alpha.30

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.
Files changed (156) hide show
  1. package/__tests__/protocol-v2.test.ts +940 -0
  2. package/dist/api/BaseMethod.d.ts +1 -3
  3. package/dist/api/BaseMethod.d.ts.map +1 -1
  4. package/dist/api/DirList.d.ts +10 -0
  5. package/dist/api/DirList.d.ts.map +1 -0
  6. package/dist/api/DirMake.d.ts +9 -0
  7. package/dist/api/DirMake.d.ts.map +1 -0
  8. package/dist/api/DirRemove.d.ts +9 -0
  9. package/dist/api/DirRemove.d.ts.map +1 -0
  10. package/dist/api/FileDelete.d.ts +9 -0
  11. package/dist/api/FileDelete.d.ts.map +1 -0
  12. package/dist/api/FileRead.d.ts +19 -0
  13. package/dist/api/FileRead.d.ts.map +1 -0
  14. package/dist/api/FileWrite.d.ts +23 -0
  15. package/dist/api/FileWrite.d.ts.map +1 -0
  16. package/dist/api/FirmwareUpdateV3.d.ts +1 -0
  17. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  18. package/dist/api/FirmwareUpdateV4.d.ts +32 -0
  19. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -0
  20. package/dist/api/GetOnekeyFeatures.d.ts.map +1 -1
  21. package/dist/api/PathInfo.d.ts +9 -0
  22. package/dist/api/PathInfo.d.ts.map +1 -0
  23. package/dist/api/SearchDevices.d.ts +2 -1
  24. package/dist/api/SearchDevices.d.ts.map +1 -1
  25. package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -1
  26. package/dist/api/device/DeviceRebootToBoardloader.d.ts +1 -1
  27. package/dist/api/device/DeviceRebootToBoardloader.d.ts.map +1 -1
  28. package/dist/api/device/DeviceRebootToBootloader.d.ts.map +1 -1
  29. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +10 -2
  30. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  31. package/dist/api/index.d.ts +26 -0
  32. package/dist/api/index.d.ts.map +1 -1
  33. package/dist/api/protocol-v2/DevFirmwareUpdate.d.ts +7 -0
  34. package/dist/api/protocol-v2/DevFirmwareUpdate.d.ts.map +1 -0
  35. package/dist/api/protocol-v2/DevGetDeviceInfo.d.ts +7 -0
  36. package/dist/api/protocol-v2/DevGetDeviceInfo.d.ts.map +1 -0
  37. package/dist/api/protocol-v2/DevGetFirmwareUpdateStatus.d.ts +6 -0
  38. package/dist/api/protocol-v2/DevGetFirmwareUpdateStatus.d.ts.map +1 -0
  39. package/dist/api/protocol-v2/DevGetOnboardingStatus.d.ts +6 -0
  40. package/dist/api/protocol-v2/DevGetOnboardingStatus.d.ts.map +1 -0
  41. package/dist/api/protocol-v2/DevReboot.d.ts +7 -0
  42. package/dist/api/protocol-v2/DevReboot.d.ts.map +1 -0
  43. package/dist/api/protocol-v2/FactoryDeviceInfoSettings.d.ts +7 -0
  44. package/dist/api/protocol-v2/FactoryDeviceInfoSettings.d.ts.map +1 -0
  45. package/dist/api/protocol-v2/FactoryGetDeviceInfo.d.ts +6 -0
  46. package/dist/api/protocol-v2/FactoryGetDeviceInfo.d.ts.map +1 -0
  47. package/dist/api/protocol-v2/FilesystemFixPermission.d.ts +6 -0
  48. package/dist/api/protocol-v2/FilesystemFixPermission.d.ts.map +1 -0
  49. package/dist/api/protocol-v2/FilesystemFormat.d.ts +6 -0
  50. package/dist/api/protocol-v2/FilesystemFormat.d.ts.map +1 -0
  51. package/dist/api/protocol-v2/GetProtoVersion.d.ts +6 -0
  52. package/dist/api/protocol-v2/GetProtoVersion.d.ts.map +1 -0
  53. package/dist/api/protocol-v2/Ping.d.ts +8 -0
  54. package/dist/api/protocol-v2/Ping.d.ts.map +1 -0
  55. package/dist/api/protocol-v2/helpers.d.ts +49 -0
  56. package/dist/api/protocol-v2/helpers.d.ts.map +1 -0
  57. package/dist/core/index.d.ts.map +1 -1
  58. package/dist/data-manager/DataManager.d.ts +4 -2
  59. package/dist/data-manager/DataManager.d.ts.map +1 -1
  60. package/dist/data-manager/TransportManager.d.ts +2 -1
  61. package/dist/data-manager/TransportManager.d.ts.map +1 -1
  62. package/dist/device/Device.d.ts +5 -3
  63. package/dist/device/Device.d.ts.map +1 -1
  64. package/dist/device/DeviceCommands.d.ts +8 -8
  65. package/dist/device/DeviceCommands.d.ts.map +1 -1
  66. package/dist/device/DeviceConnector.d.ts +2 -1
  67. package/dist/device/DeviceConnector.d.ts.map +1 -1
  68. package/dist/events/ui-request.d.ts +8 -0
  69. package/dist/events/ui-request.d.ts.map +1 -1
  70. package/dist/index.d.ts +188 -20
  71. package/dist/index.js +15626 -753
  72. package/dist/inject.d.ts.map +1 -1
  73. package/dist/protocols/protocol-v2/features.d.ts +56 -0
  74. package/dist/protocols/protocol-v2/features.d.ts.map +1 -0
  75. package/dist/protocols/protocol-v2/firmware.d.ts +12 -0
  76. package/dist/protocols/protocol-v2/firmware.d.ts.map +1 -0
  77. package/dist/protocols/protocol-v2/index.d.ts +3 -0
  78. package/dist/protocols/protocol-v2/index.d.ts.map +1 -0
  79. package/dist/types/api/export.d.ts +1 -1
  80. package/dist/types/api/export.d.ts.map +1 -1
  81. package/dist/types/api/firmwareUpdate.d.ts +7 -0
  82. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  83. package/dist/types/api/index.d.ts +28 -1
  84. package/dist/types/api/index.d.ts.map +1 -1
  85. package/dist/types/api/protocolV2.d.ts +123 -0
  86. package/dist/types/api/protocolV2.d.ts.map +1 -0
  87. package/dist/types/api/searchDevices.d.ts +2 -2
  88. package/dist/types/api/searchDevices.d.ts.map +1 -1
  89. package/dist/types/device.d.ts +1 -1
  90. package/dist/types/device.d.ts.map +1 -1
  91. package/dist/types/params.d.ts +2 -0
  92. package/dist/types/params.d.ts.map +1 -1
  93. package/dist/types/settings.d.ts +1 -1
  94. package/dist/types/settings.d.ts.map +1 -1
  95. package/dist/utils/deviceInfoUtils.d.ts +1 -0
  96. package/dist/utils/deviceInfoUtils.d.ts.map +1 -1
  97. package/dist/utils/index.d.ts +1 -1
  98. package/dist/utils/index.d.ts.map +1 -1
  99. package/dist/utils/patch.d.ts +1 -1
  100. package/dist/utils/patch.d.ts.map +1 -1
  101. package/dist/utils/versionUtils.d.ts +1 -1
  102. package/package.json +4 -4
  103. package/src/api/BaseMethod.ts +12 -60
  104. package/src/api/DirList.ts +25 -0
  105. package/src/api/DirMake.ts +20 -0
  106. package/src/api/DirRemove.ts +20 -0
  107. package/src/api/FileDelete.ts +20 -0
  108. package/src/api/FileRead.ts +158 -0
  109. package/src/api/FileWrite.ts +191 -0
  110. package/src/api/FirmwareUpdateV3.ts +21 -4
  111. package/src/api/FirmwareUpdateV4.ts +810 -0
  112. package/src/api/GetOnekeyFeatures.ts +75 -3
  113. package/src/api/PathInfo.ts +24 -0
  114. package/src/api/SearchDevices.ts +7 -2
  115. package/src/api/allnetwork/AllNetworkGetAddressBase.ts +10 -9
  116. package/src/api/device/DeviceRebootToBoardloader.ts +10 -1
  117. package/src/api/device/DeviceRebootToBootloader.ts +10 -1
  118. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +27 -4
  119. package/src/api/index.ts +28 -0
  120. package/src/api/protocol-v2/DevFirmwareUpdate.ts +33 -0
  121. package/src/api/protocol-v2/DevGetDeviceInfo.ts +35 -0
  122. package/src/api/protocol-v2/DevGetFirmwareUpdateStatus.ts +18 -0
  123. package/src/api/protocol-v2/DevGetOnboardingStatus.ts +18 -0
  124. package/src/api/protocol-v2/DevReboot.ts +22 -0
  125. package/src/api/protocol-v2/FactoryDeviceInfoSettings.ts +27 -0
  126. package/src/api/protocol-v2/FactoryGetDeviceInfo.ts +18 -0
  127. package/src/api/protocol-v2/FilesystemFixPermission.ts +14 -0
  128. package/src/api/protocol-v2/FilesystemFormat.ts +14 -0
  129. package/src/api/protocol-v2/GetProtoVersion.ts +14 -0
  130. package/src/api/protocol-v2/Ping.ts +16 -0
  131. package/src/api/protocol-v2/helpers.ts +138 -0
  132. package/src/core/index.ts +26 -4
  133. package/src/data/messages/messages-pro2.json +13102 -0
  134. package/src/data-manager/DataManager.ts +6 -2
  135. package/src/data-manager/TransportManager.ts +29 -3
  136. package/src/device/Device.ts +68 -8
  137. package/src/device/DeviceCommands.ts +162 -26
  138. package/src/device/DeviceConnector.ts +29 -4
  139. package/src/device/DevicePool.ts +1 -1
  140. package/src/events/ui-request.ts +8 -0
  141. package/src/inject.ts +42 -1
  142. package/src/protocols/protocol-v2/features.ts +266 -0
  143. package/src/protocols/protocol-v2/firmware.ts +26 -0
  144. package/src/protocols/protocol-v2/index.ts +2 -0
  145. package/src/types/api/export.ts +1 -0
  146. package/src/types/api/firmwareUpdate.ts +12 -0
  147. package/src/types/api/index.ts +63 -1
  148. package/src/types/api/protocolV2.ts +221 -0
  149. package/src/types/api/searchDevices.ts +2 -2
  150. package/src/types/device.ts +3 -1
  151. package/src/types/params.ts +7 -0
  152. package/src/types/settings.ts +1 -1
  153. package/src/utils/deviceInfoUtils.ts +14 -5
  154. package/src/utils/index.ts +1 -0
  155. package/__tests__/DeviceCommands.test.ts +0 -99
  156. package/__tests__/evmLedgerLegacySafety.test.ts +0 -261
@@ -0,0 +1,158 @@
1
+ import {
2
+ PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
3
+ PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
4
+ } from '@onekeyfe/hd-transport';
5
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
6
+
7
+ import { BaseMethod } from './BaseMethod';
8
+ import { hexToBytes, isHexString, stripHexPrefix } from './helpers/hexUtils';
9
+ import { DataManager } from '../data-manager';
10
+
11
+ export type FileReadParams = {
12
+ path: string;
13
+ offset?: number;
14
+ totalSize?: number;
15
+ chunkLen?: number;
16
+ uiPercentage?: number;
17
+ };
18
+
19
+ const MIN_FILE_READ_CHUNK_SIZE = 64;
20
+
21
+ function getProtocolV2FileReadChunkLimit() {
22
+ const env = DataManager.getSettings('env');
23
+ if (env && DataManager.isBleConnect(env)) {
24
+ return PROTOCOL_V2_BLE_FILE_CHUNK_SIZE;
25
+ }
26
+ return PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
27
+ }
28
+
29
+ function normalizeChunkSize(value: unknown, maxChunkSize: number): number {
30
+ const numeric = Number(value);
31
+ if (!Number.isFinite(numeric) || numeric <= 0) return maxChunkSize;
32
+ return Math.min(Math.max(Math.floor(numeric), MIN_FILE_READ_CHUNK_SIZE), maxChunkSize);
33
+ }
34
+
35
+ function toFiniteNumber(value: unknown): number | undefined {
36
+ if (typeof value === 'number' && Number.isFinite(value)) return value;
37
+ if (typeof value === 'string') {
38
+ const numeric = Number(value);
39
+ return Number.isFinite(numeric) ? numeric : undefined;
40
+ }
41
+ if (value && typeof value === 'object') {
42
+ const longLike = value as { toNumber?: () => number };
43
+ if (typeof longLike.toNumber === 'function') {
44
+ const numeric = longLike.toNumber();
45
+ return Number.isFinite(numeric) ? numeric : undefined;
46
+ }
47
+ }
48
+ return undefined;
49
+ }
50
+
51
+ function toUint8Array(value: unknown): Uint8Array {
52
+ if (value instanceof Uint8Array) return value;
53
+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
54
+ if (ArrayBuffer.isView(value)) {
55
+ return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
56
+ }
57
+ if (typeof value === 'string') {
58
+ const hex = stripHexPrefix(value);
59
+ if (!hex) return new Uint8Array(0);
60
+ if (!isHexString(hex) || hex.length % 2 !== 0) return new Uint8Array(0);
61
+ return hexToBytes(hex);
62
+ }
63
+ return new Uint8Array(0);
64
+ }
65
+
66
+ export default class FileRead extends BaseMethod<FileReadParams> {
67
+ init() {
68
+ this.skipForceUpdateCheck = true;
69
+ this.useDevicePassphraseState = false;
70
+ this.params = {
71
+ path: this.payload.path,
72
+ offset: this.payload.offset ?? 0,
73
+ totalSize: this.payload.totalSize ?? 0,
74
+ chunkLen: this.payload.chunkLen,
75
+ uiPercentage: this.payload.uiPercentage,
76
+ };
77
+ }
78
+
79
+ async run() {
80
+ const startOffset = this.params.offset ?? 0;
81
+ const requestedLength = Number(this.params.totalSize);
82
+ const chunkSize = normalizeChunkSize(this.params.chunkLen, getProtocolV2FileReadChunkLimit());
83
+ let totalLength = Number.isFinite(requestedLength) && requestedLength > 0 ? requestedLength : 0;
84
+
85
+ if (totalLength === 0) {
86
+ const pathInfoRes = await this.device.commands.typedCall(
87
+ 'FilesystemPathInfoQuery',
88
+ 'FilesystemPathInfo',
89
+ {
90
+ path: this.params.path,
91
+ }
92
+ );
93
+ const fileSize = toFiniteNumber(pathInfoRes.message?.size);
94
+ if (!pathInfoRes.message?.exist || pathInfoRes.message?.directory) {
95
+ throw ERRORS.TypedError(
96
+ HardwareErrorCode.RuntimeError,
97
+ `FilesystemFileRead path is not a file: ${this.params.path}`
98
+ );
99
+ }
100
+ if (fileSize === undefined || fileSize < startOffset) {
101
+ throw ERRORS.TypedError(
102
+ HardwareErrorCode.RuntimeError,
103
+ `FilesystemFileRead invalid offset ${startOffset} for ${this.params.path}`
104
+ );
105
+ }
106
+ totalLength = fileSize - startOffset;
107
+ }
108
+
109
+ const chunks: Uint8Array[] = [];
110
+ let read = 0;
111
+ let lastMessage: Record<string, unknown> | undefined;
112
+
113
+ while (read < totalLength) {
114
+ const readLen = Math.min(chunkSize, totalLength - read);
115
+ const offset = startOffset + read;
116
+ const progress =
117
+ this.params.uiPercentage ??
118
+ Math.min(Math.ceil(((read + readLen) / Math.max(totalLength, 1)) * 100), 99);
119
+ const res = await this.device.commands.typedCall('FilesystemFileRead', 'FilesystemFile', {
120
+ file: {
121
+ path: this.params.path,
122
+ offset,
123
+ total_size: 0,
124
+ },
125
+ chunk_len: readLen,
126
+ ui_percentage: progress,
127
+ });
128
+ const data = toUint8Array(res.message?.data);
129
+ lastMessage = res.message;
130
+
131
+ if (data.byteLength === 0) {
132
+ throw ERRORS.TypedError(
133
+ HardwareErrorCode.RuntimeError,
134
+ `FilesystemFileRead received empty data at offset ${offset}`
135
+ );
136
+ }
137
+
138
+ chunks.push(data);
139
+ read += data.byteLength;
140
+ }
141
+
142
+ const combined = new Uint8Array(read);
143
+ let cursor = 0;
144
+ chunks.forEach(chunk => {
145
+ combined.set(chunk, cursor);
146
+ cursor += chunk.byteLength;
147
+ });
148
+
149
+ return Promise.resolve({
150
+ ...lastMessage,
151
+ path: this.params.path,
152
+ offset: startOffset,
153
+ total_size: totalLength,
154
+ data: combined,
155
+ chunks: chunks.length,
156
+ });
157
+ }
158
+ }
@@ -0,0 +1,191 @@
1
+ import {
2
+ PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
3
+ PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE,
4
+ } from '@onekeyfe/hd-transport';
5
+ import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
6
+
7
+ import { BaseMethod } from './BaseMethod';
8
+ import { UI_REQUEST, createUiMessage } from '../events/ui-request';
9
+ import { DataManager } from '../data-manager';
10
+
11
+ export type FileWriteParams = {
12
+ path: string;
13
+ offset?: number;
14
+ totalSize?: number;
15
+ data: ArrayBuffer | Uint8Array | Blob | string;
16
+ chunkSize?: number;
17
+ chunkLen?: number;
18
+ overwrite?: boolean;
19
+ append?: boolean;
20
+ uiPercentage?: number;
21
+ };
22
+
23
+ const MIN_FILE_CHUNK_SIZE = 64;
24
+
25
+ function getProtocolV2FileChunkLimit() {
26
+ const env = DataManager.getSettings('env');
27
+ if (env && DataManager.isBleConnect(env)) {
28
+ return PROTOCOL_V2_BLE_FILE_CHUNK_SIZE;
29
+ }
30
+ return PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
31
+ }
32
+
33
+ async function dataToUint8Array(data: FileWriteParams['data'] | Blob): Promise<Uint8Array> {
34
+ if (typeof data === 'string') {
35
+ return new TextEncoder().encode(data);
36
+ }
37
+
38
+ if (data instanceof ArrayBuffer) {
39
+ return new Uint8Array(data);
40
+ }
41
+
42
+ if (ArrayBuffer.isView(data)) {
43
+ return new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
44
+ }
45
+
46
+ if (typeof Blob !== 'undefined' && data instanceof Blob) {
47
+ return new Uint8Array(await data.arrayBuffer());
48
+ }
49
+
50
+ throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Unsupported FilesystemFileWrite data');
51
+ }
52
+
53
+ function normalizeChunkSize(value: unknown, maxChunkSize: number): number {
54
+ const numeric = Number(value);
55
+ if (!Number.isFinite(numeric) || numeric <= 0) return maxChunkSize;
56
+ return Math.min(Math.max(Math.floor(numeric), MIN_FILE_CHUNK_SIZE), maxChunkSize);
57
+ }
58
+
59
+ function getConfirmedProgress(
60
+ processedByte: number,
61
+ totalSize: number,
62
+ written: number,
63
+ dataLength: number
64
+ ) {
65
+ if (Number.isFinite(processedByte) && Number.isFinite(totalSize) && totalSize > 0) {
66
+ if (processedByte >= totalSize) return 100;
67
+ return Math.min(Math.max(Math.floor((processedByte / totalSize) * 100), 0), 99);
68
+ }
69
+ if (dataLength > 0) {
70
+ if (written >= dataLength) return 100;
71
+ return Math.min(Math.max(Math.floor((written / dataLength) * 100), 0), 99);
72
+ }
73
+ return 100;
74
+ }
75
+
76
+ export default class FileWrite extends BaseMethod<FileWriteParams> {
77
+ init() {
78
+ this.skipForceUpdateCheck = true;
79
+ this.useDevicePassphraseState = false;
80
+ const offset = this.payload.offset ?? 0;
81
+ this.params = {
82
+ path: this.payload.path,
83
+ offset,
84
+ totalSize: this.payload.totalSize ?? 0,
85
+ data: this.payload.data,
86
+ chunkSize: this.payload.chunkSize,
87
+ chunkLen: this.payload.chunkLen,
88
+ overwrite: this.payload.overwrite ?? offset === 0,
89
+ append: this.payload.append ?? false,
90
+ uiPercentage: this.payload.uiPercentage,
91
+ };
92
+ }
93
+
94
+ async run() {
95
+ const data = await dataToUint8Array(this.params.data);
96
+ const dataLength = data.byteLength;
97
+ const offsetValue = Number(this.params.offset ?? 0);
98
+ const startOffset = Number.isFinite(offsetValue) && offsetValue > 0 ? offsetValue : 0;
99
+ const payloadTotalSize = Number(this.params.totalSize);
100
+ const totalSize =
101
+ Number.isFinite(payloadTotalSize) && payloadTotalSize > 0
102
+ ? payloadTotalSize
103
+ : startOffset + dataLength;
104
+
105
+ if (totalSize < startOffset + dataLength) {
106
+ throw ERRORS.TypedError(
107
+ HardwareErrorCode.RuntimeError,
108
+ `FilesystemFileWrite totalSize ${totalSize} is smaller than offset + data length ${
109
+ startOffset + dataLength
110
+ }`
111
+ );
112
+ }
113
+
114
+ const chunkSize = normalizeChunkSize(
115
+ this.params.chunkSize ?? this.params.chunkLen,
116
+ getProtocolV2FileChunkLimit()
117
+ );
118
+ const overwrite = this.params.overwrite ?? false;
119
+ const append = this.params.append ?? false;
120
+ let written = 0;
121
+ let chunkIndex = 0;
122
+ let lastMessage: Record<string, unknown> | undefined;
123
+ const startTime = Date.now();
124
+
125
+ while (written < dataLength) {
126
+ const chunkEnd = Math.min(written + chunkSize, dataLength);
127
+ const chunk = data.slice(written, chunkEnd);
128
+ const offset = startOffset + written;
129
+ const isFirstChunk = chunkIndex === 0;
130
+ const progress =
131
+ this.params.uiPercentage ??
132
+ Math.min(Math.ceil(((written + chunk.byteLength) / dataLength) * 100), 99);
133
+
134
+ const res = await this.device.commands.typedCall('FilesystemFileWrite', 'FilesystemFile', {
135
+ file: {
136
+ path: this.params.path,
137
+ offset,
138
+ total_size: totalSize,
139
+ data: chunk,
140
+ },
141
+ overwrite: isFirstChunk ? overwrite : false,
142
+ append,
143
+ ui_percentage: progress,
144
+ });
145
+
146
+ lastMessage = res.message;
147
+ const processedByte = Number(res.message?.processed_byte);
148
+ if (Number.isFinite(processedByte) && processedByte > offset) {
149
+ written = processedByte - startOffset;
150
+ } else {
151
+ written += chunk.byteLength;
152
+ }
153
+
154
+ if (written > dataLength) {
155
+ throw ERRORS.TypedError(
156
+ HardwareErrorCode.RuntimeError,
157
+ `FilesystemFileWrite invalid processed_byte ${processedByte}`
158
+ );
159
+ }
160
+
161
+ const confirmedProcessedByte =
162
+ Number.isFinite(processedByte) && processedByte > offset
163
+ ? processedByte
164
+ : startOffset + written;
165
+ if (typeof this.postMessage === 'function') {
166
+ const elapsedMs = Date.now() - startTime;
167
+ const transferredBytes = Math.min(written, dataLength);
168
+ this.postMessage(
169
+ createUiMessage(UI_REQUEST.DEVICE_PROGRESS, {
170
+ progress: getConfirmedProgress(confirmedProcessedByte, totalSize, written, dataLength),
171
+ transferredBytes,
172
+ totalBytes: dataLength,
173
+ rateBytesPerSecond:
174
+ elapsedMs > 0 ? Math.round((transferredBytes / elapsedMs) * 1000) : undefined,
175
+ elapsedMs,
176
+ })
177
+ );
178
+ }
179
+ chunkIndex += 1;
180
+ }
181
+
182
+ return Promise.resolve({
183
+ ...lastMessage,
184
+ path: this.params.path,
185
+ offset: startOffset,
186
+ total_size: totalSize,
187
+ processed_byte: startOffset + written,
188
+ chunks: chunkIndex,
189
+ });
190
+ }
191
+ }
@@ -79,6 +79,20 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
79
79
  }
80
80
 
81
81
  async run() {
82
+ if (this.device.originalDescriptor?.protocolType === 'V2') {
83
+ throw ERRORS.TypedError(
84
+ HardwareErrorCode.RuntimeError,
85
+ 'Protocol V2 firmware update must use firmwareUpdateV4'
86
+ );
87
+ }
88
+ Log.debug('FirmwareUpdateV3 strategy: Protocol V1');
89
+ return this.runProtocolV1();
90
+ }
91
+
92
+ /**
93
+ * Protocol V1 firmware update strategy for existing Pro devices.
94
+ */
95
+ private async runProtocolV1() {
82
96
  const { device } = this;
83
97
  const { features } = device;
84
98
 
@@ -251,6 +265,8 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
251
265
  }
252
266
 
253
267
  this.postTipMessage(FirmwareUpdateTipMessage.StartTransferData);
268
+ const transferStartTime = Date.now();
269
+
254
270
  // Process resource zip contents
255
271
  if (resourceBinary) {
256
272
  const file = await JSZip.loadAsync(resourceBinary);
@@ -264,6 +280,7 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
264
280
  filePath: `0:res/${name}`,
265
281
  processedSize,
266
282
  totalSize,
283
+ transferStartTime,
267
284
  });
268
285
  }
269
286
  }
@@ -275,6 +292,7 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
275
292
  filePath: `0:boot/bootloader.bin`,
276
293
  processedSize,
277
294
  totalSize,
295
+ transferStartTime,
278
296
  });
279
297
  }
280
298
 
@@ -287,16 +305,15 @@ export default class FirmwareUpdateV3 extends FirmwareUpdateBaseMethod<FirmwareU
287
305
  filePath: `0:updates/${fwbinary.fileName}`,
288
306
  processedSize,
289
307
  totalSize,
308
+ transferStartTime,
290
309
  });
291
310
  }
292
311
  }
293
312
 
294
- // trigger firmware update, support folder updates
313
+ // trigger firmware update
295
314
  try {
296
315
  this.postTipMessage(FirmwareUpdateTipMessage.ConfirmOnDevice);
297
- await this.startEmmcFirmwareUpdate({
298
- path: '0:updates',
299
- });
316
+ await this.startEmmcFirmwareUpdate({ path: '0:updates' });
300
317
  } catch (error) {
301
318
  Log.error('triggerFirmwareUpdateEmmc error: ', error);
302
319
  // Re-throw errors with specific error codes that should not be ignored