@onekeyfe/hd-transport-web-device 1.2.0-alpha.183 → 1.2.0-alpha.185

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.
@@ -73,8 +73,26 @@ const protocolV2Schema = {
73
73
  },
74
74
  },
75
75
  },
76
+ Failure: {
77
+ fields: {
78
+ code: {
79
+ type: 'FailureType',
80
+ id: 1,
81
+ },
82
+ message: {
83
+ type: 'string',
84
+ id: 2,
85
+ },
86
+ },
87
+ },
88
+ FailureType: {
89
+ values: {
90
+ Failure_ProcessError: 5,
91
+ },
92
+ },
76
93
  MessageType: {
77
94
  values: {
95
+ MessageType_Failure: 3,
78
96
  MessageType_ProtocolInfoRequest: 60200,
79
97
  MessageType_ProtocolInfo: 60201,
80
98
  MessageType_Ping: 60206,
@@ -461,6 +479,41 @@ describe('ElectronBleTransport protocol detection', () => {
461
479
  expect(transport.getProtocolType(device.id)).toBeUndefined();
462
480
  });
463
481
 
482
+ test('surfaces Protocol V2 link disabled while the initial V1 probe is active', async () => {
483
+ const device = { id: 'usb-priority-pro2-id', name: 'OneKey Pro 2' };
484
+ const nobleBle = createNobleBle(device);
485
+ let notificationHandler: ((deviceId: string, data: string) => void) | undefined;
486
+
487
+ nobleBle.onNotification.mockImplementation(handler => {
488
+ notificationHandler = handler;
489
+ return jest.fn();
490
+ });
491
+ nobleBle.write.mockImplementation(() => {
492
+ const response = ProtocolV2.encodeFrame(
493
+ schemas,
494
+ 'Failure',
495
+ { code: 5, message: 'link disabled' },
496
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART }
497
+ );
498
+ const splitAt = 4;
499
+ setTimeout(() => {
500
+ notificationHandler?.(device.id, bytesToHex(response.subarray(0, splitAt)));
501
+ notificationHandler?.(device.id, bytesToHex(response.subarray(splitAt)));
502
+ }, 0);
503
+ return Promise.resolve();
504
+ });
505
+ const transport = configureTransport(nobleBle);
506
+
507
+ await expect(transport.acquire({ uuid: device.id })).rejects.toMatchObject({
508
+ name: 'ProtocolV2LinkDisabledError',
509
+ failureCode: 'Failure_ProcessError',
510
+ firmwareMessage: 'link disabled',
511
+ });
512
+ expect(nobleBle.write).toHaveBeenCalledTimes(1);
513
+ expect(nobleBle.unsubscribe).toHaveBeenCalledWith(device.id);
514
+ expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
515
+ });
516
+
464
517
  test('keeps a first expected Protocol V2 probe miss retryable', async () => {
465
518
  const device = { id: 'first-v2-id', name: 'OneKey Pro 2' };
466
519
  const nobleBle = createNobleBle(device);
@@ -497,6 +550,40 @@ describe('ElectronBleTransport protocol detection', () => {
497
550
  expect(transport.getProtocolType(device.id)).toBeUndefined();
498
551
  });
499
552
 
553
+ test('fails Protocol V2 acquire immediately when subscribe reports insufficient encryption', async () => {
554
+ const device = { id: 'stale-bond-pro2-id', name: 'OneKey Pro 2' };
555
+ const nobleBle = createNobleBle(device);
556
+ nobleBle.subscribe.mockRejectedValue(new Error('Encryption is insufficient'));
557
+ const transport = configureTransport(nobleBle);
558
+ const probe = jest.spyOn(transport as any, 'probeProtocolV2');
559
+
560
+ await expect(
561
+ transport.acquire({ uuid: device.id, expectedProtocol: 'V2' })
562
+ ).rejects.toMatchObject({
563
+ errorCode: HardwareErrorCode.BleDeviceBondError,
564
+ });
565
+
566
+ expect(probe).not.toHaveBeenCalled();
567
+ expect(nobleBle.unsubscribe).toHaveBeenCalledWith(device.id);
568
+ expect(nobleBle.disconnect).toHaveBeenCalledWith(device.id);
569
+ });
570
+
571
+ test('keeps stale-bond subscribe mapping out of Protocol V1 acquire', async () => {
572
+ const device = { id: 'classic-v1-id', name: 'OneKey Classic' };
573
+ const nobleBle = createNobleBle(device);
574
+ nobleBle.subscribe.mockRejectedValue(new Error('Encryption is insufficient'));
575
+ const transport = configureTransport(nobleBle);
576
+
577
+ try {
578
+ await transport.acquire({ uuid: device.id, expectedProtocol: 'V1' });
579
+ throw new Error('Expected Protocol V1 acquire to fail');
580
+ } catch (error) {
581
+ expect(error).toBeInstanceOf(Error);
582
+ expect((error as Error).message).toBe('Encryption is insufficient');
583
+ expect((error as { errorCode?: unknown }).errorCode).toBeUndefined();
584
+ }
585
+ });
586
+
500
587
  test('reports a stale bond when a previously confirmed Protocol V2 device stops responding', async () => {
501
588
  const device = { id: 'reset-pro2-id', name: 'OneKey Pro 2' };
502
589
  const nobleBle = createNobleBle(device);
@@ -41,6 +41,7 @@ export default class ElectronBleTransport {
41
41
  private hostDisconnectCleanup?;
42
42
  private notificationTokens;
43
43
  private nextNotificationToken;
44
+ private toStaleBondError;
44
45
  private handleBluetoothError;
45
46
  private cleanupDeviceState;
46
47
  init(logger: any, emitter?: EventEmitter): void;
@@ -78,6 +79,7 @@ export default class ElectronBleTransport {
78
79
  private createMtuSubscription;
79
80
  private writeProtocolV2Frame;
80
81
  private handleNotification;
82
+ private readProtocolV2LinkDisabledFailure;
81
83
  private handleProtocolV2Notification;
82
84
  private getProtocolV2FrameQueue;
83
85
  private resolveProtocolV2Frame;
@@ -1 +1 @@
1
- {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -242,6 +242,7 @@ declare class ElectronBleTransport {
242
242
  private hostDisconnectCleanup?;
243
243
  private notificationTokens;
244
244
  private nextNotificationToken;
245
+ private toStaleBondError;
245
246
  private handleBluetoothError;
246
247
  private cleanupDeviceState;
247
248
  init(logger: any, emitter?: EventEmitter): void;
@@ -284,6 +285,7 @@ declare class ElectronBleTransport {
284
285
  private createMtuSubscription;
285
286
  private writeProtocolV2Frame;
286
287
  private handleNotification;
288
+ private readProtocolV2LinkDisabledFailure;
287
289
  private handleProtocolV2Notification;
288
290
  private getProtocolV2FrameQueue;
289
291
  private resolveProtocolV2Frame;
package/dist/index.js CHANGED
@@ -821,7 +821,7 @@ function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapa
821
821
  return Math.min(maximumPacketCapacity, Math.floor(mtu) - BLE_ATT_HEADER_BYTES);
822
822
  }
823
823
 
824
- const { parseConfigure, ProtocolV1, check } = transport__default["default"];
824
+ const { parseConfigure, ProtocolV1, ProtocolV2, check } = transport__default["default"];
825
825
  const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
826
826
  const BLE_PACKET_SIZE_FALLBACK = 192;
827
827
  const BLE_PACKET_SIZE_MAXIMUM = 244;
@@ -871,7 +871,29 @@ class ElectronBleTransport {
871
871
  this.notificationTokens = new Map();
872
872
  this.nextNotificationToken = 1;
873
873
  }
874
- handleBluetoothError(error) {
874
+ toStaleBondError(error) {
875
+ var _a;
876
+ if (hdShared.isBleStaleBondHardwareError(error)) {
877
+ return error;
878
+ }
879
+ const errorMessage = error && typeof error === 'object' && 'message' in error
880
+ ? String((_a = error.message) !== null && _a !== void 0 ? _a : '')
881
+ : String(error !== null && error !== void 0 ? error : '');
882
+ if (!hdShared.isBleStaleBondErrorText(errorMessage)) {
883
+ return null;
884
+ }
885
+ const normalizedErrorMessage = errorMessage.toLowerCase();
886
+ return hdShared.ERRORS.TypedError(normalizedErrorMessage.includes('peer removed pairing information')
887
+ ? hdShared.HardwareErrorCode.BlePeerRemovedPairingInformation
888
+ : hdShared.HardwareErrorCode.BleDeviceBondError, errorMessage);
889
+ }
890
+ handleBluetoothError(error, mapProtocolV2StaleBond = false) {
891
+ if (mapProtocolV2StaleBond) {
892
+ const staleBondError = this.toStaleBondError(error);
893
+ if (staleBondError) {
894
+ throw staleBondError;
895
+ }
896
+ }
875
897
  if (error && typeof error === 'object') {
876
898
  if ('code' in error) {
877
899
  if (error.code === hdShared.HardwareErrorCode.BlePoweredOff) {
@@ -1002,6 +1024,9 @@ class ElectronBleTransport {
1002
1024
  var _a, _b, _c, _d, _e, _f, _g;
1003
1025
  return __awaiter(this, void 0, void 0, function* () {
1004
1026
  const { uuid, forceCleanRunPromise, expectedProtocol } = input;
1027
+ const shouldMapProtocolV2StaleBond = expectedProtocol
1028
+ ? expectedProtocol === 'V2'
1029
+ : this.confirmedProtocolV2.has(uuid);
1005
1030
  if (!uuid) {
1006
1031
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
1007
1032
  }
@@ -1033,7 +1058,7 @@ class ElectronBleTransport {
1033
1058
  this.connectedDevices.add(uuid);
1034
1059
  }
1035
1060
  catch (error) {
1036
- this.handleBluetoothError(error);
1061
+ this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
1037
1062
  }
1038
1063
  const mtuCleanup = this.createMtuSubscription(uuid);
1039
1064
  if (mtuCleanup) {
@@ -1041,7 +1066,12 @@ class ElectronBleTransport {
1041
1066
  }
1042
1067
  this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
1043
1068
  this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
1044
- yield window.desktopApi.nobleBle.subscribe(uuid);
1069
+ try {
1070
+ yield window.desktopApi.nobleBle.subscribe(uuid);
1071
+ }
1072
+ catch (error) {
1073
+ this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
1074
+ }
1045
1075
  yield this.refreshBlePacketCapacity(uuid);
1046
1076
  const cleanup = this.createNotificationSubscription(uuid);
1047
1077
  this.notificationCleanups.set(uuid, cleanup);
@@ -1227,6 +1257,9 @@ class ElectronBleTransport {
1227
1257
  catch (error) {
1228
1258
  this.clearProbeProtocol(uuid, 'V1');
1229
1259
  (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1 GetFeatures probe failed:', error);
1260
+ if (transport.isProtocolV2LinkDisabledError(error)) {
1261
+ throw error;
1262
+ }
1230
1263
  return false;
1231
1264
  }
1232
1265
  });
@@ -1249,6 +1282,7 @@ class ElectronBleTransport {
1249
1282
  (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1250
1283
  this.resetProtocolV2Frames(uuid);
1251
1284
  },
1285
+ shouldRethrow: error => hdShared.isBleStaleBondHardwareError(error) || transport.isProtocolV2LinkDisabledError(error),
1252
1286
  });
1253
1287
  if (!detected) {
1254
1288
  this.clearProbeProtocol(uuid, 'V2');
@@ -1263,7 +1297,16 @@ class ElectronBleTransport {
1263
1297
  if (!nobleBle) {
1264
1298
  throw new Error('Noble BLE API not available');
1265
1299
  }
1266
- yield nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
1300
+ try {
1301
+ yield nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
1302
+ }
1303
+ catch (error) {
1304
+ const staleBondError = this.toStaleBondError(error);
1305
+ if (staleBondError) {
1306
+ throw staleBondError;
1307
+ }
1308
+ throw error;
1309
+ }
1267
1310
  });
1268
1311
  }
1269
1312
  refreshBlePacketCapacity(uuid) {
@@ -1332,8 +1375,39 @@ class ElectronBleTransport {
1332
1375
  this.handleProtocolV2Notification(deviceId, hexData);
1333
1376
  return;
1334
1377
  }
1378
+ const linkDisabledError = this.readProtocolV2LinkDisabledFailure(deviceId, hexData);
1379
+ if (linkDisabledError) {
1380
+ if (this.runPromise && this.runPromiseDeviceId === deviceId) {
1381
+ this.runPromise.reject(linkDisabledError);
1382
+ }
1383
+ return;
1384
+ }
1335
1385
  this.handleProtocolV1Notification(deviceId, hexData);
1336
1386
  }
1387
+ readProtocolV2LinkDisabledFailure(deviceId, hexData) {
1388
+ var _a, _b;
1389
+ if (!this._messages || !this._messagesV2)
1390
+ return undefined;
1391
+ const assembler = this.v2Assemblers.get(deviceId);
1392
+ if (!assembler)
1393
+ return undefined;
1394
+ try {
1395
+ for (const frame of assembler.drain(transport.hexToBytes(hexData))) {
1396
+ const response = check.call(ProtocolV2.decodeFrame({ protocolV1: this._messages, protocolV2: this._messagesV2 }, frame));
1397
+ if (response.type === 'Failure') {
1398
+ const failureCode = (_a = response.message) === null || _a === void 0 ? void 0 : _a.code;
1399
+ const firmwareMessage = (_b = response.message) === null || _b === void 0 ? void 0 : _b.message;
1400
+ if (transport.isProtocolV2LinkDisabledFailure(failureCode, firmwareMessage)) {
1401
+ return transport.createProtocolV2LinkDisabledError(failureCode, firmwareMessage);
1402
+ }
1403
+ }
1404
+ }
1405
+ }
1406
+ catch (_c) {
1407
+ assembler.reset();
1408
+ }
1409
+ return undefined;
1410
+ }
1337
1411
  handleProtocolV2Notification(deviceId, hexData) {
1338
1412
  var _a;
1339
1413
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-web-device",
3
- "version": "1.2.0-alpha.183",
3
+ "version": "1.2.0-alpha.185",
4
4
  "author": "OneKey",
5
5
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
6
6
  "license": "MIT",
@@ -21,13 +21,13 @@
21
21
  "lint:fix": "eslint . --fix"
22
22
  },
23
23
  "dependencies": {
24
- "@onekeyfe/hd-shared": "1.2.0-alpha.183",
25
- "@onekeyfe/hd-transport": "1.2.0-alpha.183"
24
+ "@onekeyfe/hd-shared": "1.2.0-alpha.185",
25
+ "@onekeyfe/hd-transport": "1.2.0-alpha.185"
26
26
  },
27
27
  "devDependencies": {
28
- "@onekeyfe/hd-transport-electron": "1.2.0-alpha.183",
28
+ "@onekeyfe/hd-transport-electron": "1.2.0-alpha.185",
29
29
  "@types/w3c-web-usb": "^1.0.6",
30
30
  "@types/web-bluetooth": "^0.0.17"
31
31
  },
32
- "gitHead": "fd9b6e749495b0144e734dbe32c57cf483547349"
32
+ "gitHead": "dba45132513abeef33dc448824b4eaace74900ee"
33
33
  }
@@ -6,7 +6,10 @@ import transport, {
6
6
  ProtocolV2LinkManager,
7
7
  TRANSPORT_EVENT,
8
8
  bytesToHex,
9
+ createProtocolV2LinkDisabledError,
9
10
  hexToBytes,
11
+ isProtocolV2LinkDisabledError,
12
+ isProtocolV2LinkDisabledFailure,
10
13
  probeProtocolV2 as probeProtocolV2Helper,
11
14
  writeProtocolV2BleFrame,
12
15
  } from '@onekeyfe/hd-transport';
@@ -16,6 +19,8 @@ import {
16
19
  HardwareErrorCode,
17
20
  HardwareErrorCodeMessage,
18
21
  createDeferred,
22
+ isBleStaleBondErrorText,
23
+ isBleStaleBondHardwareError,
19
24
  isHeaderChunk,
20
25
  } from '@onekeyfe/hd-shared';
21
26
 
@@ -31,7 +36,7 @@ import type {
31
36
  } from '@onekeyfe/hd-transport';
32
37
  import type EventEmitter from 'events';
33
38
 
34
- const { parseConfigure, ProtocolV1, check } = transport;
39
+ const { parseConfigure, ProtocolV1, ProtocolV2, check } = transport;
35
40
 
36
41
  declare global {
37
42
  interface Window {
@@ -159,7 +164,33 @@ export default class ElectronBleTransport {
159
164
 
160
165
  private nextNotificationToken = 1;
161
166
 
162
- private handleBluetoothError(error: any): never {
167
+ private toStaleBondError(error: unknown): Error | null {
168
+ if (isBleStaleBondHardwareError(error)) {
169
+ return error as Error;
170
+ }
171
+ const errorMessage =
172
+ error && typeof error === 'object' && 'message' in error
173
+ ? String((error as { message?: unknown }).message ?? '')
174
+ : String(error ?? '');
175
+ if (!isBleStaleBondErrorText(errorMessage)) {
176
+ return null;
177
+ }
178
+ const normalizedErrorMessage = errorMessage.toLowerCase();
179
+ return ERRORS.TypedError(
180
+ normalizedErrorMessage.includes('peer removed pairing information')
181
+ ? HardwareErrorCode.BlePeerRemovedPairingInformation
182
+ : HardwareErrorCode.BleDeviceBondError,
183
+ errorMessage
184
+ );
185
+ }
186
+
187
+ private handleBluetoothError(error: any, mapProtocolV2StaleBond = false): never {
188
+ if (mapProtocolV2StaleBond) {
189
+ const staleBondError = this.toStaleBondError(error);
190
+ if (staleBondError) {
191
+ throw staleBondError;
192
+ }
193
+ }
163
194
  if (error && typeof error === 'object') {
164
195
  if ('code' in error) {
165
196
  if (error.code === HardwareErrorCode.BlePoweredOff) {
@@ -320,6 +351,9 @@ export default class ElectronBleTransport {
320
351
 
321
352
  async acquire(input: BleAcquireInput) {
322
353
  const { uuid, forceCleanRunPromise, expectedProtocol } = input;
354
+ const shouldMapProtocolV2StaleBond = expectedProtocol
355
+ ? expectedProtocol === 'V2'
356
+ : this.confirmedProtocolV2.has(uuid);
323
357
 
324
358
  if (!uuid) {
325
359
  throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
@@ -356,7 +390,7 @@ export default class ElectronBleTransport {
356
390
  await window.desktopApi.nobleBle.connect(uuid);
357
391
  this.connectedDevices.add(uuid);
358
392
  } catch (error) {
359
- this.handleBluetoothError(error);
393
+ this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
360
394
  }
361
395
 
362
396
  const mtuCleanup = this.createMtuSubscription(uuid);
@@ -367,7 +401,11 @@ export default class ElectronBleTransport {
367
401
  this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
368
402
  this.v2Assemblers.set(uuid, new ProtocolV2FrameAssembler(PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
369
403
 
370
- await window.desktopApi.nobleBle.subscribe(uuid);
404
+ try {
405
+ await window.desktopApi.nobleBle.subscribe(uuid);
406
+ } catch (error) {
407
+ this.handleBluetoothError(error, shouldMapProtocolV2StaleBond);
408
+ }
371
409
  await this.refreshBlePacketCapacity(uuid);
372
410
 
373
411
  const cleanup = this.createNotificationSubscription(uuid);
@@ -595,6 +633,9 @@ export default class ElectronBleTransport {
595
633
  } catch (error) {
596
634
  this.clearProbeProtocol(uuid, 'V1');
597
635
  this.Log?.debug('[Electron BLE] Protocol V1 GetFeatures probe failed:', error);
636
+ if (isProtocolV2LinkDisabledError(error)) {
637
+ throw error;
638
+ }
598
639
  return false;
599
640
  }
600
641
  }
@@ -615,6 +656,8 @@ export default class ElectronBleTransport {
615
656
  this.v2Assemblers.get(uuid)?.reset();
616
657
  this.resetProtocolV2Frames(uuid);
617
658
  },
659
+ shouldRethrow: error =>
660
+ isBleStaleBondHardwareError(error) || isProtocolV2LinkDisabledError(error),
618
661
  });
619
662
  if (!detected) {
620
663
  this.clearProbeProtocol(uuid, 'V2');
@@ -628,7 +671,15 @@ export default class ElectronBleTransport {
628
671
  throw new Error('Noble BLE API not available');
629
672
  }
630
673
 
631
- await nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
674
+ try {
675
+ await nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
676
+ } catch (error) {
677
+ const staleBondError = this.toStaleBondError(error);
678
+ if (staleBondError) {
679
+ throw staleBondError;
680
+ }
681
+ throw error;
682
+ }
632
683
  }
633
684
 
634
685
  private async refreshBlePacketCapacity(uuid: string): Promise<void> {
@@ -702,9 +753,45 @@ export default class ElectronBleTransport {
702
753
  this.handleProtocolV2Notification(deviceId, hexData);
703
754
  return;
704
755
  }
756
+ const linkDisabledError = this.readProtocolV2LinkDisabledFailure(deviceId, hexData);
757
+ if (linkDisabledError) {
758
+ if (this.runPromise && this.runPromiseDeviceId === deviceId) {
759
+ this.runPromise.reject(linkDisabledError);
760
+ }
761
+ return;
762
+ }
705
763
  this.handleProtocolV1Notification(deviceId, hexData);
706
764
  }
707
765
 
766
+ private readProtocolV2LinkDisabledFailure(deviceId: string, hexData: string) {
767
+ if (!this._messages || !this._messagesV2) return undefined;
768
+
769
+ const assembler = this.v2Assemblers.get(deviceId);
770
+ if (!assembler) return undefined;
771
+
772
+ try {
773
+ for (const frame of assembler.drain(hexToBytes(hexData))) {
774
+ const response = check.call(
775
+ ProtocolV2.decodeFrame(
776
+ { protocolV1: this._messages, protocolV2: this._messagesV2 },
777
+ frame
778
+ )
779
+ );
780
+ if (response.type === 'Failure') {
781
+ const failureCode = response.message?.code;
782
+ const firmwareMessage = response.message?.message;
783
+ if (isProtocolV2LinkDisabledFailure(failureCode, firmwareMessage)) {
784
+ return createProtocolV2LinkDisabledError(failureCode, firmwareMessage);
785
+ }
786
+ }
787
+ }
788
+ } catch {
789
+ // A normal Protocol V1 notification is not a Protocol V2 frame.
790
+ assembler.reset();
791
+ }
792
+ return undefined;
793
+ }
794
+
708
795
  private handleProtocolV2Notification(deviceId: string, hexData: string): void {
709
796
  try {
710
797
  const bytes = hexToBytes(hexData);