@onekeyfe/hd-transport-react-native 1.2.0-alpha.99 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bleStaleBond.d.ts +5 -0
- package/dist/bleStaleBond.d.ts.map +1 -0
- package/dist/index.d.ts +34 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +354 -132
- package/package.json +5 -5
- package/src/__tests__/bleStaleBond.test.ts +39 -0
- package/src/__tests__/connectTimeout.test.ts +19 -8
- package/src/__tests__/enumerate.test.ts +30 -12
- package/src/__tests__/protocolReprobe.test.ts +24 -0
- package/src/__tests__/protocolV2Link.test.ts +291 -10
- package/src/bleStaleBond.ts +61 -0
- package/src/index.ts +418 -136
package/dist/index.js
CHANGED
|
@@ -194,6 +194,38 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
|
|
|
194
194
|
}, ms);
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
+
const ATT_INSUFFICIENT_AUTHENTICATION = 5;
|
|
198
|
+
const ATT_INSUFFICIENT_ENCRYPTION = 15;
|
|
199
|
+
const IOS_PEER_REMOVED_PAIRING_INFORMATION = 14;
|
|
200
|
+
const nativeErrorText = (error) => [error.reason, error.message]
|
|
201
|
+
.filter((value) => typeof value === 'string')
|
|
202
|
+
.join(' ');
|
|
203
|
+
const isNativeBleStaleBondError = (error) => {
|
|
204
|
+
if (!error || typeof error !== 'object') {
|
|
205
|
+
return typeof error === 'string' ? hdShared.isBleStaleBondErrorText(error) : false;
|
|
206
|
+
}
|
|
207
|
+
const nativeError = error;
|
|
208
|
+
if (nativeError.attErrorCode === ATT_INSUFFICIENT_AUTHENTICATION ||
|
|
209
|
+
nativeError.attErrorCode === ATT_INSUFFICIENT_ENCRYPTION ||
|
|
210
|
+
nativeError.iosErrorCode === IOS_PEER_REMOVED_PAIRING_INFORMATION) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
return hdShared.isBleStaleBondErrorText(nativeErrorText(nativeError));
|
|
214
|
+
};
|
|
215
|
+
const toBleStaleBondHardwareError = (error) => {
|
|
216
|
+
if (hdShared.isBleStaleBondHardwareError(error)) {
|
|
217
|
+
return error;
|
|
218
|
+
}
|
|
219
|
+
const nativeError = (error !== null && error !== void 0 ? error : {});
|
|
220
|
+
const text = nativeErrorText(nativeError);
|
|
221
|
+
const normalizedText = text.toLowerCase();
|
|
222
|
+
const peerRemoved = nativeError.iosErrorCode === IOS_PEER_REMOVED_PAIRING_INFORMATION ||
|
|
223
|
+
normalizedText.includes('peer removed pairing information');
|
|
224
|
+
return hdShared.ERRORS.TypedError(peerRemoved
|
|
225
|
+
? hdShared.HardwareErrorCode.BlePeerRemovedPairingInformation
|
|
226
|
+
: hdShared.HardwareErrorCode.BleDeviceBondError, text || undefined);
|
|
227
|
+
};
|
|
228
|
+
|
|
197
229
|
const isHeaderChunk = (chunk) => {
|
|
198
230
|
if (chunk.length < 9)
|
|
199
231
|
return false;
|
|
@@ -274,9 +306,10 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
274
306
|
return text.includes('GATT_CONGESTED') || hasGattCongestedStatus(text) ? 'congested' : null;
|
|
275
307
|
};
|
|
276
308
|
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
277
|
-
const PROTOCOL_PROBE_TIMEOUT_MS =
|
|
309
|
+
const PROTOCOL_PROBE_TIMEOUT_MS = 3000;
|
|
278
310
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
279
311
|
const BLE_WRITE_PACKET_TIMEOUT_MS = 10000;
|
|
312
|
+
const BLE_NATIVE_TEARDOWN_TIMEOUT_MS = 3000;
|
|
280
313
|
const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
281
314
|
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
282
315
|
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
@@ -310,9 +343,6 @@ function resetProtocolV2BleTuning() {
|
|
|
310
343
|
function getProtocolV2BleTuning() {
|
|
311
344
|
return Object.assign({}, protocolV2BleTuning);
|
|
312
345
|
}
|
|
313
|
-
function inferProtocolHintFromDeviceName(name) {
|
|
314
|
-
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
315
|
-
}
|
|
316
346
|
function getDeviceDisplayName(device) {
|
|
317
347
|
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
318
348
|
}
|
|
@@ -335,9 +365,14 @@ const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
|
335
365
|
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
336
366
|
const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
337
367
|
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
368
|
+
const BLE_SETUP_WEDGED_MESSAGE = 'BLE setup wedged repeatedly';
|
|
338
369
|
const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
|
|
339
370
|
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
340
371
|
error.message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
372
|
+
const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.PollingTimeout &&
|
|
373
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
374
|
+
error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
375
|
+
const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
341
376
|
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
342
377
|
const tryToGetConfiguration = (device) => {
|
|
343
378
|
if (!device || !device.serviceUUIDs)
|
|
@@ -369,12 +404,11 @@ const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void
|
|
|
369
404
|
}
|
|
370
405
|
});
|
|
371
406
|
const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
|
|
372
|
-
function remapError(error) {
|
|
407
|
+
function remapError(error, mapProtocolV2StaleBond) {
|
|
373
408
|
var _a;
|
|
374
409
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
375
|
-
if (
|
|
376
|
-
error
|
|
377
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePeerRemovedPairingInformation);
|
|
410
|
+
if (mapProtocolV2StaleBond && isNativeBleStaleBondError(error)) {
|
|
411
|
+
throw toBleStaleBondHardwareError(error);
|
|
378
412
|
}
|
|
379
413
|
if ((error === null || error === void 0 ? void 0 : error.attErrorCode) === 22) {
|
|
380
414
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondError);
|
|
@@ -403,7 +437,10 @@ class ReactNativeBleTransport {
|
|
|
403
437
|
this.connectionSetupTimeoutCounts = new Map();
|
|
404
438
|
this.deviceProtocolHints = new Map();
|
|
405
439
|
this.sessionProtocols = new Map();
|
|
440
|
+
this.confirmedProtocolV2 = new Set();
|
|
406
441
|
this.protocolReprobeFailures = new Map();
|
|
442
|
+
this.staleBondErrors = new Map();
|
|
443
|
+
this.acquiringProtocolV2 = new Set();
|
|
407
444
|
this.protocolV2Assemblers = new Map();
|
|
408
445
|
this.protocolV2FrameQueues = new Map();
|
|
409
446
|
this.protocolV2FramePromises = new Map();
|
|
@@ -434,6 +471,7 @@ class ReactNativeBleTransport {
|
|
|
434
471
|
this.androidHighPriorityDevices = new Set();
|
|
435
472
|
this.androidPriorityResetTimers = new Map();
|
|
436
473
|
this.nextMonitorToken = 1;
|
|
474
|
+
this.lifecycleOperations = new Map();
|
|
437
475
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
438
476
|
}
|
|
439
477
|
init(logger, emitter) {
|
|
@@ -658,7 +696,7 @@ class ReactNativeBleTransport {
|
|
|
658
696
|
allowDuplicates: true,
|
|
659
697
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
660
698
|
}, (error, device) => {
|
|
661
|
-
var _a;
|
|
699
|
+
var _a, _b;
|
|
662
700
|
if (error) {
|
|
663
701
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
664
702
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
@@ -680,15 +718,12 @@ class ReactNativeBleTransport {
|
|
|
680
718
|
}
|
|
681
719
|
const displayName = getDeviceDisplayName(device);
|
|
682
720
|
const isUnnamedIOSPeripheral = reactNative.Platform.OS === 'ios' && !(displayName === null || displayName === void 0 ? void 0 : displayName.trim());
|
|
683
|
-
const isFindMyPeripheral = hdShared.isPro2FindMyAdvertisementName(device === null || device === void 0 ? void 0 : device.name) ||
|
|
684
|
-
hdShared.isPro2FindMyAdvertisementName(device === null || device === void 0 ? void 0 : device.localName);
|
|
685
721
|
const isOneKey = !isUnnamedIOSPeripheral &&
|
|
686
|
-
!isFindMyPeripheral &&
|
|
687
722
|
hdShared.isOnekeyBluetoothDevice({
|
|
688
723
|
id: device === null || device === void 0 ? void 0 : device.id,
|
|
689
724
|
name: device === null || device === void 0 ? void 0 : device.name,
|
|
690
725
|
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
691
|
-
serviceUuids: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
726
|
+
serviceUuids: (_b = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _b !== void 0 ? _b : getBluetoothServiceUuids(),
|
|
692
727
|
});
|
|
693
728
|
if (isOneKey) {
|
|
694
729
|
addDevice(device);
|
|
@@ -707,15 +742,12 @@ class ReactNativeBleTransport {
|
|
|
707
742
|
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
708
743
|
? device.localName
|
|
709
744
|
: null;
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
localName,
|
|
717
|
-
serviceUuids: device.serviceUUIDs,
|
|
718
|
-
})) {
|
|
745
|
+
if (hdShared.isOnekeyBluetoothDevice({
|
|
746
|
+
id: device.id,
|
|
747
|
+
name: device.name,
|
|
748
|
+
localName,
|
|
749
|
+
serviceUuids: device.serviceUUIDs,
|
|
750
|
+
})) {
|
|
719
751
|
Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
|
|
720
752
|
addDevice(device);
|
|
721
753
|
}
|
|
@@ -725,16 +757,11 @@ class ReactNativeBleTransport {
|
|
|
725
757
|
var _a;
|
|
726
758
|
if (deviceList.every(d => d.id !== device.id)) {
|
|
727
759
|
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
728
|
-
const protocolHint = inferProtocolHintFromDeviceName(displayName);
|
|
729
|
-
if (protocolHint) {
|
|
730
|
-
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
731
|
-
}
|
|
732
760
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
733
761
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
734
762
|
deviceId: device.id,
|
|
735
763
|
name: displayName,
|
|
736
764
|
serviceUUIDs: device.serviceUUIDs,
|
|
737
|
-
protocolHint,
|
|
738
765
|
});
|
|
739
766
|
}
|
|
740
767
|
};
|
|
@@ -797,24 +824,57 @@ class ReactNativeBleTransport {
|
|
|
797
824
|
});
|
|
798
825
|
}
|
|
799
826
|
acquire(input) {
|
|
800
|
-
var _a, _b;
|
|
801
827
|
return __awaiter(this, void 0, void 0, function* () {
|
|
802
|
-
const { uuid
|
|
828
|
+
const { uuid } = input;
|
|
803
829
|
if (!uuid) {
|
|
804
830
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
805
831
|
}
|
|
832
|
+
return this.runLifecycleOperation(uuid, () => this.acquireUnlocked(input));
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
acquireUnlocked(input) {
|
|
836
|
+
var _a;
|
|
837
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
838
|
+
const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
|
|
839
|
+
const shouldMapProtocolV2StaleBond = expectedProtocol
|
|
840
|
+
? expectedProtocol === 'V2'
|
|
841
|
+
: this.confirmedProtocolV2.has(uuid);
|
|
806
842
|
const cachedTransport = transportCache[uuid];
|
|
843
|
+
if (skipProtocolProbe && !cachedTransport && this.blePlxManager) {
|
|
844
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] refresh uncached BLE connection for firmware install:', uuid);
|
|
845
|
+
const manager = this.blePlxManager;
|
|
846
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
847
|
+
yield this.runBestEffortNativeOperation('firmware install reconnect: cancel uncached device connection', () => manager.cancelDeviceConnection(uuid));
|
|
848
|
+
}));
|
|
849
|
+
}
|
|
807
850
|
if (cachedTransport) {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
(
|
|
813
|
-
|
|
814
|
-
|
|
851
|
+
if (skipProtocolProbe) {
|
|
852
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] refresh cached BLE connection for firmware install:', uuid);
|
|
853
|
+
const manager = this.blePlxManager;
|
|
854
|
+
yield this.releaseUnlocked(uuid, true);
|
|
855
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
856
|
+
const operations = [];
|
|
857
|
+
if (manager) {
|
|
858
|
+
operations.push(this.runBestEffortNativeOperation('firmware install reconnect: cancel device connection', () => manager.cancelDeviceConnection(uuid)));
|
|
859
|
+
}
|
|
860
|
+
operations.push(this.runBestEffortNativeOperation('firmware install reconnect: device cancel connection', () => cachedTransport.device.cancelConnection()));
|
|
861
|
+
yield Promise.all(operations);
|
|
862
|
+
}));
|
|
863
|
+
}
|
|
864
|
+
else {
|
|
865
|
+
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
866
|
+
const isCachedDeviceConnected = yield cachedTransport.device
|
|
867
|
+
.isConnected()
|
|
868
|
+
.catch(() => false);
|
|
869
|
+
if (isCachedDeviceConnected &&
|
|
870
|
+
cachedProtocol &&
|
|
871
|
+
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
872
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
873
|
+
return { uuid, protocolType: cachedProtocol };
|
|
874
|
+
}
|
|
875
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
876
|
+
yield this.releaseUnlocked(uuid, true);
|
|
815
877
|
}
|
|
816
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
817
|
-
yield this.release(uuid, true);
|
|
818
878
|
}
|
|
819
879
|
let device = null;
|
|
820
880
|
if (forceCleanRunPromise && this.runPromise) {
|
|
@@ -858,7 +918,7 @@ class ReactNativeBleTransport {
|
|
|
858
918
|
}
|
|
859
919
|
catch (e) {
|
|
860
920
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
861
|
-
if (
|
|
921
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
862
922
|
throw e;
|
|
863
923
|
}
|
|
864
924
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
@@ -871,7 +931,7 @@ class ReactNativeBleTransport {
|
|
|
871
931
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleAlreadyConnected);
|
|
872
932
|
}
|
|
873
933
|
else {
|
|
874
|
-
remapError(e);
|
|
934
|
+
remapError(e, shouldMapProtocolV2StaleBond);
|
|
875
935
|
}
|
|
876
936
|
}
|
|
877
937
|
}
|
|
@@ -886,7 +946,7 @@ class ReactNativeBleTransport {
|
|
|
886
946
|
}
|
|
887
947
|
catch (e) {
|
|
888
948
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
889
|
-
if (
|
|
949
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
890
950
|
throw e;
|
|
891
951
|
}
|
|
892
952
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
@@ -905,7 +965,7 @@ class ReactNativeBleTransport {
|
|
|
905
965
|
}
|
|
906
966
|
}
|
|
907
967
|
else {
|
|
908
|
-
remapError(e);
|
|
968
|
+
remapError(e, shouldMapProtocolV2StaleBond);
|
|
909
969
|
}
|
|
910
970
|
}
|
|
911
971
|
}
|
|
@@ -914,16 +974,43 @@ class ReactNativeBleTransport {
|
|
|
914
974
|
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
|
|
915
975
|
const protocolHint = expectedProtocol
|
|
916
976
|
? undefined
|
|
917
|
-
: (
|
|
918
|
-
yield this.
|
|
977
|
+
: (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
|
|
978
|
+
yield this.releaseUnlocked(uuid, true);
|
|
919
979
|
if (protocolHint) {
|
|
920
980
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
921
981
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
});
|
|
982
|
+
if (shouldMapProtocolV2StaleBond) {
|
|
983
|
+
this.acquiringProtocolV2.add(uuid);
|
|
984
|
+
}
|
|
926
985
|
try {
|
|
986
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice, {
|
|
987
|
+
writeCharacteristic,
|
|
988
|
+
notifyCharacteristic,
|
|
989
|
+
});
|
|
990
|
+
if (skipProtocolProbe) {
|
|
991
|
+
if (!expectedProtocol) {
|
|
992
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'skipProtocolProbe requires an expected BLE protocol');
|
|
993
|
+
}
|
|
994
|
+
const hasConfirmedProtocol = this.sessionProtocols.get(uuid) === expectedProtocol ||
|
|
995
|
+
(expectedProtocol === 'V2' && this.confirmedProtocolV2.has(uuid));
|
|
996
|
+
if (!hasConfirmedProtocol) {
|
|
997
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'skipProtocolProbe requires a previously confirmed protocol for this BLE endpoint');
|
|
998
|
+
}
|
|
999
|
+
this.deviceProtocol.set(uuid, expectedProtocol);
|
|
1000
|
+
this.sessionProtocols.set(uuid, expectedProtocol);
|
|
1001
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
1002
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected without probe', {
|
|
1003
|
+
deviceId: uuid,
|
|
1004
|
+
protocol: expectedProtocol,
|
|
1005
|
+
source: 'firmware-install-reconnect',
|
|
1006
|
+
});
|
|
1007
|
+
const currentTransport = transportCache[uuid];
|
|
1008
|
+
if (!currentTransport) {
|
|
1009
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
1010
|
+
}
|
|
1011
|
+
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
1012
|
+
return { uuid, protocolType: expectedProtocol };
|
|
1013
|
+
}
|
|
927
1014
|
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
928
1015
|
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
929
1016
|
}));
|
|
@@ -935,16 +1022,24 @@ class ReactNativeBleTransport {
|
|
|
935
1022
|
return { uuid, protocolType };
|
|
936
1023
|
}
|
|
937
1024
|
catch (error) {
|
|
938
|
-
|
|
1025
|
+
if (hdShared.isBleStaleBondHardwareError(error)) {
|
|
1026
|
+
yield this.disconnectUnlocked(uuid);
|
|
1027
|
+
}
|
|
1028
|
+
else {
|
|
1029
|
+
yield this.releaseUnlocked(uuid, true);
|
|
1030
|
+
}
|
|
939
1031
|
throw error;
|
|
940
1032
|
}
|
|
1033
|
+
finally {
|
|
1034
|
+
this.acquiringProtocolV2.delete(uuid);
|
|
1035
|
+
}
|
|
941
1036
|
});
|
|
942
1037
|
}
|
|
943
1038
|
_monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
|
|
944
1039
|
let bufferLength = 0;
|
|
945
1040
|
let buffer$1 = [];
|
|
946
1041
|
const subscription = characteristic.monitor((error, c) => {
|
|
947
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p
|
|
1042
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
948
1043
|
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
949
1044
|
if (error) {
|
|
950
1045
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
@@ -956,19 +1051,21 @@ class ReactNativeBleTransport {
|
|
|
956
1051
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
957
1052
|
return;
|
|
958
1053
|
}
|
|
1054
|
+
if ((this.getActiveProtocol(uuid) === 'V2' || this.acquiringProtocolV2.has(uuid)) &&
|
|
1055
|
+
isNativeBleStaleBondError(error)) {
|
|
1056
|
+
this.rememberStaleBondError(uuid, toBleStaleBondHardwareError(error));
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
959
1059
|
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
960
1060
|
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
961
1061
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
962
1062
|
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
963
1063
|
}
|
|
964
|
-
else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
((
|
|
969
|
-
((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
|
|
970
|
-
((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
|
|
971
|
-
((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
|
|
1064
|
+
else if (((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Cannot write client characteristic config descriptor')) ||
|
|
1065
|
+
((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot find client characteristic config descriptor')) ||
|
|
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'))) {
|
|
972
1069
|
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
973
1070
|
}
|
|
974
1071
|
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
@@ -976,17 +1073,14 @@ class ReactNativeBleTransport {
|
|
|
976
1073
|
}
|
|
977
1074
|
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
978
1075
|
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
979
|
-
if ((
|
|
1076
|
+
if ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('The connection has timed out unexpectedly')) {
|
|
980
1077
|
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
981
1078
|
}
|
|
982
|
-
if ((
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
((
|
|
987
|
-
((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
|
|
988
|
-
((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
|
|
989
|
-
((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
|
|
1079
|
+
if (((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('Cannot write client characteristic config descriptor')) ||
|
|
1080
|
+
((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Cannot find client characteristic config descriptor')) ||
|
|
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'))) {
|
|
990
1084
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
991
1085
|
this.runPromise.reject(notifyError);
|
|
992
1086
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
@@ -1028,7 +1122,7 @@ class ReactNativeBleTransport {
|
|
|
1028
1122
|
bufferLength = 0;
|
|
1029
1123
|
buffer$1 = [];
|
|
1030
1124
|
if (this.runPromiseDeviceId === uuid) {
|
|
1031
|
-
(
|
|
1125
|
+
(_o = this.runPromise) === null || _o === void 0 ? void 0 : _o.resolve(value.toString('hex'));
|
|
1032
1126
|
}
|
|
1033
1127
|
}
|
|
1034
1128
|
}
|
|
@@ -1039,22 +1133,28 @@ class ReactNativeBleTransport {
|
|
|
1039
1133
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1040
1134
|
}
|
|
1041
1135
|
else if (this.runPromiseDeviceId === uuid) {
|
|
1042
|
-
(
|
|
1136
|
+
(_p = this.runPromise) === null || _p === void 0 ? void 0 : _p.reject(notifyError);
|
|
1043
1137
|
}
|
|
1044
1138
|
}
|
|
1045
1139
|
}, notifyTransactionId);
|
|
1046
1140
|
return subscription;
|
|
1047
1141
|
}
|
|
1048
1142
|
release(uuid, onclose = false) {
|
|
1143
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1144
|
+
return this.runLifecycleOperation(uuid, () => this.releaseUnlocked(uuid, onclose));
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
releaseUnlocked(uuid, onclose = false) {
|
|
1049
1148
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1050
1149
|
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
1051
1150
|
return this.releaseNative(uuid, onclose);
|
|
1052
1151
|
});
|
|
1053
1152
|
}
|
|
1054
1153
|
releaseNative(uuid, onclose = false) {
|
|
1055
|
-
var _a, _b, _c, _d, _e
|
|
1154
|
+
var _a, _b, _c, _d, _e;
|
|
1056
1155
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1057
1156
|
const transport = transportCache[uuid];
|
|
1157
|
+
const manager = this.blePlxManager;
|
|
1058
1158
|
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
1059
1159
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1060
1160
|
this.runPromise.reject(error);
|
|
@@ -1070,7 +1170,6 @@ class ReactNativeBleTransport {
|
|
|
1070
1170
|
this.resetProtocolV2Frames(uuid);
|
|
1071
1171
|
return Promise.resolve(true);
|
|
1072
1172
|
}
|
|
1073
|
-
yield this.restoreAndroidConnectionPriority(uuid, transport);
|
|
1074
1173
|
if (transport) {
|
|
1075
1174
|
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
1076
1175
|
this.monitorTokens.delete(uuid);
|
|
@@ -1081,33 +1180,39 @@ class ReactNativeBleTransport {
|
|
|
1081
1180
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_c = transport.notifyCharacteristic) === null || _c === void 0 ? void 0 : _c.uuid);
|
|
1082
1181
|
(_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
|
|
1083
1182
|
transport.notifySubscription = undefined;
|
|
1084
|
-
if (transport
|
|
1085
|
-
|
|
1086
|
-
yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
|
|
1087
|
-
}
|
|
1088
|
-
catch (e) {
|
|
1089
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel notify transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
1090
|
-
}
|
|
1183
|
+
if (transportCache[uuid] === transport) {
|
|
1184
|
+
delete transportCache[uuid];
|
|
1091
1185
|
}
|
|
1092
|
-
delete transportCache[uuid];
|
|
1093
1186
|
}
|
|
1094
1187
|
this.protocolV2HighVolumeLogSignatures.delete(uuid);
|
|
1095
1188
|
this.deviceProtocol.delete(uuid);
|
|
1096
1189
|
this.probingProtocols.delete(uuid);
|
|
1097
|
-
|
|
1190
|
+
this.staleBondErrors.delete(uuid);
|
|
1191
|
+
this.acquiringProtocolV2.delete(uuid);
|
|
1192
|
+
(_e = this.protocolV2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
|
|
1098
1193
|
this.protocolV2Assemblers.delete(uuid);
|
|
1099
1194
|
this.resetProtocolV2Frames(uuid);
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1195
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1196
|
+
const operations = [
|
|
1197
|
+
this.runBestEffortNativeOperation('release: restore connection priority', () => this.restoreAndroidConnectionPriority(uuid, transport)),
|
|
1198
|
+
];
|
|
1199
|
+
if ((transport === null || transport === void 0 ? void 0 : transport.notifyTransactionId) && manager) {
|
|
1200
|
+
operations.push(this.runBestEffortNativeOperation('release: cancel notify transaction', () => manager.cancelTransaction(transport.notifyTransactionId)));
|
|
1201
|
+
}
|
|
1202
|
+
if (manager) {
|
|
1203
|
+
operations.push(this.runBestEffortNativeOperation('release: cancel transaction', () => manager.cancelTransaction(uuid)));
|
|
1204
|
+
}
|
|
1205
|
+
yield Promise.all(operations);
|
|
1206
|
+
}));
|
|
1106
1207
|
return Promise.resolve(true);
|
|
1107
1208
|
});
|
|
1108
1209
|
}
|
|
1109
1210
|
post(session, name, data) {
|
|
1110
1211
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1212
|
+
if (this.getProtocolType(session) === 'V2') {
|
|
1213
|
+
yield this.protocolV2Links.sendFlowControl(session, () => this.createProtocolV2Adapter(session), name, data);
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1111
1216
|
yield this.call(session, name, data);
|
|
1112
1217
|
});
|
|
1113
1218
|
}
|
|
@@ -1123,7 +1228,6 @@ class ReactNativeBleTransport {
|
|
|
1123
1228
|
if (!protocol) {
|
|
1124
1229
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1125
1230
|
}
|
|
1126
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport call', transport.createTransportCallLog(name, protocol, data));
|
|
1127
1231
|
if (protocol === 'V2') {
|
|
1128
1232
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1129
1233
|
}
|
|
@@ -1334,10 +1438,16 @@ class ReactNativeBleTransport {
|
|
|
1334
1438
|
this.stopped = true;
|
|
1335
1439
|
}
|
|
1336
1440
|
disconnect(session) {
|
|
1337
|
-
|
|
1441
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1442
|
+
return this.runLifecycleOperation(session, () => this.disconnectUnlocked(session));
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
disconnectUnlocked(session) {
|
|
1446
|
+
var _a, _b, _c;
|
|
1338
1447
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1339
1448
|
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1340
1449
|
const transport = transportCache[session];
|
|
1450
|
+
const manager = this.blePlxManager;
|
|
1341
1451
|
const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
|
|
1342
1452
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
1343
1453
|
try {
|
|
@@ -1359,40 +1469,19 @@ class ReactNativeBleTransport {
|
|
|
1359
1469
|
Log === null || Log === void 0 ? void 0 : Log.error('disconnect: remove notify subscription error: ', e);
|
|
1360
1470
|
}
|
|
1361
1471
|
}
|
|
1362
|
-
if (session) {
|
|
1363
|
-
try {
|
|
1364
|
-
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(session));
|
|
1365
|
-
}
|
|
1366
|
-
catch (e) {
|
|
1367
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
if (transport === null || transport === void 0 ? void 0 : transport.device) {
|
|
1371
|
-
try {
|
|
1372
|
-
yield transport.device.cancelConnection();
|
|
1373
|
-
}
|
|
1374
|
-
catch (e) {
|
|
1375
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: device.cancelConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
1376
|
-
}
|
|
1377
|
-
}
|
|
1378
|
-
try {
|
|
1379
|
-
yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelDeviceConnection(session));
|
|
1380
|
-
}
|
|
1381
|
-
catch (e) {
|
|
1382
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
1383
|
-
}
|
|
1384
|
-
if (transportCache[session]) {
|
|
1472
|
+
if (!transport || transportCache[session] === transport) {
|
|
1385
1473
|
delete transportCache[session];
|
|
1386
1474
|
}
|
|
1387
1475
|
this.deviceProtocol.delete(session);
|
|
1388
1476
|
this.probingProtocols.delete(session);
|
|
1477
|
+
this.staleBondErrors.delete(session);
|
|
1389
1478
|
this.deviceProtocolHints.delete(session);
|
|
1390
1479
|
this.sessionProtocols.delete(session);
|
|
1391
1480
|
this.protocolReprobeFailures.delete(session);
|
|
1392
1481
|
this.protocolV2Assemblers.delete(session);
|
|
1393
1482
|
this.resetProtocolV2Frames(session);
|
|
1394
1483
|
try {
|
|
1395
|
-
this.emitDeviceDisconnect(session, (
|
|
1484
|
+
this.emitDeviceDisconnect(session, (_c = transport === null || transport === void 0 ? void 0 : transport.device) === null || _c === void 0 ? void 0 : _c.name, monitorToken);
|
|
1396
1485
|
}
|
|
1397
1486
|
catch (e) {
|
|
1398
1487
|
Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
|
|
@@ -1400,9 +1489,81 @@ class ReactNativeBleTransport {
|
|
|
1400
1489
|
if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
|
|
1401
1490
|
this.monitorTokens.delete(session);
|
|
1402
1491
|
}
|
|
1492
|
+
yield this.runNativeTeardown(session, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1493
|
+
const operations = [];
|
|
1494
|
+
if (manager) {
|
|
1495
|
+
operations.push(this.runBestEffortNativeOperation('disconnect: cancel transaction', () => manager.cancelTransaction(session)));
|
|
1496
|
+
operations.push(this.runBestEffortNativeOperation('disconnect: cancel device connection', () => manager.cancelDeviceConnection(session)));
|
|
1497
|
+
}
|
|
1498
|
+
if (transport === null || transport === void 0 ? void 0 : transport.device) {
|
|
1499
|
+
operations.push(this.runBestEffortNativeOperation('disconnect: device cancel connection', () => transport.device.cancelConnection()));
|
|
1500
|
+
}
|
|
1501
|
+
yield Promise.all(operations);
|
|
1502
|
+
}));
|
|
1403
1503
|
yield new Promise(resolve => setTimeout(() => resolve(), 100));
|
|
1404
1504
|
});
|
|
1405
1505
|
}
|
|
1506
|
+
runNativeTeardown(uuid, manager, teardown) {
|
|
1507
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1508
|
+
let timer;
|
|
1509
|
+
let timedOut = false;
|
|
1510
|
+
const pending = Promise.resolve()
|
|
1511
|
+
.then(teardown)
|
|
1512
|
+
.catch(error => {
|
|
1513
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE native teardown error (ignored): ', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
1514
|
+
});
|
|
1515
|
+
try {
|
|
1516
|
+
yield Promise.race([
|
|
1517
|
+
pending,
|
|
1518
|
+
new Promise(resolve => {
|
|
1519
|
+
timer = setTimeout(() => {
|
|
1520
|
+
timedOut = true;
|
|
1521
|
+
resolve();
|
|
1522
|
+
}, BLE_NATIVE_TEARDOWN_TIMEOUT_MS);
|
|
1523
|
+
}),
|
|
1524
|
+
]);
|
|
1525
|
+
}
|
|
1526
|
+
finally {
|
|
1527
|
+
if (timer)
|
|
1528
|
+
clearTimeout(timer);
|
|
1529
|
+
}
|
|
1530
|
+
if (timedOut) {
|
|
1531
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE native teardown timed out:', uuid);
|
|
1532
|
+
if (this.blePlxManager === manager) {
|
|
1533
|
+
this.resetPlxManager();
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
runBestEffortNativeOperation(label, operation) {
|
|
1539
|
+
return Promise.resolve()
|
|
1540
|
+
.then(operation)
|
|
1541
|
+
.catch(error => {
|
|
1542
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`${label} error (ignored): `, (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
1543
|
+
});
|
|
1544
|
+
}
|
|
1545
|
+
runLifecycleOperation(uuid, operation) {
|
|
1546
|
+
var _a;
|
|
1547
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1548
|
+
const previousOperation = (_a = this.lifecycleOperations.get(uuid)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
1549
|
+
let completeOperation;
|
|
1550
|
+
const operationGate = new Promise(resolve => {
|
|
1551
|
+
completeOperation = resolve;
|
|
1552
|
+
});
|
|
1553
|
+
const operationTail = previousOperation.catch(() => undefined).then(() => operationGate);
|
|
1554
|
+
this.lifecycleOperations.set(uuid, operationTail);
|
|
1555
|
+
yield previousOperation.catch(() => undefined);
|
|
1556
|
+
try {
|
|
1557
|
+
return yield operation();
|
|
1558
|
+
}
|
|
1559
|
+
finally {
|
|
1560
|
+
completeOperation();
|
|
1561
|
+
if (this.lifecycleOperations.get(uuid) === operationTail) {
|
|
1562
|
+
this.lifecycleOperations.delete(uuid);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1406
1567
|
cancel() {
|
|
1407
1568
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1408
1569
|
if (this.runPromise) ;
|
|
@@ -1429,7 +1590,10 @@ class ReactNativeBleTransport {
|
|
|
1429
1590
|
}
|
|
1430
1591
|
catch (error) {
|
|
1431
1592
|
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1432
|
-
this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1593
|
+
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1594
|
+
if (resetManager) {
|
|
1595
|
+
throw this.createWedgedBleSetupError();
|
|
1596
|
+
}
|
|
1433
1597
|
}
|
|
1434
1598
|
throw error;
|
|
1435
1599
|
}
|
|
@@ -1460,7 +1624,10 @@ class ReactNativeBleTransport {
|
|
|
1460
1624
|
}
|
|
1461
1625
|
catch (error) {
|
|
1462
1626
|
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1463
|
-
this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1627
|
+
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1628
|
+
if (resetManager) {
|
|
1629
|
+
throw this.createWedgedBleSetupError();
|
|
1630
|
+
}
|
|
1464
1631
|
}
|
|
1465
1632
|
throw error;
|
|
1466
1633
|
}
|
|
@@ -1486,13 +1653,20 @@ class ReactNativeBleTransport {
|
|
|
1486
1653
|
}
|
|
1487
1654
|
this.deviceProtocol.delete(uuid);
|
|
1488
1655
|
this.probingProtocols.delete(uuid);
|
|
1656
|
+
this.staleBondErrors.delete(uuid);
|
|
1657
|
+
this.acquiringProtocolV2.delete(uuid);
|
|
1489
1658
|
this.protocolV2Assemblers.delete(uuid);
|
|
1490
1659
|
this.resetProtocolV2Frames(uuid);
|
|
1491
1660
|
if (timeouts >= BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1492
1661
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
|
|
1493
1662
|
this.resetPlxManager();
|
|
1494
1663
|
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1664
|
+
return true;
|
|
1495
1665
|
}
|
|
1666
|
+
return false;
|
|
1667
|
+
}
|
|
1668
|
+
createWedgedBleSetupError() {
|
|
1669
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.PollingTimeout, BLE_SETUP_WEDGED_MESSAGE);
|
|
1496
1670
|
}
|
|
1497
1671
|
getCachedTransport(uuid) {
|
|
1498
1672
|
const transport = transportCache[uuid];
|
|
@@ -1550,6 +1724,8 @@ class ReactNativeBleTransport {
|
|
|
1550
1724
|
}
|
|
1551
1725
|
this.deviceProtocol.delete(uuid);
|
|
1552
1726
|
this.probingProtocols.delete(uuid);
|
|
1727
|
+
this.staleBondErrors.delete(uuid);
|
|
1728
|
+
this.acquiringProtocolV2.delete(uuid);
|
|
1553
1729
|
this.protocolV2Assemblers.delete(uuid);
|
|
1554
1730
|
this.resetProtocolV2Frames(uuid);
|
|
1555
1731
|
if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
@@ -1561,11 +1737,39 @@ class ReactNativeBleTransport {
|
|
|
1561
1737
|
resetPlxManager() {
|
|
1562
1738
|
const manager = this.blePlxManager;
|
|
1563
1739
|
this.blePlxManager = undefined;
|
|
1564
|
-
|
|
1565
|
-
|
|
1740
|
+
const reason = 'React Native BLE manager reset';
|
|
1741
|
+
Object.entries(transportCache).forEach(([uuid, cachedTransport]) => {
|
|
1742
|
+
var _a, _b, _c, _d;
|
|
1743
|
+
try {
|
|
1744
|
+
(_a = cachedTransport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
1745
|
+
}
|
|
1746
|
+
catch (error) {
|
|
1747
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset disconnect subscription removal failed:', error);
|
|
1748
|
+
}
|
|
1749
|
+
cachedTransport.disconnectSubscription = undefined;
|
|
1750
|
+
try {
|
|
1751
|
+
(_b = cachedTransport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1752
|
+
}
|
|
1753
|
+
catch (error) {
|
|
1754
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset notify subscription removal failed:', error);
|
|
1755
|
+
}
|
|
1756
|
+
cachedTransport.notifySubscription = undefined;
|
|
1757
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1758
|
+
try {
|
|
1759
|
+
this.emitDeviceDisconnect(uuid, (_c = cachedTransport.device) === null || _c === void 0 ? void 0 : _c.name, (_d = cachedTransport.monitorToken) !== null && _d !== void 0 ? _d : this.monitorTokens.get(uuid));
|
|
1760
|
+
}
|
|
1761
|
+
catch (error) {
|
|
1762
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset disconnect event failed:', error);
|
|
1763
|
+
}
|
|
1764
|
+
delete transportCache[uuid];
|
|
1765
|
+
});
|
|
1766
|
+
this.protocolV2Links.invalidateAllLinks(reason).catch(error => {
|
|
1767
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager link invalidation failed:', error);
|
|
1566
1768
|
});
|
|
1567
1769
|
this.deviceProtocol.clear();
|
|
1568
1770
|
this.probingProtocols.clear();
|
|
1771
|
+
this.staleBondErrors.clear();
|
|
1772
|
+
this.acquiringProtocolV2.clear();
|
|
1569
1773
|
this.sessionProtocols.clear();
|
|
1570
1774
|
this.protocolReprobeFailures.clear();
|
|
1571
1775
|
this.writeTimeoutCounts.clear();
|
|
@@ -1600,32 +1804,23 @@ class ReactNativeBleTransport {
|
|
|
1600
1804
|
detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
|
|
1601
1805
|
var _a;
|
|
1602
1806
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1603
|
-
if (
|
|
1604
|
-
this.deviceProtocol.set(uuid,
|
|
1807
|
+
if (expectedProtocol === 'V1') {
|
|
1808
|
+
this.deviceProtocol.set(uuid, 'V1');
|
|
1605
1809
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
|
|
1606
1810
|
deviceId: uuid,
|
|
1607
|
-
protocol:
|
|
1811
|
+
protocol: 'V1',
|
|
1608
1812
|
source: 'expected',
|
|
1609
1813
|
});
|
|
1610
|
-
return
|
|
1814
|
+
return 'V1';
|
|
1611
1815
|
}
|
|
1612
|
-
if (expectedProtocol === '
|
|
1613
|
-
|
|
1614
|
-
this.deviceProtocol.set(uuid, 'V1');
|
|
1615
|
-
this.sessionProtocols.set(uuid, 'V1');
|
|
1616
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1617
|
-
deviceId: uuid,
|
|
1618
|
-
protocol: 'V1',
|
|
1619
|
-
source: 'expected',
|
|
1620
|
-
});
|
|
1621
|
-
return 'V1';
|
|
1622
|
-
}
|
|
1623
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1816
|
+
if (expectedProtocol === 'V2' || this.acquiringProtocolV2.has(uuid)) {
|
|
1817
|
+
this.throwIfStaleBondError(uuid);
|
|
1624
1818
|
}
|
|
1625
1819
|
if (expectedProtocol === 'V2') {
|
|
1626
1820
|
if (yield this.probeProtocolV2(uuid)) {
|
|
1627
1821
|
this.deviceProtocol.set(uuid, 'V2');
|
|
1628
1822
|
this.sessionProtocols.set(uuid, 'V2');
|
|
1823
|
+
this.confirmedProtocolV2.add(uuid);
|
|
1629
1824
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1630
1825
|
deviceId: uuid,
|
|
1631
1826
|
protocol: 'V2',
|
|
@@ -1657,6 +1852,9 @@ class ReactNativeBleTransport {
|
|
|
1657
1852
|
if (detected) {
|
|
1658
1853
|
this.deviceProtocol.set(uuid, protocol);
|
|
1659
1854
|
this.sessionProtocols.set(uuid, protocol);
|
|
1855
|
+
if (protocol === 'V2') {
|
|
1856
|
+
this.confirmedProtocolV2.add(uuid);
|
|
1857
|
+
}
|
|
1660
1858
|
this.protocolReprobeFailures.delete(uuid);
|
|
1661
1859
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1662
1860
|
deviceId: uuid,
|
|
@@ -1748,6 +1946,7 @@ class ReactNativeBleTransport {
|
|
|
1748
1946
|
}
|
|
1749
1947
|
this.probingProtocols.set(uuid, 'V2');
|
|
1750
1948
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1949
|
+
this.throwIfStaleBondError(uuid);
|
|
1751
1950
|
const detected = yield transport.probeProtocolV2({
|
|
1752
1951
|
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
1753
1952
|
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
|
|
@@ -1758,6 +1957,7 @@ class ReactNativeBleTransport {
|
|
|
1758
1957
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1759
1958
|
this.resetProtocolV2Frames(uuid);
|
|
1760
1959
|
},
|
|
1960
|
+
shouldRethrow: hdShared.isBleStaleBondHardwareError,
|
|
1761
1961
|
});
|
|
1762
1962
|
if (!detected) {
|
|
1763
1963
|
this.clearProbeProtocol(uuid, 'V2');
|
|
@@ -1818,6 +2018,19 @@ class ReactNativeBleTransport {
|
|
|
1818
2018
|
framePromise.reject(error);
|
|
1819
2019
|
}
|
|
1820
2020
|
}
|
|
2021
|
+
rememberStaleBondError(uuid, error) {
|
|
2022
|
+
this.staleBondErrors.set(uuid, error);
|
|
2023
|
+
this.rejectProtocolV2Frames(uuid, error);
|
|
2024
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
2025
|
+
this.runPromise.reject(error);
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
throwIfStaleBondError(uuid) {
|
|
2029
|
+
const error = this.staleBondErrors.get(uuid);
|
|
2030
|
+
if (error) {
|
|
2031
|
+
throw error;
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
1821
2034
|
readProtocolV2Frame(uuid) {
|
|
1822
2035
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1823
2036
|
const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
|
|
@@ -1866,6 +2079,11 @@ class ReactNativeBleTransport {
|
|
|
1866
2079
|
return;
|
|
1867
2080
|
}
|
|
1868
2081
|
catch (error) {
|
|
2082
|
+
if (isNativeBleStaleBondError(error) || hdShared.isBleStaleBondHardwareError(error)) {
|
|
2083
|
+
const bondError = toBleStaleBondHardwareError(error);
|
|
2084
|
+
this.rememberStaleBondError(uuid, bondError);
|
|
2085
|
+
throw bondError;
|
|
2086
|
+
}
|
|
1869
2087
|
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
1870
2088
|
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1871
2089
|
throw error;
|
|
@@ -2064,6 +2282,8 @@ class ReactNativeBleTransport {
|
|
|
2064
2282
|
}),
|
|
2065
2283
|
reset: (reason) => {
|
|
2066
2284
|
var _a;
|
|
2285
|
+
if (this.monitorTokens.get(uuid) !== generation)
|
|
2286
|
+
return;
|
|
2067
2287
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
2068
2288
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
2069
2289
|
},
|
|
@@ -2080,6 +2300,8 @@ class ReactNativeBleTransport {
|
|
|
2080
2300
|
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2081
2301
|
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2082
2302
|
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|
|
2303
|
+
exports.BLE_NATIVE_TEARDOWN_TIMEOUT_MS = BLE_NATIVE_TEARDOWN_TIMEOUT_MS;
|
|
2304
|
+
exports.BLE_SETUP_WEDGED_MESSAGE = BLE_SETUP_WEDGED_MESSAGE;
|
|
2083
2305
|
exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
|
|
2084
2306
|
exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2085
2307
|
exports.PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|