@onekeyfe/hd-transport-react-native 1.2.3-alpha.1 → 1.2.3-alpha.11
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/README.md +1 -1
- package/dist/BleManager.d.ts +1 -1
- package/dist/BleManager.d.ts.map +1 -1
- package/dist/bleNativeDisconnect.d.ts +3 -0
- package/dist/bleNativeDisconnect.d.ts.map +1 -0
- package/dist/index.d.ts +44 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +714 -147
- package/package.json +6 -6
- package/src/BleManager.ts +73 -5
- package/src/__tests__/bleNativeDisconnect.test.ts +33 -0
- package/src/__tests__/connectTimeout.test.ts +427 -3
- package/src/__tests__/protocolReprobe.test.ts +93 -1
- package/src/__tests__/protocolV2Link.test.ts +976 -62
- package/src/__tests__/staleCallTimeout.test.ts +34 -5
- package/src/bleNativeDisconnect.ts +40 -0
- package/src/index.ts +806 -161
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, '
|
|
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
|
|
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 (
|
|
111
|
+
else if (hasFailed) {
|
|
88
112
|
cleanup();
|
|
89
|
-
|
|
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,43 @@ 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
|
+
};
|
|
389
|
+
const logIosBleBondDiagnostic = (phase, error, outcome) => {
|
|
390
|
+
if (reactNative.Platform.OS !== 'ios')
|
|
391
|
+
return;
|
|
392
|
+
const nativeError = (error !== null && error !== void 0 ? error : {});
|
|
393
|
+
const scalar = (value) => typeof value === 'string' || typeof value === 'number' ? value : undefined;
|
|
394
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] probe error', {
|
|
395
|
+
phase,
|
|
396
|
+
outcome,
|
|
397
|
+
errorName: scalar(nativeError.name),
|
|
398
|
+
errorCode: scalar(nativeError.errorCode),
|
|
399
|
+
attErrorCode: scalar(nativeError.attErrorCode),
|
|
400
|
+
iosErrorCode: scalar(nativeError.iosErrorCode),
|
|
401
|
+
androidErrorCode: scalar(nativeError.androidErrorCode),
|
|
402
|
+
nativeStaleBond: isNativeBleStaleBondError(error),
|
|
403
|
+
hardwareStaleBond: hdShared.isBleStaleBondHardwareError(error),
|
|
404
|
+
nativeDisconnect: isNativeBleDisconnectError(error),
|
|
405
|
+
});
|
|
406
|
+
};
|
|
407
|
+
const isIosProbeDisconnectError = (error) => {
|
|
408
|
+
if (reactNative.Platform.OS !== 'ios')
|
|
409
|
+
return false;
|
|
410
|
+
const code = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
411
|
+
return (isNativeBleDisconnectError(error) ||
|
|
412
|
+
code === hdShared.HardwareErrorCode.BleDeviceNotBonded ||
|
|
413
|
+
code === hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
414
|
+
};
|
|
319
415
|
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
320
416
|
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
321
417
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
@@ -350,10 +446,10 @@ function getDeviceDisplayName(device) {
|
|
|
350
446
|
}
|
|
351
447
|
const IOS_REQUEST_MTU = 247;
|
|
352
448
|
const ANDROID_REQUEST_MTU = 517;
|
|
353
|
-
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
354
449
|
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
355
450
|
const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
356
451
|
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
452
|
+
const BLE_MTU_REQUEST_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS;
|
|
357
453
|
const connectOptions = {
|
|
358
454
|
requestMTU: getRequestedBleMtu(),
|
|
359
455
|
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
@@ -362,6 +458,29 @@ const connectOptions = {
|
|
|
362
458
|
const fallbackConnectOptions = {
|
|
363
459
|
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
364
460
|
};
|
|
461
|
+
const androidRefreshGattConnectOptions = {
|
|
462
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
463
|
+
refreshGatt: 'OnConnected',
|
|
464
|
+
};
|
|
465
|
+
const ANDROID_MTU_EXCHANGE_TIMEOUT_MS = 12000;
|
|
466
|
+
const ANDROID_LINK_DROP_QUIET_MS = 5000;
|
|
467
|
+
const ANDROID_LINK_DROP_POLL_MS = 250;
|
|
468
|
+
const isKnownDefaultMtu = (mtu) => typeof mtu === 'number' && Number.isFinite(mtu) && mtu <= 23;
|
|
469
|
+
const isMissingGattShapeError = (error) => {
|
|
470
|
+
const code = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
471
|
+
const message = error === null || error === void 0 ? void 0 : error.message;
|
|
472
|
+
return (code === hdShared.HardwareErrorCode.BleServiceNotFound ||
|
|
473
|
+
code === hdShared.HardwareErrorCode.BleCharacteristicNotFound ||
|
|
474
|
+
(typeof message === 'string' &&
|
|
475
|
+
(message.includes('BLECharacteristicNotFound') ||
|
|
476
|
+
message.includes('BLECharacteristicNotWritable') ||
|
|
477
|
+
message.includes('BLECharacteristicNotNotifiable'))));
|
|
478
|
+
};
|
|
479
|
+
const isStaleGattTableNotifyReason = (reason) => !!reason &&
|
|
480
|
+
(reason.includes('Cannot write client characteristic config descriptor') ||
|
|
481
|
+
reason.includes('Cannot find client characteristic config descriptor') ||
|
|
482
|
+
reason.includes('The handle is invalid') ||
|
|
483
|
+
reason.includes('Writing is not permitted'));
|
|
365
484
|
const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
366
485
|
const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
367
486
|
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
@@ -376,6 +495,11 @@ const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? v
|
|
|
376
495
|
error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
377
496
|
const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
378
497
|
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
498
|
+
const isMtuOrCancelledConnectError = (error) => {
|
|
499
|
+
const errorCode = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
500
|
+
return (errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
501
|
+
errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled);
|
|
502
|
+
};
|
|
379
503
|
const tryToGetConfiguration = (device) => {
|
|
380
504
|
if (!device || !device.serviceUUIDs)
|
|
381
505
|
return null;
|
|
@@ -387,25 +511,65 @@ const tryToGetConfiguration = (device) => {
|
|
|
387
511
|
return null;
|
|
388
512
|
return infos;
|
|
389
513
|
};
|
|
390
|
-
const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
|
|
514
|
+
const requestNegotiatedMtu = (device, stage, attempt, cancelTransaction) => __awaiter(void 0, void 0, void 0, function* () {
|
|
391
515
|
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
392
|
-
return device;
|
|
516
|
+
return { device, timedOut: false };
|
|
517
|
+
const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
|
|
518
|
+
let timeoutId;
|
|
519
|
+
let timedOut = false;
|
|
393
520
|
try {
|
|
394
|
-
const
|
|
395
|
-
|
|
521
|
+
const request = device.requestMTU(getRequestedBleMtu(), transactionId);
|
|
522
|
+
request.catch(() => undefined);
|
|
523
|
+
const mtuDevice = yield Promise.race([
|
|
524
|
+
request,
|
|
525
|
+
new Promise((_, reject) => {
|
|
526
|
+
timeoutId = setTimeout(() => {
|
|
527
|
+
timedOut = true;
|
|
528
|
+
reject(new Error(`BLE MTU request timeout after ${BLE_MTU_REQUEST_TIMEOUT_MS}ms`));
|
|
529
|
+
}, BLE_MTU_REQUEST_TIMEOUT_MS);
|
|
530
|
+
}),
|
|
531
|
+
]);
|
|
532
|
+
return { device: mtuDevice, timedOut: false };
|
|
396
533
|
}
|
|
397
534
|
catch (error) {
|
|
535
|
+
if (timedOut && cancelTransaction) {
|
|
536
|
+
try {
|
|
537
|
+
Promise.resolve(cancelTransaction(transactionId)).catch(cancelError => {
|
|
538
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
|
|
539
|
+
platform: reactNative.Platform.OS,
|
|
540
|
+
stage,
|
|
541
|
+
attempt,
|
|
542
|
+
error: cancelError instanceof Error ? cancelError.message : String(cancelError),
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
catch (cancelError) {
|
|
547
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU cancellation failed', {
|
|
548
|
+
platform: reactNative.Platform.OS,
|
|
549
|
+
stage,
|
|
550
|
+
attempt,
|
|
551
|
+
error: cancelError instanceof Error ? cancelError.message : String(cancelError),
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
398
555
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
|
|
399
556
|
platform: reactNative.Platform.OS,
|
|
400
557
|
stage,
|
|
401
558
|
attempt,
|
|
402
559
|
actual: device.mtu,
|
|
560
|
+
timedOut,
|
|
403
561
|
error: error instanceof Error ? error.message : String(error),
|
|
404
562
|
});
|
|
405
|
-
return device;
|
|
563
|
+
return { device, timedOut };
|
|
564
|
+
}
|
|
565
|
+
finally {
|
|
566
|
+
if (timeoutId)
|
|
567
|
+
clearTimeout(timeoutId);
|
|
406
568
|
}
|
|
407
569
|
});
|
|
408
|
-
const resolveNegotiatedMtu = (device) =>
|
|
570
|
+
const resolveNegotiatedMtu = (device, cancelTransaction) => shouldRefreshNegotiatedMtu(device.mtu)
|
|
571
|
+
? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
|
|
572
|
+
: Promise.resolve({ device, timedOut: false });
|
|
409
573
|
function remapError(error) {
|
|
410
574
|
var _a;
|
|
411
575
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -429,6 +593,7 @@ class ReactNativeBleTransport {
|
|
|
429
593
|
this.name = 'ReactNativeBleTransport';
|
|
430
594
|
this.configured = false;
|
|
431
595
|
this.stopped = false;
|
|
596
|
+
this.bondAbortController = new AbortController();
|
|
432
597
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
433
598
|
this.runPromise = null;
|
|
434
599
|
this.runPromiseDeviceId = null;
|
|
@@ -441,6 +606,9 @@ class ReactNativeBleTransport {
|
|
|
441
606
|
this.sessionProtocols = new Map();
|
|
442
607
|
this.confirmedProtocolV2 = new Set();
|
|
443
608
|
this.protocolReprobeFailures = new Map();
|
|
609
|
+
this.silentDetections = new Map();
|
|
610
|
+
this.iosProbeDisconnectEvidence = new Map();
|
|
611
|
+
this.androidGattCacheRefreshes = new Set();
|
|
444
612
|
this.staleBondErrors = new Map();
|
|
445
613
|
this.acquiringProtocolV2 = new Set();
|
|
446
614
|
this.protocolV2Assemblers = new Map();
|
|
@@ -458,11 +626,20 @@ class ReactNativeBleTransport {
|
|
|
458
626
|
},
|
|
459
627
|
classifyError: () => 'link-fatal',
|
|
460
628
|
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
461
|
-
var _b;
|
|
629
|
+
var _b, _c;
|
|
462
630
|
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
463
631
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
464
632
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
465
633
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
634
|
+
if (this.probingProtocols.get(uuid) !== 'V2') {
|
|
635
|
+
const transport = transportCache[uuid];
|
|
636
|
+
try {
|
|
637
|
+
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);
|
|
638
|
+
}
|
|
639
|
+
catch (_d) {
|
|
640
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 disconnect listener failed');
|
|
641
|
+
}
|
|
642
|
+
}
|
|
466
643
|
yield this.releaseNative(uuid, true);
|
|
467
644
|
}
|
|
468
645
|
}),
|
|
@@ -474,6 +651,7 @@ class ReactNativeBleTransport {
|
|
|
474
651
|
this.androidPriorityResetTimers = new Map();
|
|
475
652
|
this.nextMonitorToken = 1;
|
|
476
653
|
this.lifecycleOperations = new Map();
|
|
654
|
+
this.scanCleanups = new Set();
|
|
477
655
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
478
656
|
}
|
|
479
657
|
init(logger, emitter) {
|
|
@@ -502,10 +680,38 @@ class ReactNativeBleTransport {
|
|
|
502
680
|
listen() {
|
|
503
681
|
}
|
|
504
682
|
getPlxManager() {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
683
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
684
|
+
while (bleManagerResetPromise) {
|
|
685
|
+
yield this.waitForManagerReset();
|
|
686
|
+
}
|
|
687
|
+
if (this.stopped)
|
|
688
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
689
|
+
if (!this.blePlxManager)
|
|
690
|
+
this.blePlxManager = new reactNativeBlePlx.BleManager();
|
|
691
|
+
return this.blePlxManager;
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
waitForManagerReset() {
|
|
695
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
696
|
+
if (!bleManagerResetPromise)
|
|
697
|
+
return;
|
|
698
|
+
let timeout;
|
|
699
|
+
try {
|
|
700
|
+
yield Promise.race([
|
|
701
|
+
bleManagerResetPromise,
|
|
702
|
+
new Promise((_, reject) => {
|
|
703
|
+
timeout = setTimeout(() => reject(this.createWedgedBleSetupError()), BLE_CONNECT_TIMEOUT_MS);
|
|
704
|
+
}),
|
|
705
|
+
]);
|
|
706
|
+
}
|
|
707
|
+
catch (_a) {
|
|
708
|
+
throw this.createWedgedBleSetupError();
|
|
709
|
+
}
|
|
710
|
+
finally {
|
|
711
|
+
if (timeout)
|
|
712
|
+
clearTimeout(timeout);
|
|
713
|
+
}
|
|
714
|
+
});
|
|
509
715
|
}
|
|
510
716
|
resolveCharacteristics(device) {
|
|
511
717
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -670,30 +876,55 @@ class ReactNativeBleTransport {
|
|
|
670
876
|
}
|
|
671
877
|
enumerate() {
|
|
672
878
|
return __awaiter(this, void 0, void 0, function* () {
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
if (reactNative.
|
|
685
|
-
|
|
686
|
-
|
|
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
|
-
}
|
|
879
|
+
const scanStartedAt = Date.now();
|
|
880
|
+
let firstDeviceMs;
|
|
881
|
+
const blePlxManager = yield this.getPlxManager();
|
|
882
|
+
yield subscribeBleOn(blePlxManager);
|
|
883
|
+
if (reactNative.Platform.OS === 'android' && reactNative.Platform.Version >= 31) {
|
|
884
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, please wait...');
|
|
885
|
+
const resultConnect = yield reactNative.PermissionsAndroid.requestMultiple([
|
|
886
|
+
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
|
|
887
|
+
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
|
|
888
|
+
]);
|
|
889
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
|
|
890
|
+
if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
|
|
891
|
+
resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
|
|
892
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
|
|
696
893
|
}
|
|
894
|
+
}
|
|
895
|
+
if (this.stopped)
|
|
896
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
897
|
+
return new Promise((resolve, reject) => {
|
|
898
|
+
const deviceList = [];
|
|
899
|
+
let finished = false;
|
|
900
|
+
let scanCleanup;
|
|
901
|
+
const finishScan = (error) => {
|
|
902
|
+
if (scanCleanup)
|
|
903
|
+
return scanCleanup;
|
|
904
|
+
finished = true;
|
|
905
|
+
clearScanTimer();
|
|
906
|
+
scanCleanup = this.runNativeTeardown('scan', blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
907
|
+
yield blePlxManager.stopDeviceScan();
|
|
908
|
+
})).then(() => {
|
|
909
|
+
this.scanCleanups.delete(cancelScan);
|
|
910
|
+
if (error)
|
|
911
|
+
reject(error);
|
|
912
|
+
else
|
|
913
|
+
resolve(deviceList);
|
|
914
|
+
});
|
|
915
|
+
return scanCleanup;
|
|
916
|
+
};
|
|
917
|
+
const cancelScan = () => finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
918
|
+
this.scanCleanups.add(cancelScan);
|
|
919
|
+
const clearScanTimer = timer.timeout(() => {
|
|
920
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan completed', {
|
|
921
|
+
elapsedMs: Date.now() - scanStartedAt,
|
|
922
|
+
firstDeviceMs,
|
|
923
|
+
deviceCount: deviceList.length,
|
|
924
|
+
scanWindowMs: this.scanTimeout,
|
|
925
|
+
});
|
|
926
|
+
finishScan();
|
|
927
|
+
}, this.scanTimeout);
|
|
697
928
|
blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
|
|
698
929
|
allowDuplicates: true,
|
|
699
930
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
@@ -702,19 +933,17 @@ class ReactNativeBleTransport {
|
|
|
702
933
|
if (error) {
|
|
703
934
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
704
935
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
705
|
-
|
|
936
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
706
937
|
}
|
|
707
938
|
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.BluetoothUnauthorized) {
|
|
708
|
-
|
|
939
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
|
|
709
940
|
}
|
|
710
941
|
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.LocationServicesDisabled) {
|
|
711
|
-
|
|
712
|
-
}
|
|
713
|
-
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) {
|
|
714
|
-
timer.timeout(() => { }, this.scanTimeout);
|
|
942
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
|
|
715
943
|
}
|
|
944
|
+
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) ;
|
|
716
945
|
else {
|
|
717
|
-
|
|
946
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
|
|
718
947
|
}
|
|
719
948
|
return;
|
|
720
949
|
}
|
|
@@ -739,6 +968,8 @@ class ReactNativeBleTransport {
|
|
|
739
968
|
});
|
|
740
969
|
}
|
|
741
970
|
});
|
|
971
|
+
if (finished)
|
|
972
|
+
return;
|
|
742
973
|
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
743
974
|
for (const device of devices) {
|
|
744
975
|
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
@@ -754,10 +985,11 @@ class ReactNativeBleTransport {
|
|
|
754
985
|
addDevice(device);
|
|
755
986
|
}
|
|
756
987
|
}
|
|
757
|
-
});
|
|
988
|
+
}, error => Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral failed:', error));
|
|
758
989
|
const addDevice = (device) => {
|
|
759
990
|
var _a;
|
|
760
|
-
if (deviceList.every(d => d.id !== device.id)) {
|
|
991
|
+
if (!finished && deviceList.every(d => d.id !== device.id)) {
|
|
992
|
+
firstDeviceMs !== null && firstDeviceMs !== void 0 ? firstDeviceMs : (firstDeviceMs = Date.now() - scanStartedAt);
|
|
761
993
|
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
762
994
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
763
995
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
@@ -767,16 +999,14 @@ class ReactNativeBleTransport {
|
|
|
767
999
|
});
|
|
768
1000
|
}
|
|
769
1001
|
};
|
|
770
|
-
|
|
771
|
-
blePlxManager.stopDeviceScan();
|
|
772
|
-
resolve(deviceList);
|
|
773
|
-
}, this.scanTimeout);
|
|
774
|
-
}));
|
|
1002
|
+
});
|
|
775
1003
|
});
|
|
776
1004
|
}
|
|
777
1005
|
installTransportForAcquire(uuid, device, characteristics) {
|
|
778
1006
|
return __awaiter(this, void 0, void 0, function* () {
|
|
779
1007
|
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
|
|
1008
|
+
if (this.stopped)
|
|
1009
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
780
1010
|
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
781
1011
|
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
|
|
782
1012
|
const monitorToken = this.nextMonitorToken;
|
|
@@ -797,30 +1027,12 @@ class ReactNativeBleTransport {
|
|
|
797
1027
|
else if (reactNative.Platform.OS === 'android') {
|
|
798
1028
|
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
799
1029
|
}
|
|
800
|
-
|
|
801
|
-
|
|
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
|
-
}
|
|
1030
|
+
if (this.stopped)
|
|
1031
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
818
1032
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
819
1033
|
platform: reactNative.Platform.OS,
|
|
820
1034
|
requested: getRequestedBleMtu(),
|
|
821
|
-
initial: initialMtu,
|
|
822
1035
|
actual: transport$1.mtuSize,
|
|
823
|
-
refreshAttempts,
|
|
824
1036
|
});
|
|
825
1037
|
return transport$1;
|
|
826
1038
|
});
|
|
@@ -837,6 +1049,8 @@ class ReactNativeBleTransport {
|
|
|
837
1049
|
acquireUnlocked(input) {
|
|
838
1050
|
var _a;
|
|
839
1051
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1052
|
+
if (this.stopped)
|
|
1053
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
840
1054
|
const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
|
|
841
1055
|
const shouldMapProtocolV2StaleBond = expectedProtocol
|
|
842
1056
|
? expectedProtocol === 'V2'
|
|
@@ -868,9 +1082,13 @@ class ReactNativeBleTransport {
|
|
|
868
1082
|
const isCachedDeviceConnected = yield cachedTransport.device
|
|
869
1083
|
.isConnected()
|
|
870
1084
|
.catch(() => false);
|
|
1085
|
+
const isCachedAndroidLinkUsable = reactNative.Platform.OS !== 'android' || !this.androidGattCacheRefreshes.has(uuid);
|
|
871
1086
|
if (isCachedDeviceConnected &&
|
|
1087
|
+
isCachedAndroidLinkUsable &&
|
|
872
1088
|
cachedProtocol &&
|
|
873
1089
|
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
1090
|
+
if (this.stopped)
|
|
1091
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
874
1092
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
875
1093
|
return { uuid, protocolType: cachedProtocol };
|
|
876
1094
|
}
|
|
@@ -879,6 +1097,15 @@ class ReactNativeBleTransport {
|
|
|
879
1097
|
}
|
|
880
1098
|
}
|
|
881
1099
|
let device = null;
|
|
1100
|
+
const isAndroid = reactNative.Platform.OS === 'android';
|
|
1101
|
+
const refreshAndroidGattCache = isAndroid && (!!skipProtocolProbe || this.androidGattCacheRefreshes.has(uuid));
|
|
1102
|
+
let nativeConnectOptions = connectOptions;
|
|
1103
|
+
if (isAndroid) {
|
|
1104
|
+
nativeConnectOptions = refreshAndroidGattCache
|
|
1105
|
+
? androidRefreshGattConnectOptions
|
|
1106
|
+
: fallbackConnectOptions;
|
|
1107
|
+
}
|
|
1108
|
+
let androidRefreshConnectRan = false;
|
|
882
1109
|
if (forceCleanRunPromise && this.runPromise) {
|
|
883
1110
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
884
1111
|
this.runPromise.reject(error);
|
|
@@ -887,6 +1114,7 @@ class ReactNativeBleTransport {
|
|
|
887
1114
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
888
1115
|
}
|
|
889
1116
|
const blePlxManager = yield this.getPlxManager();
|
|
1117
|
+
let skipPostConnectMtu = false;
|
|
890
1118
|
try {
|
|
891
1119
|
yield subscribeBleOn(blePlxManager);
|
|
892
1120
|
}
|
|
@@ -894,6 +1122,27 @@ class ReactNativeBleTransport {
|
|
|
894
1122
|
Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
|
|
895
1123
|
throw error;
|
|
896
1124
|
}
|
|
1125
|
+
if (this.stopped)
|
|
1126
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1127
|
+
if (reactNative.Platform.OS === 'android') {
|
|
1128
|
+
try {
|
|
1129
|
+
const bondState = yield pairDevice(uuid);
|
|
1130
|
+
if (bondState.bonding) {
|
|
1131
|
+
yield onDeviceBondState(uuid, this.bondAbortController.signal);
|
|
1132
|
+
}
|
|
1133
|
+
else if (!bondState.bonded) {
|
|
1134
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
catch (error) {
|
|
1138
|
+
yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1139
|
+
yield this.runBestEffortNativeOperation('bond failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid));
|
|
1140
|
+
}));
|
|
1141
|
+
throw error;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
if (this.stopped)
|
|
1145
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
897
1146
|
if (!device) {
|
|
898
1147
|
const devices = yield blePlxManager.devices([uuid]);
|
|
899
1148
|
[device] = devices;
|
|
@@ -907,15 +1156,16 @@ class ReactNativeBleTransport {
|
|
|
907
1156
|
if (!device) {
|
|
908
1157
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
|
|
909
1158
|
try {
|
|
910
|
-
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid,
|
|
1159
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, nativeConnectOptions));
|
|
1160
|
+
androidRefreshConnectRan = refreshAndroidGattCache;
|
|
911
1161
|
}
|
|
912
1162
|
catch (e) {
|
|
913
1163
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
914
1164
|
if (shouldRethrowBleSetupError(e)) {
|
|
915
1165
|
throw e;
|
|
916
1166
|
}
|
|
917
|
-
if (e
|
|
918
|
-
|
|
1167
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1168
|
+
skipPostConnectMtu = true;
|
|
919
1169
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
920
1170
|
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
921
1171
|
}
|
|
@@ -931,19 +1181,27 @@ class ReactNativeBleTransport {
|
|
|
931
1181
|
if (!device) {
|
|
932
1182
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'unable to connect to device');
|
|
933
1183
|
}
|
|
1184
|
+
if (refreshAndroidGattCache &&
|
|
1185
|
+
!androidRefreshConnectRan &&
|
|
1186
|
+
(yield device.isConnected().catch(() => false))) {
|
|
1187
|
+
yield this.dropAndroidLink(uuid, blePlxManager, device, 'gatt cache refresh');
|
|
1188
|
+
if (this.stopped)
|
|
1189
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1190
|
+
}
|
|
934
1191
|
if (!(yield device.isConnected())) {
|
|
935
1192
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
936
1193
|
const disconnectedDevice = device;
|
|
937
1194
|
try {
|
|
938
|
-
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(
|
|
1195
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(nativeConnectOptions));
|
|
1196
|
+
androidRefreshConnectRan = refreshAndroidGattCache;
|
|
939
1197
|
}
|
|
940
1198
|
catch (e) {
|
|
941
1199
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
942
1200
|
if (shouldRethrowBleSetupError(e)) {
|
|
943
1201
|
throw e;
|
|
944
1202
|
}
|
|
945
|
-
if (e
|
|
946
|
-
|
|
1203
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1204
|
+
skipPostConnectMtu = true;
|
|
947
1205
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
948
1206
|
try {
|
|
949
1207
|
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
@@ -965,33 +1223,70 @@ class ReactNativeBleTransport {
|
|
|
965
1223
|
}
|
|
966
1224
|
}
|
|
967
1225
|
}
|
|
968
|
-
if (
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
1226
|
+
if (this.stopped)
|
|
1227
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1228
|
+
if (reactNative.Platform.OS === 'android' && !(yield device.isConnected().catch(() => false))) {
|
|
1229
|
+
const disconnectedDevice = device;
|
|
1230
|
+
yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1231
|
+
yield Promise.all([
|
|
1232
|
+
this.runBestEffortNativeOperation('connect failure: cancel manager connection', () => blePlxManager.cancelDeviceConnection(uuid)),
|
|
1233
|
+
this.runBestEffortNativeOperation('connect failure: cancel device connection', () => disconnectedDevice.cancelConnection()),
|
|
1234
|
+
]);
|
|
1235
|
+
}));
|
|
1236
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'device is not connected');
|
|
1237
|
+
}
|
|
1238
|
+
if (this.stopped)
|
|
1239
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1240
|
+
let characteristics;
|
|
1241
|
+
if (isAndroid) {
|
|
1242
|
+
if (refreshAndroidGattCache) {
|
|
1243
|
+
characteristics = yield this.resolveCharacteristicsWithTimeout(uuid, device);
|
|
1244
|
+
if (androidRefreshConnectRan)
|
|
1245
|
+
this.androidGattCacheRefreshes.delete(uuid);
|
|
1246
|
+
if (this.stopped)
|
|
1247
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1248
|
+
}
|
|
1249
|
+
device = yield this.negotiateAndroidMtu(uuid, blePlxManager, device);
|
|
1250
|
+
}
|
|
1251
|
+
else if (!skipPostConnectMtu) {
|
|
1252
|
+
const mtuResult = yield resolveNegotiatedMtu(device, transactionId => blePlxManager.cancelTransaction(transactionId));
|
|
1253
|
+
device = mtuResult.device;
|
|
1254
|
+
if (mtuResult.timedOut) {
|
|
1255
|
+
if (this.stopped)
|
|
1256
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1257
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] post-connect MTU timed out, reconnecting without requesting MTU');
|
|
1258
|
+
const timedOutDevice = device;
|
|
1259
|
+
let mtuTeardownSettled = false;
|
|
1260
|
+
yield this.runNativeTeardown(uuid, blePlxManager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1261
|
+
yield this.runBestEffortNativeOperation('mtu timeout: cancel device connection', () => timedOutDevice.cancelConnection());
|
|
1262
|
+
mtuTeardownSettled = true;
|
|
1263
|
+
}));
|
|
1264
|
+
if (this.stopped)
|
|
1265
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1266
|
+
if (!mtuTeardownSettled || this.blePlxManager !== blePlxManager) {
|
|
1267
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'BLE MTU cleanup timed out');
|
|
973
1268
|
}
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
yield onDeviceBondState(uuid);
|
|
1269
|
+
try {
|
|
1270
|
+
device = yield this.connectWithTimeout(uuid, () => timedOutDevice.connect(fallbackConnectOptions));
|
|
977
1271
|
}
|
|
978
|
-
|
|
979
|
-
|
|
1272
|
+
catch (error) {
|
|
1273
|
+
if (shouldRethrowBleSetupError(error))
|
|
1274
|
+
throw error;
|
|
1275
|
+
if ((error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
1276
|
+
device = timedOutDevice;
|
|
1277
|
+
}
|
|
1278
|
+
else {
|
|
1279
|
+
remapError(error);
|
|
1280
|
+
}
|
|
980
1281
|
}
|
|
981
1282
|
}
|
|
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
1283
|
}
|
|
992
|
-
|
|
1284
|
+
if (this.stopped)
|
|
1285
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
993
1286
|
const acquiredDevice = device;
|
|
994
|
-
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
|
|
1287
|
+
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice));
|
|
1288
|
+
if (this.stopped)
|
|
1289
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
995
1290
|
const protocolHint = expectedProtocol
|
|
996
1291
|
? undefined
|
|
997
1292
|
: (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
|
|
@@ -1034,6 +1329,8 @@ class ReactNativeBleTransport {
|
|
|
1034
1329
|
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
1035
1330
|
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
1036
1331
|
}));
|
|
1332
|
+
if (this.stopped)
|
|
1333
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1037
1334
|
const currentTransport = transportCache[uuid];
|
|
1038
1335
|
if (!currentTransport) {
|
|
1039
1336
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
@@ -1042,12 +1339,9 @@ class ReactNativeBleTransport {
|
|
|
1042
1339
|
return { uuid, protocolType };
|
|
1043
1340
|
}
|
|
1044
1341
|
catch (error) {
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
}
|
|
1048
|
-
else {
|
|
1049
|
-
yield this.releaseUnlocked(uuid, true);
|
|
1050
|
-
}
|
|
1342
|
+
yield this.disconnectUnlocked(uuid, {
|
|
1343
|
+
preserveIosProbeDisconnect: this.iosProbeDisconnectEvidence.has(uuid),
|
|
1344
|
+
});
|
|
1051
1345
|
throw error;
|
|
1052
1346
|
}
|
|
1053
1347
|
finally {
|
|
@@ -1059,7 +1353,7 @@ class ReactNativeBleTransport {
|
|
|
1059
1353
|
let bufferLength = 0;
|
|
1060
1354
|
let buffer$1 = [];
|
|
1061
1355
|
const subscription = characteristic.monitor((error, c) => {
|
|
1062
|
-
var _a, _b, _c, _d, _e, _f
|
|
1356
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1063
1357
|
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
1064
1358
|
if (error) {
|
|
1065
1359
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
@@ -1076,16 +1370,16 @@ class ReactNativeBleTransport {
|
|
|
1076
1370
|
this.rememberStaleBondError(uuid, toBleStaleBondHardwareError(error));
|
|
1077
1371
|
return;
|
|
1078
1372
|
}
|
|
1373
|
+
if (reactNative.Platform.OS === 'android' && isStaleGattTableNotifyReason(error.reason)) {
|
|
1374
|
+
this.androidGattCacheRefreshes.add(uuid);
|
|
1375
|
+
}
|
|
1079
1376
|
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
1080
1377
|
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
1081
1378
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
1082
1379
|
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
1083
1380
|
}
|
|
1084
|
-
else if ((
|
|
1085
|
-
((
|
|
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'))) {
|
|
1381
|
+
else if (isStaleGattTableNotifyReason(error.reason) ||
|
|
1382
|
+
((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('notify change failed for device'))) {
|
|
1089
1383
|
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
1090
1384
|
}
|
|
1091
1385
|
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
@@ -1093,14 +1387,11 @@ class ReactNativeBleTransport {
|
|
|
1093
1387
|
}
|
|
1094
1388
|
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
1095
1389
|
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
1096
|
-
if ((
|
|
1390
|
+
if ((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('The connection has timed out unexpectedly')) {
|
|
1097
1391
|
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
1098
1392
|
}
|
|
1099
|
-
if ((
|
|
1100
|
-
((
|
|
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'))) {
|
|
1393
|
+
if (isStaleGattTableNotifyReason(error.reason) ||
|
|
1394
|
+
((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('notify change failed for device'))) {
|
|
1104
1395
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
1105
1396
|
this.runPromise.reject(notifyError);
|
|
1106
1397
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
@@ -1142,7 +1433,7 @@ class ReactNativeBleTransport {
|
|
|
1142
1433
|
bufferLength = 0;
|
|
1143
1434
|
buffer$1 = [];
|
|
1144
1435
|
if (this.runPromiseDeviceId === uuid) {
|
|
1145
|
-
(
|
|
1436
|
+
(_e = this.runPromise) === null || _e === void 0 ? void 0 : _e.resolve(value.toString('hex'));
|
|
1146
1437
|
}
|
|
1147
1438
|
}
|
|
1148
1439
|
}
|
|
@@ -1153,7 +1444,7 @@ class ReactNativeBleTransport {
|
|
|
1153
1444
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1154
1445
|
}
|
|
1155
1446
|
else if (this.runPromiseDeviceId === uuid) {
|
|
1156
|
-
(
|
|
1447
|
+
(_f = this.runPromise) === null || _f === void 0 ? void 0 : _f.reject(notifyError);
|
|
1157
1448
|
}
|
|
1158
1449
|
}
|
|
1159
1450
|
}, notifyTransactionId);
|
|
@@ -1429,13 +1720,14 @@ class ReactNativeBleTransport {
|
|
|
1429
1720
|
return check.call(jsonData);
|
|
1430
1721
|
}
|
|
1431
1722
|
catch (e) {
|
|
1432
|
-
|
|
1433
|
-
|
|
1723
|
+
const isProbeTimeout = (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS &&
|
|
1724
|
+
(name === 'GetFeatures' || name === 'Initialize');
|
|
1725
|
+
if (isProbeTimeout) {
|
|
1726
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] Protocol V1 ${name} probe call failed:`, e);
|
|
1434
1727
|
}
|
|
1435
1728
|
else {
|
|
1436
1729
|
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1437
1730
|
}
|
|
1438
|
-
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1439
1731
|
const isStaleCall = this.runPromise !== runPromise;
|
|
1440
1732
|
if (!isProbeTimeout &&
|
|
1441
1733
|
!isStaleCall &&
|
|
@@ -1455,14 +1747,51 @@ class ReactNativeBleTransport {
|
|
|
1455
1747
|
});
|
|
1456
1748
|
}
|
|
1457
1749
|
stop() {
|
|
1750
|
+
var _a;
|
|
1751
|
+
if (this.stopPromise)
|
|
1752
|
+
return this.stopPromise;
|
|
1458
1753
|
this.stopped = true;
|
|
1754
|
+
this.bondAbortController.abort();
|
|
1755
|
+
const deviceIds = new Set([
|
|
1756
|
+
...this.monitorTokens.keys(),
|
|
1757
|
+
...this.sessionProtocols.keys(),
|
|
1758
|
+
...this.lifecycleOperations.keys(),
|
|
1759
|
+
...(this.runPromiseDeviceId ? [this.runPromiseDeviceId] : []),
|
|
1760
|
+
]);
|
|
1761
|
+
const scans = Array.from(this.scanCleanups, cleanup => cleanup());
|
|
1762
|
+
this.androidPriorityResetTimers.forEach(timeout => clearTimeout(timeout));
|
|
1763
|
+
this.androidPriorityResetTimers.clear();
|
|
1764
|
+
this.androidHighPriorityDevices.clear();
|
|
1765
|
+
this.iosProbeDisconnectEvidence.clear();
|
|
1766
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1767
|
+
(_a = this.runPromise) === null || _a === void 0 ? void 0 : _a.reject(error);
|
|
1768
|
+
this.runPromise = null;
|
|
1769
|
+
this.runPromiseDeviceId = null;
|
|
1770
|
+
deviceIds.forEach(uuid => this.rejectProtocolV2Frames(uuid, error));
|
|
1771
|
+
const manager = this.blePlxManager;
|
|
1772
|
+
const pendingConnections = manager
|
|
1773
|
+
? Array.from(this.lifecycleOperations.keys(), uuid => this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1774
|
+
yield this.runBestEffortNativeOperation('stop: cancel pending device connection', () => manager.cancelDeviceConnection(uuid));
|
|
1775
|
+
})))
|
|
1776
|
+
: [];
|
|
1777
|
+
this.stopPromise = Promise.all([
|
|
1778
|
+
...scans,
|
|
1779
|
+
...pendingConnections,
|
|
1780
|
+
...Array.from(deviceIds, uuid => this.disconnect(uuid)),
|
|
1781
|
+
]).then(() => __awaiter(this, void 0, void 0, function* () {
|
|
1782
|
+
yield this.protocolV2Links.invalidateAllLinks('React Native BLE transport stopped');
|
|
1783
|
+
yield this.waitForManagerReset();
|
|
1784
|
+
this.blePlxManager = undefined;
|
|
1785
|
+
this.emitter = undefined;
|
|
1786
|
+
}));
|
|
1787
|
+
return this.stopPromise;
|
|
1459
1788
|
}
|
|
1460
1789
|
disconnect(session) {
|
|
1461
1790
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1462
1791
|
return this.runLifecycleOperation(session, () => this.disconnectUnlocked(session));
|
|
1463
1792
|
});
|
|
1464
1793
|
}
|
|
1465
|
-
disconnectUnlocked(session) {
|
|
1794
|
+
disconnectUnlocked(session, options) {
|
|
1466
1795
|
var _a, _b, _c;
|
|
1467
1796
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1468
1797
|
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
@@ -1498,6 +1827,9 @@ class ReactNativeBleTransport {
|
|
|
1498
1827
|
this.deviceProtocolHints.delete(session);
|
|
1499
1828
|
this.sessionProtocols.delete(session);
|
|
1500
1829
|
this.protocolReprobeFailures.delete(session);
|
|
1830
|
+
if (!(options === null || options === void 0 ? void 0 : options.preserveIosProbeDisconnect)) {
|
|
1831
|
+
this.iosProbeDisconnectEvidence.delete(session);
|
|
1832
|
+
}
|
|
1501
1833
|
this.protocolV2Assemblers.delete(session);
|
|
1502
1834
|
this.resetProtocolV2Frames(session);
|
|
1503
1835
|
try {
|
|
@@ -1585,13 +1917,93 @@ class ReactNativeBleTransport {
|
|
|
1585
1917
|
});
|
|
1586
1918
|
}
|
|
1587
1919
|
cancel() {
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1920
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1921
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1922
|
+
const pending = this.runPromise;
|
|
1923
|
+
const deviceId = this.runPromiseDeviceId;
|
|
1924
|
+
if (pending) {
|
|
1925
|
+
pending.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallQueueActionCancelled));
|
|
1926
|
+
if (this.runPromise === pending) {
|
|
1927
|
+
this.runPromise = null;
|
|
1928
|
+
this.runPromiseDeviceId = null;
|
|
1929
|
+
}
|
|
1930
|
+
if (deviceId)
|
|
1931
|
+
yield this.disconnect(deviceId);
|
|
1932
|
+
}
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
negotiateAndroidMtu(uuid, manager, device) {
|
|
1936
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1937
|
+
if (!shouldRefreshNegotiatedMtu(device.mtu))
|
|
1938
|
+
return device;
|
|
1939
|
+
const startedAt = Date.now();
|
|
1940
|
+
let timer;
|
|
1941
|
+
let timedOut = false;
|
|
1942
|
+
let negotiated = device;
|
|
1943
|
+
let failure;
|
|
1944
|
+
try {
|
|
1945
|
+
negotiated = yield Promise.race([
|
|
1946
|
+
device.requestMTU(ANDROID_REQUEST_MTU, `${device.id}:mtu:connected:0:${startedAt}`),
|
|
1947
|
+
new Promise((_, reject) => {
|
|
1948
|
+
timer = setTimeout(() => {
|
|
1949
|
+
timedOut = true;
|
|
1950
|
+
reject(new Error(`BLE MTU exchange timeout after ${ANDROID_MTU_EXCHANGE_TIMEOUT_MS}ms`));
|
|
1951
|
+
}, ANDROID_MTU_EXCHANGE_TIMEOUT_MS);
|
|
1952
|
+
}),
|
|
1953
|
+
]);
|
|
1954
|
+
}
|
|
1955
|
+
catch (error) {
|
|
1956
|
+
failure = error instanceof Error ? error.message : String(error);
|
|
1957
|
+
}
|
|
1958
|
+
finally {
|
|
1959
|
+
if (timer)
|
|
1960
|
+
clearTimeout(timer);
|
|
1961
|
+
}
|
|
1962
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] BLE MTU exchange ${failure ? 'failed' : 'completed'}`, {
|
|
1963
|
+
connectIdSuffix: uuid.slice(-8),
|
|
1964
|
+
elapsedMs: Date.now() - startedAt,
|
|
1965
|
+
timedOut,
|
|
1966
|
+
actual: negotiated.mtu,
|
|
1967
|
+
error: failure,
|
|
1968
|
+
});
|
|
1969
|
+
if (this.stopped)
|
|
1970
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1971
|
+
if (!timedOut && !isKnownDefaultMtu(negotiated.mtu))
|
|
1972
|
+
return negotiated;
|
|
1973
|
+
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'mtu-backstop' : 'mtu-default');
|
|
1974
|
+
yield this.dropAndroidLink(uuid, manager, negotiated, timedOut ? 'mtu exchange timeout' : 'default mtu');
|
|
1975
|
+
if (resetManager)
|
|
1976
|
+
throw this.createWedgedBleSetupError();
|
|
1977
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, timedOut
|
|
1978
|
+
? 'BLE MTU exchange did not complete, reconnecting on a fresh link'
|
|
1979
|
+
: `BLE link stayed at the default MTU ${negotiated.mtu}, reconnecting on a fresh link`);
|
|
1980
|
+
});
|
|
1981
|
+
}
|
|
1982
|
+
dropAndroidLink(uuid, manager, device, reason) {
|
|
1983
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1984
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1985
|
+
yield Promise.all([
|
|
1986
|
+
this.runBestEffortNativeOperation(`${reason}: cancel manager connection`, () => manager.cancelDeviceConnection(uuid)),
|
|
1987
|
+
this.runBestEffortNativeOperation(`${reason}: cancel device connection`, () => device.cancelConnection()),
|
|
1988
|
+
]);
|
|
1989
|
+
}));
|
|
1990
|
+
const startedAt = Date.now();
|
|
1991
|
+
while (!this.stopped && Date.now() - startedAt < ANDROID_LINK_DROP_QUIET_MS) {
|
|
1992
|
+
yield delay(ANDROID_LINK_DROP_POLL_MS);
|
|
1993
|
+
}
|
|
1994
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE link drop', {
|
|
1995
|
+
connectIdSuffix: uuid.slice(-8),
|
|
1996
|
+
reason,
|
|
1997
|
+
stopped: this.stopped,
|
|
1998
|
+
});
|
|
1999
|
+
});
|
|
1592
2000
|
}
|
|
1593
2001
|
connectWithTimeout(uuid, connect) {
|
|
1594
2002
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2003
|
+
if (this.stopped)
|
|
2004
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
2005
|
+
const startedAt = Date.now();
|
|
2006
|
+
let succeeded = false;
|
|
1595
2007
|
let timer;
|
|
1596
2008
|
let timedOut = false;
|
|
1597
2009
|
const pending = connect();
|
|
@@ -1606,6 +2018,7 @@ class ReactNativeBleTransport {
|
|
|
1606
2018
|
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1607
2019
|
}),
|
|
1608
2020
|
]);
|
|
2021
|
+
succeeded = true;
|
|
1609
2022
|
return result;
|
|
1610
2023
|
}
|
|
1611
2024
|
catch (error) {
|
|
@@ -1620,11 +2033,19 @@ class ReactNativeBleTransport {
|
|
|
1620
2033
|
finally {
|
|
1621
2034
|
if (timer)
|
|
1622
2035
|
clearTimeout(timer);
|
|
2036
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] connect completed', {
|
|
2037
|
+
connectIdSuffix: uuid.slice(-8),
|
|
2038
|
+
elapsedMs: Date.now() - startedAt,
|
|
2039
|
+
succeeded,
|
|
2040
|
+
backstopExpired: timedOut,
|
|
2041
|
+
});
|
|
1623
2042
|
}
|
|
1624
2043
|
});
|
|
1625
2044
|
}
|
|
1626
2045
|
resolveCharacteristicsWithTimeout(uuid, device) {
|
|
1627
2046
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2047
|
+
const startedAt = Date.now();
|
|
2048
|
+
let succeeded = false;
|
|
1628
2049
|
let timer;
|
|
1629
2050
|
let timedOut = false;
|
|
1630
2051
|
const pending = this.resolveCharacteristics(device);
|
|
@@ -1640,6 +2061,7 @@ class ReactNativeBleTransport {
|
|
|
1640
2061
|
}),
|
|
1641
2062
|
]);
|
|
1642
2063
|
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
2064
|
+
succeeded = true;
|
|
1643
2065
|
return result;
|
|
1644
2066
|
}
|
|
1645
2067
|
catch (error) {
|
|
@@ -1649,11 +2071,20 @@ class ReactNativeBleTransport {
|
|
|
1649
2071
|
throw this.createWedgedBleSetupError();
|
|
1650
2072
|
}
|
|
1651
2073
|
}
|
|
2074
|
+
if (reactNative.Platform.OS === 'android' && isMissingGattShapeError(error)) {
|
|
2075
|
+
this.androidGattCacheRefreshes.add(uuid);
|
|
2076
|
+
}
|
|
1652
2077
|
throw error;
|
|
1653
2078
|
}
|
|
1654
2079
|
finally {
|
|
1655
2080
|
if (timer)
|
|
1656
2081
|
clearTimeout(timer);
|
|
2082
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] GATT setup completed', {
|
|
2083
|
+
connectIdSuffix: uuid.slice(-8),
|
|
2084
|
+
elapsedMs: Date.now() - startedAt,
|
|
2085
|
+
succeeded,
|
|
2086
|
+
backstopExpired: timedOut,
|
|
2087
|
+
});
|
|
1657
2088
|
}
|
|
1658
2089
|
});
|
|
1659
2090
|
}
|
|
@@ -1674,6 +2105,7 @@ class ReactNativeBleTransport {
|
|
|
1674
2105
|
this.deviceProtocol.delete(uuid);
|
|
1675
2106
|
this.probingProtocols.delete(uuid);
|
|
1676
2107
|
this.staleBondErrors.delete(uuid);
|
|
2108
|
+
this.iosProbeDisconnectEvidence.delete(uuid);
|
|
1677
2109
|
this.acquiringProtocolV2.delete(uuid);
|
|
1678
2110
|
this.protocolV2Assemblers.delete(uuid);
|
|
1679
2111
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -1745,6 +2177,7 @@ class ReactNativeBleTransport {
|
|
|
1745
2177
|
this.deviceProtocol.delete(uuid);
|
|
1746
2178
|
this.probingProtocols.delete(uuid);
|
|
1747
2179
|
this.staleBondErrors.delete(uuid);
|
|
2180
|
+
this.iosProbeDisconnectEvidence.delete(uuid);
|
|
1748
2181
|
this.acquiringProtocolV2.delete(uuid);
|
|
1749
2182
|
this.protocolV2Assemblers.delete(uuid);
|
|
1750
2183
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -1755,6 +2188,8 @@ class ReactNativeBleTransport {
|
|
|
1755
2188
|
}
|
|
1756
2189
|
}
|
|
1757
2190
|
resetPlxManager() {
|
|
2191
|
+
if (bleManagerResetPromise)
|
|
2192
|
+
return;
|
|
1758
2193
|
const manager = this.blePlxManager;
|
|
1759
2194
|
this.blePlxManager = undefined;
|
|
1760
2195
|
const reason = 'React Native BLE manager reset';
|
|
@@ -1789,19 +2224,29 @@ class ReactNativeBleTransport {
|
|
|
1789
2224
|
this.deviceProtocol.clear();
|
|
1790
2225
|
this.probingProtocols.clear();
|
|
1791
2226
|
this.staleBondErrors.clear();
|
|
2227
|
+
this.iosProbeDisconnectEvidence.clear();
|
|
1792
2228
|
this.acquiringProtocolV2.clear();
|
|
1793
2229
|
this.sessionProtocols.clear();
|
|
1794
2230
|
this.protocolReprobeFailures.clear();
|
|
2231
|
+
this.silentDetections.clear();
|
|
1795
2232
|
this.writeTimeoutCounts.clear();
|
|
1796
2233
|
this.connectionSetupTimeoutCounts.clear();
|
|
1797
2234
|
this.monitorTokens.clear();
|
|
1798
2235
|
this.protocolV2Assemblers.clear();
|
|
2236
|
+
let reset;
|
|
1799
2237
|
try {
|
|
1800
|
-
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
2238
|
+
reset = Promise.resolve(manager === null || manager === void 0 ? void 0 : manager.destroy());
|
|
1801
2239
|
}
|
|
1802
2240
|
catch (error) {
|
|
1803
|
-
|
|
2241
|
+
reset = Promise.reject(error);
|
|
1804
2242
|
}
|
|
2243
|
+
bleManagerResetPromise = reset;
|
|
2244
|
+
reset.then(() => {
|
|
2245
|
+
if (bleManagerResetPromise === reset)
|
|
2246
|
+
bleManagerResetPromise = undefined;
|
|
2247
|
+
}, error => {
|
|
2248
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE manager destroy failed:', error);
|
|
2249
|
+
});
|
|
1805
2250
|
}
|
|
1806
2251
|
createProtocolMismatchError(expected) {
|
|
1807
2252
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
@@ -1809,6 +2254,35 @@ class ReactNativeBleTransport {
|
|
|
1809
2254
|
createProtocolDetectionError() {
|
|
1810
2255
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
1811
2256
|
}
|
|
2257
|
+
rememberIosProbeDisconnect(uuid, phase, error) {
|
|
2258
|
+
if (!isIosProbeDisconnectError(error))
|
|
2259
|
+
return undefined;
|
|
2260
|
+
const previous = this.iosProbeDisconnectEvidence.get(uuid);
|
|
2261
|
+
const errorCode = error === null || error === void 0 ? void 0 : error.errorCode;
|
|
2262
|
+
const evidence = Object.assign({ phase }, (typeof errorCode === 'string' || typeof errorCode === 'number' ? { errorCode } : {}));
|
|
2263
|
+
this.iosProbeDisconnectEvidence.set(uuid, evidence);
|
|
2264
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] probe disconnect recorded', {
|
|
2265
|
+
phase,
|
|
2266
|
+
errorCode: evidence.errorCode,
|
|
2267
|
+
repeated: Boolean(previous),
|
|
2268
|
+
});
|
|
2269
|
+
if (!previous)
|
|
2270
|
+
return undefined;
|
|
2271
|
+
return this.consumeIosProbeDisconnect(uuid, 'repeated-probe-disconnect');
|
|
2272
|
+
}
|
|
2273
|
+
consumeIosProbeDisconnect(uuid, confirmation) {
|
|
2274
|
+
const evidence = this.iosProbeDisconnectEvidence.get(uuid);
|
|
2275
|
+
if (!evidence)
|
|
2276
|
+
return undefined;
|
|
2277
|
+
this.iosProbeDisconnectEvidence.delete(uuid);
|
|
2278
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] stale bond confirmed', {
|
|
2279
|
+
confirmation,
|
|
2280
|
+
triggerPhase: evidence.phase,
|
|
2281
|
+
triggerErrorCode: evidence.errorCode,
|
|
2282
|
+
finalErrorCode: hdShared.HardwareErrorCode.BleBondInvalid,
|
|
2283
|
+
});
|
|
2284
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleBondInvalid);
|
|
2285
|
+
}
|
|
1812
2286
|
clearProbeProtocol(uuid, protocol) {
|
|
1813
2287
|
if (this.probingProtocols.get(uuid) === protocol) {
|
|
1814
2288
|
this.probingProtocols.delete(uuid);
|
|
@@ -1822,9 +2296,10 @@ class ReactNativeBleTransport {
|
|
|
1822
2296
|
return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
|
|
1823
2297
|
}
|
|
1824
2298
|
detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
|
|
1825
|
-
var _a;
|
|
2299
|
+
var _a, _b;
|
|
1826
2300
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1827
2301
|
if (expectedProtocol === 'V1') {
|
|
2302
|
+
this.iosProbeDisconnectEvidence.delete(uuid);
|
|
1828
2303
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1829
2304
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
|
|
1830
2305
|
deviceId: uuid,
|
|
@@ -1838,6 +2313,7 @@ class ReactNativeBleTransport {
|
|
|
1838
2313
|
}
|
|
1839
2314
|
if (expectedProtocol === 'V2') {
|
|
1840
2315
|
if (yield this.probeProtocolV2(uuid)) {
|
|
2316
|
+
this.iosProbeDisconnectEvidence.delete(uuid);
|
|
1841
2317
|
this.deviceProtocol.set(uuid, 'V2');
|
|
1842
2318
|
this.sessionProtocols.set(uuid, 'V2');
|
|
1843
2319
|
this.confirmedProtocolV2.add(uuid);
|
|
@@ -1848,6 +2324,19 @@ class ReactNativeBleTransport {
|
|
|
1848
2324
|
});
|
|
1849
2325
|
return 'V2';
|
|
1850
2326
|
}
|
|
2327
|
+
const staleBondError = this.consumeIosProbeDisconnect(uuid, 'follow-up-no-response');
|
|
2328
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
2329
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] protocol detection ended', {
|
|
2330
|
+
outcome: 'expected-v2-no-response',
|
|
2331
|
+
expectedProtocol,
|
|
2332
|
+
protocolHint: protocolHint !== null && protocolHint !== void 0 ? protocolHint : 'none',
|
|
2333
|
+
finalErrorCode: staleBondError
|
|
2334
|
+
? hdShared.HardwareErrorCode.BleBondInvalid
|
|
2335
|
+
: hdShared.HardwareErrorCode.RuntimeError,
|
|
2336
|
+
});
|
|
2337
|
+
}
|
|
2338
|
+
if (staleBondError)
|
|
2339
|
+
throw staleBondError;
|
|
1851
2340
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1852
2341
|
}
|
|
1853
2342
|
const sessionProtocol = this.sessionProtocols.get(uuid);
|
|
@@ -1857,6 +2346,7 @@ class ReactNativeBleTransport {
|
|
|
1857
2346
|
!protocolHint &&
|
|
1858
2347
|
reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1859
2348
|
const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
|
|
2349
|
+
yield this.wakeSilentProtocolV1Device(uuid, probeOrder);
|
|
1860
2350
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1861
2351
|
const protocol = probeOrder[i];
|
|
1862
2352
|
if (i > 0) {
|
|
@@ -1870,12 +2360,14 @@ class ReactNativeBleTransport {
|
|
|
1870
2360
|
}
|
|
1871
2361
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
|
|
1872
2362
|
if (detected) {
|
|
2363
|
+
this.iosProbeDisconnectEvidence.delete(uuid);
|
|
1873
2364
|
this.deviceProtocol.set(uuid, protocol);
|
|
1874
2365
|
this.sessionProtocols.set(uuid, protocol);
|
|
1875
2366
|
if (protocol === 'V2') {
|
|
1876
2367
|
this.confirmedProtocolV2.add(uuid);
|
|
1877
2368
|
}
|
|
1878
2369
|
this.protocolReprobeFailures.delete(uuid);
|
|
2370
|
+
this.silentDetections.delete(uuid);
|
|
1879
2371
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1880
2372
|
deviceId: uuid,
|
|
1881
2373
|
protocol,
|
|
@@ -1884,6 +2376,8 @@ class ReactNativeBleTransport {
|
|
|
1884
2376
|
return protocol;
|
|
1885
2377
|
}
|
|
1886
2378
|
}
|
|
2379
|
+
if (!this.silentDetections.has(uuid))
|
|
2380
|
+
this.silentDetections.set(uuid, 'silent');
|
|
1887
2381
|
if (trustSessionProtocol) {
|
|
1888
2382
|
this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
|
|
1889
2383
|
}
|
|
@@ -1892,9 +2386,53 @@ class ReactNativeBleTransport {
|
|
|
1892
2386
|
}
|
|
1893
2387
|
this.deviceProtocol.delete(uuid);
|
|
1894
2388
|
this.probingProtocols.delete(uuid);
|
|
2389
|
+
const staleBondError = this.consumeIosProbeDisconnect(uuid, 'follow-up-no-response');
|
|
2390
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
2391
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport][BleBondDiagnostic] protocol detection ended', {
|
|
2392
|
+
outcome: 'all-probes-no-response',
|
|
2393
|
+
expectedProtocol: expectedProtocol !== null && expectedProtocol !== void 0 ? expectedProtocol : 'none',
|
|
2394
|
+
protocolHint: protocolHint !== null && protocolHint !== void 0 ? protocolHint : 'none',
|
|
2395
|
+
sessionProtocol: sessionProtocol !== null && sessionProtocol !== void 0 ? sessionProtocol : 'none',
|
|
2396
|
+
probeOrder: probeOrder.join(','),
|
|
2397
|
+
trustSessionProtocol,
|
|
2398
|
+
reprobeFailures,
|
|
2399
|
+
transportCached: Boolean(transportCache[uuid]),
|
|
2400
|
+
notifyActive: Boolean((_b = transportCache[uuid]) === null || _b === void 0 ? void 0 : _b.notifySubscription),
|
|
2401
|
+
staleBondRecorded: this.staleBondErrors.has(uuid),
|
|
2402
|
+
finalErrorCode: staleBondError
|
|
2403
|
+
? hdShared.HardwareErrorCode.BleBondInvalid
|
|
2404
|
+
: hdShared.HardwareErrorCode.BleTimeoutError,
|
|
2405
|
+
});
|
|
2406
|
+
}
|
|
2407
|
+
if (staleBondError)
|
|
2408
|
+
throw staleBondError;
|
|
1895
2409
|
throw this.createProtocolDetectionError();
|
|
1896
2410
|
});
|
|
1897
2411
|
}
|
|
2412
|
+
wakeSilentProtocolV1Device(uuid, probeOrder) {
|
|
2413
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2414
|
+
if (reactNative.Platform.OS !== 'android' ||
|
|
2415
|
+
probeOrder[0] !== 'V1' ||
|
|
2416
|
+
this.silentDetections.get(uuid) !== 'silent') {
|
|
2417
|
+
return;
|
|
2418
|
+
}
|
|
2419
|
+
this.silentDetections.set(uuid, 'woken');
|
|
2420
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] sending Protocol V1 Initialize wake', {
|
|
2421
|
+
connectIdSuffix: uuid.slice(-8),
|
|
2422
|
+
});
|
|
2423
|
+
try {
|
|
2424
|
+
this.probingProtocols.set(uuid, 'V1');
|
|
2425
|
+
yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
2426
|
+
}
|
|
2427
|
+
catch (error) {
|
|
2428
|
+
if (shouldRethrowProtocolProbeError(error))
|
|
2429
|
+
throw error;
|
|
2430
|
+
}
|
|
2431
|
+
finally {
|
|
2432
|
+
this.clearProbeProtocol(uuid, 'V1');
|
|
2433
|
+
}
|
|
2434
|
+
});
|
|
2435
|
+
}
|
|
1898
2436
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1899
2437
|
var _a, _b, _c;
|
|
1900
2438
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1951,7 +2489,12 @@ class ReactNativeBleTransport {
|
|
|
1951
2489
|
catch (error) {
|
|
1952
2490
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1953
2491
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1954
|
-
|
|
2492
|
+
const shouldRethrow = shouldRethrowProtocolProbeError(error);
|
|
2493
|
+
const staleBondError = this.rememberIosProbeDisconnect(uuid, 'protocol-v1-get-features', error);
|
|
2494
|
+
logIosBleBondDiagnostic('protocol-v1-get-features', error, shouldRethrow ? 'rethrow' : 'fallback');
|
|
2495
|
+
if (staleBondError)
|
|
2496
|
+
throw staleBondError;
|
|
2497
|
+
if (shouldRethrow) {
|
|
1955
2498
|
throw error;
|
|
1956
2499
|
}
|
|
1957
2500
|
return false;
|
|
@@ -1967,18 +2510,28 @@ class ReactNativeBleTransport {
|
|
|
1967
2510
|
this.probingProtocols.set(uuid, 'V2');
|
|
1968
2511
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1969
2512
|
this.throwIfStaleBondError(uuid);
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
2513
|
+
let detected;
|
|
2514
|
+
try {
|
|
2515
|
+
detected = yield transport.probeProtocolV2({
|
|
2516
|
+
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
2517
|
+
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
|
|
2518
|
+
logger: Log,
|
|
2519
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
2520
|
+
onProbeFailed: () => {
|
|
2521
|
+
var _a;
|
|
2522
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
2523
|
+
this.resetProtocolV2Frames(uuid);
|
|
2524
|
+
},
|
|
2525
|
+
shouldRethrow: shouldRethrowProtocolProbeError,
|
|
2526
|
+
});
|
|
2527
|
+
}
|
|
2528
|
+
catch (error) {
|
|
2529
|
+
const staleBondError = this.rememberIosProbeDisconnect(uuid, 'protocol-v2-ping', error);
|
|
2530
|
+
logIosBleBondDiagnostic('protocol-v2-ping', error, 'rethrow');
|
|
2531
|
+
if (staleBondError)
|
|
2532
|
+
throw staleBondError;
|
|
2533
|
+
throw error;
|
|
2534
|
+
}
|
|
1982
2535
|
if (!detected) {
|
|
1983
2536
|
this.clearProbeProtocol(uuid, 'V2');
|
|
1984
2537
|
}
|
|
@@ -2104,6 +2657,9 @@ class ReactNativeBleTransport {
|
|
|
2104
2657
|
this.rememberStaleBondError(uuid, bondError);
|
|
2105
2658
|
throw bondError;
|
|
2106
2659
|
}
|
|
2660
|
+
if (isNativeBleDisconnectError(error)) {
|
|
2661
|
+
throw toBleDisconnectHardwareError(error);
|
|
2662
|
+
}
|
|
2107
2663
|
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
2108
2664
|
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
2109
2665
|
throw error;
|
|
@@ -2146,6 +2702,7 @@ class ReactNativeBleTransport {
|
|
|
2146
2702
|
if (!this._messages || !this._messagesV2) {
|
|
2147
2703
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
2148
2704
|
}
|
|
2705
|
+
const isProtocolProbe = this.probingProtocols.get(uuid) === 'V2';
|
|
2149
2706
|
const callOptions = options;
|
|
2150
2707
|
const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
|
|
2151
2708
|
if (highThroughputWrite) {
|
|
@@ -2186,6 +2743,14 @@ class ReactNativeBleTransport {
|
|
|
2186
2743
|
}
|
|
2187
2744
|
catch (e) {
|
|
2188
2745
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
2746
|
+
if (!isProtocolProbe &&
|
|
2747
|
+
(e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError &&
|
|
2748
|
+
!this.monitorTokens.has(uuid)) {
|
|
2749
|
+
yield this.runLifecycleOperation(uuid, () => __awaiter(this, void 0, void 0, function* () {
|
|
2750
|
+
if (!this.monitorTokens.has(uuid))
|
|
2751
|
+
yield this.disconnectUnlocked(uuid);
|
|
2752
|
+
}));
|
|
2753
|
+
}
|
|
2189
2754
|
throw e;
|
|
2190
2755
|
}
|
|
2191
2756
|
finally {
|
|
@@ -2200,7 +2765,7 @@ class ReactNativeBleTransport {
|
|
|
2200
2765
|
const transport = this.getCachedTransport(uuid);
|
|
2201
2766
|
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
2202
2767
|
return;
|
|
2203
|
-
const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1);
|
|
2768
|
+
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
2769
|
transport.device = refreshedDevice;
|
|
2205
2770
|
transport.mtuSize =
|
|
2206
2771
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
@@ -2317,6 +2882,8 @@ class ReactNativeBleTransport {
|
|
|
2317
2882
|
}
|
|
2318
2883
|
}
|
|
2319
2884
|
|
|
2885
|
+
exports.ANDROID_LINK_DROP_QUIET_MS = ANDROID_LINK_DROP_QUIET_MS;
|
|
2886
|
+
exports.ANDROID_MTU_EXCHANGE_TIMEOUT_MS = ANDROID_MTU_EXCHANGE_TIMEOUT_MS;
|
|
2320
2887
|
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2321
2888
|
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2322
2889
|
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|