@onekeyfe/hd-transport-react-native 1.2.2-alpha.12 → 1.2.2-alpha.122
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/bleStaleBond.d.ts.map +1 -1
- package/dist/index.d.ts +35 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +598 -127
- package/package.json +6 -6
- package/src/BleManager.ts +73 -5
- package/src/__tests__/bleNativeDisconnect.test.ts +33 -0
- package/src/__tests__/bleStaleBond.test.ts +8 -0
- package/src/__tests__/connectTimeout.test.ts +427 -3
- package/src/__tests__/protocolV2Link.test.ts +1075 -33
- package/src/__tests__/staleCallTimeout.test.ts +34 -5
- package/src/bleNativeDisconnect.ts +40 -0
- package/src/bleStaleBond.ts +3 -0
- package/src/index.ts +643 -134
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;
|
|
@@ -207,6 +265,8 @@ const isNativeBleStaleBondError = (error) => {
|
|
|
207
265
|
const nativeError = error;
|
|
208
266
|
if (nativeError.attErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
|
|
209
267
|
nativeError.attErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
|
|
268
|
+
nativeError.androidErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
|
|
269
|
+
nativeError.androidErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
|
|
210
270
|
nativeError.iosErrorCode === IOS_PEER_REMOVED_PAIRING_INFORMATION) {
|
|
211
271
|
return true;
|
|
212
272
|
}
|
|
@@ -256,6 +316,7 @@ class BleTransport {
|
|
|
256
316
|
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
257
317
|
const Log = bleLogger;
|
|
258
318
|
const transportCache = {};
|
|
319
|
+
let bleManagerResetPromise;
|
|
259
320
|
const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
|
|
260
321
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
261
322
|
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
|
|
@@ -314,6 +375,17 @@ const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
|
314
375
|
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
315
376
|
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
316
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
|
+
};
|
|
317
389
|
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
318
390
|
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
319
391
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
@@ -348,10 +420,10 @@ function getDeviceDisplayName(device) {
|
|
|
348
420
|
}
|
|
349
421
|
const IOS_REQUEST_MTU = 247;
|
|
350
422
|
const ANDROID_REQUEST_MTU = 517;
|
|
351
|
-
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
352
423
|
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
353
424
|
const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
354
425
|
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
426
|
+
const BLE_MTU_REQUEST_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS;
|
|
355
427
|
const connectOptions = {
|
|
356
428
|
requestMTU: getRequestedBleMtu(),
|
|
357
429
|
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
@@ -360,6 +432,29 @@ const connectOptions = {
|
|
|
360
432
|
const fallbackConnectOptions = {
|
|
361
433
|
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
362
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'));
|
|
363
458
|
const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
364
459
|
const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
365
460
|
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
@@ -374,6 +469,11 @@ const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? v
|
|
|
374
469
|
error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
375
470
|
const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
376
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
|
+
};
|
|
377
477
|
const tryToGetConfiguration = (device) => {
|
|
378
478
|
if (!device || !device.serviceUUIDs)
|
|
379
479
|
return null;
|
|
@@ -385,29 +485,69 @@ const tryToGetConfiguration = (device) => {
|
|
|
385
485
|
return null;
|
|
386
486
|
return infos;
|
|
387
487
|
};
|
|
388
|
-
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* () {
|
|
389
489
|
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
390
|
-
return device;
|
|
490
|
+
return { device, timedOut: false };
|
|
491
|
+
const transactionId = `${device.id}:mtu:${stage}:${attempt}:${Date.now()}`;
|
|
492
|
+
let timeoutId;
|
|
493
|
+
let timedOut = false;
|
|
391
494
|
try {
|
|
392
|
-
const
|
|
393
|
-
|
|
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 };
|
|
394
507
|
}
|
|
395
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
|
+
}
|
|
396
529
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
|
|
397
530
|
platform: reactNative.Platform.OS,
|
|
398
531
|
stage,
|
|
399
532
|
attempt,
|
|
400
533
|
actual: device.mtu,
|
|
534
|
+
timedOut,
|
|
401
535
|
error: error instanceof Error ? error.message : String(error),
|
|
402
536
|
});
|
|
403
|
-
return device;
|
|
537
|
+
return { device, timedOut };
|
|
538
|
+
}
|
|
539
|
+
finally {
|
|
540
|
+
if (timeoutId)
|
|
541
|
+
clearTimeout(timeoutId);
|
|
404
542
|
}
|
|
405
543
|
});
|
|
406
|
-
const resolveNegotiatedMtu = (device) =>
|
|
407
|
-
|
|
544
|
+
const resolveNegotiatedMtu = (device, cancelTransaction) => shouldRefreshNegotiatedMtu(device.mtu)
|
|
545
|
+
? requestNegotiatedMtu(device, 'connected', 0, cancelTransaction)
|
|
546
|
+
: Promise.resolve({ device, timedOut: false });
|
|
547
|
+
function remapError(error) {
|
|
408
548
|
var _a;
|
|
409
549
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
410
|
-
if (
|
|
550
|
+
if (isNativeBleStaleBondError(error)) {
|
|
411
551
|
throw toBleStaleBondHardwareError(error);
|
|
412
552
|
}
|
|
413
553
|
if ((error === null || error === void 0 ? void 0 : error.attErrorCode) === 22) {
|
|
@@ -427,6 +567,7 @@ class ReactNativeBleTransport {
|
|
|
427
567
|
this.name = 'ReactNativeBleTransport';
|
|
428
568
|
this.configured = false;
|
|
429
569
|
this.stopped = false;
|
|
570
|
+
this.bondAbortController = new AbortController();
|
|
430
571
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
431
572
|
this.runPromise = null;
|
|
432
573
|
this.runPromiseDeviceId = null;
|
|
@@ -439,6 +580,8 @@ class ReactNativeBleTransport {
|
|
|
439
580
|
this.sessionProtocols = new Map();
|
|
440
581
|
this.confirmedProtocolV2 = new Set();
|
|
441
582
|
this.protocolReprobeFailures = new Map();
|
|
583
|
+
this.silentDetections = new Map();
|
|
584
|
+
this.androidGattCacheRefreshes = new Set();
|
|
442
585
|
this.staleBondErrors = new Map();
|
|
443
586
|
this.acquiringProtocolV2 = new Set();
|
|
444
587
|
this.protocolV2Assemblers = new Map();
|
|
@@ -456,11 +599,20 @@ class ReactNativeBleTransport {
|
|
|
456
599
|
},
|
|
457
600
|
classifyError: () => 'link-fatal',
|
|
458
601
|
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
459
|
-
var _b;
|
|
602
|
+
var _b, _c;
|
|
460
603
|
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
461
604
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
462
605
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
463
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
|
+
}
|
|
464
616
|
yield this.releaseNative(uuid, true);
|
|
465
617
|
}
|
|
466
618
|
}),
|
|
@@ -472,6 +624,7 @@ class ReactNativeBleTransport {
|
|
|
472
624
|
this.androidPriorityResetTimers = new Map();
|
|
473
625
|
this.nextMonitorToken = 1;
|
|
474
626
|
this.lifecycleOperations = new Map();
|
|
627
|
+
this.scanCleanups = new Set();
|
|
475
628
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
476
629
|
}
|
|
477
630
|
init(logger, emitter) {
|
|
@@ -500,10 +653,38 @@ class ReactNativeBleTransport {
|
|
|
500
653
|
listen() {
|
|
501
654
|
}
|
|
502
655
|
getPlxManager() {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
+
});
|
|
507
688
|
}
|
|
508
689
|
resolveCharacteristics(device) {
|
|
509
690
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -668,30 +849,55 @@ class ReactNativeBleTransport {
|
|
|
668
849
|
}
|
|
669
850
|
enumerate() {
|
|
670
851
|
return __awaiter(this, void 0, void 0, function* () {
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
if (reactNative.
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT,
|
|
686
|
-
reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN,
|
|
687
|
-
]);
|
|
688
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('requesting permissions, result: ', resultConnect);
|
|
689
|
-
if (resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_CONNECT] !== 'granted' ||
|
|
690
|
-
resultConnect[reactNative.PermissionsAndroid.PERMISSIONS.BLUETOOTH_SCAN] !== 'granted') {
|
|
691
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
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);
|
|
694
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);
|
|
695
901
|
blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
|
|
696
902
|
allowDuplicates: true,
|
|
697
903
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
@@ -700,19 +906,17 @@ class ReactNativeBleTransport {
|
|
|
700
906
|
if (error) {
|
|
701
907
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
702
908
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
703
|
-
|
|
909
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
704
910
|
}
|
|
705
911
|
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.BluetoothUnauthorized) {
|
|
706
|
-
|
|
912
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationError));
|
|
707
913
|
}
|
|
708
914
|
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.LocationServicesDisabled) {
|
|
709
|
-
|
|
710
|
-
}
|
|
711
|
-
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) {
|
|
712
|
-
timer.timeout(() => { }, this.scanTimeout);
|
|
915
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleLocationServicesDisabled));
|
|
713
916
|
}
|
|
917
|
+
else if (error.errorCode === reactNativeBlePlx.BleErrorCode.ScanStartFailed) ;
|
|
714
918
|
else {
|
|
715
|
-
|
|
919
|
+
finishScan(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleScanError, (_a = error.reason) !== null && _a !== void 0 ? _a : ''));
|
|
716
920
|
}
|
|
717
921
|
return;
|
|
718
922
|
}
|
|
@@ -737,6 +941,8 @@ class ReactNativeBleTransport {
|
|
|
737
941
|
});
|
|
738
942
|
}
|
|
739
943
|
});
|
|
944
|
+
if (finished)
|
|
945
|
+
return;
|
|
740
946
|
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
741
947
|
for (const device of devices) {
|
|
742
948
|
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
@@ -752,10 +958,11 @@ class ReactNativeBleTransport {
|
|
|
752
958
|
addDevice(device);
|
|
753
959
|
}
|
|
754
960
|
}
|
|
755
|
-
});
|
|
961
|
+
}, error => Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral failed:', error));
|
|
756
962
|
const addDevice = (device) => {
|
|
757
963
|
var _a;
|
|
758
|
-
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);
|
|
759
966
|
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
760
967
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
761
968
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
@@ -765,16 +972,14 @@ class ReactNativeBleTransport {
|
|
|
765
972
|
});
|
|
766
973
|
}
|
|
767
974
|
};
|
|
768
|
-
|
|
769
|
-
blePlxManager.stopDeviceScan();
|
|
770
|
-
resolve(deviceList);
|
|
771
|
-
}, this.scanTimeout);
|
|
772
|
-
}));
|
|
975
|
+
});
|
|
773
976
|
});
|
|
774
977
|
}
|
|
775
978
|
installTransportForAcquire(uuid, device, characteristics) {
|
|
776
979
|
return __awaiter(this, void 0, void 0, function* () {
|
|
777
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);
|
|
778
983
|
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
779
984
|
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
|
|
780
985
|
const monitorToken = this.nextMonitorToken;
|
|
@@ -795,30 +1000,12 @@ class ReactNativeBleTransport {
|
|
|
795
1000
|
else if (reactNative.Platform.OS === 'android') {
|
|
796
1001
|
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
797
1002
|
}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
|
|
801
|
-
shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
802
|
-
refreshAttempts += 1;
|
|
803
|
-
let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
|
|
804
|
-
transport$1.device = refreshedDevice;
|
|
805
|
-
transport$1.mtuSize =
|
|
806
|
-
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
807
|
-
if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
808
|
-
yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
809
|
-
refreshAttempts += 1;
|
|
810
|
-
refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
|
|
811
|
-
transport$1.device = refreshedDevice;
|
|
812
|
-
transport$1.mtuSize =
|
|
813
|
-
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
814
|
-
}
|
|
815
|
-
}
|
|
1003
|
+
if (this.stopped)
|
|
1004
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
816
1005
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
817
1006
|
platform: reactNative.Platform.OS,
|
|
818
1007
|
requested: getRequestedBleMtu(),
|
|
819
|
-
initial: initialMtu,
|
|
820
1008
|
actual: transport$1.mtuSize,
|
|
821
|
-
refreshAttempts,
|
|
822
1009
|
});
|
|
823
1010
|
return transport$1;
|
|
824
1011
|
});
|
|
@@ -835,6 +1022,8 @@ class ReactNativeBleTransport {
|
|
|
835
1022
|
acquireUnlocked(input) {
|
|
836
1023
|
var _a;
|
|
837
1024
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1025
|
+
if (this.stopped)
|
|
1026
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
838
1027
|
const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
|
|
839
1028
|
const shouldMapProtocolV2StaleBond = expectedProtocol
|
|
840
1029
|
? expectedProtocol === 'V2'
|
|
@@ -866,9 +1055,13 @@ class ReactNativeBleTransport {
|
|
|
866
1055
|
const isCachedDeviceConnected = yield cachedTransport.device
|
|
867
1056
|
.isConnected()
|
|
868
1057
|
.catch(() => false);
|
|
1058
|
+
const isCachedAndroidLinkUsable = reactNative.Platform.OS !== 'android' || !this.androidGattCacheRefreshes.has(uuid);
|
|
869
1059
|
if (isCachedDeviceConnected &&
|
|
1060
|
+
isCachedAndroidLinkUsable &&
|
|
870
1061
|
cachedProtocol &&
|
|
871
1062
|
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
1063
|
+
if (this.stopped)
|
|
1064
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
872
1065
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
873
1066
|
return { uuid, protocolType: cachedProtocol };
|
|
874
1067
|
}
|
|
@@ -877,6 +1070,15 @@ class ReactNativeBleTransport {
|
|
|
877
1070
|
}
|
|
878
1071
|
}
|
|
879
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;
|
|
880
1082
|
if (forceCleanRunPromise && this.runPromise) {
|
|
881
1083
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
882
1084
|
this.runPromise.reject(error);
|
|
@@ -885,6 +1087,7 @@ class ReactNativeBleTransport {
|
|
|
885
1087
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
886
1088
|
}
|
|
887
1089
|
const blePlxManager = yield this.getPlxManager();
|
|
1090
|
+
let skipPostConnectMtu = false;
|
|
888
1091
|
try {
|
|
889
1092
|
yield subscribeBleOn(blePlxManager);
|
|
890
1093
|
}
|
|
@@ -892,15 +1095,27 @@ class ReactNativeBleTransport {
|
|
|
892
1095
|
Log === null || Log === void 0 ? void 0 : Log.debug('subscribeBleOn error: ', error);
|
|
893
1096
|
throw error;
|
|
894
1097
|
}
|
|
1098
|
+
if (this.stopped)
|
|
1099
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
895
1100
|
if (reactNative.Platform.OS === 'android') {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
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
|
+
}
|
|
899
1109
|
}
|
|
900
|
-
|
|
901
|
-
|
|
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;
|
|
902
1115
|
}
|
|
903
1116
|
}
|
|
1117
|
+
if (this.stopped)
|
|
1118
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
904
1119
|
if (!device) {
|
|
905
1120
|
const devices = yield blePlxManager.devices([uuid]);
|
|
906
1121
|
[device] = devices;
|
|
@@ -914,15 +1129,16 @@ class ReactNativeBleTransport {
|
|
|
914
1129
|
if (!device) {
|
|
915
1130
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
|
|
916
1131
|
try {
|
|
917
|
-
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid,
|
|
1132
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, nativeConnectOptions));
|
|
1133
|
+
androidRefreshConnectRan = refreshAndroidGattCache;
|
|
918
1134
|
}
|
|
919
1135
|
catch (e) {
|
|
920
1136
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
921
1137
|
if (shouldRethrowBleSetupError(e)) {
|
|
922
1138
|
throw e;
|
|
923
1139
|
}
|
|
924
|
-
if (e
|
|
925
|
-
|
|
1140
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1141
|
+
skipPostConnectMtu = true;
|
|
926
1142
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
927
1143
|
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
928
1144
|
}
|
|
@@ -931,47 +1147,119 @@ class ReactNativeBleTransport {
|
|
|
931
1147
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleAlreadyConnected);
|
|
932
1148
|
}
|
|
933
1149
|
else {
|
|
934
|
-
remapError(e
|
|
1150
|
+
remapError(e);
|
|
935
1151
|
}
|
|
936
1152
|
}
|
|
937
1153
|
}
|
|
938
1154
|
if (!device) {
|
|
939
1155
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, 'unable to connect to device');
|
|
940
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
|
+
}
|
|
941
1164
|
if (!(yield device.isConnected())) {
|
|
942
1165
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
943
1166
|
const disconnectedDevice = device;
|
|
944
1167
|
try {
|
|
945
|
-
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(
|
|
1168
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(nativeConnectOptions));
|
|
1169
|
+
androidRefreshConnectRan = refreshAndroidGattCache;
|
|
946
1170
|
}
|
|
947
1171
|
catch (e) {
|
|
948
1172
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
949
1173
|
if (shouldRethrowBleSetupError(e)) {
|
|
950
1174
|
throw e;
|
|
951
1175
|
}
|
|
952
|
-
if (e
|
|
953
|
-
|
|
1176
|
+
if (isMtuOrCancelledConnectError(e)) {
|
|
1177
|
+
skipPostConnectMtu = true;
|
|
954
1178
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
955
1179
|
try {
|
|
956
1180
|
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
957
1181
|
}
|
|
958
|
-
catch (
|
|
959
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ',
|
|
960
|
-
if (
|
|
1182
|
+
catch (fallbackError) {
|
|
1183
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', fallbackError);
|
|
1184
|
+
if (fallbackError.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
961
1185
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
962
1186
|
yield disconnectedDevice.cancelConnection();
|
|
963
1187
|
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
964
1188
|
}
|
|
1189
|
+
else {
|
|
1190
|
+
remapError(fallbackError);
|
|
1191
|
+
}
|
|
965
1192
|
}
|
|
966
1193
|
}
|
|
967
1194
|
else {
|
|
968
|
-
remapError(e
|
|
1195
|
+
remapError(e);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
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');
|
|
1241
|
+
}
|
|
1242
|
+
try {
|
|
1243
|
+
device = yield this.connectWithTimeout(uuid, () => timedOutDevice.connect(fallbackConnectOptions));
|
|
1244
|
+
}
|
|
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
|
+
}
|
|
969
1254
|
}
|
|
970
1255
|
}
|
|
971
1256
|
}
|
|
972
|
-
|
|
1257
|
+
if (this.stopped)
|
|
1258
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
973
1259
|
const acquiredDevice = device;
|
|
974
|
-
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);
|
|
975
1263
|
const protocolHint = expectedProtocol
|
|
976
1264
|
? undefined
|
|
977
1265
|
: (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
|
|
@@ -1014,6 +1302,8 @@ class ReactNativeBleTransport {
|
|
|
1014
1302
|
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
1015
1303
|
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
1016
1304
|
}));
|
|
1305
|
+
if (this.stopped)
|
|
1306
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected);
|
|
1017
1307
|
const currentTransport = transportCache[uuid];
|
|
1018
1308
|
if (!currentTransport) {
|
|
1019
1309
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
@@ -1022,12 +1312,7 @@ class ReactNativeBleTransport {
|
|
|
1022
1312
|
return { uuid, protocolType };
|
|
1023
1313
|
}
|
|
1024
1314
|
catch (error) {
|
|
1025
|
-
|
|
1026
|
-
yield this.disconnectUnlocked(uuid);
|
|
1027
|
-
}
|
|
1028
|
-
else {
|
|
1029
|
-
yield this.releaseUnlocked(uuid, true);
|
|
1030
|
-
}
|
|
1315
|
+
yield this.disconnectUnlocked(uuid);
|
|
1031
1316
|
throw error;
|
|
1032
1317
|
}
|
|
1033
1318
|
finally {
|
|
@@ -1039,7 +1324,7 @@ class ReactNativeBleTransport {
|
|
|
1039
1324
|
let bufferLength = 0;
|
|
1040
1325
|
let buffer$1 = [];
|
|
1041
1326
|
const subscription = characteristic.monitor((error, c) => {
|
|
1042
|
-
var _a, _b, _c, _d, _e, _f
|
|
1327
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1043
1328
|
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
1044
1329
|
if (error) {
|
|
1045
1330
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
@@ -1056,16 +1341,16 @@ class ReactNativeBleTransport {
|
|
|
1056
1341
|
this.rememberStaleBondError(uuid, toBleStaleBondHardwareError(error));
|
|
1057
1342
|
return;
|
|
1058
1343
|
}
|
|
1344
|
+
if (reactNative.Platform.OS === 'android' && isStaleGattTableNotifyReason(error.reason)) {
|
|
1345
|
+
this.androidGattCacheRefreshes.add(uuid);
|
|
1346
|
+
}
|
|
1059
1347
|
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
1060
1348
|
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
1061
1349
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
1062
1350
|
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
1063
1351
|
}
|
|
1064
|
-
else if ((
|
|
1065
|
-
((
|
|
1066
|
-
((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('The handle is invalid')) ||
|
|
1067
|
-
((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('Writing is not permitted')) ||
|
|
1068
|
-
((_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'))) {
|
|
1069
1354
|
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
1070
1355
|
}
|
|
1071
1356
|
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
@@ -1073,14 +1358,11 @@ class ReactNativeBleTransport {
|
|
|
1073
1358
|
}
|
|
1074
1359
|
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
1075
1360
|
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
1076
|
-
if ((
|
|
1361
|
+
if ((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('The connection has timed out unexpectedly')) {
|
|
1077
1362
|
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
1078
1363
|
}
|
|
1079
|
-
if ((
|
|
1080
|
-
((
|
|
1081
|
-
((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('The handle is invalid')) ||
|
|
1082
|
-
((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Writing is not permitted')) ||
|
|
1083
|
-
((_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'))) {
|
|
1084
1366
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
1085
1367
|
this.runPromise.reject(notifyError);
|
|
1086
1368
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
@@ -1122,7 +1404,7 @@ class ReactNativeBleTransport {
|
|
|
1122
1404
|
bufferLength = 0;
|
|
1123
1405
|
buffer$1 = [];
|
|
1124
1406
|
if (this.runPromiseDeviceId === uuid) {
|
|
1125
|
-
(
|
|
1407
|
+
(_e = this.runPromise) === null || _e === void 0 ? void 0 : _e.resolve(value.toString('hex'));
|
|
1126
1408
|
}
|
|
1127
1409
|
}
|
|
1128
1410
|
}
|
|
@@ -1133,7 +1415,7 @@ class ReactNativeBleTransport {
|
|
|
1133
1415
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1134
1416
|
}
|
|
1135
1417
|
else if (this.runPromiseDeviceId === uuid) {
|
|
1136
|
-
(
|
|
1418
|
+
(_f = this.runPromise) === null || _f === void 0 ? void 0 : _f.reject(notifyError);
|
|
1137
1419
|
}
|
|
1138
1420
|
}
|
|
1139
1421
|
}, notifyTransactionId);
|
|
@@ -1409,13 +1691,14 @@ class ReactNativeBleTransport {
|
|
|
1409
1691
|
return check.call(jsonData);
|
|
1410
1692
|
}
|
|
1411
1693
|
catch (e) {
|
|
1412
|
-
|
|
1413
|
-
|
|
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);
|
|
1414
1698
|
}
|
|
1415
1699
|
else {
|
|
1416
1700
|
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1417
1701
|
}
|
|
1418
|
-
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1419
1702
|
const isStaleCall = this.runPromise !== runPromise;
|
|
1420
1703
|
if (!isProbeTimeout &&
|
|
1421
1704
|
!isStaleCall &&
|
|
@@ -1435,7 +1718,43 @@ class ReactNativeBleTransport {
|
|
|
1435
1718
|
});
|
|
1436
1719
|
}
|
|
1437
1720
|
stop() {
|
|
1721
|
+
var _a;
|
|
1722
|
+
if (this.stopPromise)
|
|
1723
|
+
return this.stopPromise;
|
|
1438
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;
|
|
1439
1758
|
}
|
|
1440
1759
|
disconnect(session) {
|
|
1441
1760
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1565,13 +1884,93 @@ class ReactNativeBleTransport {
|
|
|
1565
1884
|
});
|
|
1566
1885
|
}
|
|
1567
1886
|
cancel() {
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
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
|
+
});
|
|
1572
1967
|
}
|
|
1573
1968
|
connectWithTimeout(uuid, connect) {
|
|
1574
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;
|
|
1575
1974
|
let timer;
|
|
1576
1975
|
let timedOut = false;
|
|
1577
1976
|
const pending = connect();
|
|
@@ -1586,6 +1985,7 @@ class ReactNativeBleTransport {
|
|
|
1586
1985
|
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1587
1986
|
}),
|
|
1588
1987
|
]);
|
|
1988
|
+
succeeded = true;
|
|
1589
1989
|
return result;
|
|
1590
1990
|
}
|
|
1591
1991
|
catch (error) {
|
|
@@ -1600,11 +2000,19 @@ class ReactNativeBleTransport {
|
|
|
1600
2000
|
finally {
|
|
1601
2001
|
if (timer)
|
|
1602
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
|
+
});
|
|
1603
2009
|
}
|
|
1604
2010
|
});
|
|
1605
2011
|
}
|
|
1606
2012
|
resolveCharacteristicsWithTimeout(uuid, device) {
|
|
1607
2013
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2014
|
+
const startedAt = Date.now();
|
|
2015
|
+
let succeeded = false;
|
|
1608
2016
|
let timer;
|
|
1609
2017
|
let timedOut = false;
|
|
1610
2018
|
const pending = this.resolveCharacteristics(device);
|
|
@@ -1620,6 +2028,7 @@ class ReactNativeBleTransport {
|
|
|
1620
2028
|
}),
|
|
1621
2029
|
]);
|
|
1622
2030
|
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
2031
|
+
succeeded = true;
|
|
1623
2032
|
return result;
|
|
1624
2033
|
}
|
|
1625
2034
|
catch (error) {
|
|
@@ -1629,11 +2038,20 @@ class ReactNativeBleTransport {
|
|
|
1629
2038
|
throw this.createWedgedBleSetupError();
|
|
1630
2039
|
}
|
|
1631
2040
|
}
|
|
2041
|
+
if (reactNative.Platform.OS === 'android' && isMissingGattShapeError(error)) {
|
|
2042
|
+
this.androidGattCacheRefreshes.add(uuid);
|
|
2043
|
+
}
|
|
1632
2044
|
throw error;
|
|
1633
2045
|
}
|
|
1634
2046
|
finally {
|
|
1635
2047
|
if (timer)
|
|
1636
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
|
+
});
|
|
1637
2055
|
}
|
|
1638
2056
|
});
|
|
1639
2057
|
}
|
|
@@ -1735,6 +2153,8 @@ class ReactNativeBleTransport {
|
|
|
1735
2153
|
}
|
|
1736
2154
|
}
|
|
1737
2155
|
resetPlxManager() {
|
|
2156
|
+
if (bleManagerResetPromise)
|
|
2157
|
+
return;
|
|
1738
2158
|
const manager = this.blePlxManager;
|
|
1739
2159
|
this.blePlxManager = undefined;
|
|
1740
2160
|
const reason = 'React Native BLE manager reset';
|
|
@@ -1772,16 +2192,25 @@ class ReactNativeBleTransport {
|
|
|
1772
2192
|
this.acquiringProtocolV2.clear();
|
|
1773
2193
|
this.sessionProtocols.clear();
|
|
1774
2194
|
this.protocolReprobeFailures.clear();
|
|
2195
|
+
this.silentDetections.clear();
|
|
1775
2196
|
this.writeTimeoutCounts.clear();
|
|
1776
2197
|
this.connectionSetupTimeoutCounts.clear();
|
|
1777
2198
|
this.monitorTokens.clear();
|
|
1778
2199
|
this.protocolV2Assemblers.clear();
|
|
2200
|
+
let reset;
|
|
1779
2201
|
try {
|
|
1780
|
-
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
2202
|
+
reset = Promise.resolve(manager === null || manager === void 0 ? void 0 : manager.destroy());
|
|
1781
2203
|
}
|
|
1782
2204
|
catch (error) {
|
|
1783
|
-
|
|
2205
|
+
reset = Promise.reject(error);
|
|
1784
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
|
+
});
|
|
1785
2214
|
}
|
|
1786
2215
|
createProtocolMismatchError(expected) {
|
|
1787
2216
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
@@ -1837,6 +2266,7 @@ class ReactNativeBleTransport {
|
|
|
1837
2266
|
!protocolHint &&
|
|
1838
2267
|
reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1839
2268
|
const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
|
|
2269
|
+
yield this.wakeSilentProtocolV1Device(uuid, probeOrder);
|
|
1840
2270
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1841
2271
|
const protocol = probeOrder[i];
|
|
1842
2272
|
if (i > 0) {
|
|
@@ -1856,6 +2286,7 @@ class ReactNativeBleTransport {
|
|
|
1856
2286
|
this.confirmedProtocolV2.add(uuid);
|
|
1857
2287
|
}
|
|
1858
2288
|
this.protocolReprobeFailures.delete(uuid);
|
|
2289
|
+
this.silentDetections.delete(uuid);
|
|
1859
2290
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1860
2291
|
deviceId: uuid,
|
|
1861
2292
|
protocol,
|
|
@@ -1864,6 +2295,8 @@ class ReactNativeBleTransport {
|
|
|
1864
2295
|
return protocol;
|
|
1865
2296
|
}
|
|
1866
2297
|
}
|
|
2298
|
+
if (!this.silentDetections.has(uuid))
|
|
2299
|
+
this.silentDetections.set(uuid, 'silent');
|
|
1867
2300
|
if (trustSessionProtocol) {
|
|
1868
2301
|
this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
|
|
1869
2302
|
}
|
|
@@ -1875,6 +2308,30 @@ class ReactNativeBleTransport {
|
|
|
1875
2308
|
throw this.createProtocolDetectionError();
|
|
1876
2309
|
});
|
|
1877
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
|
+
}
|
|
1878
2335
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1879
2336
|
var _a, _b, _c;
|
|
1880
2337
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1931,7 +2388,7 @@ class ReactNativeBleTransport {
|
|
|
1931
2388
|
catch (error) {
|
|
1932
2389
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1933
2390
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1934
|
-
if (
|
|
2391
|
+
if (shouldRethrowProtocolProbeError(error)) {
|
|
1935
2392
|
throw error;
|
|
1936
2393
|
}
|
|
1937
2394
|
return false;
|
|
@@ -1957,7 +2414,7 @@ class ReactNativeBleTransport {
|
|
|
1957
2414
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1958
2415
|
this.resetProtocolV2Frames(uuid);
|
|
1959
2416
|
},
|
|
1960
|
-
shouldRethrow:
|
|
2417
|
+
shouldRethrow: shouldRethrowProtocolProbeError,
|
|
1961
2418
|
});
|
|
1962
2419
|
if (!detected) {
|
|
1963
2420
|
this.clearProbeProtocol(uuid, 'V2');
|
|
@@ -2084,6 +2541,9 @@ class ReactNativeBleTransport {
|
|
|
2084
2541
|
this.rememberStaleBondError(uuid, bondError);
|
|
2085
2542
|
throw bondError;
|
|
2086
2543
|
}
|
|
2544
|
+
if (isNativeBleDisconnectError(error)) {
|
|
2545
|
+
throw toBleDisconnectHardwareError(error);
|
|
2546
|
+
}
|
|
2087
2547
|
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
2088
2548
|
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
2089
2549
|
throw error;
|
|
@@ -2126,6 +2586,7 @@ class ReactNativeBleTransport {
|
|
|
2126
2586
|
if (!this._messages || !this._messagesV2) {
|
|
2127
2587
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
2128
2588
|
}
|
|
2589
|
+
const isProtocolProbe = this.probingProtocols.get(uuid) === 'V2';
|
|
2129
2590
|
const callOptions = options;
|
|
2130
2591
|
const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
|
|
2131
2592
|
if (highThroughputWrite) {
|
|
@@ -2166,6 +2627,14 @@ class ReactNativeBleTransport {
|
|
|
2166
2627
|
}
|
|
2167
2628
|
catch (e) {
|
|
2168
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
|
+
}
|
|
2169
2638
|
throw e;
|
|
2170
2639
|
}
|
|
2171
2640
|
finally {
|
|
@@ -2180,7 +2649,7 @@ class ReactNativeBleTransport {
|
|
|
2180
2649
|
const transport = this.getCachedTransport(uuid);
|
|
2181
2650
|
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
2182
2651
|
return;
|
|
2183
|
-
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); });
|
|
2184
2653
|
transport.device = refreshedDevice;
|
|
2185
2654
|
transport.mtuSize =
|
|
2186
2655
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
@@ -2297,6 +2766,8 @@ class ReactNativeBleTransport {
|
|
|
2297
2766
|
}
|
|
2298
2767
|
}
|
|
2299
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;
|
|
2300
2771
|
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2301
2772
|
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2302
2773
|
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|