@onekeyfe/hd-transport-react-native 1.2.0-alpha.147 → 1.2.0-alpha.149
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -19
- package/package.json +5 -5
- package/src/__tests__/connectTimeout.test.ts +19 -8
- package/src/__tests__/protocolV2Link.test.ts +56 -3
- package/src/index.ts +56 -23
package/dist/index.d.ts
CHANGED
|
@@ -91,6 +91,7 @@ declare const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
|
91
91
|
declare const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
92
92
|
/** BLE setup timeouts since the last successful setup before the manager is recreated. */
|
|
93
93
|
declare const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
94
|
+
declare const BLE_SETUP_WEDGED_MESSAGE = "BLE setup wedged repeatedly";
|
|
94
95
|
type IOneKeyDevice = OneKeyDeviceInfoBase & Device;
|
|
95
96
|
declare class ReactNativeBleTransport {
|
|
96
97
|
blePlxManager: BleManager | undefined;
|
|
@@ -121,6 +122,8 @@ declare class ReactNativeBleTransport {
|
|
|
121
122
|
private deviceProtocolHints;
|
|
122
123
|
/** Protocol this device actually answered on, kept across reconnects of one session. */
|
|
123
124
|
private sessionProtocols;
|
|
125
|
+
/** Endpoints that answered a V2 probe in this transport lifetime. Survives disconnect. */
|
|
126
|
+
private confirmedProtocolV2;
|
|
124
127
|
/** Consecutive detections that failed while trusting sessionProtocols. */
|
|
125
128
|
private protocolReprobeFailures;
|
|
126
129
|
private protocolV2Assemblers;
|
|
@@ -179,8 +182,10 @@ declare class ReactNativeBleTransport {
|
|
|
179
182
|
* Give up on a BLE setup operation the native layer did not settle. The abandoned
|
|
180
183
|
* operation still owns native connection/GATT state that can poison the next attempt,
|
|
181
184
|
* so it is cleared here without awaiting the same queue that stopped responding.
|
|
185
|
+
* Returns true when the manager itself was reset so the caller can stop Core retries.
|
|
182
186
|
*/
|
|
183
187
|
private abandonStalledConnection;
|
|
188
|
+
private createWedgedBleSetupError;
|
|
184
189
|
private getCachedTransport;
|
|
185
190
|
/**
|
|
186
191
|
* Write one packet under a bounded budget. A write that never settles means the
|
|
@@ -224,4 +229,4 @@ declare class ReactNativeBleTransport {
|
|
|
224
229
|
getProtocolType(path: string): ProtocolType | undefined;
|
|
225
230
|
}
|
|
226
231
|
|
|
227
|
-
export { BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD, BLE_CONNECT_TIMEOUT_MS, BLE_GATT_SETUP_TIMEOUT_MS, BLE_NATIVE_TEARDOWN_TIMEOUT_MS, BLE_WRITE_PACKET_TIMEOUT_MS, BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD, IOneKeyDevice, PROTOCOL_REPROBE_FALLBACK_ATTEMPTS, ProtocolV2BleTuning, configureProtocolV2BleTuning, ReactNativeBleTransport as default, getFirmwareUploadWriteRetryType, getProtocolV2BleTuning, resetProtocolV2BleTuning };
|
|
232
|
+
export { BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD, BLE_CONNECT_TIMEOUT_MS, BLE_GATT_SETUP_TIMEOUT_MS, BLE_NATIVE_TEARDOWN_TIMEOUT_MS, BLE_SETUP_WEDGED_MESSAGE, BLE_WRITE_PACKET_TIMEOUT_MS, BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD, IOneKeyDevice, PROTOCOL_REPROBE_FALLBACK_ATTEMPTS, ProtocolV2BleTuning, configureProtocolV2BleTuning, ReactNativeBleTransport as default, getFirmwareUploadWriteRetryType, getProtocolV2BleTuning, resetProtocolV2BleTuning };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAG5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAChB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAKjB,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AA0BhC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAI1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAgBjE,KAAK,4BAA4B,GAAG,WAAW,CAAC;AAChD,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkCF,eAAO,MAAM,+BAA+B,UACnC,OAAO,KACb,4BAA4B,GAAG,IAsBjC,CAAC;AAcF,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAClD,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AAOpD,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAI3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAiBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QAY5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;EAErC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAG5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAChB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAKjB,KAAK,oBAAoB,EAI1B,MAAM,wBAAwB,CAAC;AA0BhC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAI1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAgBjE,KAAK,4BAA4B,GAAG,WAAW,CAAC;AAChD,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkCF,eAAO,MAAM,+BAA+B,UACnC,OAAO,KACb,4BAA4B,GAAG,IAsBjC,CAAC;AAcF,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAClD,eAAO,MAAM,8BAA8B,OAAQ,CAAC;AAOpD,eAAO,MAAM,yCAAyC,IAAI,CAAC;AAI3D,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAiBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QAY5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;EAErC;AAkCD,eAAO,MAAM,sBAAsB,QAA2C,CAAC;AAO/E,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAQhD,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,eAAO,MAAM,2CAA2C,IAAI,CAAC;AAE7D,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AActE,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAqE1D,MAAM,CAAC,OAAO,OAAO,uBAAuB;IAC1C,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IAEzC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,WAAW,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAErE,OAAO,CAAC,6BAA6B,CAAqB;IAE1D,IAAI,SAA6B;IAEjC,UAAU,UAAS;IAEnB,OAAO,UAAS;IAEhB,WAAW,SAA0B;IAErC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,OAAO,CAAC,kBAAkB,CAAuB;IAEjD,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,8BAA8B,cAAqB;IAGnD,OAAO,CAAC,cAAc,CAAwC;IAQ9D,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,kBAAkB,CAAkC;IAG5D,OAAO,CAAC,4BAA4B,CAAkC;IAEtE,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,gBAAgB,CAAwC;IAGhE,OAAO,CAAC,mBAAmB,CAAqB;IAGhD,OAAO,CAAC,uBAAuB,CAAkC;IAEjE,OAAO,CAAC,oBAAoB,CAAoD;IAEhF,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,uBAAuB,CAAgD;IAE/E,OAAO,CAAC,eAAe,CAmBpB;IAEH,OAAO,CAAC,aAAa,CAAkC;IAEvD,OAAO,CAAC,qBAAqB,CAAkC;IAE/D,OAAO,CAAC,iCAAiC,CAAuC;IAEhF,OAAO,CAAC,0BAA0B,CAA0B;IAE5D,OAAO,CAAC,0BAA0B,CAAyD;IAE3F,OAAO,CAAC,gBAAgB,CAAK;IAG7B,OAAO,CAAC,mBAAmB,CAAyC;gBAExD,OAAO,EAAE,gBAAgB;IAIrC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY;IAKvC,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAgBnC,MAAM;IAIN,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;IAMjC,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAmFjF,4BAA4B,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAgClF,OAAO,CAAC,oBAAoB;IAgBtB,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY;IAsDtE,SAAS;YAsID,0BAA0B;IAyElC,OAAO,CAAC,KAAK,EAAE,eAAe;;;;YAUtB,eAAe;IAoL7B,sBAAsB,CACpB,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,YAAY;IAsIT,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ;YAI7B,eAAe;YAKf,aAAa;IA4ErB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAajE,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA6BlB,cAAc;IAyP5B,IAAI;IAIE,UAAU,CAAC,OAAO,EAAE,MAAM;YAIlB,kBAAkB;YAkFlB,iBAAiB;IAkC/B,OAAO,CAAC,4BAA4B;YAQtB,qBAAqB;IAoBnC,MAAM;YAUQ,kBAAkB;YAwClB,iCAAiC;IA+C/C,OAAO,CAAC,wBAAwB;IAkChC,OAAO,CAAC,yBAAyB;IAMjC,OAAO,CAAC,kBAAkB;YAcZ,cAAc;IA8C5B,OAAO,CAAC,kBAAkB;IA6B1B,OAAO,CAAC,eAAe;IAmDvB,OAAO,CAAC,2BAA2B;IAUnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,iBAAiB;YAIX,cAAc;YA0Gd,iCAAiC;YAoDjC,eAAe;YAwBf,eAAe;IA0B7B,OAAO,CAAC,4BAA4B;IA2BpC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,sBAAsB;YAShB,mBAAmB;YAiBnB,qBAAqB;YA2DrB,oBAAoB;YAgCpB,cAAc;YAqEd,iCAAiC;IAiB/C,OAAO,CAAC,8BAA8B;YAQxB,mCAAmC;IAsBjD,OAAO,CAAC,yCAAyC;YAanC,gCAAgC;IAoB9C,OAAO,CAAC,uBAAuB;IAmD/B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
|
package/dist/index.js
CHANGED
|
@@ -311,9 +311,6 @@ function resetProtocolV2BleTuning() {
|
|
|
311
311
|
function getProtocolV2BleTuning() {
|
|
312
312
|
return Object.assign({}, protocolV2BleTuning);
|
|
313
313
|
}
|
|
314
|
-
function inferProtocolHintFromDeviceName(name) {
|
|
315
|
-
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
316
|
-
}
|
|
317
314
|
function getDeviceDisplayName(device) {
|
|
318
315
|
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
319
316
|
}
|
|
@@ -336,9 +333,14 @@ const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
|
336
333
|
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
337
334
|
const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
338
335
|
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
336
|
+
const BLE_SETUP_WEDGED_MESSAGE = 'BLE setup wedged repeatedly';
|
|
339
337
|
const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
|
|
340
338
|
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
341
339
|
error.message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
340
|
+
const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.PollingTimeout &&
|
|
341
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
342
|
+
error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
343
|
+
const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
342
344
|
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
343
345
|
const tryToGetConfiguration = (device) => {
|
|
344
346
|
if (!device || !device.serviceUUIDs)
|
|
@@ -404,6 +406,7 @@ class ReactNativeBleTransport {
|
|
|
404
406
|
this.connectionSetupTimeoutCounts = new Map();
|
|
405
407
|
this.deviceProtocolHints = new Map();
|
|
406
408
|
this.sessionProtocols = new Map();
|
|
409
|
+
this.confirmedProtocolV2 = new Set();
|
|
407
410
|
this.protocolReprobeFailures = new Map();
|
|
408
411
|
this.protocolV2Assemblers = new Map();
|
|
409
412
|
this.protocolV2FrameQueues = new Map();
|
|
@@ -721,16 +724,11 @@ class ReactNativeBleTransport {
|
|
|
721
724
|
var _a;
|
|
722
725
|
if (deviceList.every(d => d.id !== device.id)) {
|
|
723
726
|
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
724
|
-
const protocolHint = inferProtocolHintFromDeviceName(displayName);
|
|
725
|
-
if (protocolHint) {
|
|
726
|
-
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
727
|
-
}
|
|
728
727
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
729
728
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
730
729
|
deviceId: device.id,
|
|
731
730
|
name: displayName,
|
|
732
731
|
serviceUUIDs: device.serviceUUIDs,
|
|
733
|
-
protocolHint,
|
|
734
732
|
});
|
|
735
733
|
}
|
|
736
734
|
};
|
|
@@ -802,7 +800,7 @@ class ReactNativeBleTransport {
|
|
|
802
800
|
});
|
|
803
801
|
}
|
|
804
802
|
acquireUnlocked(input) {
|
|
805
|
-
var _a
|
|
803
|
+
var _a;
|
|
806
804
|
return __awaiter(this, void 0, void 0, function* () {
|
|
807
805
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
808
806
|
const cachedTransport = transportCache[uuid];
|
|
@@ -860,7 +858,7 @@ class ReactNativeBleTransport {
|
|
|
860
858
|
}
|
|
861
859
|
catch (e) {
|
|
862
860
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
863
|
-
if (
|
|
861
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
864
862
|
throw e;
|
|
865
863
|
}
|
|
866
864
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
@@ -888,7 +886,7 @@ class ReactNativeBleTransport {
|
|
|
888
886
|
}
|
|
889
887
|
catch (e) {
|
|
890
888
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
891
|
-
if (
|
|
889
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
892
890
|
throw e;
|
|
893
891
|
}
|
|
894
892
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
@@ -916,7 +914,7 @@ class ReactNativeBleTransport {
|
|
|
916
914
|
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
|
|
917
915
|
const protocolHint = expectedProtocol
|
|
918
916
|
? undefined
|
|
919
|
-
: (
|
|
917
|
+
: (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
|
|
920
918
|
yield this.releaseUnlocked(uuid, true);
|
|
921
919
|
if (protocolHint) {
|
|
922
920
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
@@ -937,7 +935,12 @@ class ReactNativeBleTransport {
|
|
|
937
935
|
return { uuid, protocolType };
|
|
938
936
|
}
|
|
939
937
|
catch (error) {
|
|
940
|
-
|
|
938
|
+
if ((error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleDeviceBondError) {
|
|
939
|
+
yield this.disconnectUnlocked(uuid);
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
yield this.releaseUnlocked(uuid, true);
|
|
943
|
+
}
|
|
941
944
|
throw error;
|
|
942
945
|
}
|
|
943
946
|
});
|
|
@@ -1495,7 +1498,10 @@ class ReactNativeBleTransport {
|
|
|
1495
1498
|
}
|
|
1496
1499
|
catch (error) {
|
|
1497
1500
|
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1498
|
-
this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1501
|
+
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1502
|
+
if (resetManager) {
|
|
1503
|
+
throw this.createWedgedBleSetupError();
|
|
1504
|
+
}
|
|
1499
1505
|
}
|
|
1500
1506
|
throw error;
|
|
1501
1507
|
}
|
|
@@ -1526,7 +1532,10 @@ class ReactNativeBleTransport {
|
|
|
1526
1532
|
}
|
|
1527
1533
|
catch (error) {
|
|
1528
1534
|
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1529
|
-
this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1535
|
+
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1536
|
+
if (resetManager) {
|
|
1537
|
+
throw this.createWedgedBleSetupError();
|
|
1538
|
+
}
|
|
1530
1539
|
}
|
|
1531
1540
|
throw error;
|
|
1532
1541
|
}
|
|
@@ -1558,7 +1567,12 @@ class ReactNativeBleTransport {
|
|
|
1558
1567
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
|
|
1559
1568
|
this.resetPlxManager();
|
|
1560
1569
|
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1570
|
+
return true;
|
|
1561
1571
|
}
|
|
1572
|
+
return false;
|
|
1573
|
+
}
|
|
1574
|
+
createWedgedBleSetupError() {
|
|
1575
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.PollingTimeout, BLE_SETUP_WEDGED_MESSAGE);
|
|
1562
1576
|
}
|
|
1563
1577
|
getCachedTransport(uuid) {
|
|
1564
1578
|
const transport = transportCache[uuid];
|
|
@@ -1659,6 +1673,7 @@ class ReactNativeBleTransport {
|
|
|
1659
1673
|
this.deviceProtocol.clear();
|
|
1660
1674
|
this.probingProtocols.clear();
|
|
1661
1675
|
this.sessionProtocols.clear();
|
|
1676
|
+
this.confirmedProtocolV2.clear();
|
|
1662
1677
|
this.protocolReprobeFailures.clear();
|
|
1663
1678
|
this.writeTimeoutCounts.clear();
|
|
1664
1679
|
this.connectionSetupTimeoutCounts.clear();
|
|
@@ -1671,8 +1686,9 @@ class ReactNativeBleTransport {
|
|
|
1671
1686
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
|
|
1672
1687
|
}
|
|
1673
1688
|
}
|
|
1674
|
-
createProtocolMismatchError(expected) {
|
|
1675
|
-
|
|
1689
|
+
createProtocolMismatchError(expected, uuid) {
|
|
1690
|
+
const isStaleV2Bond = expected === 'V2' && this.confirmedProtocolV2.has(uuid);
|
|
1691
|
+
return hdShared.ERRORS.TypedError(isStaleV2Bond ? hdShared.HardwareErrorCode.BleDeviceBondError : hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1676
1692
|
}
|
|
1677
1693
|
createProtocolDetectionError() {
|
|
1678
1694
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
@@ -1712,12 +1728,13 @@ class ReactNativeBleTransport {
|
|
|
1712
1728
|
});
|
|
1713
1729
|
return 'V1';
|
|
1714
1730
|
}
|
|
1715
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1731
|
+
throw this.createProtocolMismatchError(expectedProtocol, uuid);
|
|
1716
1732
|
}
|
|
1717
1733
|
if (expectedProtocol === 'V2') {
|
|
1718
1734
|
if (yield this.probeProtocolV2(uuid)) {
|
|
1719
1735
|
this.deviceProtocol.set(uuid, 'V2');
|
|
1720
1736
|
this.sessionProtocols.set(uuid, 'V2');
|
|
1737
|
+
this.confirmedProtocolV2.add(uuid);
|
|
1721
1738
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1722
1739
|
deviceId: uuid,
|
|
1723
1740
|
protocol: 'V2',
|
|
@@ -1725,7 +1742,7 @@ class ReactNativeBleTransport {
|
|
|
1725
1742
|
});
|
|
1726
1743
|
return 'V2';
|
|
1727
1744
|
}
|
|
1728
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1745
|
+
throw this.createProtocolMismatchError(expectedProtocol, uuid);
|
|
1729
1746
|
}
|
|
1730
1747
|
const sessionProtocol = this.sessionProtocols.get(uuid);
|
|
1731
1748
|
const reprobeFailures = (_a = this.protocolReprobeFailures.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
@@ -1749,6 +1766,9 @@ class ReactNativeBleTransport {
|
|
|
1749
1766
|
if (detected) {
|
|
1750
1767
|
this.deviceProtocol.set(uuid, protocol);
|
|
1751
1768
|
this.sessionProtocols.set(uuid, protocol);
|
|
1769
|
+
if (protocol === 'V2') {
|
|
1770
|
+
this.confirmedProtocolV2.add(uuid);
|
|
1771
|
+
}
|
|
1752
1772
|
this.protocolReprobeFailures.delete(uuid);
|
|
1753
1773
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1754
1774
|
deviceId: uuid,
|
|
@@ -2175,6 +2195,7 @@ exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGE
|
|
|
2175
2195
|
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2176
2196
|
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|
|
2177
2197
|
exports.BLE_NATIVE_TEARDOWN_TIMEOUT_MS = BLE_NATIVE_TEARDOWN_TIMEOUT_MS;
|
|
2198
|
+
exports.BLE_SETUP_WEDGED_MESSAGE = BLE_SETUP_WEDGED_MESSAGE;
|
|
2178
2199
|
exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
|
|
2179
2200
|
exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2180
2201
|
exports.PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.149",
|
|
4
4
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"lint:fix": "eslint . --fix"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-core": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.149",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.149",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.149",
|
|
26
26
|
"@onekeyfe/react-native-ble-utils": "^0.1.6",
|
|
27
27
|
"react-native-ble-plx": "3.5.1"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "0c2b72c1edbafb2b738e3eb0b9ecdad8d8b92df7"
|
|
30
30
|
}
|
|
@@ -6,6 +6,7 @@ import ReactNativeBleTransport, {
|
|
|
6
6
|
BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD,
|
|
7
7
|
BLE_CONNECT_TIMEOUT_MS,
|
|
8
8
|
BLE_GATT_SETUP_TIMEOUT_MS,
|
|
9
|
+
BLE_SETUP_WEDGED_MESSAGE,
|
|
9
10
|
} from '../index';
|
|
10
11
|
import protocolV1Schema from './protocolV1SchemaFixture';
|
|
11
12
|
|
|
@@ -179,7 +180,7 @@ describe('BLE connect timeout', () => {
|
|
|
179
180
|
expect(bleManager.cancelDeviceConnection).toHaveBeenCalledWith(UUID);
|
|
180
181
|
});
|
|
181
182
|
|
|
182
|
-
test('repeated stalled connects recreate the BLE manager', async () => {
|
|
183
|
+
test('repeated stalled connects recreate the BLE manager and stop with PollingTimeout', async () => {
|
|
183
184
|
const { transport, bleManager } = createHarness(
|
|
184
185
|
() =>
|
|
185
186
|
new Promise(() => {
|
|
@@ -188,10 +189,12 @@ describe('BLE connect timeout', () => {
|
|
|
188
189
|
);
|
|
189
190
|
const destroy = jest.fn();
|
|
190
191
|
(bleManager as unknown as { destroy: jest.Mock }).destroy = destroy;
|
|
192
|
+
const errors: Array<{ errorCode?: unknown; message?: unknown }> = [];
|
|
191
193
|
|
|
192
194
|
for (let attempt = 0; attempt < BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD; attempt += 1) {
|
|
193
195
|
let settled = false;
|
|
194
|
-
transport.acquire({ uuid: UUID }).catch(
|
|
196
|
+
transport.acquire({ uuid: UUID }).catch(error => {
|
|
197
|
+
errors.push(error);
|
|
195
198
|
settled = true;
|
|
196
199
|
});
|
|
197
200
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -202,6 +205,11 @@ describe('BLE connect timeout', () => {
|
|
|
202
205
|
|
|
203
206
|
expect(destroy).toHaveBeenCalledTimes(1);
|
|
204
207
|
expect((transport as unknown as { blePlxManager?: unknown }).blePlxManager).toBeUndefined();
|
|
208
|
+
expect(errors[0]?.errorCode).toBe(HardwareErrorCode.BleConnectedError);
|
|
209
|
+
expect(errors[1]).toMatchObject({
|
|
210
|
+
errorCode: HardwareErrorCode.PollingTimeout,
|
|
211
|
+
message: BLE_SETUP_WEDGED_MESSAGE,
|
|
212
|
+
});
|
|
205
213
|
});
|
|
206
214
|
|
|
207
215
|
test('a recreated BLE manager starts with fresh timeout budgets for every device', () => {
|
|
@@ -224,12 +232,15 @@ describe('BLE connect timeout', () => {
|
|
|
224
232
|
errorCode: BleErrorCode.OperationTimedOut,
|
|
225
233
|
});
|
|
226
234
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
).
|
|
232
|
-
|
|
235
|
+
await expect(
|
|
236
|
+
(transport as any).connectWithTimeout(UUID, () => Promise.reject(nativeTimeout))
|
|
237
|
+
).rejects.toBe(nativeTimeout);
|
|
238
|
+
await expect(
|
|
239
|
+
(transport as any).connectWithTimeout(UUID, () => Promise.reject(nativeTimeout))
|
|
240
|
+
).rejects.toMatchObject({
|
|
241
|
+
errorCode: HardwareErrorCode.PollingTimeout,
|
|
242
|
+
message: BLE_SETUP_WEDGED_MESSAGE,
|
|
243
|
+
});
|
|
233
244
|
|
|
234
245
|
expect(destroy).toHaveBeenCalledTimes(1);
|
|
235
246
|
});
|
|
@@ -405,7 +405,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
405
405
|
await transport.release(uuid, true);
|
|
406
406
|
});
|
|
407
407
|
|
|
408
|
-
test('
|
|
408
|
+
test('detects Protocol V2 on iOS without using the BLE name as a protocol hint', async () => {
|
|
409
409
|
const { transport, uuid, device, sentSeqs, writeCharacteristic } = createHarness({
|
|
410
410
|
deviceName: 'Pro2 6E9E',
|
|
411
411
|
});
|
|
@@ -415,15 +415,68 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
415
415
|
protocolType: 'V2',
|
|
416
416
|
});
|
|
417
417
|
expect(device.requestMTU).toHaveBeenCalledWith(247);
|
|
418
|
-
expect(writeCharacteristic.writeWithResponse).
|
|
418
|
+
expect(writeCharacteristic.writeWithResponse.mock.calls.length).toBeGreaterThan(1);
|
|
419
419
|
|
|
420
420
|
await expect(
|
|
421
421
|
transport.call(uuid, 'Ping', { message: 'first-core-command' })
|
|
422
422
|
).resolves.toBeDefined();
|
|
423
|
-
expect(sentSeqs).toEqual([1, 2]);
|
|
423
|
+
expect(sentSeqs.filter(seq => seq > 0)).toEqual([1, 2]);
|
|
424
424
|
await transport.release(uuid, true);
|
|
425
425
|
});
|
|
426
426
|
|
|
427
|
+
test.each(['ios', 'android'] as const)(
|
|
428
|
+
'keeps a first expected Protocol V2 probe miss retryable on %s',
|
|
429
|
+
async platform => {
|
|
430
|
+
setPlatformOS(platform);
|
|
431
|
+
const { transport, uuid, device } = createHarness();
|
|
432
|
+
jest.spyOn(transport as any, 'probeProtocolV2').mockResolvedValue(false);
|
|
433
|
+
|
|
434
|
+
await expect(transport.acquire({ uuid, expectedProtocol: 'V2' })).rejects.toMatchObject({
|
|
435
|
+
errorCode: HardwareErrorCode.RuntimeError,
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
expect(device.cancelConnection).not.toHaveBeenCalled();
|
|
439
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
440
|
+
}
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
test.each(['ios', 'android'] as const)(
|
|
444
|
+
'keeps a second expected Protocol V2 probe miss retryable on %s',
|
|
445
|
+
async platform => {
|
|
446
|
+
setPlatformOS(platform);
|
|
447
|
+
const { transport, uuid, device } = createHarness();
|
|
448
|
+
jest.spyOn(transport as any, 'probeProtocolV2').mockResolvedValue(false);
|
|
449
|
+
|
|
450
|
+
await expect(transport.acquire({ uuid, expectedProtocol: 'V2' })).rejects.toMatchObject({
|
|
451
|
+
errorCode: HardwareErrorCode.RuntimeError,
|
|
452
|
+
});
|
|
453
|
+
await expect(transport.acquire({ uuid, expectedProtocol: 'V2' })).rejects.toMatchObject({
|
|
454
|
+
errorCode: HardwareErrorCode.RuntimeError,
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
expect(device.cancelConnection).not.toHaveBeenCalled();
|
|
458
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
459
|
+
}
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
test.each(['ios', 'android'] as const)(
|
|
463
|
+
'reports a stale bond on %s when a previously confirmed Protocol V2 device stops responding',
|
|
464
|
+
async platform => {
|
|
465
|
+
setPlatformOS(platform);
|
|
466
|
+
const { transport, uuid, device } = createHarness();
|
|
467
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
468
|
+
await transport.release(uuid, true);
|
|
469
|
+
jest.spyOn(transport as any, 'probeProtocolV2').mockResolvedValue(false);
|
|
470
|
+
|
|
471
|
+
await expect(transport.acquire({ uuid, expectedProtocol: 'V2' })).rejects.toMatchObject({
|
|
472
|
+
errorCode: HardwareErrorCode.BleDeviceBondError,
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
expect(device.cancelConnection).toHaveBeenCalled();
|
|
476
|
+
expect(transport.getProtocolType(uuid)).toBeUndefined();
|
|
477
|
+
}
|
|
478
|
+
);
|
|
479
|
+
|
|
427
480
|
test('waits for an in-flight release before reacquiring the same device', async () => {
|
|
428
481
|
const { transport, uuid } = createHarness();
|
|
429
482
|
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
package/src/index.ts
CHANGED
|
@@ -203,10 +203,6 @@ export function getProtocolV2BleTuning() {
|
|
|
203
203
|
return { ...protocolV2BleTuning };
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
function inferProtocolHintFromDeviceName(name?: string | null): ProtocolType | undefined {
|
|
207
|
-
return /\bpro\s*2\b/i.test(name ?? '') ? 'V2' : undefined;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
206
|
function getDeviceDisplayName(device?: Device | null) {
|
|
211
207
|
return device?.name || device?.localName || null;
|
|
212
208
|
}
|
|
@@ -258,10 +254,17 @@ export const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
|
258
254
|
/** BLE setup timeouts since the last successful setup before the manager is recreated. */
|
|
259
255
|
export const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
260
256
|
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
257
|
+
export const BLE_SETUP_WEDGED_MESSAGE = 'BLE setup wedged repeatedly';
|
|
261
258
|
const isConnectTimeoutError = (error: unknown): boolean =>
|
|
262
259
|
(error as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleConnectedError &&
|
|
263
260
|
typeof (error as { message?: unknown })?.message === 'string' &&
|
|
264
261
|
(error as { message: string }).message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
262
|
+
const isWedgedBleSetupError = (error: unknown): boolean =>
|
|
263
|
+
(error as { errorCode?: unknown })?.errorCode === HardwareErrorCode.PollingTimeout &&
|
|
264
|
+
typeof (error as { message?: unknown })?.message === 'string' &&
|
|
265
|
+
(error as { message: string }).message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
266
|
+
const shouldRethrowBleSetupError = (error: unknown): boolean =>
|
|
267
|
+
isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
265
268
|
const isNativeOperationTimeoutError = (error: unknown): boolean =>
|
|
266
269
|
(error as { errorCode?: unknown })?.errorCode === BleErrorCode.OperationTimedOut;
|
|
267
270
|
|
|
@@ -381,6 +384,9 @@ export default class ReactNativeBleTransport {
|
|
|
381
384
|
/** Protocol this device actually answered on, kept across reconnects of one session. */
|
|
382
385
|
private sessionProtocols: Map<string, ProtocolType> = new Map();
|
|
383
386
|
|
|
387
|
+
/** Endpoints that answered a V2 probe in this transport lifetime. Survives disconnect. */
|
|
388
|
+
private confirmedProtocolV2 = new Set<string>();
|
|
389
|
+
|
|
384
390
|
/** Consecutive detections that failed while trusting sessionProtocols. */
|
|
385
391
|
private protocolReprobeFailures: Map<string, number> = new Map();
|
|
386
392
|
|
|
@@ -765,10 +771,7 @@ export default class ReactNativeBleTransport {
|
|
|
765
771
|
const addDevice = (device: Device) => {
|
|
766
772
|
if (deviceList.every(d => d.id !== device.id)) {
|
|
767
773
|
const displayName = getDeviceDisplayName(device) ?? 'Unknown BLE Device';
|
|
768
|
-
|
|
769
|
-
if (protocolHint) {
|
|
770
|
-
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
771
|
-
}
|
|
774
|
+
|
|
772
775
|
deviceList.push({
|
|
773
776
|
...device,
|
|
774
777
|
name: displayName,
|
|
@@ -778,7 +781,6 @@ export default class ReactNativeBleTransport {
|
|
|
778
781
|
deviceId: device.id,
|
|
779
782
|
name: displayName,
|
|
780
783
|
serviceUUIDs: device.serviceUUIDs,
|
|
781
|
-
protocolHint,
|
|
782
784
|
});
|
|
783
785
|
}
|
|
784
786
|
};
|
|
@@ -944,7 +946,7 @@ export default class ReactNativeBleTransport {
|
|
|
944
946
|
);
|
|
945
947
|
} catch (e) {
|
|
946
948
|
Log?.debug('try to connect to device has error: ', e);
|
|
947
|
-
if (
|
|
949
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
948
950
|
throw e;
|
|
949
951
|
}
|
|
950
952
|
if (
|
|
@@ -978,7 +980,7 @@ export default class ReactNativeBleTransport {
|
|
|
978
980
|
);
|
|
979
981
|
} catch (e) {
|
|
980
982
|
Log?.debug('not connected, try to connect to device has error: ', e);
|
|
981
|
-
if (
|
|
983
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
982
984
|
throw e;
|
|
983
985
|
}
|
|
984
986
|
if (
|
|
@@ -1015,9 +1017,7 @@ export default class ReactNativeBleTransport {
|
|
|
1015
1017
|
|
|
1016
1018
|
const protocolHint = expectedProtocol
|
|
1017
1019
|
? undefined
|
|
1018
|
-
: input.protocolHint ??
|
|
1019
|
-
this.deviceProtocolHints.get(uuid) ??
|
|
1020
|
-
inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
|
|
1020
|
+
: input.protocolHint ?? this.deviceProtocolHints.get(uuid);
|
|
1021
1021
|
|
|
1022
1022
|
// release transport before new transport instance
|
|
1023
1023
|
await this.releaseUnlocked(uuid, true);
|
|
@@ -1046,7 +1046,11 @@ export default class ReactNativeBleTransport {
|
|
|
1046
1046
|
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
1047
1047
|
return { uuid, protocolType };
|
|
1048
1048
|
} catch (error) {
|
|
1049
|
-
|
|
1049
|
+
if ((error as { errorCode?: unknown })?.errorCode === HardwareErrorCode.BleDeviceBondError) {
|
|
1050
|
+
await this.disconnectUnlocked(uuid);
|
|
1051
|
+
} else {
|
|
1052
|
+
await this.releaseUnlocked(uuid, true);
|
|
1053
|
+
}
|
|
1050
1054
|
throw error;
|
|
1051
1055
|
}
|
|
1052
1056
|
}
|
|
@@ -1244,7 +1248,7 @@ export default class ReactNativeBleTransport {
|
|
|
1244
1248
|
|
|
1245
1249
|
this.deviceProtocol.delete(uuid);
|
|
1246
1250
|
this.probingProtocols.delete(uuid);
|
|
1247
|
-
//
|
|
1251
|
+
// Confirmed protocol and caller hints stay in deviceProtocol / protocolHint.
|
|
1248
1252
|
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1249
1253
|
this.protocolV2Assemblers.delete(uuid);
|
|
1250
1254
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -1757,7 +1761,13 @@ export default class ReactNativeBleTransport {
|
|
|
1757
1761
|
return result;
|
|
1758
1762
|
} catch (error) {
|
|
1759
1763
|
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1760
|
-
this.abandonStalledConnection(
|
|
1764
|
+
const resetManager = this.abandonStalledConnection(
|
|
1765
|
+
uuid,
|
|
1766
|
+
timedOut ? 'connect-backstop' : 'connect-native'
|
|
1767
|
+
);
|
|
1768
|
+
if (resetManager) {
|
|
1769
|
+
throw this.createWedgedBleSetupError();
|
|
1770
|
+
}
|
|
1761
1771
|
}
|
|
1762
1772
|
throw error;
|
|
1763
1773
|
} finally {
|
|
@@ -1793,7 +1803,13 @@ export default class ReactNativeBleTransport {
|
|
|
1793
1803
|
return result;
|
|
1794
1804
|
} catch (error) {
|
|
1795
1805
|
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1796
|
-
this.abandonStalledConnection(
|
|
1806
|
+
const resetManager = this.abandonStalledConnection(
|
|
1807
|
+
uuid,
|
|
1808
|
+
timedOut ? 'gatt-backstop' : 'gatt-native'
|
|
1809
|
+
);
|
|
1810
|
+
if (resetManager) {
|
|
1811
|
+
throw this.createWedgedBleSetupError();
|
|
1812
|
+
}
|
|
1797
1813
|
}
|
|
1798
1814
|
throw error;
|
|
1799
1815
|
} finally {
|
|
@@ -1805,11 +1821,12 @@ export default class ReactNativeBleTransport {
|
|
|
1805
1821
|
* Give up on a BLE setup operation the native layer did not settle. The abandoned
|
|
1806
1822
|
* operation still owns native connection/GATT state that can poison the next attempt,
|
|
1807
1823
|
* so it is cleared here without awaiting the same queue that stopped responding.
|
|
1824
|
+
* Returns true when the manager itself was reset so the caller can stop Core retries.
|
|
1808
1825
|
*/
|
|
1809
1826
|
private abandonStalledConnection(
|
|
1810
1827
|
uuid: string,
|
|
1811
1828
|
stage: 'connect-backstop' | 'connect-native' | 'gatt-backstop' | 'gatt-native'
|
|
1812
|
-
) {
|
|
1829
|
+
): boolean {
|
|
1813
1830
|
const timeouts = (this.connectionSetupTimeoutCounts.get(uuid) ?? 0) + 1;
|
|
1814
1831
|
this.connectionSetupTimeoutCounts.set(uuid, timeouts);
|
|
1815
1832
|
Log?.error('[ReactNativeBleTransport] BLE setup timed out:', uuid, {
|
|
@@ -1835,7 +1852,15 @@ export default class ReactNativeBleTransport {
|
|
|
1835
1852
|
Log?.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
|
|
1836
1853
|
this.resetPlxManager();
|
|
1837
1854
|
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1855
|
+
return true;
|
|
1838
1856
|
}
|
|
1857
|
+
return false;
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
private createWedgedBleSetupError() {
|
|
1861
|
+
// PollingTimeout is not retried by connectDeviceForBle and already maps
|
|
1862
|
+
// to the App "connection failed" help text.
|
|
1863
|
+
return ERRORS.TypedError(HardwareErrorCode.PollingTimeout, BLE_SETUP_WEDGED_MESSAGE);
|
|
1839
1864
|
}
|
|
1840
1865
|
|
|
1841
1866
|
private getCachedTransport(uuid: string) {
|
|
@@ -1965,6 +1990,7 @@ export default class ReactNativeBleTransport {
|
|
|
1965
1990
|
this.deviceProtocol.clear();
|
|
1966
1991
|
this.probingProtocols.clear();
|
|
1967
1992
|
this.sessionProtocols.clear();
|
|
1993
|
+
this.confirmedProtocolV2.clear();
|
|
1968
1994
|
this.protocolReprobeFailures.clear();
|
|
1969
1995
|
this.writeTimeoutCounts.clear();
|
|
1970
1996
|
this.connectionSetupTimeoutCounts.clear();
|
|
@@ -1977,9 +2003,12 @@ export default class ReactNativeBleTransport {
|
|
|
1977
2003
|
}
|
|
1978
2004
|
}
|
|
1979
2005
|
|
|
1980
|
-
private createProtocolMismatchError(expected: ProtocolType) {
|
|
2006
|
+
private createProtocolMismatchError(expected: ProtocolType, uuid: string) {
|
|
2007
|
+
// A generic Ping miss is not a bond failure. Only a later miss after this
|
|
2008
|
+
// endpoint already answered V2, or a native encryption/pairing error, is.
|
|
2009
|
+
const isStaleV2Bond = expected === 'V2' && this.confirmedProtocolV2.has(uuid);
|
|
1981
2010
|
return ERRORS.TypedError(
|
|
1982
|
-
HardwareErrorCode.RuntimeError,
|
|
2011
|
+
isStaleV2Bond ? HardwareErrorCode.BleDeviceBondError : HardwareErrorCode.RuntimeError,
|
|
1983
2012
|
`Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`
|
|
1984
2013
|
);
|
|
1985
2014
|
}
|
|
@@ -2035,13 +2064,14 @@ export default class ReactNativeBleTransport {
|
|
|
2035
2064
|
});
|
|
2036
2065
|
return 'V1';
|
|
2037
2066
|
}
|
|
2038
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
2067
|
+
throw this.createProtocolMismatchError(expectedProtocol, uuid);
|
|
2039
2068
|
}
|
|
2040
2069
|
|
|
2041
2070
|
if (expectedProtocol === 'V2') {
|
|
2042
2071
|
if (await this.probeProtocolV2(uuid)) {
|
|
2043
2072
|
this.deviceProtocol.set(uuid, 'V2');
|
|
2044
2073
|
this.sessionProtocols.set(uuid, 'V2');
|
|
2074
|
+
this.confirmedProtocolV2.add(uuid);
|
|
2045
2075
|
Log?.debug('[ReactNativeBleTransport] protocol detected', {
|
|
2046
2076
|
deviceId: uuid,
|
|
2047
2077
|
protocol: 'V2',
|
|
@@ -2049,7 +2079,7 @@ export default class ReactNativeBleTransport {
|
|
|
2049
2079
|
});
|
|
2050
2080
|
return 'V2';
|
|
2051
2081
|
}
|
|
2052
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
2082
|
+
throw this.createProtocolMismatchError(expectedProtocol, uuid);
|
|
2053
2083
|
}
|
|
2054
2084
|
|
|
2055
2085
|
// Protocol must be actively probed after connection. Name, PID, and descriptors only
|
|
@@ -2084,6 +2114,9 @@ export default class ReactNativeBleTransport {
|
|
|
2084
2114
|
if (detected) {
|
|
2085
2115
|
this.deviceProtocol.set(uuid, protocol);
|
|
2086
2116
|
this.sessionProtocols.set(uuid, protocol);
|
|
2117
|
+
if (protocol === 'V2') {
|
|
2118
|
+
this.confirmedProtocolV2.add(uuid);
|
|
2119
|
+
}
|
|
2087
2120
|
this.protocolReprobeFailures.delete(uuid);
|
|
2088
2121
|
Log?.debug('[ReactNativeBleTransport] protocol detected', {
|
|
2089
2122
|
deviceId: uuid,
|