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

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.
@@ -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> {
@@ -45,6 +47,8 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
45
47
  private prepareRemoteProtocolV2Binaries;
46
48
  private getProtocolV2DeviceType;
47
49
  private prepareProtocolV2BootResources;
50
+ private isProtocolV2BootResourceCurrent;
51
+ private mergeProtocolV2ResourceBundles;
48
52
  private prepareExplicitProtocolV2ResourceFiles;
49
53
  private prepareProtocolV2ResourceBundles;
50
54
  private downloadProtocolV2Resource;
@@ -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;AAyBlG,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,QAgB/B;AAgUD,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;IAwBhC,GAAG;;;;;YAKK,aAAa;YAwHb,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;YA0C9B,+BAA+B;IAgD7C,OAAO,CAAC,8BAA8B;IAetC,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"}
@@ -20,6 +20,7 @@ export type ProtocolV2FileWriteOptions = {
20
20
  totalSize?: number;
21
21
  chunkSize?: number;
22
22
  chunkLen?: number;
23
+ chunkSizeLimit?: number;
23
24
  overwrite?: boolean;
24
25
  append?: boolean;
25
26
  uiPercentage?: number;
@@ -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,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,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;;;;;;GAuO5E"}
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;
@@ -1454,6 +1454,7 @@ interface FirmwareUpdateV4Params {
1454
1454
  /**
1455
1455
  * Arbitrary Protocol V2 resource files written directly with FilesystemFileWrite.
1456
1456
  * Use this for manifest-driven boot resources and other non-RESC files.
1457
+ * When provided, these files are authoritative for resource and boot_resources targets.
1457
1458
  */
1458
1459
  resourceFiles?: Array<{
1459
1460
  binary: ArrayBuffer;
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,22 @@ 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
+ const unsupportedTargets = new Set(((_a = params.targetsToUpdate) !== null && _a !== void 0 ? _a : []).filter(target => PROTOCOL_V2_NEO_UNSUPPORTED_TARGETS.has(target)));
50956
+ if (params.se03Binary)
50957
+ unsupportedTargets.add('se03');
50958
+ if (params.se04Binary)
50959
+ unsupportedTargets.add('se04');
50960
+ if (!unsupportedTargets.size || deviceType === hdShared.EDeviceType.Pro2)
50961
+ return;
50962
+ const targetList = Array.from(unsupportedTargets).join(', ');
50963
+ const message = deviceType === hdShared.EDeviceType.Neo
50964
+ ? `Neo only supports SE01 and SE02; unsupported firmware targets: ${targetList}`
50965
+ : `Cannot safely update ${targetList} without a confirmed Pro2 device type`;
50966
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotSupportMethod, message);
50967
+ }
50942
50968
  const getProtocolV2DeviceTransferProgress = (bytesBeforeChunk, bytesAfterChunk, totalBytes) => {
50943
50969
  if (!Number.isFinite(totalBytes) || totalBytes <= 0) {
50944
50970
  return 100;
@@ -50993,6 +51019,7 @@ const PROTOCOL_V2_REMOTE_COMPONENT_TARGETS = {
50993
51019
  kind: 'firmware',
50994
51020
  },
50995
51021
  };
51022
+ const PROTOCOL_V2_FIRMWARE_STAGING_PATHS = new Set(Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => `${PROTOCOL_V2_FIRMWARE_STAGING_VOLUME}${target.fileName}`));
50996
51023
  const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map([
50997
51024
  [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_BOOTLOADER, 'boot'],
50998
51025
  [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_APPLICATION_P1, 'app_v1'],
@@ -51268,17 +51295,21 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51268
51295
  resourceBundleArtifacts: payload.resourceBundleArtifacts,
51269
51296
  };
51270
51297
  }
51271
- getProtocolV2FirmwareChunkSize(direction = 'write') {
51298
+ getProtocolV2FirmwareChunkSize(direction = 'write', filePath) {
51272
51299
  var _a, _b;
51273
51300
  const payloadChunkSize = Number((_a = this.params) === null || _a === void 0 ? void 0 : _a.chunkSize);
51274
51301
  const env = DataManager.getSettings('env');
51275
51302
  const isBle = ((_b = this.params) === null || _b === void 0 ? void 0 : _b.platform) === 'native' || (env && DataManager.isBleConnect(env));
51276
51303
  let maxChunkSize = hdTransport.PROTOCOL_V2_WEBUSB_FILE_CHUNK_SIZE;
51277
51304
  if (isBle) {
51278
- maxChunkSize =
51279
- direction === 'read'
51280
- ? hdTransport.PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE
51305
+ if (direction === 'read') {
51306
+ maxChunkSize = hdTransport.PROTOCOL_V2_BLE_FILE_READ_CHUNK_SIZE;
51307
+ }
51308
+ else {
51309
+ maxChunkSize = PROTOCOL_V2_FIRMWARE_STAGING_PATHS.has(filePath !== null && filePath !== void 0 ? filePath : '')
51310
+ ? hdTransport.PROTOCOL_V2_BLE_FIRMWARE_FILE_CHUNK_SIZE
51281
51311
  : hdTransport.PROTOCOL_V2_BLE_FILE_CHUNK_SIZE;
51312
+ }
51282
51313
  }
51283
51314
  if (!Number.isFinite(payloadChunkSize) || payloadChunkSize <= 0) {
51284
51315
  return maxChunkSize;
@@ -51296,6 +51327,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51296
51327
  return __awaiter(this, void 0, void 0, function* () {
51297
51328
  yield this.captureProtocolV2PhysicalIdentity();
51298
51329
  const deviceFeatures = yield this.getProtocolV2DeviceFeatures();
51330
+ const currentDeviceType = this.device.getCurrentDeviceType();
51331
+ const capabilityDeviceType = currentDeviceType === hdShared.EDeviceType.Pro2 || currentDeviceType === hdShared.EDeviceType.Neo
51332
+ ? currentDeviceType
51333
+ : getDeviceType(deviceFeatures);
51334
+ assertProtocolV2FirmwareTargetsSupported(capabilityDeviceType, this.params);
51299
51335
  const deviceFirmwareType = getFirmwareType(deviceFeatures);
51300
51336
  const firmwareType = (_a = this.params.firmwareType) !== null && _a !== void 0 ? _a : deviceFirmwareType;
51301
51337
  this.validateExpectedTargetVersions();
@@ -51303,8 +51339,11 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51303
51339
  ((_b = this.params.resourceBundleArtifacts) === null || _b === void 0 ? void 0 : _b.length)) {
51304
51340
  return this.runProtocolV2PreparedArtifacts(deviceFeatures, firmwareType);
51305
51341
  }
51306
- 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'));
51342
+ const hasExplicitResourceFiles = !!((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length);
51343
+ const wantsStableResources = !!((_d = this.params.targetsToUpdate) === null || _d === void 0 ? void 0 : _d.includes('resource'));
51344
+ const wantsBootResources = !!((_e = this.params.targetsToUpdate) === null || _e === void 0 ? void 0 : _e.includes('boot_resources'));
51345
+ const needsRemoteResources = !hasExplicitResourceFiles && wantsStableResources;
51346
+ const needsRemoteBootResources = !hasExplicitResourceFiles && (wantsBootResources || wantsStableResources);
51308
51347
  let fwBinaryMap = [];
51309
51348
  let bootloaderBinary = null;
51310
51349
  let installItems;
@@ -51335,7 +51374,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51335
51374
  }
51336
51375
  const bootResourceFiles = yield this.prepareProtocolV2BootResources();
51337
51376
  if (bootResourceFiles === null || bootResourceFiles === void 0 ? void 0 : bootResourceFiles.length) {
51338
- resourceBundles = [...(resourceBundles !== null && resourceBundles !== void 0 ? resourceBundles : []), ...bootResourceFiles];
51377
+ resourceBundles = this.mergeProtocolV2ResourceBundles(resourceBundles, bootResourceFiles);
51339
51378
  }
51340
51379
  if (!needsRemoteResources) {
51341
51380
  this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
@@ -51358,7 +51397,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51358
51397
  const enteredBootloader = yield this.enterProtocolV2BootloaderMode();
51359
51398
  try {
51360
51399
  const stableResources = yield this.prepareProtocolV2ResourceBundles();
51361
- resourceBundles = [...(resourceBundles !== null && resourceBundles !== void 0 ? resourceBundles : []), ...(stableResources !== null && stableResources !== void 0 ? stableResources : [])];
51400
+ resourceBundles = this.mergeProtocolV2ResourceBundles(resourceBundles, stableResources);
51362
51401
  this.postTipMessage(exports.FirmwareUpdateTipMessage.FinishDownloadFirmware);
51363
51402
  }
51364
51403
  catch (err) {
@@ -51787,29 +51826,95 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51787
51826
  throw new Error(`Unsupported Protocol V2 device type: ${deviceType}`);
51788
51827
  }
51789
51828
  prepareProtocolV2BootResources() {
51790
- var _a, _b, _c;
51829
+ var _a, _b, _c, _d, _e;
51791
51830
  return __awaiter(this, void 0, void 0, function* () {
51792
- if (!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('boot_resources')))
51831
+ const wantsStableResources = !!((_a = this.params.targetsToUpdate) === null || _a === void 0 ? void 0 : _a.includes('resource'));
51832
+ const wantsBootResources = !!((_b = this.params.targetsToUpdate) === null || _b === void 0 ? void 0 : _b.includes('boot_resources'));
51833
+ if (!wantsStableResources && !wantsBootResources) {
51793
51834
  return undefined;
51835
+ }
51836
+ if ((_c = this.params.resourceFiles) === null || _c === void 0 ? void 0 : _c.length) {
51837
+ return undefined;
51838
+ }
51794
51839
  const resource = DataManager.getProtocolV2BootResources(this.getProtocolV2DeviceType());
51795
- if (!resource)
51796
- throw new Error('Missing Protocol V2 boot resources configuration');
51840
+ if (!resource) {
51841
+ if (wantsBootResources) {
51842
+ throw new Error('Missing Protocol V2 boot resources configuration');
51843
+ }
51844
+ Log$6.debug('[FirmwareUpdateV4] no boot resources configured; continue with stable resources');
51845
+ return undefined;
51846
+ }
51797
51847
  const files = [];
51798
51848
  for (const file of resource.files) {
51799
- Log$6.log(`[FirmwareUpdateV4] downloading boot resource ${file.devicePath}`);
51800
- const { binary } = yield getSysResourceBinary(file.url);
51801
- if (!isProtocolV2ResourceFileValid(binary, file)) {
51802
- throw new Error(`Boot resource file verification failed: ${file.devicePath}`);
51849
+ const isCurrent = !this.params.forcedUpdateRes && (yield this.isProtocolV2BootResourceCurrent(file));
51850
+ if (isCurrent) {
51851
+ Log$6.log(`[FirmwareUpdateV4] boot resource unchanged, skipping ${file.devicePath}`);
51852
+ }
51853
+ else {
51854
+ Log$6.log(`[FirmwareUpdateV4] downloading boot resource ${file.devicePath}`);
51855
+ const { binary } = yield getSysResourceBinary(file.url);
51856
+ if (!isProtocolV2ResourceFileValid(binary, file)) {
51857
+ throw new Error(`Boot resource file verification failed: ${file.devicePath}`);
51858
+ }
51859
+ files.push({
51860
+ name: (_e = (_d = file.name) !== null && _d !== void 0 ? _d : file.devicePath.split('/').pop()) !== null && _e !== void 0 ? _e : file.devicePath,
51861
+ binary,
51862
+ devicePath: file.devicePath,
51863
+ });
51803
51864
  }
51804
- files.push({
51805
- name: (_c = (_b = file.name) !== null && _b !== void 0 ? _b : file.devicePath.split('/').pop()) !== null && _c !== void 0 ? _c : file.devicePath,
51806
- binary,
51807
- devicePath: file.devicePath,
51808
- });
51809
51865
  }
51810
51866
  return files;
51811
51867
  });
51812
51868
  }
51869
+ isProtocolV2BootResourceCurrent(file) {
51870
+ var _a, _b, _c, _d;
51871
+ return __awaiter(this, void 0, void 0, function* () {
51872
+ try {
51873
+ const commands = this.device.getCommands();
51874
+ const pathInfo = yield commands.typedCall('FilesystemPathInfoQuery', 'FilesystemPathInfo', { path: file.devicePath }, { timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT });
51875
+ const size = toProtocolV2FiniteNumber((_a = pathInfo.message) === null || _a === void 0 ? void 0 : _a.size);
51876
+ if (!((_b = pathInfo.message) === null || _b === void 0 ? void 0 : _b.exist) ||
51877
+ ((_c = pathInfo.message) === null || _c === void 0 ? void 0 : _c.directory) ||
51878
+ !Number.isSafeInteger(size) ||
51879
+ size !== file.size) {
51880
+ return false;
51881
+ }
51882
+ const digest = sha256.sha256.create();
51883
+ const chunkSize = this.getProtocolV2FirmwareChunkSize();
51884
+ let offset = 0;
51885
+ while (offset < file.size) {
51886
+ const response = yield commands.typedCall('FilesystemFileRead', 'FilesystemFile', {
51887
+ file: { path: file.devicePath, offset, total_size: 0 },
51888
+ chunk_len: Math.min(chunkSize, file.size - offset),
51889
+ }, { timeoutMs: PROTOCOL_V2_SHORT_RESPONSE_TIMEOUT });
51890
+ const data = toProtocolV2Bytes((_d = response.message) === null || _d === void 0 ? void 0 : _d.data);
51891
+ if (data.byteLength === 0)
51892
+ return false;
51893
+ const consumed = data.subarray(0, Math.min(data.byteLength, file.size - offset));
51894
+ digest.update(consumed);
51895
+ offset += consumed.byteLength;
51896
+ }
51897
+ return bytesToHex(digest.digest()) === normalizeProtocolV2Hex(file.fileHash);
51898
+ }
51899
+ catch (error) {
51900
+ Log$6.debug(`[FirmwareUpdateV4] unable to compare boot resource ${file.devicePath}; scheduling rewrite`, error);
51901
+ return false;
51902
+ }
51903
+ });
51904
+ }
51905
+ mergeProtocolV2ResourceBundles(...groups) {
51906
+ const merged = groups.flatMap(group => group !== null && group !== void 0 ? group : []);
51907
+ if (!merged.length)
51908
+ return undefined;
51909
+ const seenPaths = new Set();
51910
+ for (const bundle of merged) {
51911
+ if (seenPaths.has(bundle.devicePath)) {
51912
+ throw new Error(`Duplicate Protocol V2 resource devicePath: ${bundle.devicePath}`);
51913
+ }
51914
+ seenPaths.add(bundle.devicePath);
51915
+ }
51916
+ return merged;
51917
+ }
51813
51918
  prepareExplicitProtocolV2ResourceFiles() {
51814
51919
  var _a;
51815
51920
  const files = (_a = this.params.resourceFiles) !== null && _a !== void 0 ? _a : [];
@@ -52240,7 +52345,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52240
52345
  const transferStartedAt = Date.now();
52241
52346
  yield writeFirmwareByteSource({
52242
52347
  source,
52243
- chunkSize: this.getProtocolV2FirmwareChunkSize(),
52348
+ chunkSize: this.getProtocolV2FirmwareChunkSize('write', filePath),
52244
52349
  write: ({ data, sourceOffset, length, first }) => __awaiter(this, void 0, void 0, function* () {
52245
52350
  const chunkEnd = sourceOffset + length;
52246
52351
  const deviceProgress = getProtocolV2DeviceTransferProgress(processedSize + sourceOffset, processedSize + chunkEnd, totalSize);
@@ -52623,7 +52728,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52623
52728
  });
52624
52729
  }
52625
52730
  isProtocolV2ReconnectIdentityError(error) {
52626
- return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity');
52731
+ return this.normalizeErrorMessage(error).includes('Protocol V2 reconnect physical identity mismatch');
52627
52732
  }
52628
52733
  fileWriteChunk(filePath, totalFileSize, offset, chunk, overwrite, progress) {
52629
52734
  var _a;
@@ -52639,7 +52744,10 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52639
52744
  overwrite,
52640
52745
  append: false,
52641
52746
  ui_percentage: progress !== null && progress !== void 0 ? progress : undefined,
52642
- }, { writeWithResponse: true });
52747
+ }, {
52748
+ writeWithResponse: false,
52749
+ onWriteCompleted: () => undefined,
52750
+ });
52643
52751
  if (writeRes.type !== 'FilesystemFile') {
52644
52752
  if (writeRes.type === 'CallMethodError') {
52645
52753
  if (((_a = writeRes.message.error) !== null && _a !== void 0 ? _a : '').indexOf(SESSION_ERROR) > -1) {
@@ -52808,7 +52916,7 @@ class DeviceGetOnboardingStatus extends BaseMethod {
52808
52916
  }
52809
52917
  }
52810
52918
 
52811
- const Log$4 = getLogger(exports.LoggerNames.Method);
52919
+ const Log$4 = getLogger(exports.LoggerNames.Core);
52812
52920
  const MIN_FILE_CHUNK_SIZE = 64;
52813
52921
  const FILE_TRANSFER_RATE_WINDOW_MS = 1000;
52814
52922
  const FILE_TRANSFER_LOG_INTERVAL_MS = 10000;
@@ -52825,8 +52933,11 @@ function getFileTransferTransport() {
52825
52933
  const env = DataManager.getSettings('env');
52826
52934
  return env && DataManager.isBleConnect(env) ? 'BLE' : String(env !== null && env !== void 0 ? env : 'unknown');
52827
52935
  }
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`);
52936
+ function logFileTransferMetrics({ transport, status, path, transferredBytes, totalBytes, elapsedMs, rateBytesPerSecond, hostWriteElapsedMs, responseWaitElapsedMs, measuredAttempts, }) {
52937
+ const segmentedMetrics = measuredAttempts > 0
52938
+ ? ` hostWriteTotal=${(hostWriteElapsedMs / 1000).toFixed(2)}s responseWaitTotal=${(responseWaitElapsedMs / 1000).toFixed(2)}s measuredAttempts=${measuredAttempts}`
52939
+ : '';
52940
+ 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
52941
  }
52831
52942
  function isProtocolV2ResponseTimeout(error) {
52832
52943
  var _a, _b;
@@ -52897,7 +53008,12 @@ function writeProtocolV2File(options) {
52897
53008
  if (totalSize < startOffset + dataLength) {
52898
53009
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `FilesystemFileWrite totalSize ${totalSize} is smaller than offset + data length ${startOffset + dataLength}`);
52899
53010
  }
52900
- const chunkSize = normalizeChunkSize((_b = options.chunkSize) !== null && _b !== void 0 ? _b : options.chunkLen, getProtocolV2FileChunkLimit());
53011
+ const defaultChunkSizeLimit = getProtocolV2FileChunkLimit();
53012
+ const configuredChunkSizeLimit = Number(options.chunkSizeLimit);
53013
+ const chunkSizeLimit = Number.isFinite(configuredChunkSizeLimit) && configuredChunkSizeLimit > 0
53014
+ ? Math.floor(configuredChunkSizeLimit)
53015
+ : defaultChunkSizeLimit;
53016
+ const chunkSize = normalizeChunkSize((_b = options.chunkSize) !== null && _b !== void 0 ? _b : options.chunkLen, chunkSizeLimit);
52901
53017
  let written = 0;
52902
53018
  let chunks = 0;
52903
53019
  let lastMessage;
@@ -52908,7 +53024,11 @@ function writeProtocolV2File(options) {
52908
53024
  let lastConfirmedAt = startTime;
52909
53025
  let logWindowStartedAt = startTime;
52910
53026
  let logWindowStartedBytes = 0;
53027
+ let hostWriteElapsedMs = 0;
53028
+ let responseWaitElapsedMs = 0;
53029
+ let measuredAttempts = 0;
52911
53030
  const transport = getFileTransferTransport();
53031
+ Log$4.log(`[FileWrite] started transport=${transport} path=${options.path} bytes=${dataLength} offset=${startOffset} chunk=${chunkSize}`);
52912
53032
  try {
52913
53033
  while (written < dataLength) {
52914
53034
  (_c = options.throwIfAborted) === null || _c === void 0 ? void 0 : _c.call(options);
@@ -52930,10 +53050,21 @@ function writeProtocolV2File(options) {
52930
53050
  let response;
52931
53051
  let isWritePending = true;
52932
53052
  while (isWritePending) {
53053
+ let currentHostWriteElapsedMs;
53054
+ let responseWaitStartedAt;
52933
53055
  try {
52934
53056
  const callOptions = options.writeWithResponse === undefined
52935
- ? { timeoutMs: options.timeoutMs }
52936
- : Object.assign(Object.assign({}, (options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs })), { writeWithResponse: options.writeWithResponse });
53057
+ ? {
53058
+ timeoutMs: options.timeoutMs,
53059
+ onWriteCompleted: ({ elapsedMs }) => {
53060
+ currentHostWriteElapsedMs = elapsedMs;
53061
+ responseWaitStartedAt = Date.now();
53062
+ },
53063
+ }
53064
+ : Object.assign(Object.assign({}, (options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs })), { writeWithResponse: options.writeWithResponse, onWriteCompleted: ({ elapsedMs }) => {
53065
+ currentHostWriteElapsedMs = elapsedMs;
53066
+ responseWaitStartedAt = Date.now();
53067
+ } });
52937
53068
  response = yield options.commands.typedCall('FilesystemFileWrite', 'FilesystemFile', request, callOptions);
52938
53069
  isWritePending = false;
52939
53070
  }
@@ -52943,6 +53074,13 @@ function writeProtocolV2File(options) {
52943
53074
  retryCount += 1;
52944
53075
  (_k = options.throwIfAborted) === null || _k === void 0 ? void 0 : _k.call(options);
52945
53076
  }
53077
+ finally {
53078
+ if (currentHostWriteElapsedMs !== undefined && responseWaitStartedAt !== undefined) {
53079
+ hostWriteElapsedMs += currentHostWriteElapsedMs;
53080
+ responseWaitElapsedMs += Math.max(Date.now() - responseWaitStartedAt, 0);
53081
+ measuredAttempts += 1;
53082
+ }
53083
+ }
52946
53084
  }
52947
53085
  if (!response) {
52948
53086
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'FilesystemFileWrite completed without a response');
@@ -52995,10 +53133,14 @@ function writeProtocolV2File(options) {
52995
53133
  logFileTransferMetrics({
52996
53134
  transport,
52997
53135
  status: 'progress',
53136
+ path: options.path,
52998
53137
  transferredBytes,
52999
53138
  totalBytes: dataLength,
53000
53139
  elapsedMs,
53001
53140
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
53141
+ hostWriteElapsedMs,
53142
+ responseWaitElapsedMs,
53143
+ measuredAttempts,
53002
53144
  });
53003
53145
  logWindowStartedAt = now;
53004
53146
  logWindowStartedBytes = transferredBytes;
@@ -53018,10 +53160,14 @@ function writeProtocolV2File(options) {
53018
53160
  logFileTransferMetrics({
53019
53161
  transport,
53020
53162
  status: 'failed',
53163
+ path: options.path,
53021
53164
  transferredBytes: written,
53022
53165
  totalBytes: dataLength,
53023
53166
  elapsedMs,
53024
53167
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
53168
+ hostWriteElapsedMs,
53169
+ responseWaitElapsedMs,
53170
+ measuredAttempts,
53025
53171
  });
53026
53172
  throw error;
53027
53173
  }
@@ -53031,10 +53177,14 @@ function writeProtocolV2File(options) {
53031
53177
  logFileTransferMetrics({
53032
53178
  transport,
53033
53179
  status: 'completed',
53180
+ path: options.path,
53034
53181
  transferredBytes: written,
53035
53182
  totalBytes: dataLength,
53036
53183
  elapsedMs,
53037
53184
  rateBytesPerSecond: getAverageFileTransferRate(logWindowBytes, logWindowElapsedMs),
53185
+ hostWriteElapsedMs,
53186
+ responseWaitElapsedMs,
53187
+ measuredAttempts,
53038
53188
  });
53039
53189
  return Object.assign(Object.assign({}, lastMessage), { path: options.path, offset: startOffset, total_size: totalSize, processed_byte: startOffset + written, chunks });
53040
53190
  });
@@ -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 = {