@onekeyfe/hd-transport-react-native 1.2.0-alpha.8 → 1.2.0-alpha.9
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 +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +137 -117
- package/package.json +5 -5
- package/src/__tests__/protocolV2Link.test.ts +237 -0
- package/src/index.ts +138 -102
package/dist/index.d.ts
CHANGED
|
@@ -69,8 +69,7 @@ declare class ReactNativeBleTransport {
|
|
|
69
69
|
private protocolV2Assemblers;
|
|
70
70
|
private protocolV2FrameQueues;
|
|
71
71
|
private protocolV2FramePromises;
|
|
72
|
-
private
|
|
73
|
-
private nextProtocolV2CallToken;
|
|
72
|
+
private protocolV2Links;
|
|
74
73
|
private monitorTokens;
|
|
75
74
|
private nextMonitorToken;
|
|
76
75
|
constructor(options: TransportOptions);
|
|
@@ -108,10 +107,11 @@ declare class ReactNativeBleTransport {
|
|
|
108
107
|
private resolveProtocolV2Frame;
|
|
109
108
|
private rejectAllProtocolV2Frames;
|
|
110
109
|
private resetProtocolV2Frames;
|
|
111
|
-
private
|
|
110
|
+
private rejectProtocolV2Frames;
|
|
112
111
|
private readProtocolV2Frame;
|
|
113
112
|
private writeProtocolV2Frame;
|
|
114
113
|
private callProtocolV2;
|
|
114
|
+
private createProtocolV2Adapter;
|
|
115
115
|
getProtocolType(path: string): ProtocolType | undefined;
|
|
116
116
|
}
|
|
117
117
|
|
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,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAEhB,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -414,8 +414,27 @@ class ReactNativeBleTransport {
|
|
|
414
414
|
this.protocolV2Assemblers = new Map();
|
|
415
415
|
this.protocolV2FrameQueues = new Map();
|
|
416
416
|
this.protocolV2FramePromises = new Map();
|
|
417
|
-
this.
|
|
418
|
-
|
|
417
|
+
this.protocolV2Links = new transport.ProtocolV2LinkManager({
|
|
418
|
+
getSchemas: () => {
|
|
419
|
+
if (!this._messages || !this._messagesV2) {
|
|
420
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
protocolV1: this._messages,
|
|
424
|
+
protocolV2: this._messagesV2,
|
|
425
|
+
};
|
|
426
|
+
},
|
|
427
|
+
classifyError: () => 'link-fatal',
|
|
428
|
+
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
429
|
+
var _b;
|
|
430
|
+
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
431
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
432
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
433
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
434
|
+
yield this.release(uuid, true);
|
|
435
|
+
}
|
|
436
|
+
}),
|
|
437
|
+
});
|
|
419
438
|
this.monitorTokens = new Map();
|
|
420
439
|
this.nextMonitorToken = 1;
|
|
421
440
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
@@ -431,6 +450,9 @@ class ReactNativeBleTransport {
|
|
|
431
450
|
}
|
|
432
451
|
configureProtocolV2(signedData) {
|
|
433
452
|
this._messagesV2 = parseConfigure(signedData);
|
|
453
|
+
this.protocolV2Links
|
|
454
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
455
|
+
.catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
|
|
434
456
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
|
|
435
457
|
}
|
|
436
458
|
listen() {
|
|
@@ -729,7 +751,6 @@ class ReactNativeBleTransport {
|
|
|
729
751
|
this.runPromise.reject(error);
|
|
730
752
|
this.rejectAllProtocolV2Frames(error);
|
|
731
753
|
this.runPromise = null;
|
|
732
|
-
this.activeProtocolV2Call = null;
|
|
733
754
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
734
755
|
}
|
|
735
756
|
const blePlxManager = yield this.getPlxManager();
|
|
@@ -854,7 +875,7 @@ class ReactNativeBleTransport {
|
|
|
854
875
|
let bufferLength = 0;
|
|
855
876
|
let buffer$1 = [];
|
|
856
877
|
const subscription = characteristic.monitor((error, c) => {
|
|
857
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
878
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
858
879
|
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
859
880
|
if (error) {
|
|
860
881
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
@@ -866,19 +887,37 @@ class ReactNativeBleTransport {
|
|
|
866
887
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
867
888
|
return;
|
|
868
889
|
}
|
|
869
|
-
if (this.
|
|
870
|
-
let
|
|
890
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
891
|
+
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
871
892
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
872
|
-
|
|
893
|
+
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
873
894
|
}
|
|
874
|
-
if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
875
|
-
|
|
895
|
+
else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
896
|
+
errorCode = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
876
897
|
}
|
|
877
|
-
if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
898
|
+
else if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
878
899
|
((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('Cannot find client characteristic config descriptor')) ||
|
|
879
900
|
((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
|
|
880
901
|
((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
|
|
881
902
|
((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
|
|
903
|
+
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
904
|
+
}
|
|
905
|
+
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
if (this.runPromise) {
|
|
909
|
+
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
910
|
+
if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
|
|
911
|
+
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
912
|
+
}
|
|
913
|
+
if ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Encryption is insufficient')) {
|
|
914
|
+
ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
915
|
+
}
|
|
916
|
+
if (((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('Cannot write client characteristic config descriptor')) ||
|
|
917
|
+
((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Cannot find client characteristic config descriptor')) ||
|
|
918
|
+
((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
|
|
919
|
+
((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
|
|
920
|
+
((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
|
|
882
921
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
883
922
|
this.runPromise.reject(notifyError);
|
|
884
923
|
this.rejectAllProtocolV2Frames(notifyError);
|
|
@@ -907,7 +946,7 @@ class ReactNativeBleTransport {
|
|
|
907
946
|
return;
|
|
908
947
|
}
|
|
909
948
|
if (protocol === 'V2') {
|
|
910
|
-
this.handleProtocolV2Notification(uuid, new Uint8Array(data));
|
|
949
|
+
this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
|
|
911
950
|
return;
|
|
912
951
|
}
|
|
913
952
|
if (isHeaderChunk(data)) {
|
|
@@ -921,28 +960,32 @@ class ReactNativeBleTransport {
|
|
|
921
960
|
const value = buffer.Buffer.from(buffer$1);
|
|
922
961
|
bufferLength = 0;
|
|
923
962
|
buffer$1 = [];
|
|
924
|
-
(
|
|
963
|
+
(_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
|
|
925
964
|
}
|
|
926
965
|
}
|
|
927
966
|
catch (error) {
|
|
928
967
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
929
968
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
930
|
-
(
|
|
931
|
-
|
|
969
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
970
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
971
|
+
}
|
|
972
|
+
else {
|
|
973
|
+
(_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
|
|
974
|
+
}
|
|
932
975
|
}
|
|
933
976
|
}, notifyTransactionId);
|
|
934
977
|
return subscription;
|
|
935
978
|
}
|
|
936
979
|
release(uuid, onclose = false) {
|
|
937
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
980
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
938
981
|
return __awaiter(this, void 0, void 0, function* () {
|
|
939
982
|
const transport = transportCache[uuid];
|
|
983
|
+
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
940
984
|
if (this.runPromise) {
|
|
941
985
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
942
986
|
this.runPromise.reject(error);
|
|
943
987
|
this.runPromise = null;
|
|
944
988
|
this.rejectAllProtocolV2Frames(error);
|
|
945
|
-
this.activeProtocolV2Call = null;
|
|
946
989
|
}
|
|
947
990
|
else {
|
|
948
991
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -950,9 +993,6 @@ class ReactNativeBleTransport {
|
|
|
950
993
|
if (reactNative.Platform.OS === 'android' && !onclose && transport) {
|
|
951
994
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
952
995
|
this.resetProtocolV2Frames(uuid);
|
|
953
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
954
|
-
this.activeProtocolV2Call = null;
|
|
955
|
-
}
|
|
956
996
|
return Promise.resolve(true);
|
|
957
997
|
}
|
|
958
998
|
if (transport) {
|
|
@@ -960,14 +1000,14 @@ class ReactNativeBleTransport {
|
|
|
960
1000
|
this.monitorTokens.delete(uuid);
|
|
961
1001
|
}
|
|
962
1002
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
|
|
963
|
-
(
|
|
1003
|
+
(_b = transport.disconnectSubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
964
1004
|
transport.disconnectSubscription = undefined;
|
|
965
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (
|
|
966
|
-
(
|
|
1005
|
+
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);
|
|
1006
|
+
(_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
|
|
967
1007
|
transport.notifySubscription = undefined;
|
|
968
1008
|
if (transport.notifyTransactionId) {
|
|
969
1009
|
try {
|
|
970
|
-
yield ((
|
|
1010
|
+
yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
|
|
971
1011
|
}
|
|
972
1012
|
catch (e) {
|
|
973
1013
|
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);
|
|
@@ -976,12 +1016,11 @@ class ReactNativeBleTransport {
|
|
|
976
1016
|
delete transportCache[uuid];
|
|
977
1017
|
}
|
|
978
1018
|
this.deviceProtocol.delete(uuid);
|
|
979
|
-
this.
|
|
980
|
-
(_g = this.protocolV2Assemblers.get(uuid)) === null || _g === void 0 ? void 0 : _g.reset();
|
|
1019
|
+
(_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
|
|
981
1020
|
this.protocolV2Assemblers.delete(uuid);
|
|
982
1021
|
this.resetProtocolV2Frames(uuid);
|
|
983
1022
|
try {
|
|
984
|
-
yield ((
|
|
1023
|
+
yield ((_g = this.blePlxManager) === null || _g === void 0 ? void 0 : _g.cancelTransaction(uuid));
|
|
985
1024
|
}
|
|
986
1025
|
catch (e) {
|
|
987
1026
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1002,11 +1041,6 @@ class ReactNativeBleTransport {
|
|
|
1002
1041
|
if (this._messages == null) {
|
|
1003
1042
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1004
1043
|
}
|
|
1005
|
-
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1006
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native call this.runPromise', this.runPromise);
|
|
1007
|
-
if (this.runPromise && !forceRun) {
|
|
1008
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1009
|
-
}
|
|
1010
1044
|
const protocol = this.getProtocolType(uuid);
|
|
1011
1045
|
if (!protocol) {
|
|
1012
1046
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
@@ -1026,6 +1060,11 @@ class ReactNativeBleTransport {
|
|
|
1026
1060
|
if (protocol === 'V2') {
|
|
1027
1061
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1028
1062
|
}
|
|
1063
|
+
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1064
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native call this.runPromise', this.runPromise);
|
|
1065
|
+
if (this.runPromise && !forceRun) {
|
|
1066
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1067
|
+
}
|
|
1029
1068
|
return this.callProtocolV1(uuid, name, data, options);
|
|
1030
1069
|
});
|
|
1031
1070
|
}
|
|
@@ -1216,9 +1255,10 @@ class ReactNativeBleTransport {
|
|
|
1216
1255
|
this.stopped = true;
|
|
1217
1256
|
}
|
|
1218
1257
|
disconnect(session) {
|
|
1219
|
-
var _a, _b, _c, _d, _e
|
|
1258
|
+
var _a, _b, _c, _d, _e;
|
|
1220
1259
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1221
1260
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport resetSession: ', session);
|
|
1261
|
+
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1222
1262
|
const transport = transportCache[session];
|
|
1223
1263
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
1224
1264
|
try {
|
|
@@ -1269,12 +1309,9 @@ class ReactNativeBleTransport {
|
|
|
1269
1309
|
this.deviceProtocolHints.delete(session);
|
|
1270
1310
|
this.protocolV2Assemblers.delete(session);
|
|
1271
1311
|
this.resetProtocolV2Frames(session);
|
|
1272
|
-
if (((_d = this.activeProtocolV2Call) === null || _d === void 0 ? void 0 : _d.uuid) === session) {
|
|
1273
|
-
this.activeProtocolV2Call = null;
|
|
1274
|
-
}
|
|
1275
1312
|
try {
|
|
1276
|
-
(
|
|
1277
|
-
name: (
|
|
1313
|
+
(_d = this.emitter) === null || _d === void 0 ? void 0 : _d.emit('device-disconnect', {
|
|
1314
|
+
name: (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name,
|
|
1278
1315
|
id: session,
|
|
1279
1316
|
connectId: session,
|
|
1280
1317
|
});
|
|
@@ -1341,14 +1378,12 @@ class ReactNativeBleTransport {
|
|
|
1341
1378
|
});
|
|
1342
1379
|
}
|
|
1343
1380
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1344
|
-
var _a, _b, _c
|
|
1381
|
+
var _a, _b, _c;
|
|
1345
1382
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1346
1383
|
const transport = transportCache[uuid];
|
|
1384
|
+
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1347
1385
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1348
1386
|
this.resetProtocolV2Frames(uuid);
|
|
1349
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
1350
|
-
this.activeProtocolV2Call = null;
|
|
1351
|
-
}
|
|
1352
1387
|
if (this.runPromise) {
|
|
1353
1388
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1354
1389
|
this.runPromise.reject(error);
|
|
@@ -1360,11 +1395,11 @@ class ReactNativeBleTransport {
|
|
|
1360
1395
|
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
1361
1396
|
this.monitorTokens.delete(uuid);
|
|
1362
1397
|
}
|
|
1363
|
-
(
|
|
1398
|
+
(_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1364
1399
|
transport.notifySubscription = undefined;
|
|
1365
1400
|
if (previousNotifyTransactionId) {
|
|
1366
1401
|
try {
|
|
1367
|
-
yield ((
|
|
1402
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(previousNotifyTransactionId));
|
|
1368
1403
|
}
|
|
1369
1404
|
catch (error) {
|
|
1370
1405
|
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] cancel notify after Protocol ${protocol} probe failed:`, (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
@@ -1426,14 +1461,10 @@ class ReactNativeBleTransport {
|
|
|
1426
1461
|
return detected;
|
|
1427
1462
|
});
|
|
1428
1463
|
}
|
|
1429
|
-
handleProtocolV2Notification(uuid, data) {
|
|
1430
|
-
var _a, _b, _c;
|
|
1464
|
+
handleProtocolV2Notification(uuid, monitorToken, data) {
|
|
1431
1465
|
try {
|
|
1432
|
-
if (
|
|
1433
|
-
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1434
|
-
this.resetProtocolV2Frames(uuid);
|
|
1466
|
+
if (this.monitorTokens.get(uuid) !== monitorToken)
|
|
1435
1467
|
return;
|
|
1436
|
-
}
|
|
1437
1468
|
if (data.length === 0)
|
|
1438
1469
|
return;
|
|
1439
1470
|
const assembler = this.protocolV2Assemblers.get(uuid);
|
|
@@ -1446,8 +1477,10 @@ class ReactNativeBleTransport {
|
|
|
1446
1477
|
catch (error) {
|
|
1447
1478
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
|
|
1448
1479
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1449
|
-
|
|
1450
|
-
this.
|
|
1480
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1481
|
+
this.protocolV2Links
|
|
1482
|
+
.invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
|
|
1483
|
+
.catch(invalidateError => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notify cleanup failed:', invalidateError));
|
|
1451
1484
|
}
|
|
1452
1485
|
}
|
|
1453
1486
|
getProtocolV2FrameQueue(uuid) {
|
|
@@ -1478,9 +1511,13 @@ class ReactNativeBleTransport {
|
|
|
1478
1511
|
this.protocolV2FrameQueues.delete(uuid);
|
|
1479
1512
|
this.protocolV2FramePromises.delete(uuid);
|
|
1480
1513
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1514
|
+
rejectProtocolV2Frames(uuid, error) {
|
|
1515
|
+
this.protocolV2FrameQueues.delete(uuid);
|
|
1516
|
+
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1517
|
+
if (framePromise) {
|
|
1518
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1519
|
+
framePromise.reject(error);
|
|
1520
|
+
}
|
|
1484
1521
|
}
|
|
1485
1522
|
readProtocolV2Frame(uuid) {
|
|
1486
1523
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1535,32 +1572,12 @@ class ReactNativeBleTransport {
|
|
|
1535
1572
|
});
|
|
1536
1573
|
}
|
|
1537
1574
|
callProtocolV2(uuid, name, data, options) {
|
|
1538
|
-
var _a
|
|
1575
|
+
var _a;
|
|
1539
1576
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1540
1577
|
if (!this._messages || !this._messagesV2) {
|
|
1541
1578
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1542
1579
|
}
|
|
1543
|
-
const
|
|
1544
|
-
if (this.runPromise) {
|
|
1545
|
-
if (!forceRun) {
|
|
1546
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1547
|
-
}
|
|
1548
|
-
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1549
|
-
this.runPromise.reject(error);
|
|
1550
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1551
|
-
this.runPromise = null;
|
|
1552
|
-
this.activeProtocolV2Call = null;
|
|
1553
|
-
}
|
|
1554
|
-
const transport$1 = this.getCachedTransport(uuid);
|
|
1555
|
-
const runPromise = hdShared.createDeferred();
|
|
1556
|
-
runPromise.promise.catch(() => undefined);
|
|
1557
|
-
this.runPromise = runPromise;
|
|
1558
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1559
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1560
|
-
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1561
|
-
this.resetProtocolV2Frames(uuid);
|
|
1562
|
-
let completed = false;
|
|
1563
|
-
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
|
|
1580
|
+
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_a = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _a !== void 0 ? _a : BLE_RESPONSE_TIMEOUT_MS });
|
|
1564
1581
|
const highVolumeWrite = transport.LogBlockCommand.has(name);
|
|
1565
1582
|
if (highVolumeWrite) {
|
|
1566
1583
|
const tuning = getProtocolV2BleTuning();
|
|
@@ -1573,54 +1590,57 @@ class ReactNativeBleTransport {
|
|
|
1573
1590
|
});
|
|
1574
1591
|
}
|
|
1575
1592
|
try {
|
|
1576
|
-
|
|
1577
|
-
schemas: {
|
|
1578
|
-
protocolV1: this._messages,
|
|
1579
|
-
protocolV2: this._messagesV2,
|
|
1580
|
-
},
|
|
1581
|
-
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1582
|
-
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
1583
|
-
yield this.writeProtocolV2Frame(transport$1, frame, {
|
|
1584
|
-
highVolume: highVolumeWrite,
|
|
1585
|
-
});
|
|
1586
|
-
}),
|
|
1587
|
-
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1588
|
-
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1589
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
1590
|
-
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1591
|
-
}
|
|
1592
|
-
return rxFrame;
|
|
1593
|
-
}),
|
|
1594
|
-
logger: Log,
|
|
1595
|
-
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1596
|
-
createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
|
|
1597
|
-
});
|
|
1598
|
-
const result = yield session.call(name, data, callOptions);
|
|
1599
|
-
completed = true;
|
|
1600
|
-
return result;
|
|
1593
|
+
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1601
1594
|
}
|
|
1602
1595
|
catch (e) {
|
|
1603
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1604
|
-
(_c = this.protocolV2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1605
|
-
this.resetProtocolV2Frames(uuid);
|
|
1606
|
-
}
|
|
1607
1596
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1608
1597
|
throw e;
|
|
1609
1598
|
}
|
|
1610
|
-
finally {
|
|
1611
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1612
|
-
if (!completed) {
|
|
1613
|
-
(_d = this.protocolV2Assemblers.get(uuid)) === null || _d === void 0 ? void 0 : _d.reset();
|
|
1614
|
-
}
|
|
1615
|
-
this.resetProtocolV2Frames(uuid);
|
|
1616
|
-
this.activeProtocolV2Call = null;
|
|
1617
|
-
}
|
|
1618
|
-
if (this.runPromise === runPromise) {
|
|
1619
|
-
this.runPromise = null;
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
1599
|
});
|
|
1623
1600
|
}
|
|
1601
|
+
createProtocolV2Adapter(uuid) {
|
|
1602
|
+
var _a;
|
|
1603
|
+
const generation = (_a = this.monitorTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1604
|
+
const assertCurrentGeneration = () => {
|
|
1605
|
+
if (this.monitorTokens.get(uuid) !== generation) {
|
|
1606
|
+
throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
return {
|
|
1610
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1611
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1612
|
+
generation,
|
|
1613
|
+
prepareCall: () => {
|
|
1614
|
+
var _a;
|
|
1615
|
+
assertCurrentGeneration();
|
|
1616
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1617
|
+
this.resetProtocolV2Frames(uuid);
|
|
1618
|
+
},
|
|
1619
|
+
writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
|
|
1620
|
+
assertCurrentGeneration();
|
|
1621
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
1622
|
+
yield this.writeProtocolV2Frame(currentTransport, frame, {
|
|
1623
|
+
highVolume: context.highVolume,
|
|
1624
|
+
});
|
|
1625
|
+
}),
|
|
1626
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1627
|
+
assertCurrentGeneration();
|
|
1628
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1629
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1630
|
+
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1631
|
+
}
|
|
1632
|
+
return rxFrame;
|
|
1633
|
+
}),
|
|
1634
|
+
reset: (reason) => {
|
|
1635
|
+
var _a;
|
|
1636
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1637
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1638
|
+
},
|
|
1639
|
+
logger: Log,
|
|
1640
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1641
|
+
createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1624
1644
|
getProtocolType(path) {
|
|
1625
1645
|
return this.deviceProtocol.get(path);
|
|
1626
1646
|
}
|
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.9",
|
|
4
4
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"lint:fix": "eslint . --fix"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@onekeyfe/hd-core": "1.2.0-alpha.
|
|
23
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
22
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.9",
|
|
23
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.9",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.9",
|
|
25
25
|
"@onekeyfe/react-native-ble-utils": "^0.1.4",
|
|
26
26
|
"react-native-ble-plx": "3.5.1"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "f90ef9921b742f68cce9f4e7a0425e45e8ae7ec9"
|
|
29
29
|
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import transportPackage, {
|
|
3
|
+
PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
4
|
+
ProtocolV2,
|
|
5
|
+
bytesToHex,
|
|
6
|
+
} from '@onekeyfe/hd-transport';
|
|
7
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
8
|
+
|
|
9
|
+
import ReactNativeBleTransport from '../index';
|
|
10
|
+
|
|
11
|
+
jest.mock(
|
|
12
|
+
'react-native',
|
|
13
|
+
() => ({
|
|
14
|
+
PermissionsAndroid: {},
|
|
15
|
+
Platform: { OS: 'ios' },
|
|
16
|
+
}),
|
|
17
|
+
{ virtual: true }
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
jest.mock('react-native-ble-plx', () => ({
|
|
21
|
+
BleATTErrorCode: { UnlikelyError: 14 },
|
|
22
|
+
BleError: class BleError extends Error {},
|
|
23
|
+
BleErrorCode: {
|
|
24
|
+
DeviceAlreadyConnected: 203,
|
|
25
|
+
DeviceDisconnected: 205,
|
|
26
|
+
DeviceMTUChangeFailed: 206,
|
|
27
|
+
OperationCancelled: 2,
|
|
28
|
+
CharacteristicNotFound: 404,
|
|
29
|
+
},
|
|
30
|
+
BleManager: jest.fn(),
|
|
31
|
+
ScanMode: { LowLatency: 2 },
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
jest.mock('../BleManager', () => ({
|
|
35
|
+
getConnectedDeviceIds: jest.fn(() => Promise.resolve([])),
|
|
36
|
+
onDeviceBondState: jest.fn(() => Promise.resolve()),
|
|
37
|
+
pairDevice: jest.fn(() => Promise.resolve({ bonded: true, bonding: false })),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
jest.mock('../subscribeBleOn', () => ({
|
|
41
|
+
subscribeBleOn: jest.fn(() => Promise.resolve()),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
const { parseConfigure } = transportPackage;
|
|
45
|
+
|
|
46
|
+
const protocolV1Schema = {
|
|
47
|
+
nested: {
|
|
48
|
+
Initialize: { fields: {} },
|
|
49
|
+
Success: {
|
|
50
|
+
fields: {
|
|
51
|
+
message: { type: 'string', id: 1 },
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
MessageType: {
|
|
55
|
+
values: {
|
|
56
|
+
MessageType_Initialize: 1,
|
|
57
|
+
MessageType_Success: 2,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const protocolV2Schema = {
|
|
64
|
+
nested: {
|
|
65
|
+
Ping: {
|
|
66
|
+
fields: {
|
|
67
|
+
message: { type: 'string', id: 1 },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
FileWrite: { fields: {} },
|
|
71
|
+
Success: {
|
|
72
|
+
fields: {
|
|
73
|
+
message: { type: 'string', id: 1 },
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
MessageType: {
|
|
77
|
+
values: {
|
|
78
|
+
MessageType_Ping: 60206,
|
|
79
|
+
MessageType_Success: 60207,
|
|
80
|
+
MessageType_FileWrite: 60805,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const schemas = {
|
|
87
|
+
protocolV1: parseConfigure(protocolV1Schema),
|
|
88
|
+
protocolV2: parseConfigure(protocolV2Schema),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const createHarness = () => {
|
|
92
|
+
const uuid = 'rn-pro2-id';
|
|
93
|
+
const sentSeqs: number[] = [];
|
|
94
|
+
let shouldRespond = true;
|
|
95
|
+
let notifyCallback:
|
|
96
|
+
| ((
|
|
97
|
+
error: (Error & { reason?: string }) | null,
|
|
98
|
+
characteristic: { value: string } | null
|
|
99
|
+
) => void)
|
|
100
|
+
| undefined;
|
|
101
|
+
const notifyCharacteristic = {
|
|
102
|
+
uuid: '0003',
|
|
103
|
+
deviceID: uuid,
|
|
104
|
+
isNotifiable: true,
|
|
105
|
+
monitor: jest.fn(callback => {
|
|
106
|
+
notifyCallback = callback;
|
|
107
|
+
return { remove: jest.fn() };
|
|
108
|
+
}),
|
|
109
|
+
};
|
|
110
|
+
const writeCharacteristic = {
|
|
111
|
+
uuid: '0002',
|
|
112
|
+
deviceID: uuid,
|
|
113
|
+
isWritableWithResponse: true,
|
|
114
|
+
isWritableWithoutResponse: true,
|
|
115
|
+
writeWithResponse: jest.fn((base64: string) => {
|
|
116
|
+
const frame = Buffer.from(base64, 'base64');
|
|
117
|
+
sentSeqs.push(frame[6]);
|
|
118
|
+
if (shouldRespond) {
|
|
119
|
+
const response = ProtocolV2.encodeFrame(
|
|
120
|
+
schemas,
|
|
121
|
+
'Success',
|
|
122
|
+
{ message: 'ok' },
|
|
123
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART }
|
|
124
|
+
);
|
|
125
|
+
notifyCallback?.(null, { value: Buffer.from(response).toString('base64') });
|
|
126
|
+
}
|
|
127
|
+
return Promise.resolve();
|
|
128
|
+
}),
|
|
129
|
+
writeWithoutResponse: jest.fn(async (base64: string) => {
|
|
130
|
+
await writeCharacteristic.writeWithResponse(base64);
|
|
131
|
+
}),
|
|
132
|
+
};
|
|
133
|
+
const device = {
|
|
134
|
+
id: uuid,
|
|
135
|
+
name: 'OneKey Pro 2',
|
|
136
|
+
localName: 'OneKey Pro 2',
|
|
137
|
+
serviceUUIDs: ['fffd'],
|
|
138
|
+
isConnected: jest.fn(() => Promise.resolve(true)),
|
|
139
|
+
onDisconnected: jest.fn(() => ({ remove: jest.fn() })),
|
|
140
|
+
};
|
|
141
|
+
const bleManager = {
|
|
142
|
+
devices: jest.fn(() => Promise.resolve([device])),
|
|
143
|
+
connectedDevices: jest.fn(() => Promise.resolve([])),
|
|
144
|
+
cancelTransaction: jest.fn(() => Promise.resolve()),
|
|
145
|
+
};
|
|
146
|
+
const transport = new ReactNativeBleTransport({ scanTimeout: 1 });
|
|
147
|
+
transport.blePlxManager = bleManager;
|
|
148
|
+
transport.resolveCharacteristics = jest.fn(() =>
|
|
149
|
+
Promise.resolve({ writeCharacteristic, notifyCharacteristic })
|
|
150
|
+
);
|
|
151
|
+
transport.init({ debug: jest.fn(), error: jest.fn() }, new EventEmitter());
|
|
152
|
+
transport.configure(protocolV1Schema);
|
|
153
|
+
transport.configureProtocolV2(protocolV2Schema);
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
transport,
|
|
157
|
+
uuid,
|
|
158
|
+
sentSeqs,
|
|
159
|
+
setShouldRespond(value: boolean) {
|
|
160
|
+
shouldRespond = value;
|
|
161
|
+
},
|
|
162
|
+
emitMonitorError(error: Error & { reason?: string }) {
|
|
163
|
+
notifyCallback?.(error, null);
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
169
|
+
test('keeps the Protocol V2 sequence across probe and the next call', async () => {
|
|
170
|
+
const { transport, uuid, sentSeqs } = createHarness();
|
|
171
|
+
|
|
172
|
+
await transport.acquire({ uuid });
|
|
173
|
+
await transport.call(uuid, 'Ping', { message: 'after-probe' });
|
|
174
|
+
|
|
175
|
+
expect(sentSeqs).toEqual([1, 2]);
|
|
176
|
+
expect(bytesToHex(new Uint8Array([sentSeqs[0], sentSeqs[1]]))).toBe('0102');
|
|
177
|
+
await transport.release(uuid, true);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('rejects the active Protocol V2 reader when the current monitor errors', async () => {
|
|
181
|
+
const harness = createHarness();
|
|
182
|
+
const { transport, uuid, sentSeqs } = harness;
|
|
183
|
+
await transport.acquire({ uuid });
|
|
184
|
+
harness.setShouldRespond(false);
|
|
185
|
+
|
|
186
|
+
const call = transport.call(uuid, 'Ping', { message: 'wait-for-monitor' }, { timeoutMs: 50 });
|
|
187
|
+
while (sentSeqs.length < 2) {
|
|
188
|
+
await Promise.resolve();
|
|
189
|
+
}
|
|
190
|
+
await new Promise(resolve => {
|
|
191
|
+
setTimeout(resolve, 0);
|
|
192
|
+
});
|
|
193
|
+
harness.emitMonitorError(Object.assign(new Error('monitor failed'), { reason: 'link lost' }));
|
|
194
|
+
|
|
195
|
+
await expect(call).rejects.toMatchObject({
|
|
196
|
+
errorCode: HardwareErrorCode.BleCharacteristicNotifyError,
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test('retains the sequence cursor when a new monitor generation is acquired', async () => {
|
|
201
|
+
const { transport, uuid, sentSeqs } = createHarness();
|
|
202
|
+
|
|
203
|
+
await transport.acquire({ uuid });
|
|
204
|
+
await transport.release(uuid, true);
|
|
205
|
+
await transport.acquire({ uuid });
|
|
206
|
+
|
|
207
|
+
expect(sentSeqs).toEqual([1, 2]);
|
|
208
|
+
await transport.release(uuid, true);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test('passes high-volume context to the persistent link adapter', async () => {
|
|
212
|
+
const { transport, uuid } = createHarness();
|
|
213
|
+
const writeSpy = jest.spyOn(transport as any, 'writeProtocolV2Frame');
|
|
214
|
+
|
|
215
|
+
await transport.acquire({ uuid });
|
|
216
|
+
await transport.call(uuid, 'FileWrite', {});
|
|
217
|
+
|
|
218
|
+
expect(writeSpy.mock.calls.map(([, , options]) => options?.highVolume)).toEqual([false, true]);
|
|
219
|
+
await transport.release(uuid, true);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test('rejects an active Protocol V2 reader when disconnect resets the link', async () => {
|
|
223
|
+
const harness = createHarness();
|
|
224
|
+
const { transport, uuid, sentSeqs } = harness;
|
|
225
|
+
await transport.acquire({ uuid });
|
|
226
|
+
harness.setShouldRespond(false);
|
|
227
|
+
|
|
228
|
+
const call = transport.call(uuid, 'Ping', { message: 'disconnect' }, { timeoutMs: 50 });
|
|
229
|
+
while (sentSeqs.length < 2) {
|
|
230
|
+
await Promise.resolve();
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const rejection = expect(call).rejects.toThrow('React Native BLE transport disconnected');
|
|
234
|
+
await transport.disconnect(uuid);
|
|
235
|
+
await rejection;
|
|
236
|
+
});
|
|
237
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -12,10 +12,11 @@ import transport, {
|
|
|
12
12
|
LogBlockCommand,
|
|
13
13
|
type OneKeyDeviceInfoBase,
|
|
14
14
|
PROTOCOL_V1_MESSAGE_HEADER_SIZE,
|
|
15
|
+
PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
15
16
|
PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
16
17
|
type ProtocolType,
|
|
17
18
|
ProtocolV2FrameAssembler,
|
|
18
|
-
|
|
19
|
+
ProtocolV2LinkManager,
|
|
19
20
|
type TransportCallOptions,
|
|
20
21
|
probeProtocolV2 as probeProtocolV2Helper,
|
|
21
22
|
} from '@onekeyfe/hd-transport';
|
|
@@ -297,9 +298,26 @@ export default class ReactNativeBleTransport {
|
|
|
297
298
|
|
|
298
299
|
private protocolV2FramePromises: Map<string, Deferred<Uint8Array>> = new Map();
|
|
299
300
|
|
|
300
|
-
private
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
private protocolV2Links = new ProtocolV2LinkManager<string>({
|
|
302
|
+
getSchemas: () => {
|
|
303
|
+
if (!this._messages || !this._messagesV2) {
|
|
304
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
protocolV1: this._messages,
|
|
308
|
+
protocolV2: this._messagesV2,
|
|
309
|
+
};
|
|
310
|
+
},
|
|
311
|
+
classifyError: () => 'link-fatal',
|
|
312
|
+
onLinkInvalidated: async (uuid, reason) => {
|
|
313
|
+
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
314
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
315
|
+
Log?.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
316
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
317
|
+
await this.release(uuid, true);
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
});
|
|
303
321
|
|
|
304
322
|
private monitorTokens: Map<string, number> = new Map();
|
|
305
323
|
|
|
@@ -322,6 +340,9 @@ export default class ReactNativeBleTransport {
|
|
|
322
340
|
|
|
323
341
|
configureProtocolV2(signedData: any) {
|
|
324
342
|
this._messagesV2 = parseConfigure(signedData);
|
|
343
|
+
this.protocolV2Links
|
|
344
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
345
|
+
.catch(error => Log?.debug('Protocol V2 schema link cleanup failed:', error));
|
|
325
346
|
Log?.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
|
|
326
347
|
}
|
|
327
348
|
|
|
@@ -686,7 +707,6 @@ export default class ReactNativeBleTransport {
|
|
|
686
707
|
this.runPromise.reject(error);
|
|
687
708
|
this.rejectAllProtocolV2Frames(error);
|
|
688
709
|
this.runPromise = null;
|
|
689
|
-
this.activeProtocolV2Call = null;
|
|
690
710
|
Log?.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
691
711
|
}
|
|
692
712
|
|
|
@@ -853,6 +873,29 @@ export default class ReactNativeBleTransport {
|
|
|
853
873
|
Log?.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
854
874
|
return;
|
|
855
875
|
}
|
|
876
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
877
|
+
let errorCode:
|
|
878
|
+
| typeof HardwareErrorCode.BleDeviceBondError
|
|
879
|
+
| typeof HardwareErrorCode.BleCharacteristicNotifyError
|
|
880
|
+
| typeof HardwareErrorCode.BleCharacteristicNotifyChangeFailure
|
|
881
|
+
| typeof HardwareErrorCode.BleTimeoutError =
|
|
882
|
+
HardwareErrorCode.BleCharacteristicNotifyError;
|
|
883
|
+
if (error.reason?.includes('The connection has timed out unexpectedly')) {
|
|
884
|
+
errorCode = HardwareErrorCode.BleTimeoutError;
|
|
885
|
+
} else if (error.reason?.includes('Encryption is insufficient')) {
|
|
886
|
+
errorCode = HardwareErrorCode.BleDeviceBondError;
|
|
887
|
+
} else if (
|
|
888
|
+
error.reason?.includes('Cannot write client characteristic config descriptor') ||
|
|
889
|
+
error.reason?.includes('Cannot find client characteristic config descriptor') ||
|
|
890
|
+
error.reason?.includes('The handle is invalid') ||
|
|
891
|
+
error.reason?.includes('Writing is not permitted') ||
|
|
892
|
+
error.reason?.includes('notify change failed for device')
|
|
893
|
+
) {
|
|
894
|
+
errorCode = HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
895
|
+
}
|
|
896
|
+
this.rejectProtocolV2Frames(uuid, ERRORS.TypedError(errorCode));
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
856
899
|
if (this.runPromise) {
|
|
857
900
|
let ERROR:
|
|
858
901
|
| typeof HardwareErrorCode.BleDeviceBondError
|
|
@@ -908,7 +951,7 @@ export default class ReactNativeBleTransport {
|
|
|
908
951
|
return;
|
|
909
952
|
}
|
|
910
953
|
if (protocol === 'V2') {
|
|
911
|
-
this.handleProtocolV2Notification(uuid, new Uint8Array(data));
|
|
954
|
+
this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
|
|
912
955
|
return;
|
|
913
956
|
}
|
|
914
957
|
// console.log('[hd-transport-react-native] Received a packet, ', 'buffer: ', data);
|
|
@@ -934,8 +977,11 @@ export default class ReactNativeBleTransport {
|
|
|
934
977
|
} catch (error) {
|
|
935
978
|
Log?.debug('monitor data error: ', error);
|
|
936
979
|
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
937
|
-
this.
|
|
938
|
-
|
|
980
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
981
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
982
|
+
} else {
|
|
983
|
+
this.runPromise?.reject(notifyError);
|
|
984
|
+
}
|
|
939
985
|
}
|
|
940
986
|
}, notifyTransactionId);
|
|
941
987
|
|
|
@@ -944,12 +990,12 @@ export default class ReactNativeBleTransport {
|
|
|
944
990
|
|
|
945
991
|
async release(uuid: string, onclose = false) {
|
|
946
992
|
const transport = transportCache[uuid];
|
|
993
|
+
await this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
947
994
|
if (this.runPromise) {
|
|
948
995
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
949
996
|
this.runPromise.reject(error);
|
|
950
997
|
this.runPromise = null;
|
|
951
998
|
this.rejectAllProtocolV2Frames(error);
|
|
952
|
-
this.activeProtocolV2Call = null;
|
|
953
999
|
} else {
|
|
954
1000
|
this.resetProtocolV2Frames(uuid);
|
|
955
1001
|
}
|
|
@@ -957,9 +1003,6 @@ export default class ReactNativeBleTransport {
|
|
|
957
1003
|
if (Platform.OS === 'android' && !onclose && transport) {
|
|
958
1004
|
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
959
1005
|
this.resetProtocolV2Frames(uuid);
|
|
960
|
-
if (this.activeProtocolV2Call?.uuid === uuid) {
|
|
961
|
-
this.activeProtocolV2Call = null;
|
|
962
|
-
}
|
|
963
1006
|
return Promise.resolve(true);
|
|
964
1007
|
}
|
|
965
1008
|
|
|
@@ -993,7 +1036,7 @@ export default class ReactNativeBleTransport {
|
|
|
993
1036
|
}
|
|
994
1037
|
|
|
995
1038
|
this.deviceProtocol.delete(uuid);
|
|
996
|
-
|
|
1039
|
+
// 设备名称提示不依赖当前连接;保留它可让重连优先探测 V2。
|
|
997
1040
|
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
998
1041
|
this.protocolV2Assemblers.delete(uuid);
|
|
999
1042
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -1025,13 +1068,6 @@ export default class ReactNativeBleTransport {
|
|
|
1025
1068
|
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
1026
1069
|
}
|
|
1027
1070
|
|
|
1028
|
-
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1029
|
-
|
|
1030
|
-
Log?.debug('transport-react-native call this.runPromise', this.runPromise);
|
|
1031
|
-
if (this.runPromise && !forceRun) {
|
|
1032
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
|
|
1033
|
-
}
|
|
1034
|
-
|
|
1035
1071
|
const protocol = this.getProtocolType(uuid);
|
|
1036
1072
|
if (!protocol) {
|
|
1037
1073
|
throw ERRORS.TypedError(
|
|
@@ -1064,6 +1100,12 @@ export default class ReactNativeBleTransport {
|
|
|
1064
1100
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1065
1101
|
}
|
|
1066
1102
|
|
|
1103
|
+
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1104
|
+
Log?.debug('transport-react-native call this.runPromise', this.runPromise);
|
|
1105
|
+
if (this.runPromise && !forceRun) {
|
|
1106
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1067
1109
|
return this.callProtocolV1(uuid, name, data, options);
|
|
1068
1110
|
}
|
|
1069
1111
|
|
|
@@ -1280,6 +1322,7 @@ export default class ReactNativeBleTransport {
|
|
|
1280
1322
|
|
|
1281
1323
|
async disconnect(session: string) {
|
|
1282
1324
|
Log?.debug('transport-react-native transport resetSession: ', session);
|
|
1325
|
+
await this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1283
1326
|
const transport = transportCache[session];
|
|
1284
1327
|
|
|
1285
1328
|
// Clean up disconnect subscription first to prevent onDisconnected callback
|
|
@@ -1341,9 +1384,6 @@ export default class ReactNativeBleTransport {
|
|
|
1341
1384
|
this.deviceProtocolHints.delete(session);
|
|
1342
1385
|
this.protocolV2Assemblers.delete(session);
|
|
1343
1386
|
this.resetProtocolV2Frames(session);
|
|
1344
|
-
if (this.activeProtocolV2Call?.uuid === session) {
|
|
1345
|
-
this.activeProtocolV2Call = null;
|
|
1346
|
-
}
|
|
1347
1387
|
|
|
1348
1388
|
// emit the disconnect event
|
|
1349
1389
|
try {
|
|
@@ -1444,11 +1484,12 @@ export default class ReactNativeBleTransport {
|
|
|
1444
1484
|
|
|
1445
1485
|
private async resetProbeStateAfterProtocolProbe(uuid: string, protocol: ProtocolType) {
|
|
1446
1486
|
const transport = transportCache[uuid];
|
|
1487
|
+
await this.protocolV2Links.invalidateLink(
|
|
1488
|
+
uuid,
|
|
1489
|
+
`Reset notify state after Protocol ${protocol} probe`
|
|
1490
|
+
);
|
|
1447
1491
|
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1448
1492
|
this.resetProtocolV2Frames(uuid);
|
|
1449
|
-
if (this.activeProtocolV2Call?.uuid === uuid) {
|
|
1450
|
-
this.activeProtocolV2Call = null;
|
|
1451
|
-
}
|
|
1452
1493
|
if (this.runPromise) {
|
|
1453
1494
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
1454
1495
|
this.runPromise.reject(error);
|
|
@@ -1533,13 +1574,9 @@ export default class ReactNativeBleTransport {
|
|
|
1533
1574
|
return detected;
|
|
1534
1575
|
}
|
|
1535
1576
|
|
|
1536
|
-
private handleProtocolV2Notification(uuid: string, data: Uint8Array) {
|
|
1577
|
+
private handleProtocolV2Notification(uuid: string, monitorToken: number, data: Uint8Array) {
|
|
1537
1578
|
try {
|
|
1538
|
-
if (
|
|
1539
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1540
|
-
this.resetProtocolV2Frames(uuid);
|
|
1541
|
-
return;
|
|
1542
|
-
}
|
|
1579
|
+
if (this.monitorTokens.get(uuid) !== monitorToken) return;
|
|
1543
1580
|
|
|
1544
1581
|
if (data.length === 0) return;
|
|
1545
1582
|
|
|
@@ -1552,8 +1589,15 @@ export default class ReactNativeBleTransport {
|
|
|
1552
1589
|
} catch (error) {
|
|
1553
1590
|
Log?.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
|
|
1554
1591
|
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
1555
|
-
this.
|
|
1556
|
-
this.
|
|
1592
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1593
|
+
this.protocolV2Links
|
|
1594
|
+
.invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
|
|
1595
|
+
.catch(invalidateError =>
|
|
1596
|
+
Log?.debug(
|
|
1597
|
+
'[ReactNativeBleTransport] Protocol V2 notify cleanup failed:',
|
|
1598
|
+
invalidateError
|
|
1599
|
+
)
|
|
1600
|
+
);
|
|
1557
1601
|
}
|
|
1558
1602
|
}
|
|
1559
1603
|
|
|
@@ -1589,8 +1633,13 @@ export default class ReactNativeBleTransport {
|
|
|
1589
1633
|
this.protocolV2FramePromises.delete(uuid);
|
|
1590
1634
|
}
|
|
1591
1635
|
|
|
1592
|
-
private
|
|
1593
|
-
|
|
1636
|
+
private rejectProtocolV2Frames(uuid: string, error: Error) {
|
|
1637
|
+
this.protocolV2FrameQueues.delete(uuid);
|
|
1638
|
+
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1639
|
+
if (framePromise) {
|
|
1640
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1641
|
+
framePromise.reject(error);
|
|
1642
|
+
}
|
|
1594
1643
|
}
|
|
1595
1644
|
|
|
1596
1645
|
private async readProtocolV2Frame(uuid: string) {
|
|
@@ -1665,27 +1714,6 @@ export default class ReactNativeBleTransport {
|
|
|
1665
1714
|
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
1666
1715
|
}
|
|
1667
1716
|
|
|
1668
|
-
const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'Ping';
|
|
1669
|
-
if (this.runPromise) {
|
|
1670
|
-
if (!forceRun) {
|
|
1671
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
|
|
1672
|
-
}
|
|
1673
|
-
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
1674
|
-
this.runPromise.reject(error);
|
|
1675
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1676
|
-
this.runPromise = null;
|
|
1677
|
-
this.activeProtocolV2Call = null;
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
const transport = this.getCachedTransport(uuid);
|
|
1681
|
-
const runPromise = createDeferred<Uint8Array>();
|
|
1682
|
-
runPromise.promise.catch(() => undefined);
|
|
1683
|
-
this.runPromise = runPromise;
|
|
1684
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1685
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1686
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1687
|
-
this.resetProtocolV2Frames(uuid);
|
|
1688
|
-
let completed = false;
|
|
1689
1717
|
const callOptions = {
|
|
1690
1718
|
...options,
|
|
1691
1719
|
timeoutMs: options?.timeoutMs ?? BLE_RESPONSE_TIMEOUT_MS,
|
|
@@ -1709,57 +1737,65 @@ export default class ReactNativeBleTransport {
|
|
|
1709
1737
|
}
|
|
1710
1738
|
|
|
1711
1739
|
try {
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
await this.writeProtocolV2Frame(transport, frame, {
|
|
1720
|
-
highVolume: highVolumeWrite,
|
|
1721
|
-
});
|
|
1722
|
-
},
|
|
1723
|
-
readFrame: async () => {
|
|
1724
|
-
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
1725
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
1726
|
-
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1727
|
-
}
|
|
1728
|
-
return rxFrame;
|
|
1729
|
-
},
|
|
1730
|
-
logger: Log,
|
|
1731
|
-
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1732
|
-
createTimeoutError: (_messageName: string, timeout: number) =>
|
|
1733
|
-
ERRORS.TypedError(
|
|
1734
|
-
HardwareErrorCode.BleTimeoutError,
|
|
1735
|
-
`BLE response timeout after ${timeout}ms for ${name}`
|
|
1736
|
-
),
|
|
1737
|
-
});
|
|
1738
|
-
|
|
1739
|
-
const result = await session.call(name, data, callOptions);
|
|
1740
|
-
completed = true;
|
|
1741
|
-
return result;
|
|
1740
|
+
return await this.protocolV2Links.call(
|
|
1741
|
+
uuid,
|
|
1742
|
+
() => this.createProtocolV2Adapter(uuid),
|
|
1743
|
+
name,
|
|
1744
|
+
data,
|
|
1745
|
+
callOptions
|
|
1746
|
+
);
|
|
1742
1747
|
} catch (e) {
|
|
1743
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1744
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1745
|
-
this.resetProtocolV2Frames(uuid);
|
|
1746
|
-
}
|
|
1747
1748
|
Log?.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1748
1749
|
throw e;
|
|
1749
|
-
} finally {
|
|
1750
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1751
|
-
if (!completed) {
|
|
1752
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1753
|
-
}
|
|
1754
|
-
this.resetProtocolV2Frames(uuid);
|
|
1755
|
-
this.activeProtocolV2Call = null;
|
|
1756
|
-
}
|
|
1757
|
-
if (this.runPromise === runPromise) {
|
|
1758
|
-
this.runPromise = null;
|
|
1759
|
-
}
|
|
1760
1750
|
}
|
|
1761
1751
|
}
|
|
1762
1752
|
|
|
1753
|
+
private createProtocolV2Adapter(uuid: string) {
|
|
1754
|
+
const generation = this.monitorTokens.get(uuid) ?? 0;
|
|
1755
|
+
const assertCurrentGeneration = () => {
|
|
1756
|
+
if (this.monitorTokens.get(uuid) !== generation) {
|
|
1757
|
+
throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
|
|
1761
|
+
return {
|
|
1762
|
+
router: PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1763
|
+
maxFrameBytes: PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1764
|
+
generation,
|
|
1765
|
+
prepareCall: () => {
|
|
1766
|
+
assertCurrentGeneration();
|
|
1767
|
+
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1768
|
+
this.resetProtocolV2Frames(uuid);
|
|
1769
|
+
},
|
|
1770
|
+
writeFrame: async (frame: Uint8Array, context: { highVolume: boolean }) => {
|
|
1771
|
+
assertCurrentGeneration();
|
|
1772
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
1773
|
+
await this.writeProtocolV2Frame(currentTransport, frame, {
|
|
1774
|
+
highVolume: context.highVolume,
|
|
1775
|
+
});
|
|
1776
|
+
},
|
|
1777
|
+
readFrame: async () => {
|
|
1778
|
+
assertCurrentGeneration();
|
|
1779
|
+
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
1780
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1781
|
+
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1782
|
+
}
|
|
1783
|
+
return rxFrame;
|
|
1784
|
+
},
|
|
1785
|
+
reset: (reason: string) => {
|
|
1786
|
+
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1787
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1788
|
+
},
|
|
1789
|
+
logger: Log,
|
|
1790
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1791
|
+
createTimeoutError: (messageName: string, timeout: number) =>
|
|
1792
|
+
ERRORS.TypedError(
|
|
1793
|
+
HardwareErrorCode.BleTimeoutError,
|
|
1794
|
+
`BLE response timeout after ${timeout}ms for ${messageName}`
|
|
1795
|
+
),
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1798
|
+
|
|
1763
1799
|
getProtocolType(path: string): ProtocolType | undefined {
|
|
1764
1800
|
return this.deviceProtocol.get(path);
|
|
1765
1801
|
}
|