@onekeyfe/hd-transport-react-native 1.2.3-alpha.2 → 1.2.3-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -57,36 +57,73 @@ const bleLogger = {
57
57
  };
58
58
 
59
59
  const Logger = bleLogger;
60
+ const bondFailureReasons = {
61
+ 1: 'authentication_failed',
62
+ 2: 'rejected',
63
+ 3: 'canceled',
64
+ 4: 'device_unreachable',
65
+ 5: 'discovery_in_progress',
66
+ 6: 'timeout',
67
+ 7: 'repeated_attempts',
68
+ 8: 'remote_canceled',
69
+ 9: 'removed',
70
+ };
60
71
  const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
61
72
  const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
62
- const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
73
+ const onDeviceBondState = (bleMacAddress, signal) => new Promise((resolve, reject) => {
74
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
75
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
76
+ return;
77
+ }
63
78
  const cleanup = () => {
64
79
  if (timeout) {
65
80
  clearTimeout(timeout);
66
81
  }
67
82
  if (cleanupListener)
68
83
  cleanupListener();
84
+ signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort);
85
+ };
86
+ const onAbort = () => {
87
+ cleanup();
88
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
69
89
  };
90
+ signal === null || signal === void 0 ? void 0 : signal.addEventListener('abort', onAbort, { once: true });
70
91
  const timeout = setTimeout(() => {
71
92
  cleanup();
72
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
93
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', {
94
+ phase: 'bond',
95
+ reason: 'timeout',
96
+ }));
73
97
  }, 60 * 1000);
74
98
  const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
75
- var _a;
99
+ var _a, _b;
76
100
  if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
77
101
  return;
78
102
  }
79
103
  const { bondState } = peripheral;
80
104
  const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
81
- const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
105
+ const hasFailed = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
82
106
  Logger.debug('onDeviceBondState bondState:', bondState);
83
107
  if (hasBonded) {
84
108
  cleanup();
85
109
  resolve(peripheral);
86
110
  }
87
- else if (hasCanceled) {
111
+ else if (hasFailed) {
88
112
  cleanup();
89
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
113
+ const nativeReason = 'reason' in bondState && typeof bondState.reason === 'number'
114
+ ? bondState.reason
115
+ : undefined;
116
+ const reason = nativeReason === undefined ? 'unknown' : (_b = bondFailureReasons[nativeReason]) !== null && _b !== void 0 ? _b : 'unknown';
117
+ const params = Object.assign({ phase: 'bond', reason }, (nativeReason === undefined ? {} : { nativeReason }));
118
+ if (reason === 'timeout') {
119
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing timed out', params));
120
+ }
121
+ else if (reason === 'canceled') {
122
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'Bluetooth pairing canceled', params));
123
+ }
124
+ else {
125
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'Bluetooth pairing failed', params));
126
+ }
90
127
  }
91
128
  });
92
129
  });
@@ -194,6 +231,27 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
194
231
  }, ms);
195
232
  });
196
233
 
234
+ const BLE_PLX_DEVICE_DISCONNECTED = 201;
235
+ const IOS_PERIPHERAL_DISCONNECTED = 7;
236
+ const nativeErrorText$1 = (error) => [error.reason, error.message]
237
+ .filter((value) => typeof value === 'string')
238
+ .join(' ');
239
+ const isNativeBleDisconnectError = (error) => {
240
+ if (!error || typeof error !== 'object') {
241
+ return false;
242
+ }
243
+ const nativeError = error;
244
+ return (nativeError.errorCode === BLE_PLX_DEVICE_DISCONNECTED ||
245
+ nativeError.iosErrorCode === IOS_PERIPHERAL_DISCONNECTED);
246
+ };
247
+ const toBleDisconnectHardwareError = (error) => {
248
+ if ((error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleDeviceDisconnected) {
249
+ return error;
250
+ }
251
+ const nativeError = (error !== null && error !== void 0 ? error : {});
252
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected, nativeErrorText$1(nativeError) || undefined);
253
+ };
254
+
197
255
  const ATT_INSUFFICIENT_AUTHENTICATION = 5;
198
256
  const ATT_INSUFFICIENT_ENCRYPTION = 15;
199
257
  const IOS_PEER_REMOVED_PAIRING_INFORMATION = 14;
@@ -258,6 +316,7 @@ class BleTransport {
258
316
  const { check, ProtocolV1, parseConfigure } = transport__default["default"];
259
317
  const Log = bleLogger;
260
318
  const transportCache = {};
319
+ let bleManagerResetPromise;
261
320
  const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
262
321
  const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
263
322
  const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
@@ -316,6 +375,17 @@ const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
316
375
  const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
317
376
  typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
318
377
  error.message.startsWith(WEDGED_WRITE_MESSAGE);
378
+ const shouldRethrowProtocolProbeError = (error) => {
379
+ const code = error === null || error === void 0 ? void 0 : error.errorCode;
380
+ return (hdShared.isBleStaleBondHardwareError(error) ||
381
+ isNativeBleDisconnectError(error) ||
382
+ code === hdShared.HardwareErrorCode.BleDeviceNotBonded ||
383
+ code === hdShared.HardwareErrorCode.BleDeviceBondedCanceled ||
384
+ code === hdShared.HardwareErrorCode.BleDeviceDisconnected ||
385
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotifyError ||
386
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure ||
387
+ code === hdShared.HardwareErrorCode.BleWriteCharacteristicError);
388
+ };
319
389
  const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
320
390
  const DEVICE_SCAN_TIMEOUT_MS = 3000;
321
391
  const IOS_NOTIFY_READY_DELAY_MS = 150;
@@ -350,10 +420,10 @@ function getDeviceDisplayName(device) {
350
420
  }
351
421
  const IOS_REQUEST_MTU = 247;
352
422
  const ANDROID_REQUEST_MTU = 517;
353
- const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
354
423
  const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
355
424
  const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
356
425
  const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
426
+ const BLE_MTU_REQUEST_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS;
357
427
  const connectOptions = {
358
428
  requestMTU: getRequestedBleMtu(),
359
429
  timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
@@ -362,6 +432,29 @@ const connectOptions = {
362
432
  const fallbackConnectOptions = {
363
433
  timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
364
434
  };
435
+ const androidRefreshGattConnectOptions = {
436
+ timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
437
+ refreshGatt: 'OnConnected',
438
+ };
439
+ const ANDROID_MTU_EXCHANGE_TIMEOUT_MS = 12000;
440
+ const ANDROID_LINK_DROP_QUIET_MS = 5000;
441
+ const ANDROID_LINK_DROP_POLL_MS = 250;
442
+ const isKnownDefaultMtu = (mtu) => typeof mtu === 'number' && Number.isFinite(mtu) && mtu <= 23;
443
+ const isMissingGattShapeError = (error) => {
444
+ const code = error === null || error === void 0 ? void 0 : error.errorCode;
445
+ const message = error === null || error === void 0 ? void 0 : error.message;
446
+ return (code === hdShared.HardwareErrorCode.BleServiceNotFound ||
447
+ code === hdShared.HardwareErrorCode.BleCharacteristicNotFound ||
448
+ (typeof message === 'string' &&
449
+ (message.includes('BLECharacteristicNotFound') ||
450
+ message.includes('BLECharacteristicNotWritable') ||
451
+ message.includes('BLECharacteristicNotNotifiable'))));
452
+ };
453
+ const isStaleGattTableNotifyReason = (reason) => !!reason &&
454
+ (reason.includes('Cannot write client characteristic config descriptor') ||
455
+ reason.includes('Cannot find client characteristic config descriptor') ||
456
+ reason.includes('The handle is invalid') ||
457
+ reason.includes('Writing is not permitted'));
365
458
  const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
366
459
  const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
367
460
  const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
@@ -376,6 +469,11 @@ const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? v
376
469
  error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
377
470
  const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
378
471
  const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
472
+ const isMtuOrCancelledConnectError = (error) => {
473
+ const errorCode = error === null || error === void 0 ? void 0 : error.errorCode;
474
+ return (errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
475
+ errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled);
476
+ };
379
477
  const tryToGetConfiguration = (device) => {
380
478
  if (!device || !device.serviceUUIDs)
381
479
  return null;
@@ -387,25 +485,65 @@ const tryToGetConfiguration = (device) => {
387
485
  return null;
388
486
  return infos;
389
487
  };
390
- const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
488
+ const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __awaiter(void 0, void 0, void 0, function* () {
391
489
  if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
392
- return device;
490
+ return { device, timedOut: false };
491
+ const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
492
+ let timeoutId;
493
+ let timedOut = false;
393
494
  try {
394
- const mtuDevice = yield device.requestMTU(getRequestedBleMtu());
395
- return mtuDevice;
495
+ const request = device.requestMTU(getRequestedBleMtu(), transactionId);
496
+ request.catch(() => undefined);
497
+ const mtuDevice = yield Promise.race([
498
+ request,
499
+ new Promise((_, reject) => {
500
+ timeoutId = setTimeout(() => {
501
+ timedOut = true;
502
+ reject(new Error(`BLE MTU request timeout after ${BLE_MTU_REQUEST_TIMEOUT_MS}ms`));
503
+ }, BLE_MTU_REQUEST_TIMEOUT_MS);
504
+ }),
505
+ ]);
506
+ return { device: mtuDevice, timedOut: false };
396
507
  }
397
508
  catch (error) {
509
+ if (timedOut && cancelTransaction) {
510
+ try {
511
+ Promise.resolve(cancelTransaction(transactionId)).catch(cancelError => {
512
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
513
+ platform: reactNative.Platform.OS,
514
+ stage,
515
+ attempt,
516
+ error: cancelError instanceof Error ? cancelError.message : String(cancelError),
517
+ });
518
+ });
519
+ }
520
+ catch (cancelError) {
521
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
522
+ platform: reactNative.Platform.OS,
523
+ stage,
524
+ attempt,
525
+ error: cancelError instanceof Error ? cancelError.message : String(cancelError),
526
+ });
527
+ }
528
+ }
398
529
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
399
530
  platform: reactNative.Platform.OS,
400
531
  stage,
401
532
  attempt,
402
533
  actual: device.mtu,
534
+ timedOut,
403
535
  error: error instanceof Error ? error.message : String(error),
404
536
  });
405
- return device;
537
+ return { device, timedOut };
538
+ }
539
+ finally {
540
+ if (timeoutId)
541
+ clearTimeout(timeoutId);
406
542
  }
407
543
  });
408
- const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
544
+ const resolveNegotiatedMtu = (device, cancelTransaction) => shouldRefreshNegotiatedMtu(device.mtu)
545
+ ? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
546
+ : Promise.resolve({ device, timedOut: false });
409
547
  function remapError(error) {
410
548
  var _a;
411
549
  if (error instanceof reactNativeBlePlx.BleError) {
@@ -429,6 +567,7 @@ class ReactNativeBleTransport {
429
567
  this.name = 'ReactNativeBleTransport';
430
568
  this.configured = false;
431
569
  this.stopped = false;
570
+ this.bondAbortController = new AbortController();
432
571
  this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
433
572
  this.runPromise = null;
434
573
  this.runPromiseDeviceId = null;
@@ -441,6 +580,8 @@ class ReactNativeBleTransport {
441
580
  this.sessionProtocols = new Map();
442
581
  this.confirmedProtocolV2 = new Set();
443
582
  this.protocolReprobeFailures = new Map();
583
+ this.silentDetections = new Map();
584
+ this.androidGattCacheRefreshes = new Set();
444
585
  this.staleBondErrors = new Map();
445
586
  this.acquiringProtocolV2 = new Set();
446
587
  this.protocolV2Assemblers = new Map();
@@ -458,11 +599,20 @@ class ReactNativeBleTransport {
458
599
  },
459
600
  classifyError: () => 'link-fatal',
460
601
  onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
461
- var _b;
602
+ var _b, _c;
462
603
  (_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
463
604
  this.rejectProtocolV2Frames(uuid, new Error(reason));
464
605
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
465
606
  if (reason.startsWith('Protocol V2 link-fatal error:')) {
607
+ if (this.probingProtocols.get(uuid) !== 'V2') {
608
+ const transport = transportCache[uuid];
609
+ try {
610
+ this.emitDeviceDisconnect(uuid, (_c = transport === null || transport === void 0 ? void 0 : transport.device) === null || _c === void 0 ? void 0 : _c.name, transport === null || transport === void 0 ? void 0 : transport.monitorToken);
611
+ }
612
+ catch (_d) {
613
+ Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 disconnect listener failed');
614
+ }
615
+ }
466
616
  yield this.releaseNative(uuid, true);
467
617
  }
468
618
  }),
@@ -474,6 +624,7 @@ class ReactNativeBleTransport {
474
624
  this.androidPriorityResetTimers = new Map();
475
625
  this.nextMonitorToken = 1;
476
626
  this.lifecycleOperations = new Map();
627
+ this.scanCleanups = new Set();
477
628
  this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
478
629
  }
479
630
  init(logger, emitter) {
@@ -502,10 +653,38 @@ class ReactNativeBleTransport {
502
653
  listen() {
503
654
  }
504
655
  getPlxManager() {
505
- if (this.blePlxManager)
506
- return Promise.resolve(this.blePlxManager);
507
- this.blePlxManager = new reactNativeBlePlx.BleManager();
508
- return Promise.resolve(this.blePlxManager);
656
+ return __awaiter(this, void 0, void 0, function* () {
657
+ while (bleManagerResetPromise) {
658
+ yield this.waitForManagerReset();
659
+ }
660
+ if (this.stopped)
661
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
662
+ if (!this.blePlxManager)
663
+ this.blePlxManager = new reactNativeBlePlx.BleManager();
664
+ return this.blePlxManager;
665
+ });
666
+ }
667
+ waitForManagerReset() {
668
+ return __awaiter(this, void 0, void 0, function* () {
669
+ if (!bleManagerResetPromise)
670
+ return;
671
+ let timeout;
672
+ try {
673
+ yield Promise.race([
674
+ bleManagerResetPromise,
675
+ new Promise((_, reject) => {
676
+ timeout = setTimeout(() => reject(this.createWedgedBleSetupError()), BLE_CONNECT_TIMEOUT_MS);
677
+ }),
678
+ ]);
679
+ }
680
+ catch (_a) {
681
+ throw this.createWedgedBleSetupError();
682
+ }
683
+ finally {
684
+ if (timeout)
685
+ clearTimeout(timeout);
686
+ }
687
+ });
509
688
  }
510
689
  resolveCharacteristics(device) {
511
690
  return __awaiter(this, void 0, void 0, function* () {
@@ -670,30 +849,55 @@ class ReactNativeBleTransport {
670
849
  }
671
850
  enumerate() {
672
851
  return __awaiter(this, void 0, void 0, function* () {
673
- return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
674
- const deviceList = [];
675
- const blePlxManager = yield this.getPlxManager();
676
- try {
677
- yield subscribeBleOn(blePlxManager);
678
- }
679
- catch (error) {
680
- Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
681
- reject(error);
682
- return;
683
- }
684
- if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
685
- Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
686
- const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
687
- reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
688
- reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
689
- ]);
690
- Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
691
- if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
692
- resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
693
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
694
- return;
695
- }
852
+ const scanStartedAt = Date.now();
853
+ let firstDeviceMs;
854
+ const blePlxManager = yield this.getPlxManager();
855
+ yield subscribeBleOn(blePlxManager);
856
+ if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
857
+ Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
858
+ const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
859
+ reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
860
+ reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
861
+ ]);
862
+ Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
863
+ if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
864
+ resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
865
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
696
866
  }
867
+ }
868
+ if (this.stopped)
869
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
870
+ return new Promise((resolve, reject) => {
871
+ const deviceList = [];
872
+ let finished = false;
873
+ let scanCleanup;
874
+ const finishScan = (error) => {
875
+ if (scanCleanup)
876
+ return scanCleanup;
877
+ finished = true;
878
+ clearScanTimer();
879
+ scanCleanup = this.runNativeTeardown('scan', blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
880
+ yield blePlxManager.stopDeviceScan();
881
+ })).then(() => {
882
+ this.scanCleanups.delete(cancelScan);
883
+ if (error)
884
+ reject(error);
885
+ else
886
+ resolve(deviceList);
887
+ });
888
+ return scanCleanup;
889
+ };
890
+ const cancelScan = () => finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
891
+ this.scanCleanups.add(cancelScan);
892
+ const clearScanTimer = timer.timeout(() => {
893
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan completed', {
894
+ elapsedMs: Date.now() - scanStartedAt,
895
+ firstDeviceMs,
896
+ deviceCount: deviceList.length,
897
+ scanWindowMs: this.scanTimeout,
898
+ });
899
+ finishScan();
900
+ }, this.scanTimeout);
697
901
  blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
698
902
  allowDuplicates: true,
699
903
  scanMode: reactNativeBlePlx.ScanMode.LowLatency,
@@ -702,19 +906,17 @@ class ReactNativeBleTransport {
702
906
  if (error) {
703
907
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
704
908
  if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
705
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
909
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
706
910
  }
707
911
  else if (error.errorCode === reactNativeBlePlx.BleErrorCode.BluetoothUnauthorized) {
708
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
912
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
709
913
  }
710
914
  else if (error.errorCode === reactNativeBlePlx.BleErrorCode.LocationServicesDisabled) {
711
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
712
- }
713
- else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) {
714
- timer.timeout(() => { }, this.scanTimeout);
915
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
715
916
  }
917
+ else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) ;
716
918
  else {
717
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
919
+ finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
718
920
  }
719
921
  return;
720
922
  }
@@ -739,6 +941,8 @@ class ReactNativeBleTransport {
739
941
  });
740
942
  }
741
943
  });
944
+ if (finished)
945
+ return;
742
946
  getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
743
947
  for (const device of devices) {
744
948
  const localName = 'localName' in device && typeof device.localName === 'string'
@@ -754,10 +958,11 @@ class ReactNativeBleTransport {
754
958
  addDevice(device);
755
959
  }
756
960
  }
757
- });
961
+ }, error => Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral failed:', error));
758
962
  const addDevice = (device) => {
759
963
  var _a;
760
- if (deviceList.every(d => d.id !== device.id)) {
964
+ if (!finished && deviceList.every(d => d.id !== device.id)) {
965
+ firstDeviceMs !== null && firstDeviceMs !== void 0 ? firstDeviceMs : (firstDeviceMs = Date.now() - scanStartedAt);
761
966
  const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
762
967
  deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
763
968
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
@@ -767,16 +972,14 @@ class ReactNativeBleTransport {
767
972
  });
768
973
  }
769
974
  };
770
- timer.timeout(() => {
771
- blePlxManager.stopDeviceScan();
772
- resolve(deviceList);
773
- }, this.scanTimeout);
774
- }));
975
+ });
775
976
  });
776
977
  }
777
978
  installTransportForAcquire(uuid, device, characteristics) {
778
979
  return __awaiter(this, void 0, void 0, function* () {
779
980
  const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
981
+ if (this.stopped)
982
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
780
983
  const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
781
984
  transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
782
985
  const monitorToken = this.nextMonitorToken;
@@ -797,30 +1000,12 @@ class ReactNativeBleTransport {
797
1000
  else if (reactNative.Platform.OS === 'android') {
798
1001
  yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
799
1002
  }
800
- const initialMtu = transport$1.mtuSize;
801
- let refreshAttempts = 0;
802
- if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
803
- shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
804
- refreshAttempts += 1;
805
- let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
806
- transport$1.device = refreshedDevice;
807
- transport$1.mtuSize =
808
- typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
809
- if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
810
- yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
811
- refreshAttempts += 1;
812
- refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
813
- transport$1.device = refreshedDevice;
814
- transport$1.mtuSize =
815
- typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
816
- }
817
- }
1003
+ if (this.stopped)
1004
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
818
1005
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
819
1006
  platform: reactNative.Platform.OS,
820
1007
  requested: getRequestedBleMtu(),
821
- initial: initialMtu,
822
1008
  actual: transport$1.mtuSize,
823
- refreshAttempts,
824
1009
  });
825
1010
  return transport$1;
826
1011
  });
@@ -837,6 +1022,8 @@ class ReactNativeBleTransport {
837
1022
  acquireUnlocked(input) {
838
1023
  var _a;
839
1024
  return __awaiter(this, void 0, void 0, function* () {
1025
+ if (this.stopped)
1026
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
840
1027
  const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
841
1028
  const shouldMapProtocolV2StaleBond = expectedProtocol
842
1029
  ? expectedProtocol === 'V2'
@@ -868,9 +1055,13 @@ class ReactNativeBleTransport {
868
1055
  const isCachedDeviceConnected = yield cachedTransport.device
869
1056
  .isConnected()
870
1057
  .catch(() => false);
1058
+ const isCachedAndroidLinkUsable = reactNative.Platform.OS !== 'android' || !this.androidGattCacheRefreshes.has(uuid);
871
1059
  if (isCachedDeviceConnected &&
1060
+ isCachedAndroidLinkUsable &&
872
1061
  cachedProtocol &&
873
1062
  (!expectedProtocol || cachedProtocol === expectedProtocol)) {
1063
+ if (this.stopped)
1064
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
874
1065
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
875
1066
  return { uuid, protocolType: cachedProtocol };
876
1067
  }
@@ -879,6 +1070,15 @@ class ReactNativeBleTransport {
879
1070
  }
880
1071
  }
881
1072
  let device = null;
1073
+ const isAndroid = reactNative.Platform.OS === 'android';
1074
+ const refreshAndroidGattCache = isAndroid && (!!skipProtocolProbe || this.androidGattCacheRefreshes.has(uuid));
1075
+ let nativeConnectOptions = connectOptions;
1076
+ if (isAndroid) {
1077
+ nativeConnectOptions = refreshAndroidGattCache
1078
+ ? androidRefreshGattConnectOptions
1079
+ : fallbackConnectOptions;
1080
+ }
1081
+ let androidRefreshConnectRan = false;
882
1082
  if (forceCleanRunPromise && this.runPromise) {
883
1083
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
884
1084
  this.runPromise.reject(error);
@@ -887,6 +1087,7 @@ class ReactNativeBleTransport {
887
1087
  Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
888
1088
  }
889
1089
  const blePlxManager = yield this.getPlxManager();
1090
+ let skipPostConnectMtu = false;
890
1091
  try {
891
1092
  yield subscribeBleOn(blePlxManager);
892
1093
  }
@@ -894,6 +1095,27 @@ class ReactNativeBleTransport {
894
1095
  Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
895
1096
  throw error;
896
1097
  }
1098
+ if (this.stopped)
1099
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1100
+ if (reactNative.Platform.OS === 'android') {
1101
+ try {
1102
+ const bondState = yield pairDevice(uuid);
1103
+ if (bondState.bonding) {
1104
+ yield onDeviceBondState(uuid, this.bondAbortController.signal);
1105
+ }
1106
+ else if (!bondState.bonded) {
1107
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
1108
+ }
1109
+ }
1110
+ catch (error) {
1111
+ yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
1112
+ yield this.runBestEffortNativeOperation('bond failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid));
1113
+ }));
1114
+ throw error;
1115
+ }
1116
+ }
1117
+ if (this.stopped)
1118
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
897
1119
  if (!device) {
898
1120
  const devices = yield blePlxManager.devices([uuid]);
899
1121
  [device] = devices;
@@ -907,15 +1129,16 @@ class ReactNativeBleTransport {
907
1129
  if (!device) {
908
1130
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
909
1131
  try {
910
- device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, connectOptions));
1132
+ device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, nativeConnectOptions));
1133
+ androidRefreshConnectRan = refreshAndroidGattCache;
911
1134
  }
912
1135
  catch (e) {
913
1136
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
914
1137
  if (shouldRethrowBleSetupError(e)) {
915
1138
  throw e;
916
1139
  }
917
- if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
918
- e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
1140
+ if (isMtuOrCancelledConnectError(e)) {
1141
+ skipPostConnectMtu = true;
919
1142
  Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
920
1143
  device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
921
1144
  }
@@ -931,19 +1154,27 @@ class ReactNativeBleTransport {
931
1154
  if (!device) {
932
1155
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'unable to connect to device');
933
1156
  }
1157
+ if (refreshAndroidGattCache &&
1158
+ !androidRefreshConnectRan &&
1159
+ (yield device.isConnected().catch(() => false))) {
1160
+ yield this.dropAndroidLink(uuid, blePlxManager, device, 'gatt cache refresh');
1161
+ if (this.stopped)
1162
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1163
+ }
934
1164
  if (!(yield device.isConnected())) {
935
1165
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
936
1166
  const disconnectedDevice = device;
937
1167
  try {
938
- device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(connectOptions));
1168
+ device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(nativeConnectOptions));
1169
+ androidRefreshConnectRan = refreshAndroidGattCache;
939
1170
  }
940
1171
  catch (e) {
941
1172
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
942
1173
  if (shouldRethrowBleSetupError(e)) {
943
1174
  throw e;
944
1175
  }
945
- if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
946
- e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
1176
+ if (isMtuOrCancelledConnectError(e)) {
1177
+ skipPostConnectMtu = true;
947
1178
  Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
948
1179
  try {
949
1180
  device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
@@ -965,33 +1196,70 @@ class ReactNativeBleTransport {
965
1196
  }
966
1197
  }
967
1198
  }
968
- if (reactNative.Platform.OS === 'android') {
969
- const connectedDevice = device;
970
- try {
971
- if (!(yield connectedDevice.isConnected().catch(() => false))) {
972
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `Device ${uuid} is not connected before bonding`);
1199
+ if (this.stopped)
1200
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1201
+ if (reactNative.Platform.OS === 'android' && !(yield device.isConnected().catch(() => false))) {
1202
+ const disconnectedDevice = device;
1203
+ yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
1204
+ yield Promise.all([
1205
+ this.runBestEffortNativeOperation('connect failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid)),
1206
+ this.runBestEffortNativeOperation('connect failure: cancel device connection', () => disconnectedDevice.cancelConnection()),
1207
+ ]);
1208
+ }));
1209
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'device is not connected');
1210
+ }
1211
+ if (this.stopped)
1212
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1213
+ let characteristics;
1214
+ if (isAndroid) {
1215
+ if (refreshAndroidGattCache) {
1216
+ characteristics = yield this.resolveCharacteristicsWithTimeout(uuid, device);
1217
+ if (androidRefreshConnectRan)
1218
+ this.androidGattCacheRefreshes.delete(uuid);
1219
+ if (this.stopped)
1220
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1221
+ }
1222
+ device = yield this.negotiateAndroidMtu(uuid, blePlxManager, device);
1223
+ }
1224
+ else if (!skipPostConnectMtu) {
1225
+ const mtuResult = yield resolveNegotiatedMtu(device, transactionId => blePlxManager.cancelTransaction(transactionId));
1226
+ device = mtuResult.device;
1227
+ if (mtuResult.timedOut) {
1228
+ if (this.stopped)
1229
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1230
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] post-connect MTU timed out, reconnecting without requesting MTU');
1231
+ const timedOutDevice = device;
1232
+ let mtuTeardownSettled = false;
1233
+ yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
1234
+ yield this.runBestEffortNativeOperation('mtu timeout: cancel device connection', () => timedOutDevice.cancelConnection());
1235
+ mtuTeardownSettled = true;
1236
+ }));
1237
+ if (this.stopped)
1238
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1239
+ if (!mtuTeardownSettled || this.blePlxManager !== blePlxManager) {
1240
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'BLE MTU cleanup timed out');
973
1241
  }
974
- const bondState = yield pairDevice(uuid);
975
- if (bondState.bonding) {
976
- yield onDeviceBondState(uuid);
1242
+ try {
1243
+ device = yield this.connectWithTimeout(uuid, () => timedOutDevice.connect(fallbackConnectOptions));
977
1244
  }
978
- else if (!bondState.bonded) {
979
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
1245
+ catch (error) {
1246
+ if (shouldRethrowBleSetupError(error))
1247
+ throw error;
1248
+ if ((error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
1249
+ device = timedOutDevice;
1250
+ }
1251
+ else {
1252
+ remapError(error);
1253
+ }
980
1254
  }
981
1255
  }
982
- catch (error) {
983
- yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
984
- yield Promise.all([
985
- this.runBestEffortNativeOperation('bond failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid)),
986
- this.runBestEffortNativeOperation('bond failure: cancel device connection', () => connectedDevice.cancelConnection()),
987
- ]);
988
- }));
989
- throw error;
990
- }
991
1256
  }
992
- device = yield resolveNegotiatedMtu(device);
1257
+ if (this.stopped)
1258
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
993
1259
  const acquiredDevice = device;
994
- const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
1260
+ const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice));
1261
+ if (this.stopped)
1262
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
995
1263
  const protocolHint = expectedProtocol
996
1264
  ? undefined
997
1265
  : (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
@@ -1034,6 +1302,8 @@ class ReactNativeBleTransport {
1034
1302
  const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
1035
1303
  yield this.installTransportForAcquire(uuid, acquiredDevice);
1036
1304
  }));
1305
+ if (this.stopped)
1306
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1037
1307
  const currentTransport = transportCache[uuid];
1038
1308
  if (!currentTransport) {
1039
1309
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
@@ -1042,12 +1312,7 @@ class ReactNativeBleTransport {
1042
1312
  return { uuid, protocolType };
1043
1313
  }
1044
1314
  catch (error) {
1045
- if (hdShared.isBleStaleBondHardwareError(error)) {
1046
- yield this.disconnectUnlocked(uuid);
1047
- }
1048
- else {
1049
- yield this.releaseUnlocked(uuid, true);
1050
- }
1315
+ yield this.disconnectUnlocked(uuid);
1051
1316
  throw error;
1052
1317
  }
1053
1318
  finally {
@@ -1059,7 +1324,7 @@ class ReactNativeBleTransport {
1059
1324
  let bufferLength = 0;
1060
1325
  let buffer$1 = [];
1061
1326
  const subscription = characteristic.monitor((error, c) => {
1062
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
1327
+ var _a, _b, _c, _d, _e, _f;
1063
1328
  const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
1064
1329
  if (error) {
1065
1330
  Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
@@ -1076,16 +1341,16 @@ class ReactNativeBleTransport {
1076
1341
  this.rememberStaleBondError(uuid, toBleStaleBondHardwareError(error));
1077
1342
  return;
1078
1343
  }
1344
+ if (reactNative.Platform.OS === 'android' && isStaleGattTableNotifyReason(error.reason)) {
1345
+ this.androidGattCacheRefreshes.add(uuid);
1346
+ }
1079
1347
  if (this.getActiveProtocol(uuid) === 'V2') {
1080
1348
  let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
1081
1349
  if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
1082
1350
  errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
1083
1351
  }
1084
- else if (((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Cannot write client characteristic config descriptor')) ||
1085
- ((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot find client characteristic config descriptor')) ||
1086
- ((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('The handle is invalid')) ||
1087
- ((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('Writing is not permitted')) ||
1088
- ((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('notify change failed for device'))) {
1352
+ else if (isStaleGattTableNotifyReason(error.reason) ||
1353
+ ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('notify change failed for device'))) {
1089
1354
  errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
1090
1355
  }
1091
1356
  this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
@@ -1093,14 +1358,11 @@ class ReactNativeBleTransport {
1093
1358
  }
1094
1359
  if (this.runPromise && this.runPromiseDeviceId === uuid) {
1095
1360
  let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
1096
- if ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('The connection has timed out unexpectedly')) {
1361
+ if ((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('The connection has timed out unexpectedly')) {
1097
1362
  ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
1098
1363
  }
1099
- if (((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('Cannot write client characteristic config descriptor')) ||
1100
- ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Cannot find client characteristic config descriptor')) ||
1101
- ((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('The handle is invalid')) ||
1102
- ((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Writing is not permitted')) ||
1103
- ((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('notify change failed for device'))) {
1364
+ if (isStaleGattTableNotifyReason(error.reason) ||
1365
+ ((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('notify change failed for device'))) {
1104
1366
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
1105
1367
  this.runPromise.reject(notifyError);
1106
1368
  Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
@@ -1142,7 +1404,7 @@ class ReactNativeBleTransport {
1142
1404
  bufferLength = 0;
1143
1405
  buffer$1 = [];
1144
1406
  if (this.runPromiseDeviceId === uuid) {
1145
- (_o = this.runPromise) === null || _o === void 0 ? void 0 : _o.resolve(value.toString('hex'));
1407
+ (_e = this.runPromise) === null || _e === void 0 ? void 0 : _e.resolve(value.toString('hex'));
1146
1408
  }
1147
1409
  }
1148
1410
  }
@@ -1153,7 +1415,7 @@ class ReactNativeBleTransport {
1153
1415
  this.rejectProtocolV2Frames(uuid, notifyError);
1154
1416
  }
1155
1417
  else if (this.runPromiseDeviceId === uuid) {
1156
- (_p = this.runPromise) === null || _p === void 0 ? void 0 : _p.reject(notifyError);
1418
+ (_f = this.runPromise) === null || _f === void 0 ? void 0 : _f.reject(notifyError);
1157
1419
  }
1158
1420
  }
1159
1421
  }, notifyTransactionId);
@@ -1429,13 +1691,14 @@ class ReactNativeBleTransport {
1429
1691
  return check.call(jsonData);
1430
1692
  }
1431
1693
  catch (e) {
1432
- if (name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
1433
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
1694
+ const isProbeTimeout = (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS &&
1695
+ (name === 'GetFeatures' || name === 'Initialize');
1696
+ if (isProbeTimeout) {
1697
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] Protocol V1 ${name} probe call failed:`, e);
1434
1698
  }
1435
1699
  else {
1436
1700
  Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
1437
1701
  }
1438
- const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
1439
1702
  const isStaleCall = this.runPromise !== runPromise;
1440
1703
  if (!isProbeTimeout &&
1441
1704
  !isStaleCall &&
@@ -1455,7 +1718,43 @@ class ReactNativeBleTransport {
1455
1718
  });
1456
1719
  }
1457
1720
  stop() {
1721
+ var _a;
1722
+ if (this.stopPromise)
1723
+ return this.stopPromise;
1458
1724
  this.stopped = true;
1725
+ this.bondAbortController.abort();
1726
+ const deviceIds = new Set([
1727
+ ...this.monitorTokens.keys(),
1728
+ ...this.sessionProtocols.keys(),
1729
+ ...this.lifecycleOperations.keys(),
1730
+ ...(this.runPromiseDeviceId ? [this.runPromiseDeviceId] : []),
1731
+ ]);
1732
+ const scans = Array.from(this.scanCleanups, cleanup => cleanup());
1733
+ this.androidPriorityResetTimers.forEach(timeout => clearTimeout(timeout));
1734
+ this.androidPriorityResetTimers.clear();
1735
+ this.androidHighPriorityDevices.clear();
1736
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1737
+ (_a = this.runPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
1738
+ this.runPromise = null;
1739
+ this.runPromiseDeviceId = null;
1740
+ deviceIds.forEach(uuid => this.rejectProtocolV2Frames(uuid, error));
1741
+ const manager = this.blePlxManager;
1742
+ const pendingConnections = manager
1743
+ ? Array.from(this.lifecycleOperations.keys(), uuid => this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
1744
+ yield this.runBestEffortNativeOperation('stop: cancel pending device connection', () => manager.cancelDeviceConnection(uuid));
1745
+ })))
1746
+ : [];
1747
+ this.stopPromise = Promise.all([
1748
+ ...scans,
1749
+ ...pendingConnections,
1750
+ ...Array.from(deviceIds, uuid => this.disconnect(uuid)),
1751
+ ]).then(() => __awaiter(this, void 0, void 0, function* () {
1752
+ yield this.protocolV2Links.invalidateAllLinks('React Native BLE transport stopped');
1753
+ yield this.waitForManagerReset();
1754
+ this.blePlxManager = undefined;
1755
+ this.emitter = undefined;
1756
+ }));
1757
+ return this.stopPromise;
1459
1758
  }
1460
1759
  disconnect(session) {
1461
1760
  return __awaiter(this, void 0, void 0, function* () {
@@ -1585,13 +1884,93 @@ class ReactNativeBleTransport {
1585
1884
  });
1586
1885
  }
1587
1886
  cancel() {
1588
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1589
- if (this.runPromise) ;
1590
- this.runPromise = null;
1591
- this.runPromiseDeviceId = null;
1887
+ return __awaiter(this, void 0, void 0, function* () {
1888
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1889
+ const pending = this.runPromise;
1890
+ const deviceId = this.runPromiseDeviceId;
1891
+ if (pending) {
1892
+ pending.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled));
1893
+ if (this.runPromise === pending) {
1894
+ this.runPromise = null;
1895
+ this.runPromiseDeviceId = null;
1896
+ }
1897
+ if (deviceId)
1898
+ yield this.disconnect(deviceId);
1899
+ }
1900
+ });
1901
+ }
1902
+ negotiateAndroidMtu(uuid, manager, device) {
1903
+ return __awaiter(this, void 0, void 0, function* () {
1904
+ if (!shouldRefreshNegotiatedMtu(device.mtu))
1905
+ return device;
1906
+ const startedAt = Date.now();
1907
+ let timer;
1908
+ let timedOut = false;
1909
+ let negotiated = device;
1910
+ let failure;
1911
+ try {
1912
+ negotiated = yield Promise.race([
1913
+ device.requestMTU(ANDROID_REQUEST_MTU, `${device.id}:mtu:connected:0:${startedAt}`),
1914
+ new Promise((_, reject) => {
1915
+ timer = setTimeout(() => {
1916
+ timedOut = true;
1917
+ reject(new Error(`BLE MTU exchange timeout after ${ANDROID_MTU_EXCHANGE_TIMEOUT_MS}ms`));
1918
+ }, ANDROID_MTU_EXCHANGE_TIMEOUT_MS);
1919
+ }),
1920
+ ]);
1921
+ }
1922
+ catch (error) {
1923
+ failure = error instanceof Error ? error.message : String(error);
1924
+ }
1925
+ finally {
1926
+ if (timer)
1927
+ clearTimeout(timer);
1928
+ }
1929
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] BLE MTU exchange ${failure ? 'failed' : 'completed'}`, {
1930
+ connectIdSuffix: uuid.slice(-8),
1931
+ elapsedMs: Date.now() - startedAt,
1932
+ timedOut,
1933
+ actual: negotiated.mtu,
1934
+ error: failure,
1935
+ });
1936
+ if (this.stopped)
1937
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1938
+ if (!timedOut && !isKnownDefaultMtu(negotiated.mtu))
1939
+ return negotiated;
1940
+ const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'mtu-backstop' : 'mtu-default');
1941
+ yield this.dropAndroidLink(uuid, manager, negotiated, timedOut ? 'mtu exchange timeout' : 'default mtu');
1942
+ if (resetManager)
1943
+ throw this.createWedgedBleSetupError();
1944
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, timedOut
1945
+ ? 'BLE MTU exchange did not complete, reconnecting on a fresh link'
1946
+ : `BLE link stayed at the default MTU ${negotiated.mtu}, reconnecting on a fresh link`);
1947
+ });
1948
+ }
1949
+ dropAndroidLink(uuid, manager, device, reason) {
1950
+ return __awaiter(this, void 0, void 0, function* () {
1951
+ yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
1952
+ yield Promise.all([
1953
+ this.runBestEffortNativeOperation(`${reason}: cancel manager connection`, () => manager.cancelDeviceConnection(uuid)),
1954
+ this.runBestEffortNativeOperation(`${reason}: cancel device connection`, () => device.cancelConnection()),
1955
+ ]);
1956
+ }));
1957
+ const startedAt = Date.now();
1958
+ while (!this.stopped && Date.now() - startedAt < ANDROID_LINK_DROP_QUIET_MS) {
1959
+ yield delay(ANDROID_LINK_DROP_POLL_MS);
1960
+ }
1961
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE link drop', {
1962
+ connectIdSuffix: uuid.slice(-8),
1963
+ reason,
1964
+ stopped: this.stopped,
1965
+ });
1966
+ });
1592
1967
  }
1593
1968
  connectWithTimeout(uuid, connect) {
1594
1969
  return __awaiter(this, void 0, void 0, function* () {
1970
+ if (this.stopped)
1971
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
1972
+ const startedAt = Date.now();
1973
+ let succeeded = false;
1595
1974
  let timer;
1596
1975
  let timedOut = false;
1597
1976
  const pending = connect();
@@ -1606,6 +1985,7 @@ class ReactNativeBleTransport {
1606
1985
  }, BLE_CONNECT_TIMEOUT_MS);
1607
1986
  }),
1608
1987
  ]);
1988
+ succeeded = true;
1609
1989
  return result;
1610
1990
  }
1611
1991
  catch (error) {
@@ -1620,11 +2000,19 @@ class ReactNativeBleTransport {
1620
2000
  finally {
1621
2001
  if (timer)
1622
2002
  clearTimeout(timer);
2003
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] connect completed', {
2004
+ connectIdSuffix: uuid.slice(-8),
2005
+ elapsedMs: Date.now() - startedAt,
2006
+ succeeded,
2007
+ backstopExpired: timedOut,
2008
+ });
1623
2009
  }
1624
2010
  });
1625
2011
  }
1626
2012
  resolveCharacteristicsWithTimeout(uuid, device) {
1627
2013
  return __awaiter(this, void 0, void 0, function* () {
2014
+ const startedAt = Date.now();
2015
+ let succeeded = false;
1628
2016
  let timer;
1629
2017
  let timedOut = false;
1630
2018
  const pending = this.resolveCharacteristics(device);
@@ -1640,6 +2028,7 @@ class ReactNativeBleTransport {
1640
2028
  }),
1641
2029
  ]);
1642
2030
  this.connectionSetupTimeoutCounts.delete(uuid);
2031
+ succeeded = true;
1643
2032
  return result;
1644
2033
  }
1645
2034
  catch (error) {
@@ -1649,11 +2038,20 @@ class ReactNativeBleTransport {
1649
2038
  throw this.createWedgedBleSetupError();
1650
2039
  }
1651
2040
  }
2041
+ if (reactNative.Platform.OS === 'android' && isMissingGattShapeError(error)) {
2042
+ this.androidGattCacheRefreshes.add(uuid);
2043
+ }
1652
2044
  throw error;
1653
2045
  }
1654
2046
  finally {
1655
2047
  if (timer)
1656
2048
  clearTimeout(timer);
2049
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] GATT setup completed', {
2050
+ connectIdSuffix: uuid.slice(-8),
2051
+ elapsedMs: Date.now() - startedAt,
2052
+ succeeded,
2053
+ backstopExpired: timedOut,
2054
+ });
1657
2055
  }
1658
2056
  });
1659
2057
  }
@@ -1755,6 +2153,8 @@ class ReactNativeBleTransport {
1755
2153
  }
1756
2154
  }
1757
2155
  resetPlxManager() {
2156
+ if (bleManagerResetPromise)
2157
+ return;
1758
2158
  const manager = this.blePlxManager;
1759
2159
  this.blePlxManager = undefined;
1760
2160
  const reason = 'React Native BLE manager reset';
@@ -1792,16 +2192,25 @@ class ReactNativeBleTransport {
1792
2192
  this.acquiringProtocolV2.clear();
1793
2193
  this.sessionProtocols.clear();
1794
2194
  this.protocolReprobeFailures.clear();
2195
+ this.silentDetections.clear();
1795
2196
  this.writeTimeoutCounts.clear();
1796
2197
  this.connectionSetupTimeoutCounts.clear();
1797
2198
  this.monitorTokens.clear();
1798
2199
  this.protocolV2Assemblers.clear();
2200
+ let reset;
1799
2201
  try {
1800
- manager === null || manager === void 0 ? void 0 : manager.destroy();
2202
+ reset = Promise.resolve(manager === null || manager === void 0 ? void 0 : manager.destroy());
1801
2203
  }
1802
2204
  catch (error) {
1803
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
2205
+ reset = Promise.reject(error);
1804
2206
  }
2207
+ bleManagerResetPromise = reset;
2208
+ reset.then(() => {
2209
+ if (bleManagerResetPromise === reset)
2210
+ bleManagerResetPromise = undefined;
2211
+ }, error => {
2212
+ Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE manager destroy failed:', error);
2213
+ });
1805
2214
  }
1806
2215
  createProtocolMismatchError(expected) {
1807
2216
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
@@ -1857,6 +2266,7 @@ class ReactNativeBleTransport {
1857
2266
  !protocolHint &&
1858
2267
  reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
1859
2268
  const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
2269
+ yield this.wakeSilentProtocolV1Device(uuid, probeOrder);
1860
2270
  for (let i = 0; i < probeOrder.length; i += 1) {
1861
2271
  const protocol = probeOrder[i];
1862
2272
  if (i > 0) {
@@ -1876,6 +2286,7 @@ class ReactNativeBleTransport {
1876
2286
  this.confirmedProtocolV2.add(uuid);
1877
2287
  }
1878
2288
  this.protocolReprobeFailures.delete(uuid);
2289
+ this.silentDetections.delete(uuid);
1879
2290
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1880
2291
  deviceId: uuid,
1881
2292
  protocol,
@@ -1884,6 +2295,8 @@ class ReactNativeBleTransport {
1884
2295
  return protocol;
1885
2296
  }
1886
2297
  }
2298
+ if (!this.silentDetections.has(uuid))
2299
+ this.silentDetections.set(uuid, 'silent');
1887
2300
  if (trustSessionProtocol) {
1888
2301
  this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
1889
2302
  }
@@ -1895,6 +2308,30 @@ class ReactNativeBleTransport {
1895
2308
  throw this.createProtocolDetectionError();
1896
2309
  });
1897
2310
  }
2311
+ wakeSilentProtocolV1Device(uuid, probeOrder) {
2312
+ return __awaiter(this, void 0, void 0, function* () {
2313
+ if (reactNative.Platform.OS !== 'android' ||
2314
+ probeOrder[0] !== 'V1' ||
2315
+ this.silentDetections.get(uuid) !== 'silent') {
2316
+ return;
2317
+ }
2318
+ this.silentDetections.set(uuid, 'woken');
2319
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] sending Protocol V1 Initialize wake', {
2320
+ connectIdSuffix: uuid.slice(-8),
2321
+ });
2322
+ try {
2323
+ this.probingProtocols.set(uuid, 'V1');
2324
+ yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
2325
+ }
2326
+ catch (error) {
2327
+ if (shouldRethrowProtocolProbeError(error))
2328
+ throw error;
2329
+ }
2330
+ finally {
2331
+ this.clearProbeProtocol(uuid, 'V1');
2332
+ }
2333
+ });
2334
+ }
1898
2335
  resetProbeStateAfterProtocolProbe(uuid, protocol) {
1899
2336
  var _a, _b, _c;
1900
2337
  return __awaiter(this, void 0, void 0, function* () {
@@ -1951,7 +2388,7 @@ class ReactNativeBleTransport {
1951
2388
  catch (error) {
1952
2389
  this.clearProbeProtocol(uuid, 'V1');
1953
2390
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
1954
- if (isWedgedWriteError(error)) {
2391
+ if (shouldRethrowProtocolProbeError(error)) {
1955
2392
  throw error;
1956
2393
  }
1957
2394
  return false;
@@ -1977,7 +2414,7 @@ class ReactNativeBleTransport {
1977
2414
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1978
2415
  this.resetProtocolV2Frames(uuid);
1979
2416
  },
1980
- shouldRethrow: hdShared.isBleStaleBondHardwareError,
2417
+ shouldRethrow: shouldRethrowProtocolProbeError,
1981
2418
  });
1982
2419
  if (!detected) {
1983
2420
  this.clearProbeProtocol(uuid, 'V2');
@@ -2104,6 +2541,9 @@ class ReactNativeBleTransport {
2104
2541
  this.rememberStaleBondError(uuid, bondError);
2105
2542
  throw bondError;
2106
2543
  }
2544
+ if (isNativeBleDisconnectError(error)) {
2545
+ throw toBleDisconnectHardwareError(error);
2546
+ }
2107
2547
  if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
2108
2548
  attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
2109
2549
  throw error;
@@ -2146,6 +2586,7 @@ class ReactNativeBleTransport {
2146
2586
  if (!this._messages || !this._messagesV2) {
2147
2587
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
2148
2588
  }
2589
+ const isProtocolProbe = this.probingProtocols.get(uuid) === 'V2';
2149
2590
  const callOptions = options;
2150
2591
  const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
2151
2592
  if (highThroughputWrite) {
@@ -2186,6 +2627,14 @@ class ReactNativeBleTransport {
2186
2627
  }
2187
2628
  catch (e) {
2188
2629
  Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
2630
+ if (!isProtocolProbe &&
2631
+ (e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError &&
2632
+ !this.monitorTokens.has(uuid)) {
2633
+ yield this.runLifecycleOperation(uuid, () => __awaiter(this, void 0, void 0, function* () {
2634
+ if (!this.monitorTokens.has(uuid))
2635
+ yield this.disconnectUnlocked(uuid);
2636
+ }));
2637
+ }
2189
2638
  throw e;
2190
2639
  }
2191
2640
  finally {
@@ -2200,7 +2649,7 @@ class ReactNativeBleTransport {
2200
2649
  const transport = this.getCachedTransport(uuid);
2201
2650
  if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
2202
2651
  return;
2203
- const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1);
2652
+ const { device: refreshedDevice } = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1, transactionId => { var _a; return (_a = this.blePlxManager) === null || _a === void 0 ? void 0 : _a.cancelTransaction(transactionId); });
2204
2653
  transport.device = refreshedDevice;
2205
2654
  transport.mtuSize =
2206
2655
  typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
@@ -2317,6 +2766,8 @@ class ReactNativeBleTransport {
2317
2766
  }
2318
2767
  }
2319
2768
 
2769
+ exports.ANDROID_LINK_DROP_QUIET_MS = ANDROID_LINK_DROP_QUIET_MS;
2770
+ exports.ANDROID_MTU_EXCHANGE_TIMEOUT_MS = ANDROID_MTU_EXCHANGE_TIMEOUT_MS;
2320
2771
  exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
2321
2772
  exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
2322
2773
  exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;