@onekeyfe/hd-core 1.2.0-alpha.70 → 1.2.0-alpha.71

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.
@@ -163,6 +163,34 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
163
163
  });
164
164
  });
165
165
 
166
+ test('marks SE03 and SE04 as unsupported in a Neo firmware plan', () => {
167
+ const neoRelease: IFirmwareReleaseInfo = {
168
+ ...release,
169
+ installOrder: ['se01', 'se02', 'se03', 'se04'],
170
+ components: {
171
+ se01: { target: 'SE01', url: 'https://example.com/se01.bin', version: [2, 0, 0] },
172
+ se02: { target: 'SE02', url: 'https://example.com/se02.bin', version: [3, 0, 0] },
173
+ se03: { target: 'SE03', url: 'https://example.com/se03.bin', version: [2, 0, 0] },
174
+ se04: { target: 'SE04', url: 'https://example.com/se04.bin', version: [2, 0, 0] },
175
+ },
176
+ };
177
+
178
+ const result = buildProtocolV2FirmwareRelease({
179
+ currentVersions,
180
+ firmwareType: EFirmwareType.Universal,
181
+ release: neoRelease,
182
+ deviceType: 'neo',
183
+ });
184
+
185
+ expect(result.targetsToUpdate).toEqual(['se01', 'se02']);
186
+ expect(result.components).toEqual(
187
+ expect.arrayContaining([
188
+ expect.objectContaining({ configKey: 'se03', status: 'unsupported', updateTarget: null }),
189
+ expect.objectContaining({ configKey: 'se04', status: 'unsupported', updateTarget: null }),
190
+ ])
191
+ );
192
+ });
193
+
166
194
  test('returns an unavailable plan when no Pro2 release is configured', () => {
167
195
  expect(
168
196
  buildProtocolV2FirmwareRelease({
@@ -1,5 +1,10 @@
1
+ import { EDeviceType } from '@onekeyfe/hd-shared';
2
+
1
3
  import { ProtocolV2FirmwareTargetType } from '../src/protocols/protocol-v2/firmware';
2
- import { isProtocolV2FirmwareFingerprintValid } from '../src/api/FirmwareUpdateV4';
4
+ import {
5
+ assertProtocolV2FirmwareTargetsSupported,
6
+ isProtocolV2FirmwareFingerprintValid,
7
+ } from '../src/api/FirmwareUpdateV4';
3
8
 
4
9
  jest.mock('../src/data/config', () => ({
5
10
  DEFAULT_DOMAIN: 'https://example.com/',
@@ -34,4 +39,31 @@ describe('Protocol V2 firmware target contract', () => {
34
39
  ).toBe(true);
35
40
  expect(isProtocolV2FirmwareFingerprintValid(binary, '00'.repeat(32))).toBe(false);
36
41
  });
42
+
43
+ test('allows only SE01 and SE02 firmware targets on Neo', () => {
44
+ expect(() =>
45
+ assertProtocolV2FirmwareTargetsSupported(EDeviceType.Neo, {
46
+ platform: 'web',
47
+ targetsToUpdate: ['se01', 'se02'],
48
+ })
49
+ ).not.toThrow();
50
+
51
+ expect(() =>
52
+ assertProtocolV2FirmwareTargetsSupported(EDeviceType.Neo, {
53
+ platform: 'web',
54
+ targetsToUpdate: ['se03'],
55
+ se04Binary: new ArrayBuffer(1),
56
+ })
57
+ ).toThrow('Neo only supports SE01 and SE02; unsupported firmware targets: se03, se04');
58
+ });
59
+
60
+ test('keeps all four SE firmware targets available on Pro2', () => {
61
+ expect(() =>
62
+ assertProtocolV2FirmwareTargetsSupported(EDeviceType.Pro2, {
63
+ platform: 'web',
64
+ targetsToUpdate: ['se03'],
65
+ se04Binary: new ArrayBuffer(1),
66
+ })
67
+ ).not.toThrow();
68
+ });
37
69
  });
@@ -95,7 +95,7 @@ describe('Pro2 resource configuration', () => {
95
95
  DataManager.lastCheckTimestamp = 0;
96
96
  });
97
97
 
98
- test('accepts exactly six resources and normalizes their deterministic order', () => {
98
+ test('accepts exactly seven resources and normalizes their deterministic order', () => {
99
99
  const parsed = parseProtocolV2Resources({
100
100
  stable: [...resources].reverse(),
101
101
  boot: bootResources,
@@ -106,15 +106,18 @@ describe('Pro2 resource configuration', () => {
106
106
  expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.translations).toBe(
107
107
  'vol0:/bundles/translations/translations.okpkg'
108
108
  );
109
+ expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.firmware_logo).toBe(
110
+ 'vol0:/bundles/firmware_logo.okpkg'
111
+ );
109
112
  });
110
113
 
111
114
  test('rejects incomplete, duplicate, or malformed stable sets', () => {
112
115
  expect(() => parseProtocolV2Resources({ stable: resources.slice(1) })).toThrow(
113
- 'six unique resource types'
116
+ '7 unique resource types'
114
117
  );
115
118
  expect(() =>
116
- parseProtocolV2Resources({ stable: [...resources.slice(0, 5), resources[0]] })
117
- ).toThrow('six unique resource types');
119
+ parseProtocolV2Resources({ stable: [...resources.slice(0, 6), resources[0]] })
120
+ ).toThrow('7 unique resource types');
118
121
  expect(() =>
119
122
  parseProtocolV2Resources({
120
123
  stable: resources.map((resource, index) =>
@@ -224,7 +227,7 @@ describe('Pro2 resource configuration', () => {
224
227
  );
225
228
  expect(typedCall.mock.calls.some(call => call[0] === 'ResourceInventoryGet')).toBe(false);
226
229
  expect(typedCall.mock.calls.filter(call => call[0] === 'FilesystemPathInfoQuery')).toHaveLength(
227
- 6
230
+ 7
228
231
  );
229
232
  expect(typedCall.mock.calls.some(call => call[0] === 'FilesystemFileRead')).toBe(true);
230
233
  });
@@ -255,7 +258,7 @@ describe('Pro2 resource configuration', () => {
255
258
  });
256
259
  expect(
257
260
  buildProtocolV2ResourceUpdatePlan({ resources, mode: 'bootloader-recovery' }).resources
258
- ).toHaveLength(6);
261
+ ).toHaveLength(7);
259
262
  });
260
263
 
261
264
  test('uses a filesystem inventory for incremental recovery mode updates', () => {
@@ -35,7 +35,10 @@ import ProtocolInfoRequest from '../src/api/protocol-v2/ProtocolInfoRequest';
35
35
  import EVMSignTypedData from '../src/api/evm/EVMSignTypedData';
36
36
  import EVMSignMessageEIP712 from '../src/api/evm/EVMSignMessageEIP712';
37
37
  import FirmwareUpdateV3 from '../src/api/FirmwareUpdateV3';
38
- import FirmwareUpdateV4, { assertProtocolV2ReconnectIdentity } from '../src/api/FirmwareUpdateV4';
38
+ import FirmwareUpdateV4, {
39
+ assertProtocolV2FirmwareTargetsSupported,
40
+ assertProtocolV2ReconnectIdentity,
41
+ } from '../src/api/FirmwareUpdateV4';
39
42
  import GetPassphraseState from '../src/api/GetPassphraseState';
40
43
  import GetOnekeyFeatures from '../src/api/GetOnekeyFeatures';
41
44
  import { batchGetPublickeys } from '../src/api/helpers/batchGetPublickeys';
@@ -255,7 +258,10 @@ describe('UploadPortfolio', () => {
255
258
  'FilesystemFileWrite',
256
259
  'FilesystemFile',
257
260
  expect.any(Object),
258
- { timeoutMs: undefined }
261
+ expect.objectContaining({
262
+ timeoutMs: undefined,
263
+ onWriteCompleted: expect.any(Function),
264
+ })
259
265
  );
260
266
  expect(typedCall).toHaveBeenNthCalledWith(2, 'PortfolioUpdate', 'Success', {});
261
267
  });
@@ -298,7 +304,10 @@ describe('UploadPortfolio', () => {
298
304
  append: false,
299
305
  ui_percentage: 100,
300
306
  },
301
- { timeoutMs: undefined }
307
+ expect.objectContaining({
308
+ timeoutMs: undefined,
309
+ onWriteCompleted: expect.any(Function),
310
+ })
302
311
  );
303
312
  expect(typedCall).toHaveBeenNthCalledWith(2, 'PortfolioUpdate', 'Success', {});
304
313
  expect(method.postMessage).not.toHaveBeenCalled();
@@ -3989,6 +3998,10 @@ describe('Protocol V2 firmware update targets', () => {
3989
3998
  });
3990
3999
 
3991
4000
  const order: string[] = [];
4001
+ (method as any).prepareProtocolV2BootResources = jest.fn().mockImplementation(() => {
4002
+ order.push('prepare-startup-resources');
4003
+ return Promise.resolve([]);
4004
+ });
3992
4005
  (method as any).enterProtocolV2BootloaderMode = jest.fn().mockImplementation(() => {
3993
4006
  order.push('enter-bootloader');
3994
4007
  return Promise.resolve(true);
@@ -4017,7 +4030,12 @@ describe('Protocol V2 firmware update targets', () => {
4017
4030
 
4018
4031
  await method.run();
4019
4032
 
4020
- expect(order).toEqual(['enter-bootloader', 'prepare-resources', 'execute-update']);
4033
+ expect(order).toEqual([
4034
+ 'prepare-startup-resources',
4035
+ 'enter-bootloader',
4036
+ 'prepare-resources',
4037
+ 'execute-update',
4038
+ ]);
4021
4039
  });
4022
4040
 
4023
4041
  test('reboots Protocol V2 normal-mode device to bootloader before transfer', async () => {
@@ -4261,6 +4279,41 @@ describe('Protocol V2 firmware update targets', () => {
4261
4279
  expect(typedCall.mock.calls.map(call => call[0])).toEqual(['DeviceInfoGet']);
4262
4280
  });
4263
4281
 
4282
+ test('polls again when Protocol V2 bootloader serial is temporarily unavailable', async () => {
4283
+ const method = new FirmwareUpdateV4({
4284
+ id: 1,
4285
+ payload: {
4286
+ method: 'firmwareUpdateV4',
4287
+ },
4288
+ });
4289
+ const typedCall = jest
4290
+ .fn()
4291
+ .mockResolvedValueOnce({
4292
+ type: 'DeviceInfo',
4293
+ message: { protocol_version: 1, hw: {} },
4294
+ })
4295
+ .mockResolvedValueOnce({
4296
+ type: 'DeviceInfo',
4297
+ message: protocolV2BootloaderDeviceInfo,
4298
+ });
4299
+ const reconnectProtocolV2Device = jest.fn().mockResolvedValue(undefined);
4300
+ (method as any).device = stubDevice({
4301
+ originalDescriptor: { id: 'ble-id', protocolType: 'V2' },
4302
+ getCommands: () => ({ typedCall }),
4303
+ probeProtocolV2RuntimeState: jest.fn().mockResolvedValue({
4304
+ mode: 'bootloader',
4305
+ bootloaderMode: true,
4306
+ }),
4307
+ });
4308
+ (method as any).reconnectProtocolV2Device = reconnectProtocolV2Device;
4309
+ (method as any).protocolV2ExpectedSerialNumber = 'PR9999999999';
4310
+
4311
+ await (method as any).waitForProtocolV2BootloaderMode(60 * 1000, 0);
4312
+
4313
+ expect(reconnectProtocolV2Device).toHaveBeenCalledTimes(2);
4314
+ expect(typedCall).toHaveBeenCalledTimes(2);
4315
+ });
4316
+
4264
4317
  test('does not run generic initialize during Protocol V2 USB firmware reconnect', async () => {
4265
4318
  const method = new FirmwareUpdateV4({
4266
4319
  id: 1,
@@ -6374,8 +6427,14 @@ describe('Protocol V2 firmware update targets', () => {
6374
6427
  expect(writePayloads.map(payload => payload.file.data.byteLength)).toEqual([1800, 1]);
6375
6428
  expect(writePayloads.map(payload => payload.ui_percentage)).toEqual([0, 100]);
6376
6429
  expect(typedCall.mock.calls.map(call => call[3])).toEqual([
6377
- { writeWithResponse: true },
6378
- { writeWithResponse: true },
6430
+ expect.objectContaining({
6431
+ writeWithResponse: false,
6432
+ onWriteCompleted: expect.any(Function),
6433
+ }),
6434
+ expect.objectContaining({
6435
+ writeWithResponse: false,
6436
+ onWriteCompleted: expect.any(Function),
6437
+ }),
6379
6438
  ]);
6380
6439
  });
6381
6440
 
@@ -6941,7 +7000,7 @@ describe('Protocol V2 firmware reconnect identity', () => {
6941
7000
  resourcesSpy.mockRestore();
6942
7001
  });
6943
7002
 
6944
- test('does not resolve boot resources unless the optional target is selected', async () => {
7003
+ test('does not resolve boot resources when no resource target is selected', async () => {
6945
7004
  const method = new FirmwareUpdateV4({
6946
7005
  id: 1,
6947
7006
  payload: { method: 'firmwareUpdateV4', platform: 'web' },
@@ -6956,7 +7015,7 @@ describe('Protocol V2 firmware reconnect identity', () => {
6956
7015
  expect(downloadSpy).not.toHaveBeenCalled();
6957
7016
  });
6958
7017
 
6959
- test('downloads and maps selected boot resources as direct RES files', async () => {
7018
+ test('includes startup resources in the complete resource target', async () => {
6960
7019
  const bytes = new Uint8Array([1, 2, 3, 4]);
6961
7020
  const binary = bytes.buffer as ArrayBuffer;
6962
7021
  const fileHash = Array.from(sha256(bytes), byte => byte.toString(16).padStart(2, '0')).join('');
@@ -6978,7 +7037,7 @@ describe('Protocol V2 firmware reconnect identity', () => {
6978
7037
  payload: {
6979
7038
  method: 'firmwareUpdateV4',
6980
7039
  platform: 'web',
6981
- targetsToUpdate: ['boot_resources'],
7040
+ targetsToUpdate: ['resource'],
6982
7041
  },
6983
7042
  });
6984
7043
  method.init();
@@ -7921,7 +7980,10 @@ describe('Protocol V2 file write method', () => {
7921
7980
  append: false,
7922
7981
  ui_percentage: 100,
7923
7982
  },
7924
- { timeoutMs: undefined }
7983
+ expect.objectContaining({
7984
+ timeoutMs: undefined,
7985
+ onWriteCompleted: expect.any(Function),
7986
+ })
7925
7987
  );
7926
7988
  expect(method.postMessage).toHaveBeenCalledWith({
7927
7989
  event: 'UI_EVENT',
@@ -7970,7 +8032,10 @@ describe('Protocol V2 file write method', () => {
7970
8032
  append: false,
7971
8033
  ui_percentage: 0,
7972
8034
  },
7973
- { timeoutMs: undefined }
8035
+ expect.objectContaining({
8036
+ timeoutMs: undefined,
8037
+ onWriteCompleted: expect.any(Function),
8038
+ })
7974
8039
  );
7975
8040
  expect(typedCall).toHaveBeenNthCalledWith(
7976
8041
  2,
@@ -7987,7 +8052,10 @@ describe('Protocol V2 file write method', () => {
7987
8052
  append: false,
7988
8053
  ui_percentage: 100,
7989
8054
  },
7990
- { timeoutMs: undefined }
8055
+ expect.objectContaining({
8056
+ timeoutMs: undefined,
8057
+ onWriteCompleted: expect.any(Function),
8058
+ })
7991
8059
  );
7992
8060
  expect(result).toMatchObject({
7993
8061
  path: 'vol1:test.bin',
@@ -131,10 +131,43 @@ describe('writeProtocolV2File', () => {
131
131
  'FilesystemFileWrite',
132
132
  'FilesystemFile',
133
133
  expect.objectContaining({ ui_percentage: 42 }),
134
- { writeWithResponse: true }
134
+ expect.objectContaining({
135
+ writeWithResponse: true,
136
+ onWriteCompleted: expect.any(Function),
137
+ })
135
138
  );
136
139
  });
137
140
 
141
+ test('记录主机整帧写入与设备响应等待的分段耗时', async () => {
142
+ const log = getLogger(LoggerNames.Core);
143
+ const logSpy = jest.spyOn(log, 'log').mockImplementation(() => undefined);
144
+ const typedCall = jest.fn().mockImplementation((_type, _resType, _request, options) => {
145
+ options.onWriteCompleted({ elapsedMs: 25, frameBytes: 128 });
146
+ return Promise.resolve({ message: { processed_byte: 3 } });
147
+ });
148
+ const dateNowSpy = jest
149
+ .spyOn(Date, 'now')
150
+ .mockReturnValueOnce(1_000)
151
+ .mockReturnValueOnce(1_010)
152
+ .mockReturnValueOnce(1_040)
153
+ .mockReturnValueOnce(1_050);
154
+
155
+ try {
156
+ await writeProtocolV2File({
157
+ commands: { typedCall } as any,
158
+ path: 'vol0:/firmware.bin',
159
+ data: new Uint8Array([1, 2, 3]),
160
+ });
161
+
162
+ expect(logSpy).toHaveBeenLastCalledWith(
163
+ '[FileWrite] metrics transport=unknown status=completed path=vol0:/firmware.bin bytes=3/3 elapsed=0.05s speed=0.06 KiB/s hostWriteTotal=0.03s responseWaitTotal=0.03s measuredAttempts=1'
164
+ );
165
+ } finally {
166
+ dateNowSpy.mockRestore();
167
+ logSpy.mockRestore();
168
+ }
169
+ });
170
+
138
171
  test('按确认分片的时间窗口记录实时传输速率', async () => {
139
172
  const data = new Uint8Array(4097);
140
173
  const typedCall = jest.fn().mockResolvedValue({ message: {} });
@@ -175,7 +208,7 @@ describe('writeProtocolV2File', () => {
175
208
  });
176
209
 
177
210
  test('通过 Core Log 每十秒输出一次 BLE 传输关键指标', async () => {
178
- const log = getLogger(LoggerNames.Method);
211
+ const log = getLogger(LoggerNames.Core);
179
212
  const logSpy = jest.spyOn(log, 'log').mockImplementation(() => undefined);
180
213
  const getSettingsSpy = jest
181
214
  .spyOn(DataManager, 'getSettings')
@@ -197,14 +230,18 @@ describe('writeProtocolV2File', () => {
197
230
  data,
198
231
  });
199
232
 
200
- expect(logSpy).toHaveBeenCalledTimes(2);
233
+ expect(logSpy).toHaveBeenCalledTimes(3);
201
234
  expect(logSpy).toHaveBeenNthCalledWith(
202
235
  1,
203
- '[FileWrite] metrics transport=BLE status=progress bytes=3600/5400 elapsed=10.00s speed=0.35 KiB/s'
236
+ '[FileWrite] started transport=BLE path=vol1:/wallpapers/test.bin bytes=5400 offset=0 chunk=1800'
204
237
  );
205
238
  expect(logSpy).toHaveBeenNthCalledWith(
206
239
  2,
207
- '[FileWrite] metrics transport=BLE status=completed bytes=5400/5400 elapsed=14.00s speed=0.44 KiB/s'
240
+ '[FileWrite] metrics transport=BLE status=progress path=vol1:/wallpapers/test.bin bytes=3600/5400 elapsed=10.00s speed=0.35 KiB/s'
241
+ );
242
+ expect(logSpy).toHaveBeenNthCalledWith(
243
+ 3,
244
+ '[FileWrite] metrics transport=BLE status=completed path=vol1:/wallpapers/test.bin bytes=5400/5400 elapsed=14.00s speed=0.44 KiB/s'
208
245
  );
209
246
  } finally {
210
247
  dateNowSpy.mockRestore();
@@ -215,7 +252,7 @@ describe('writeProtocolV2File', () => {
215
252
  });
216
253
 
217
254
  test('写入失败时通过 Core Log 输出已传输字节和平均速率', async () => {
218
- const log = getLogger(LoggerNames.Method);
255
+ const log = getLogger(LoggerNames.Core);
219
256
  const logSpy = jest.spyOn(log, 'log').mockImplementation(() => undefined);
220
257
  const typedCall = jest.fn().mockRejectedValue(new Error('write failed'));
221
258
  const dateNowSpy = jest
@@ -234,7 +271,11 @@ describe('writeProtocolV2File', () => {
234
271
 
235
272
  expect(logSpy).toHaveBeenNthCalledWith(
236
273
  1,
237
- '[FileWrite] metrics transport=unknown status=failed bytes=0/4000 elapsed=1.00s speed=0.00 KiB/s'
274
+ '[FileWrite] started transport=unknown path=vol1:/wallpapers/test.bin bytes=4000 offset=0 chunk=4000'
275
+ );
276
+ expect(logSpy).toHaveBeenNthCalledWith(
277
+ 2,
278
+ '[FileWrite] metrics transport=unknown status=failed path=vol1:/wallpapers/test.bin bytes=0/4000 elapsed=1.00s speed=0.00 KiB/s'
238
279
  );
239
280
  } finally {
240
281
  dateNowSpy.mockRestore();
@@ -13,13 +13,14 @@ type ProtocolV2FirmwareReleasePlan = {
13
13
  targetsToUpdate: FirmwareUpdateV4Target[];
14
14
  release: IFirmwareReleaseInfo | undefined;
15
15
  };
16
- export declare function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification, checkFirmwareHash, remotePayloadHashes, firmwareType, release, }: {
16
+ export declare function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification, checkFirmwareHash, remotePayloadHashes, firmwareType, release, deviceType, }: {
17
17
  currentVersions: DeviceStateVersions;
18
18
  currentVerification?: Partial<DeviceFeaturesVerify>;
19
19
  checkFirmwareHash?: boolean;
20
20
  remotePayloadHashes?: Readonly<Record<string, string | null>>;
21
21
  firmwareType: EFirmwareType;
22
22
  release: IFirmwareReleaseInfo | undefined;
23
+ deviceType?: 'pro2' | 'neo';
23
24
  }): ProtocolV2FirmwareReleasePlan;
24
25
  export default class CheckAllFirmwareRelease extends BaseMethod {
25
26
  getSupportedProtocols(): readonly ["V1", "V2"];
@@ -1 +1 @@
1
- {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAId,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAyB1C,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,KAAK,6BAA6B,GAAG;IACnC,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,GACR,EAAE;IACD,eAAe,EAAE,mBAAmB,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,GAAG,6BAA6B,CAqEhC;AAID,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAME,GAAG;YAuFK,aAAa;CA2F5B"}
1
+ {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,aAAa,EAId,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAyB1C,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,KAAK,6BAA6B,GAAG;IACnC,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,eAAe,EAAE,mBAAmB,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC7B,GAAG,6BAA6B,CAiFhC;AAID,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAME,GAAG;YAuFK,aAAa;CA4F5B"}
@@ -1,5 +1,7 @@
1
+ import { EDeviceType } from '@onekeyfe/hd-shared';
1
2
  import { FirmwareUpdateBaseMethod } from './firmware/FirmwareUpdateBaseMethod';
2
3
  import type { FirmwareUpdateV4Params } from '../types/api/firmwareUpdate';
4
+ export declare function assertProtocolV2FirmwareTargetsSupported(deviceType: EDeviceType | string | undefined, params: FirmwareUpdateV4Params): void;
3
5
  export declare const isProtocolV2FirmwareFingerprintValid: (binary: ArrayBuffer | Uint8Array, fingerprint: string | undefined) => boolean;
4
6
  export declare const assertProtocolV2ReconnectIdentity: (expectedSerialNumber?: string, actualSerialNumber?: string, expectedPath?: string, actualPath?: string) => void;
5
7
  export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareUpdateV4Params> {
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAwB/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AAiWrC,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IAoHJ,OAAO,CAAC,8BAA8B;IAoBhC,GAAG;;;;;YAKK,aAAa;YA+Gb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqD/B,gCAAgC;YAmDhC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAkBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YAmCjC,+BAA+B;IAqD7C,OAAO,CAAC,uBAAuB;YAMjB,8BAA8B;IAuB5C,OAAO,CAAC,sCAAsC;YAmChC,gCAAgC;YAqChC,0BAA0B;IAexC,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA8C9B,kCAAkC;IAgChD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;IAc3B,6BAA6B;YAgCrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YA0CvB,8BAA8B;YA2D9B,6BAA6B;IAuE3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;IAyGpC,OAAO,CAAC,6BAA6B;YAcvB,uCAAuC;YA0JvC,gCAAgC;YAehC,yBAAyB;YAQzB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAgDrC,yBAAyB;YA8DzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAI5B,cAAc;YAoCd,6BAA6B;YAW7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
1
+ {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AAwBlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AAwB/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AA2CrC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,QAkB/B;AA0TD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IAoHJ,OAAO,CAAC,8BAA8B;IAoBhC,GAAG;;;;;YAKK,aAAa;YAuHb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqD/B,gCAAgC;YAmDhC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAkBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,4BAA4B;IAQpC,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YAmCjC,+BAA+B;IAqD7C,OAAO,CAAC,uBAAuB;YAMjB,8BAA8B;IA4B5C,OAAO,CAAC,sCAAsC;YAmChC,gCAAgC;YAqChC,0BAA0B;IAexC,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA8C9B,kCAAkC;IAgChD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;IAc3B,6BAA6B;YAgCrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YA0CvB,8BAA8B;YA2D9B,6BAA6B;IAuE3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;IAyGpC,OAAO,CAAC,6BAA6B;YAcvB,uCAAuC;YA0JvC,gCAAgC;YAehC,yBAAyB;YAQzB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAgDrC,yBAAyB;YA8DzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAQ5B,cAAc;YAuCd,6BAA6B;YAW7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"protocolV2FileWrite.d.ts","sourceRoot":"","sources":["../../../src/api/helpers/protocolV2FileWrite.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,MAAM,uBAAuB,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,MAAM,GAAG,SAAS,CAAC;IACnF,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC9D,CAAC;AA2CF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,WASzD;AA8CD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B;;;;;;GAgM5E"}
1
+ {"version":3,"file":"protocolV2FileWrite.d.ts","sourceRoot":"","sources":["../../../src/api/helpers/protocolV2FileWrite.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAIlE,MAAM,MAAM,uBAAuB,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,uBAAuB,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,+BAA+B,KAAK,MAAM,GAAG,SAAS,CAAC;IACnF,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,IAAI,CAAC;CAC9D,CAAC;AAyDF,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,WASzD;AA8CD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B;;;;;;GAoO5E"}
package/dist/index.d.ts CHANGED
@@ -211,7 +211,7 @@ type IProtocolV2FirmwareComponent = {
211
211
  expectedSize?: number;
212
212
  version?: IVersionArray;
213
213
  };
214
- type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto';
214
+ type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto' | 'firmware_logo';
215
215
  /** Pro2 RES package descriptor. Hashes identify content without a human-managed version. */
216
216
  type IProtocolV2Resource = {
217
217
  type: IProtocolV2ResourceType;
package/dist/index.js CHANGED
@@ -40511,6 +40511,7 @@ const PROTOCOL_V2_RESOURCE_TYPES = [
40511
40511
  'translations',
40512
40512
  'roobert',
40513
40513
  'noto',
40514
+ 'firmware_logo',
40514
40515
  ];
40515
40516
  const PROTOCOL_V2_RESOURCE_DEVICE_PATHS = {
40516
40517
  images: 'vol0:/bundles/images/images.okpkg',
@@ -40519,6 +40520,7 @@ const PROTOCOL_V2_RESOURCE_DEVICE_PATHS = {
40519
40520
  translations: 'vol0:/bundles/translations/translations.okpkg',
40520
40521
  roobert: 'vol0:/bundles/font/roobert.okpkg',
40521
40522
  noto: 'vol0:/bundles/font/noto.okpkg',
40523
+ firmware_logo: 'vol0:/bundles/firmware_logo.okpkg',
40522
40524
  };
40523
40525
  const RESOURCE_TYPE_SET = new Set(PROTOCOL_V2_RESOURCE_TYPES);
40524
40526
  const SHA256_HEX_LENGTH = 64;
@@ -40725,7 +40727,7 @@ function parseProtocolV2Resources(value) {
40725
40727
  const stable = config.stable.map(validateResource);
40726
40728
  const types = new Set(stable.map(resource => resource.type));
40727
40729
  if (stable.length !== PROTOCOL_V2_RESOURCE_TYPES.length || types.size !== stable.length) {
40728
- throw new Error('Invalid Pro2 resources config: stable must contain six unique resource types');
40730
+ throw new Error(`Invalid Pro2 resources config: stable must contain ${PROTOCOL_V2_RESOURCE_TYPES.length} unique resource types`);
40729
40731
  }
40730
40732
  for (const type of PROTOCOL_V2_RESOURCE_TYPES) {
40731
40733
  if (!types.has(type)) {
@@ -47498,7 +47500,7 @@ function buildComponentRelease({ configKey, component, currentVersions, currentV
47498
47500
  required: releaseRequired && status === 'outdated',
47499
47501
  };
47500
47502
  }
47501
- function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification = {}, checkFirmwareHash = false, remotePayloadHashes = {}, firmwareType, release, }) {
47503
+ function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification = {}, checkFirmwareHash = false, remotePayloadHashes = {}, firmwareType, release, deviceType, }) {
47502
47504
  if (!release) {
47503
47505
  return {
47504
47506
  firmwareType,
@@ -47511,17 +47513,24 @@ function buildProtocolV2FirmwareRelease({ currentVersions, currentVerification =
47511
47513
  release: undefined,
47512
47514
  };
47513
47515
  }
47514
- let components = getOrderedComponentEntries(release).map(([configKey, component]) => buildComponentRelease({
47515
- configKey,
47516
- component,
47517
- currentVersions,
47518
- currentVerification,
47519
- checkFirmwareHash,
47520
- remotePayloadHash: Object.prototype.hasOwnProperty.call(remotePayloadHashes, configKey)
47521
- ? remotePayloadHashes[configKey]
47522
- : normalizeHex(component.payloadHash),
47523
- releaseRequired: release.required,
47524
- }));
47516
+ let components = getOrderedComponentEntries(release).map(([configKey, component]) => {
47517
+ const result = buildComponentRelease({
47518
+ configKey,
47519
+ component,
47520
+ currentVersions,
47521
+ currentVerification,
47522
+ checkFirmwareHash,
47523
+ remotePayloadHash: Object.prototype.hasOwnProperty.call(remotePayloadHashes, configKey)
47524
+ ? remotePayloadHashes[configKey]
47525
+ : normalizeHex(component.payloadHash),
47526
+ releaseRequired: release.required,
47527
+ });
47528
+ if (deviceType === 'neo' &&
47529
+ (result.componentTarget === 'SE03' || result.componentTarget === 'SE04')) {
47530
+ return Object.assign(Object.assign({}, result), { updateTarget: null, status: 'unsupported', required: false });
47531
+ }
47532
+ return result;
47533
+ });
47525
47534
  if (!currentVersions.applicationP2) {
47526
47535
  const applicationP1 = components.find(component => component.componentTarget === 'APPLICATION_P1');
47527
47536
  if (applicationP1) {
@@ -47663,6 +47672,7 @@ class CheckAllFirmwareRelease extends BaseMethod {
47663
47672
  checkFirmwareHash,
47664
47673
  firmwareType,
47665
47674
  release,
47675
+ deviceType: state.identity.deviceType,
47666
47676
  });
47667
47677
  const resourceDeviceType = state.identity.deviceType === 'neo' ? hdShared.EDeviceType.Neo : hdShared.EDeviceType.Pro2;
47668
47678
  const resources = DataManager.getProtocolV2Resources(resourceDeviceType);
@@ -50939,6 +50949,20 @@ const PROTOCOL_V2_OKPP_HEADER_SIZE = 0x52a0;
50939
50949
  const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
50940
50950
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
50941
50951
  const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
50952
+ const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set(['se03', 'se04']);
50953
+ function assertProtocolV2FirmwareTargetsSupported(deviceType, params) {
50954
+ var _a;
50955
+ if (deviceType !== hdShared.EDeviceType.Neo)
50956
+ return;
50957
+ const unsupportedTargets = new Set(((_a = params.targetsToUpdate) !== null && _a !== void 0 ? _a : []).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target)));
50958
+ if (params.se03Binary)
50959
+ unsupportedTargets.add('se03');
50960
+ if (params.se04Binary)
50961
+ unsupportedTargets.add('se04');
50962
+ if (unsupportedTargets.size) {
50963
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Neo only supports SE01 and SE02; unsupported firmware targets: ${Array.from(unsupportedTargets).join(', ')}`);
50964
+ }
50965
+ }
50942
50966
  const getProtocolV2DeviceTransferProgress = (bytesBeforeChunk, bytesAfterChunk, totalBytes) => {
50943
50967
  if (!Number.isFinite(totalBytes) || totalBytes <= 0) {
50944
50968
  return 100;
@@ -51292,10 +51316,15 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51292
51316
  });
51293
51317
  }
51294
51318
  runProtocolV2() {
51295
- var _a, _b, _c, _d, _e;
51319
+ var _a, _b, _c, _d, _e, _f;
51296
51320
  return __awaiter(this, void 0, void 0, function* () {
51297
51321
  yield this.captureProtocolV2PhysicalIdentity();
51298
51322
  const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
51323
+ const currentDeviceType = this.device.getCurrentDeviceType();
51324
+ const capabilityDeviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
51325
+ ? currentDeviceType
51326
+ : getDeviceType(deviceFeatures);
51327
+ assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params);
51299
51328
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
51300
51329
  const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
51301
51330
  this.validateExpectedTargetVersions();
@@ -51304,7 +51333,8 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51304
51333
  return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
51305
51334
  }
51306
51335
  const needsRemoteResources = !((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length) && !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
51307
- const needsRemoteBootResources = !!((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.includes('boot_resources'));
51336
+ const needsRemoteBootResources = !!((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.includes('resource')) ||
51337
+ !!((_f = this.params.targetsToUpdate) === null || _f === void 0 ? void 0 : _f.includes('boot_resources'));
51308
51338
  let fwBinaryMap = [];
51309
51339
  let bootloaderBinary = null;
51310
51340
  let installItems;
@@ -51787,10 +51817,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51787
51817
  throw new Error(`Unsupported Protocol V2 device type: ${deviceType}`);
51788
51818
  }
51789
51819
  prepareProtocolV2BootResources() {
51790
- var _a, _b, _c;
51820
+ var _a, _b, _c, _d;
51791
51821
  return __awaiter(this, void 0, void 0, function* () {
51792
- if (!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('boot_resources')))
51822
+ if (!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource')) &&
51823
+ !((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('boot_resources'))) {
51793
51824
  return undefined;
51825
+ }
51794
51826
  const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
51795
51827
  if (!resource)
51796
51828
  throw new Error('Missing Protocol V2 boot resources configuration');
@@ -51802,7 +51834,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51802
51834
  throw new Error(`Boot resource file verification failed: ${file.devicePath}`);
51803
51835
  }
51804
51836
  files.push({
51805
- name: (_c = (_b = file.name) !== null && _b !== void 0 ? _b : file.devicePath.split('/').pop()) !== null && _c !== void 0 ? _c : file.devicePath,
51837
+ name: (_d = (_c = file.name) !== null && _c !== void 0 ? _c : file.devicePath.split('/').pop()) !== null && _d !== void 0 ? _d : file.devicePath,
51806
51838
  binary,
51807
51839
  devicePath: file.devicePath,
51808
51840
  });
@@ -52623,7 +52655,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52623
52655
  });
52624
52656
  }
52625
52657
  isProtocolV2ReconnectIdentityError(error) {
52626
- return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity');
52658
+ return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity mismatch');
52627
52659
  }
52628
52660
  fileWriteChunk(filePath, totalFileSize, offset, chunk, overwrite, progress) {
52629
52661
  var _a;
@@ -52639,7 +52671,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52639
52671
  overwrite,
52640
52672
  append: false,
52641
52673
  ui_percentage: progress !== null && progress !== void 0 ? progress : undefined,
52642
- }, { writeWithResponse: true });
52674
+ }, {
52675
+ writeWithResponse: false,
52676
+ onWriteCompleted: () => undefined,
52677
+ });
52643
52678
  if (writeRes.type !== 'FilesystemFile') {
52644
52679
  if (writeRes.type === 'CallMethodError') {
52645
52680
  if (((_a = writeRes.message.error) !== null && _a !== void 0 ? _a : '').indexOf(SESSION_ERROR) > -1) {
@@ -52808,7 +52843,7 @@ class DeviceGetOnboardingStatus extends BaseMethod {
52808
52843
  }
52809
52844
  }
52810
52845
 
52811
- const Log$4 = getLogger(exports.LoggerNames.Method);
52846
+ const Log$4 = getLogger(exports.LoggerNames.Core);
52812
52847
  const MIN_FILE_CHUNK_SIZE = 64;
52813
52848
  const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
52814
52849
  const FILE_TRANSFER_LOG_INTERVAL_MS = 10000;
@@ -52825,8 +52860,11 @@ function getFileTransferTransport() {
52825
52860
  const env = DataManager.getSettings('env');
52826
52861
  return env && DataManager.isBleConnect(env) ? 'BLE' : String(env !== null && env !== void 0 ? env : 'unknown');
52827
52862
  }
52828
- function logFileTransferMetrics({ transport, status, transferredBytes, totalBytes, elapsedMs, rateBytesPerSecond, }) {
52829
- Log$4.log(`[FileWrite] metrics transport=${transport} status=${status} bytes=${transferredBytes}/${totalBytes} elapsed=${(elapsedMs / 1000).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s`);
52863
+ function logFileTransferMetrics({ transport, status, path, transferredBytes, totalBytes, elapsedMs, rateBytesPerSecond, hostWriteElapsedMs, responseWaitElapsedMs, measuredAttempts, }) {
52864
+ const segmentedMetrics = measuredAttempts > 0
52865
+ ? ` hostWriteTotal=${(hostWriteElapsedMs / 1000).toFixed(2)}s responseWaitTotal=${(responseWaitElapsedMs / 1000).toFixed(2)}s measuredAttempts=${measuredAttempts}`
52866
+ : '';
52867
+ Log$4.log(`[FileWrite] metrics transport=${transport} status=${status} path=${path} bytes=${transferredBytes}/${totalBytes} elapsed=${(elapsedMs / 1000).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s${segmentedMetrics}`);
52830
52868
  }
52831
52869
  function isProtocolV2ResponseTimeout(error) {
52832
52870
  var _a, _b;
@@ -52908,7 +52946,11 @@ function writeProtocolV2File(options) {
52908
52946
  let lastConfirmedAt = startTime;
52909
52947
  let logWindowStartedAt = startTime;
52910
52948
  let logWindowStartedBytes = 0;
52949
+ let hostWriteElapsedMs = 0;
52950
+ let responseWaitElapsedMs = 0;
52951
+ let measuredAttempts = 0;
52911
52952
  const transport = getFileTransferTransport();
52953
+ Log$4.log(`[FileWrite] started transport=${transport} path=${options.path} bytes=${dataLength} offset=${startOffset} chunk=${chunkSize}`);
52912
52954
  try {
52913
52955
  while (written < dataLength) {
52914
52956
  (_c = options.throwIfAborted) === null || _c === void 0 ? void 0 : _c.call(options);
@@ -52930,10 +52972,21 @@ function writeProtocolV2File(options) {
52930
52972
  let response;
52931
52973
  let isWritePending = true;
52932
52974
  while (isWritePending) {
52975
+ let currentHostWriteElapsedMs;
52976
+ let responseWaitStartedAt;
52933
52977
  try {
52934
52978
  const callOptions = options.writeWithResponse === undefined
52935
- ? { timeoutMs: options.timeoutMs }
52936
- : Object.assign(Object.assign({}, (options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs })), { writeWithResponse: options.writeWithResponse });
52979
+ ? {
52980
+ timeoutMs: options.timeoutMs,
52981
+ onWriteCompleted: ({ elapsedMs }) => {
52982
+ currentHostWriteElapsedMs = elapsedMs;
52983
+ responseWaitStartedAt = Date.now();
52984
+ },
52985
+ }
52986
+ : Object.assign(Object.assign({}, (options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs })), { writeWithResponse: options.writeWithResponse, onWriteCompleted: ({ elapsedMs }) => {
52987
+ currentHostWriteElapsedMs = elapsedMs;
52988
+ responseWaitStartedAt = Date.now();
52989
+ } });
52937
52990
  response = yield options.commands.typedCall('FilesystemFileWrite', 'FilesystemFile', request, callOptions);
52938
52991
  isWritePending = false;
52939
52992
  }
@@ -52943,6 +52996,13 @@ function writeProtocolV2File(options) {
52943
52996
  retryCount += 1;
52944
52997
  (_k = options.throwIfAborted) === null || _k === void 0 ? void 0 : _k.call(options);
52945
52998
  }
52999
+ finally {
53000
+ if (currentHostWriteElapsedMs !== undefined && responseWaitStartedAt !== undefined) {
53001
+ hostWriteElapsedMs += currentHostWriteElapsedMs;
53002
+ responseWaitElapsedMs += Math.max(Date.now() - responseWaitStartedAt, 0);
53003
+ measuredAttempts += 1;
53004
+ }
53005
+ }
52946
53006
  }
52947
53007
  if (!response) {
52948
53008
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'FilesystemFileWrite completed without a response');
@@ -52995,10 +53055,14 @@ function writeProtocolV2File(options) {
52995
53055
  logFileTransferMetrics({
52996
53056
  transport,
52997
53057
  status: 'progress',
53058
+ path: options.path,
52998
53059
  transferredBytes,
52999
53060
  totalBytes: dataLength,
53000
53061
  elapsedMs,
53001
53062
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
53063
+ hostWriteElapsedMs,
53064
+ responseWaitElapsedMs,
53065
+ measuredAttempts,
53002
53066
  });
53003
53067
  logWindowStartedAt = now;
53004
53068
  logWindowStartedBytes = transferredBytes;
@@ -53018,10 +53082,14 @@ function writeProtocolV2File(options) {
53018
53082
  logFileTransferMetrics({
53019
53083
  transport,
53020
53084
  status: 'failed',
53085
+ path: options.path,
53021
53086
  transferredBytes: written,
53022
53087
  totalBytes: dataLength,
53023
53088
  elapsedMs,
53024
53089
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
53090
+ hostWriteElapsedMs,
53091
+ responseWaitElapsedMs,
53092
+ measuredAttempts,
53025
53093
  });
53026
53094
  throw error;
53027
53095
  }
@@ -53031,10 +53099,14 @@ function writeProtocolV2File(options) {
53031
53099
  logFileTransferMetrics({
53032
53100
  transport,
53033
53101
  status: 'completed',
53102
+ path: options.path,
53034
53103
  transferredBytes: written,
53035
53104
  totalBytes: dataLength,
53036
53105
  elapsedMs,
53037
53106
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
53107
+ hostWriteElapsedMs,
53108
+ responseWaitElapsedMs,
53109
+ measuredAttempts,
53038
53110
  });
53039
53111
  return Object.assign(Object.assign({}, lastMessage), { path: options.path, offset: startOffset, total_size: totalSize, processed_byte: startOffset + written, chunks });
53040
53112
  });
@@ -1,6 +1,6 @@
1
1
  import type { IProtocolV2Resource, IProtocolV2ResourceFile, IProtocolV2ResourceType, IProtocolV2Resources } from '../../types';
2
2
  import type { DeviceCommands } from '../../device/DeviceCommands';
3
- export declare const PROTOCOL_V2_RESOURCE_TYPES: readonly ["images", "animation", "wallpaper", "translations", "roobert", "noto"];
3
+ export declare const PROTOCOL_V2_RESOURCE_TYPES: readonly ["images", "animation", "wallpaper", "translations", "roobert", "noto", "firmware_logo"];
4
4
  export declare const PROTOCOL_V2_RESOURCE_DEVICE_PATHS: Readonly<Record<IProtocolV2ResourceType, string>>;
5
5
  export declare const PROTOCOL_V2_RESOURCE_INVENTORY_TIMEOUT_MS: number;
6
6
  export type ProtocolV2ResourceInventoryItem = {
@@ -1 +1 @@
1
- {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/resources.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,eAAO,MAAM,0BAA0B,kFAOgB,CAAC;AAExD,eAAO,MAAM,iCAAiC,EAAE,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAQ7F,CAAC;AAaJ,eAAO,MAAM,yCAAyC,QAAW,CAAC;AAElE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,uBAAuB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,aAAa,GAAG,qBAAqB,CAAC;AAEjF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACzC,SAAS,EAAE,mBAAmB,EAAE,CAAC;CAClC,CAAC;AAwHF,wBAAsB,+BAA+B,CAAC,EACpD,QAAQ,EACR,SAAS,EACT,SAAgD,EAChD,SAAqD,GACtD,EAAE;IACD,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC5C,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAmB7C;AAiGD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAgCzF;AAGD,wBAAgB,iCAAiC,CAAC,EAChD,SAAS,EACT,SAAS,EACT,IAAI,EACJ,MAAc,GACf,EAAE;IACD,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,SAAS,+BAA+B,EAAE,CAAC;IACvD,IAAI,EAAE,4BAA4B,CAAC;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,4BAA4B,CA8B/B;AAOD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,GAAG,UAAU,CAAC,GAC3D,OAAO,CAGT"}
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/resources.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,mBAAmB,EACnB,uBAAuB,EACvB,uBAAuB,EACvB,oBAAoB,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAElE,eAAO,MAAM,0BAA0B,mGAQgB,CAAC;AAExD,eAAO,MAAM,iCAAiC,EAAE,QAAQ,CAAC,MAAM,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAS7F,CAAC;AAaJ,eAAO,MAAM,yCAAyC,QAAW,CAAC;AAElE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,uBAAuB,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG,aAAa,GAAG,qBAAqB,CAAC;AAEjF,MAAM,MAAM,4BAA4B,GAAG;IACzC,MAAM,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC;IACzC,SAAS,EAAE,mBAAmB,EAAE,CAAC;CAClC,CAAC;AAwHF,wBAAsB,+BAA+B,CAAC,EACpD,QAAQ,EACR,SAAS,EACT,SAAgD,EAChD,SAAqD,GACtD,EAAE;IACD,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IAC5C,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,+BAA+B,EAAE,CAAC,CAmB7C;AAiGD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CAkCzF;AAGD,wBAAgB,iCAAiC,CAAC,EAChD,SAAS,EACT,SAAS,EACT,IAAI,EACJ,MAAc,GACf,EAAE;IACD,SAAS,EAAE,SAAS,mBAAmB,EAAE,CAAC;IAC1C,SAAS,CAAC,EAAE,SAAS,+BAA+B,EAAE,CAAC;IACvD,IAAI,EAAE,4BAA4B,CAAC;IACnC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,4BAA4B,CA8B/B;AAOD,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,GAAG,UAAU,CAAC,GAC3D,OAAO,CAGT"}
@@ -35,7 +35,7 @@ export type IProtocolV2FirmwareComponent = {
35
35
  expectedSize?: number;
36
36
  version?: IVersionArray;
37
37
  };
38
- export type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto';
38
+ export type IProtocolV2ResourceType = 'images' | 'animation' | 'wallpaper' | 'translations' | 'roobert' | 'noto' | 'firmware_logo';
39
39
  export type IProtocolV2Resource = {
40
40
  type: IProtocolV2ResourceType;
41
41
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/types/settings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../src/types/settings.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.70",
3
+ "version": "1.2.0-alpha.71",
4
4
  "description": "Core processes and APIs for communicating with OneKey hardware devices.",
5
5
  "author": "OneKey",
6
6
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
@@ -25,8 +25,8 @@
25
25
  "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
26
26
  },
27
27
  "dependencies": {
28
- "@onekeyfe/hd-shared": "1.2.0-alpha.70",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.70",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.71",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.71",
30
30
  "axios": "1.15.2",
31
31
  "bignumber.js": "^9.0.2",
32
32
  "bytebuffer": "^5.0.1",
@@ -44,5 +44,5 @@
44
44
  "@types/w3c-web-usb": "^1.0.10",
45
45
  "@types/web-bluetooth": "^0.0.21"
46
46
  },
47
- "gitHead": "d86b033cf970f97e060c49fe4cf618f38b9ce666"
47
+ "gitHead": "c58f39f2e5c54a98faa8844cd8b6b0453a17d80c"
48
48
  }
@@ -191,6 +191,7 @@ export function buildProtocolV2FirmwareRelease({
191
191
  remotePayloadHashes = {},
192
192
  firmwareType,
193
193
  release,
194
+ deviceType,
194
195
  }: {
195
196
  currentVersions: DeviceStateVersions;
196
197
  currentVerification?: Partial<DeviceFeaturesVerify>;
@@ -198,6 +199,7 @@ export function buildProtocolV2FirmwareRelease({
198
199
  remotePayloadHashes?: Readonly<Record<string, string | null>>;
199
200
  firmwareType: EFirmwareType;
200
201
  release: IFirmwareReleaseInfo | undefined;
202
+ deviceType?: 'pro2' | 'neo';
201
203
  }): ProtocolV2FirmwareReleasePlan {
202
204
  if (!release) {
203
205
  return {
@@ -212,8 +214,8 @@ export function buildProtocolV2FirmwareRelease({
212
214
  };
213
215
  }
214
216
 
215
- let components = getOrderedComponentEntries(release).map(([configKey, component]) =>
216
- buildComponentRelease({
217
+ let components = getOrderedComponentEntries(release).map(([configKey, component]) => {
218
+ const result = buildComponentRelease({
217
219
  configKey,
218
220
  component,
219
221
  currentVersions,
@@ -223,8 +225,20 @@ export function buildProtocolV2FirmwareRelease({
223
225
  ? remotePayloadHashes[configKey]
224
226
  : normalizeHex(component.payloadHash),
225
227
  releaseRequired: release.required,
226
- })
227
- );
228
+ });
229
+ if (
230
+ deviceType === 'neo' &&
231
+ (result.componentTarget === 'SE03' || result.componentTarget === 'SE04')
232
+ ) {
233
+ return {
234
+ ...result,
235
+ updateTarget: null,
236
+ status: 'unsupported' as const,
237
+ required: false,
238
+ };
239
+ }
240
+ return result;
241
+ });
228
242
  if (!currentVersions.applicationP2) {
229
243
  const applicationP1 = components.find(
230
244
  component => component.componentTarget === 'APPLICATION_P1'
@@ -401,6 +415,7 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
401
415
  checkFirmwareHash,
402
416
  firmwareType,
403
417
  release,
418
+ deviceType: state.identity.deviceType,
404
419
  });
405
420
  const resourceDeviceType =
406
421
  state.identity.deviceType === 'neo' ? EDeviceType.Neo : EDeviceType.Pro2;
@@ -15,6 +15,7 @@ import {
15
15
  getDeviceBLEFirmwareVersion,
16
16
  getDeviceBootloaderVersion,
17
17
  getDeviceFirmwareVersion,
18
+ getDeviceType,
18
19
  getFirmwareType,
19
20
  getLogger,
20
21
  } from '../utils';
@@ -90,6 +91,30 @@ const PROTOCOL_V2_OKPP_PAYLOAD_HASH_OFFSET = 0x200;
90
91
  const PROTOCOL_V2_OKPP_HEADER_HASH_OFFSET = 0x240;
91
92
  const PROTOCOL_V2_OKPP_HASH_SIZE = 64;
92
93
 
94
+ const PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS = new Set<FirmwareUpdateV4Target>(['se03', 'se04']);
95
+
96
+ export function assertProtocolV2FirmwareTargetsSupported(
97
+ deviceType: EDeviceType | string | undefined,
98
+ params: FirmwareUpdateV4Params
99
+ ) {
100
+ if (deviceType !== EDeviceType.Neo) return;
101
+
102
+ const unsupportedTargets = new Set(
103
+ (params.targetsToUpdate ?? []).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target))
104
+ );
105
+ if (params.se03Binary) unsupportedTargets.add('se03');
106
+ if (params.se04Binary) unsupportedTargets.add('se04');
107
+
108
+ if (unsupportedTargets.size) {
109
+ throw ERRORS.TypedError(
110
+ HardwareErrorCode.RuntimeError,
111
+ `Neo only supports SE01 and SE02; unsupported firmware targets: ${Array.from(
112
+ unsupportedTargets
113
+ ).join(', ')}`
114
+ );
115
+ }
116
+ }
117
+
93
118
  const getProtocolV2DeviceTransferProgress = (
94
119
  bytesBeforeChunk: number,
95
120
  bytesAfterChunk: number,
@@ -610,6 +635,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
610
635
  private async runProtocolV2() {
611
636
  await this.captureProtocolV2PhysicalIdentity();
612
637
  const deviceFeatures = await this.getProtocolV2DeviceFeatures();
638
+ const currentDeviceType = this.device.getCurrentDeviceType();
639
+ const capabilityDeviceType =
640
+ currentDeviceType === EDeviceType.Pro2 || currentDeviceType === EDeviceType.Neo
641
+ ? currentDeviceType
642
+ : getDeviceType(deviceFeatures);
643
+ assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params);
613
644
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
614
645
  const firmwareType = this.params.firmwareType ?? deviceFirmwareType;
615
646
  this.validateExpectedTargetVersions();
@@ -622,7 +653,9 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
622
653
  }
623
654
  const needsRemoteResources =
624
655
  !this.params.resourceFiles?.length && !!this.params.targetsToUpdate?.includes('resource');
625
- const needsRemoteBootResources = !!this.params.targetsToUpdate?.includes('boot_resources');
656
+ const needsRemoteBootResources =
657
+ !!this.params.targetsToUpdate?.includes('resource') ||
658
+ !!this.params.targetsToUpdate?.includes('boot_resources');
626
659
 
627
660
  let fwBinaryMap: ProtocolV2TargetBinary[] = [];
628
661
  let bootloaderBinary: ArrayBuffer | null = null;
@@ -1223,7 +1256,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1223
1256
  private async prepareProtocolV2BootResources(): Promise<
1224
1257
  ProtocolV2ResourceBundleBinary[] | undefined
1225
1258
  > {
1226
- if (!this.params.targetsToUpdate?.includes('boot_resources')) return undefined;
1259
+ if (
1260
+ !this.params.targetsToUpdate?.includes('resource') &&
1261
+ !this.params.targetsToUpdate?.includes('boot_resources')
1262
+ ) {
1263
+ return undefined;
1264
+ }
1227
1265
  const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
1228
1266
  if (!resource) throw new Error('Missing Protocol V2 boot resources configuration');
1229
1267
 
@@ -2289,7 +2327,11 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2289
2327
  }
2290
2328
 
2291
2329
  private isProtocolV2ReconnectIdentityError(error: unknown) {
2292
- return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity');
2330
+ // A serial can be temporarily unavailable while Loader starts, and BLE has no stable path.
2331
+ // Keep polling unless the device explicitly reports a different serial.
2332
+ return this.normalizeErrorMessage(error).includes(
2333
+ 'Protocol V2 reconnect physical identity mismatch'
2334
+ );
2293
2335
  }
2294
2336
 
2295
2337
  private async fileWriteChunk(
@@ -2315,7 +2357,10 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
2315
2357
  append: false,
2316
2358
  ui_percentage: progress ?? undefined,
2317
2359
  },
2318
- { writeWithResponse: true }
2360
+ {
2361
+ writeWithResponse: false,
2362
+ onWriteCompleted: () => undefined,
2363
+ }
2319
2364
  );
2320
2365
  if (writeRes.type !== 'FilesystemFile') {
2321
2366
  if ((writeRes as any).type === 'CallMethodError') {
@@ -9,7 +9,7 @@ import { LoggerNames, getLogger } from '../../utils/logger';
9
9
 
10
10
  import type { DeviceCommands } from '../../device/DeviceCommands';
11
11
 
12
- const Log = getLogger(LoggerNames.Method);
12
+ const Log = getLogger(LoggerNames.Core);
13
13
 
14
14
  export type ProtocolV2FileWriteData = ArrayBuffer | Uint8Array | Blob | string;
15
15
 
@@ -69,22 +69,36 @@ function getFileTransferTransport() {
69
69
  function logFileTransferMetrics({
70
70
  transport,
71
71
  status,
72
+ path,
72
73
  transferredBytes,
73
74
  totalBytes,
74
75
  elapsedMs,
75
76
  rateBytesPerSecond,
77
+ hostWriteElapsedMs,
78
+ responseWaitElapsedMs,
79
+ measuredAttempts,
76
80
  }: {
77
81
  transport: string;
78
82
  status: 'progress' | 'completed' | 'failed';
83
+ path: string;
79
84
  transferredBytes: number;
80
85
  totalBytes: number;
81
86
  elapsedMs: number;
82
87
  rateBytesPerSecond: number;
88
+ hostWriteElapsedMs: number;
89
+ responseWaitElapsedMs: number;
90
+ measuredAttempts: number;
83
91
  }) {
92
+ const segmentedMetrics =
93
+ measuredAttempts > 0
94
+ ? ` hostWriteTotal=${(hostWriteElapsedMs / 1000).toFixed(2)}s responseWaitTotal=${(
95
+ responseWaitElapsedMs / 1000
96
+ ).toFixed(2)}s measuredAttempts=${measuredAttempts}`
97
+ : '';
84
98
  Log.log(
85
- `[FileWrite] metrics transport=${transport} status=${status} bytes=${transferredBytes}/${totalBytes} elapsed=${(
99
+ `[FileWrite] metrics transport=${transport} status=${status} path=${path} bytes=${transferredBytes}/${totalBytes} elapsed=${(
86
100
  elapsedMs / 1000
87
- ).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s`
101
+ ).toFixed(2)}s speed=${formatFileTransferRate(rateBytesPerSecond)} KiB/s${segmentedMetrics}`
88
102
  );
89
103
  }
90
104
 
@@ -177,7 +191,13 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
177
191
  let lastConfirmedAt = startTime;
178
192
  let logWindowStartedAt = startTime;
179
193
  let logWindowStartedBytes = 0;
194
+ let hostWriteElapsedMs = 0;
195
+ let responseWaitElapsedMs = 0;
196
+ let measuredAttempts = 0;
180
197
  const transport = getFileTransferTransport();
198
+ Log.log(
199
+ `[FileWrite] started transport=${transport} path=${options.path} bytes=${dataLength} offset=${startOffset} chunk=${chunkSize}`
200
+ );
181
201
 
182
202
  try {
183
203
  while (written < dataLength) {
@@ -203,13 +223,25 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
203
223
  let response;
204
224
  let isWritePending = true;
205
225
  while (isWritePending) {
226
+ let currentHostWriteElapsedMs: number | undefined;
227
+ let responseWaitStartedAt: number | undefined;
206
228
  try {
207
229
  const callOptions =
208
230
  options.writeWithResponse === undefined
209
- ? { timeoutMs: options.timeoutMs }
231
+ ? {
232
+ timeoutMs: options.timeoutMs,
233
+ onWriteCompleted: ({ elapsedMs }: { elapsedMs: number }) => {
234
+ currentHostWriteElapsedMs = elapsedMs;
235
+ responseWaitStartedAt = Date.now();
236
+ },
237
+ }
210
238
  : {
211
239
  ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
212
240
  writeWithResponse: options.writeWithResponse,
241
+ onWriteCompleted: ({ elapsedMs }: { elapsedMs: number }) => {
242
+ currentHostWriteElapsedMs = elapsedMs;
243
+ responseWaitStartedAt = Date.now();
244
+ },
213
245
  };
214
246
  response = await options.commands.typedCall(
215
247
  'FilesystemFileWrite',
@@ -222,6 +254,12 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
222
254
  if (retryCount >= maxChunkRetries || !isProtocolV2ResponseTimeout(error)) throw error;
223
255
  retryCount += 1;
224
256
  options.throwIfAborted?.();
257
+ } finally {
258
+ if (currentHostWriteElapsedMs !== undefined && responseWaitStartedAt !== undefined) {
259
+ hostWriteElapsedMs += currentHostWriteElapsedMs;
260
+ responseWaitElapsedMs += Math.max(Date.now() - responseWaitStartedAt, 0);
261
+ measuredAttempts += 1;
262
+ }
225
263
  }
226
264
  }
227
265
  if (!response) {
@@ -285,10 +323,14 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
285
323
  logFileTransferMetrics({
286
324
  transport,
287
325
  status: 'progress',
326
+ path: options.path,
288
327
  transferredBytes,
289
328
  totalBytes: dataLength,
290
329
  elapsedMs,
291
330
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
331
+ hostWriteElapsedMs,
332
+ responseWaitElapsedMs,
333
+ measuredAttempts,
292
334
  });
293
335
  logWindowStartedAt = now;
294
336
  logWindowStartedBytes = transferredBytes;
@@ -307,10 +349,14 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
307
349
  logFileTransferMetrics({
308
350
  transport,
309
351
  status: 'failed',
352
+ path: options.path,
310
353
  transferredBytes: written,
311
354
  totalBytes: dataLength,
312
355
  elapsedMs,
313
356
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
357
+ hostWriteElapsedMs,
358
+ responseWaitElapsedMs,
359
+ measuredAttempts,
314
360
  });
315
361
  throw error;
316
362
  }
@@ -321,10 +367,14 @@ export async function writeProtocolV2File(options: ProtocolV2FileWriteOptions) {
321
367
  logFileTransferMetrics({
322
368
  transport,
323
369
  status: 'completed',
370
+ path: options.path,
324
371
  transferredBytes: written,
325
372
  totalBytes: dataLength,
326
373
  elapsedMs,
327
374
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
375
+ hostWriteElapsedMs,
376
+ responseWaitElapsedMs,
377
+ measuredAttempts,
328
378
  });
329
379
 
330
380
  return {
@@ -17,6 +17,7 @@ export const PROTOCOL_V2_RESOURCE_TYPES = [
17
17
  'translations',
18
18
  'roobert',
19
19
  'noto',
20
+ 'firmware_logo',
20
21
  ] as const satisfies readonly IProtocolV2ResourceType[];
21
22
 
22
23
  export const PROTOCOL_V2_RESOURCE_DEVICE_PATHS: Readonly<Record<IProtocolV2ResourceType, string>> =
@@ -27,6 +28,7 @@ export const PROTOCOL_V2_RESOURCE_DEVICE_PATHS: Readonly<Record<IProtocolV2Resou
27
28
  translations: 'vol0:/bundles/translations/translations.okpkg',
28
29
  roobert: 'vol0:/bundles/font/roobert.okpkg',
29
30
  noto: 'vol0:/bundles/font/noto.okpkg',
31
+ firmware_logo: 'vol0:/bundles/firmware_logo.okpkg',
30
32
  };
31
33
 
32
34
  const RESOURCE_TYPE_SET = new Set<string>(PROTOCOL_V2_RESOURCE_TYPES);
@@ -313,7 +315,9 @@ export function parseProtocolV2Resources(value: unknown): IProtocolV2Resources |
313
315
  const stable = config.stable.map(validateResource);
314
316
  const types = new Set(stable.map(resource => resource.type));
315
317
  if (stable.length !== PROTOCOL_V2_RESOURCE_TYPES.length || types.size !== stable.length) {
316
- throw new Error('Invalid Pro2 resources config: stable must contain six unique resource types');
318
+ throw new Error(
319
+ `Invalid Pro2 resources config: stable must contain ${PROTOCOL_V2_RESOURCE_TYPES.length} unique resource types`
320
+ );
317
321
  }
318
322
  for (const type of PROTOCOL_V2_RESOURCE_TYPES) {
319
323
  if (!types.has(type)) {
@@ -70,7 +70,8 @@ export type IProtocolV2ResourceType =
70
70
  | 'wallpaper'
71
71
  | 'translations'
72
72
  | 'roobert'
73
- | 'noto';
73
+ | 'noto'
74
+ | 'firmware_logo';
74
75
 
75
76
  /** Pro2 RES package descriptor. Hashes identify content without a human-managed version. */
76
77
  export type IProtocolV2Resource = {