@onekeyfe/hd-transport-web-device 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.
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import transport, { PROTOCOL_V2_CHANNEL_BLE_UART, bytesToHex } from '@onekeyfe/hd-transport';
|
|
2
|
+
import { HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
2
3
|
|
|
3
4
|
import ElectronBleTransport from '../src/electron-ble-transport';
|
|
4
5
|
|
|
@@ -245,6 +246,95 @@ describe('ElectronBleTransport protocol detection', () => {
|
|
|
245
246
|
);
|
|
246
247
|
expect(nobleBle.write).toHaveBeenCalledTimes(1);
|
|
247
248
|
expect(transport.getProtocolType(device.id)).toBe('V2');
|
|
249
|
+
await expect(transport.call(device.id, 'Ping', { message: 'after-probe' })).resolves.toEqual({
|
|
250
|
+
type: 'Success',
|
|
251
|
+
message: { message: 'ok' },
|
|
252
|
+
});
|
|
253
|
+
const sentSeqs = nobleBle.write.mock.calls.map(([, hex]) =>
|
|
254
|
+
Number.parseInt(hex.slice(12, 14), 16)
|
|
255
|
+
);
|
|
256
|
+
expect(sentSeqs).toEqual([1, 2]);
|
|
257
|
+
} finally {
|
|
258
|
+
await transport.release(device.id);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test('rejects the active Protocol V2 reader when pairing is rejected', async () => {
|
|
263
|
+
const device = { id: 'pairing-rejected-pro2-id', name: 'OneKey Pro 2' };
|
|
264
|
+
const nobleBle = createNobleBle(device);
|
|
265
|
+
let notificationHandler: ((deviceId: string, data: string) => void) | undefined;
|
|
266
|
+
let pairingRejected = false;
|
|
267
|
+
const probeResponse = ProtocolV2.encodeFrame(
|
|
268
|
+
schemas,
|
|
269
|
+
'Success',
|
|
270
|
+
{ message: 'ok' },
|
|
271
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART }
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
nobleBle.onNotification.mockImplementation(handler => {
|
|
275
|
+
notificationHandler = handler;
|
|
276
|
+
return jest.fn();
|
|
277
|
+
});
|
|
278
|
+
nobleBle.write.mockImplementation(() => {
|
|
279
|
+
setTimeout(
|
|
280
|
+
() =>
|
|
281
|
+
notificationHandler?.(
|
|
282
|
+
device.id,
|
|
283
|
+
pairingRejected ? 'PAIRING_REJECTED' : bytesToHex(probeResponse)
|
|
284
|
+
),
|
|
285
|
+
0
|
|
286
|
+
);
|
|
287
|
+
return Promise.resolve();
|
|
288
|
+
});
|
|
289
|
+
const transport = configureTransport(nobleBle);
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
await transport.acquire({ uuid: device.id });
|
|
293
|
+
pairingRejected = true;
|
|
294
|
+
|
|
295
|
+
await expect(
|
|
296
|
+
transport.call(device.id, 'Ping', { message: 'pairing' }, { timeoutMs: 50 })
|
|
297
|
+
).rejects.toMatchObject({ errorCode: HardwareErrorCode.BleDeviceBondedCanceled });
|
|
298
|
+
} finally {
|
|
299
|
+
await transport.release(device.id);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test('rebuilds the active link when Core acquires the same device again', async () => {
|
|
304
|
+
const device = { id: 'repeated-acquire-pro2-id', name: 'OneKey Pro 2' };
|
|
305
|
+
const nobleBle = createNobleBle(device);
|
|
306
|
+
let notificationHandler: ((deviceId: string, data: string) => void) | undefined;
|
|
307
|
+
const response = ProtocolV2.encodeFrame(
|
|
308
|
+
schemas,
|
|
309
|
+
'Success',
|
|
310
|
+
{ message: 'ok' },
|
|
311
|
+
{ router: PROTOCOL_V2_CHANNEL_BLE_UART }
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
nobleBle.onNotification.mockImplementation(handler => {
|
|
315
|
+
notificationHandler = handler;
|
|
316
|
+
return jest.fn();
|
|
317
|
+
});
|
|
318
|
+
nobleBle.write.mockImplementation(() => {
|
|
319
|
+
setTimeout(() => notificationHandler?.(device.id, bytesToHex(response)), 0);
|
|
320
|
+
return Promise.resolve();
|
|
321
|
+
});
|
|
322
|
+
const transport = configureTransport(nobleBle);
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
await transport.acquire({ uuid: device.id });
|
|
326
|
+
await transport.acquire({ uuid: device.id, expectedProtocol: 'V2' });
|
|
327
|
+
await expect(
|
|
328
|
+
transport.call(device.id, 'Ping', { message: 'after-reacquire' })
|
|
329
|
+
).resolves.toEqual({
|
|
330
|
+
type: 'Success',
|
|
331
|
+
message: { message: 'ok' },
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
const sentSeqs = nobleBle.write.mock.calls.map(([, hex]) =>
|
|
335
|
+
Number.parseInt(hex.slice(12, 14), 16)
|
|
336
|
+
);
|
|
337
|
+
expect(sentSeqs).toEqual([1, 2]);
|
|
248
338
|
} finally {
|
|
249
339
|
await transport.release(device.id);
|
|
250
340
|
}
|
|
@@ -28,8 +28,7 @@ export default class ElectronBleTransport {
|
|
|
28
28
|
private v2Assemblers;
|
|
29
29
|
private v2FrameQueues;
|
|
30
30
|
private v2FramePromises;
|
|
31
|
-
private
|
|
32
|
-
private nextProtocolV2CallToken;
|
|
31
|
+
private protocolV2Links;
|
|
33
32
|
private notificationCleanups;
|
|
34
33
|
private disconnectCleanups;
|
|
35
34
|
private notificationTokens;
|
|
@@ -69,12 +68,13 @@ export default class ElectronBleTransport {
|
|
|
69
68
|
private resolveProtocolV2Frame;
|
|
70
69
|
private rejectAllProtocolV2Frames;
|
|
71
70
|
private resetProtocolV2Frames;
|
|
72
|
-
private
|
|
71
|
+
private rejectProtocolV2Frames;
|
|
73
72
|
private readProtocolV2Frame;
|
|
74
73
|
private handleProtocolV1Notification;
|
|
75
74
|
call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<import("@onekeyfe/hd-transport").MessageFromOneKey>;
|
|
76
75
|
private callProtocolV1;
|
|
77
76
|
private callProtocolV2;
|
|
77
|
+
private createProtocolV2Adapter;
|
|
78
78
|
private processProtocolV1Notification;
|
|
79
79
|
getProtocolType(path: string): ProtocolType | undefined;
|
|
80
80
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnG,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AAevC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB;CACF;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,gBAAgB,CAAC,EAAE,YAAY,CAAC;CACjC,CAAC;AAqCF,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,OAAO,CAAC,SAAS,CAA0D;IAE3E,OAAO,CAAC,WAAW,CAA0D;IAE7E,IAAI,SAA0B;IAE9B,UAAU,UAAS;IAEnB,UAAU,EAAE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,IAAI,CAAQ;IAExD,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,OAAO,CAAC,gBAAgB,CAA0B;IAElD,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAEnE,OAAO,CAAC,SAAS,CAAsE;IAEvF,OAAO,CAAC,YAAY,CAAoD;IAExE,OAAO,CAAC,aAAa,CAAwC;IAE7D,OAAO,CAAC,eAAe,CAAgD;IAEvE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"electron-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-ble-transport.ts"],"names":[],"mappings":";AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACnG,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AAevC,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,UAAU,CAAC,EAAE,UAAU,CAAC;KACzB;CACF;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,gBAAgB,CAAC,EAAE,YAAY,CAAC;CACjC,CAAC;AAqCF,MAAM,CAAC,OAAO,OAAO,oBAAoB;IACvC,OAAO,CAAC,SAAS,CAA0D;IAE3E,OAAO,CAAC,WAAW,CAA0D;IAE7E,IAAI,SAA0B;IAE9B,UAAU,UAAS;IAEnB,UAAU,EAAE,QAAQ,CAAC,UAAU,GAAG,MAAM,CAAC,GAAG,IAAI,CAAQ;IAExD,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,OAAO,CAAC,gBAAgB,CAA0B;IAElD,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAEnE,OAAO,CAAC,SAAS,CAAsE;IAEvF,OAAO,CAAC,YAAY,CAAoD;IAExE,OAAO,CAAC,aAAa,CAAwC;IAE7D,OAAO,CAAC,eAAe,CAAgD;IAEvE,OAAO,CAAC,eAAe,CAmBpB;IAEH,OAAO,CAAC,oBAAoB,CAAsC;IAElE,OAAO,CAAC,kBAAkB,CAAsC;IAEhE,OAAO,CAAC,kBAAkB,CAAkC;IAE5D,OAAO,CAAC,qBAAqB,CAAK;IAElC,OAAO,CAAC,oBAAoB;IA+B5B,OAAO,CAAC,kBAAkB;IA0B1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAcxC,SAAS,CAAC,UAAU,EAAE,GAAG;IAKzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAQ7B,MAAM;IAIN,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAqBxC,OAAO,CAAC,KAAK,EAAE,eAAe;;;;;;;;;;;IA0F9B,OAAO,CAAC,EAAE,EAAE,MAAM;IAgBxB,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;YAMZ,cAAc;IA+C5B,OAAO,CAAC,8BAA8B;YAgBxB,iCAAiC;YAqCjC,eAAe;YAgBf,eAAe;YAuBf,iBAAiB;YAsBjB,SAAS;IASvB,OAAO,CAAC,kBAAkB;IAwB1B,OAAO,CAAC,4BAA4B;IAkBpC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,sBAAsB;YAShB,mBAAmB;IAiBjC,OAAO,CAAC,4BAA4B;IAgB9B,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA+BlB,cAAc;YAuEd,cAAc;IA6B5B,OAAO,CAAC,uBAAuB;IA0C/B,OAAO,CAAC,6BAA6B;IAsCrC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -93,8 +93,7 @@ declare class ElectronBleTransport {
|
|
|
93
93
|
private v2Assemblers;
|
|
94
94
|
private v2FrameQueues;
|
|
95
95
|
private v2FramePromises;
|
|
96
|
-
private
|
|
97
|
-
private nextProtocolV2CallToken;
|
|
96
|
+
private protocolV2Links;
|
|
98
97
|
private notificationCleanups;
|
|
99
98
|
private disconnectCleanups;
|
|
100
99
|
private notificationTokens;
|
|
@@ -134,12 +133,13 @@ declare class ElectronBleTransport {
|
|
|
134
133
|
private resolveProtocolV2Frame;
|
|
135
134
|
private rejectAllProtocolV2Frames;
|
|
136
135
|
private resetProtocolV2Frames;
|
|
137
|
-
private
|
|
136
|
+
private rejectProtocolV2Frames;
|
|
138
137
|
private readProtocolV2Frame;
|
|
139
138
|
private handleProtocolV1Notification;
|
|
140
139
|
call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<_onekeyfe_hd_transport.MessageFromOneKey>;
|
|
141
140
|
private callProtocolV1;
|
|
142
141
|
private callProtocolV2;
|
|
142
|
+
private createProtocolV2Adapter;
|
|
143
143
|
private processProtocolV1Notification;
|
|
144
144
|
getProtocolType(path: string): ProtocolType | undefined;
|
|
145
145
|
}
|
package/dist/index.js
CHANGED
|
@@ -781,8 +781,27 @@ class ElectronBleTransport {
|
|
|
781
781
|
this.v2Assemblers = new Map();
|
|
782
782
|
this.v2FrameQueues = new Map();
|
|
783
783
|
this.v2FramePromises = new Map();
|
|
784
|
-
this.
|
|
785
|
-
|
|
784
|
+
this.protocolV2Links = new transport.ProtocolV2LinkManager({
|
|
785
|
+
getSchemas: () => {
|
|
786
|
+
if (!this._messages || !this._messagesV2) {
|
|
787
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
788
|
+
}
|
|
789
|
+
return {
|
|
790
|
+
protocolV1: this._messages,
|
|
791
|
+
protocolV2: this._messagesV2,
|
|
792
|
+
};
|
|
793
|
+
},
|
|
794
|
+
classifyError: () => 'link-fatal',
|
|
795
|
+
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
796
|
+
var _a, _b;
|
|
797
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
798
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
799
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
800
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
801
|
+
yield this.release(uuid);
|
|
802
|
+
}
|
|
803
|
+
}),
|
|
804
|
+
});
|
|
786
805
|
this.notificationCleanups = new Map();
|
|
787
806
|
this.disconnectCleanups = new Map();
|
|
788
807
|
this.notificationTokens = new Map();
|
|
@@ -818,15 +837,14 @@ class ElectronBleTransport {
|
|
|
818
837
|
throw error;
|
|
819
838
|
}
|
|
820
839
|
cleanupDeviceState(deviceId) {
|
|
821
|
-
|
|
840
|
+
this.protocolV2Links
|
|
841
|
+
.invalidateLink(deviceId, 'Electron BLE device state cleaned')
|
|
842
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
|
|
822
843
|
this.connectedDevices.delete(deviceId);
|
|
823
844
|
this.deviceProtocol.delete(deviceId);
|
|
824
845
|
this.v1Buffers.delete(deviceId);
|
|
825
846
|
this.v2Assemblers.delete(deviceId);
|
|
826
847
|
this.resetProtocolV2Frames(deviceId);
|
|
827
|
-
if (((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === deviceId) {
|
|
828
|
-
this.activeProtocolV2Call = null;
|
|
829
|
-
}
|
|
830
848
|
this.notificationTokens.delete(deviceId);
|
|
831
849
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
832
850
|
if (notifyCleanup) {
|
|
@@ -855,6 +873,9 @@ class ElectronBleTransport {
|
|
|
855
873
|
configureProtocolV2(signedData) {
|
|
856
874
|
var _a;
|
|
857
875
|
this._messagesV2 = parseConfigure(signedData);
|
|
876
|
+
this.protocolV2Links
|
|
877
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
878
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] schema link cleanup failed:', error); });
|
|
858
879
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V2 schema configured');
|
|
859
880
|
}
|
|
860
881
|
listen() {
|
|
@@ -893,12 +914,14 @@ class ElectronBleTransport {
|
|
|
893
914
|
if (!uuid) {
|
|
894
915
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
895
916
|
}
|
|
917
|
+
if (this.connectedDevices.has(uuid)) {
|
|
918
|
+
yield this.release(uuid);
|
|
919
|
+
}
|
|
896
920
|
if (forceCleanRunPromise && this.runPromise) {
|
|
897
921
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
898
922
|
this.runPromise.reject(error);
|
|
899
923
|
this.rejectAllProtocolV2Frames(error);
|
|
900
924
|
this.runPromise = null;
|
|
901
|
-
this.activeProtocolV2Call = null;
|
|
902
925
|
}
|
|
903
926
|
try {
|
|
904
927
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
@@ -966,6 +989,7 @@ class ElectronBleTransport {
|
|
|
966
989
|
var _a, _b;
|
|
967
990
|
return __awaiter(this, void 0, void 0, function* () {
|
|
968
991
|
try {
|
|
992
|
+
yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
969
993
|
if (this.connectedDevices.has(id)) {
|
|
970
994
|
if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
|
|
971
995
|
yield window.desktopApi.nobleBle.unsubscribe(id);
|
|
@@ -1039,14 +1063,12 @@ class ElectronBleTransport {
|
|
|
1039
1063
|
});
|
|
1040
1064
|
}
|
|
1041
1065
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1042
|
-
var _a, _b, _c, _d, _e, _f, _g
|
|
1066
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1043
1067
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1068
|
+
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1044
1069
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1045
1070
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1046
1071
|
this.resetProtocolV2Frames(uuid);
|
|
1047
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
1048
|
-
this.activeProtocolV2Call = null;
|
|
1049
|
-
}
|
|
1050
1072
|
if (this.runPromise) {
|
|
1051
1073
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1052
1074
|
this.runPromise.reject(error);
|
|
@@ -1059,16 +1081,16 @@ class ElectronBleTransport {
|
|
|
1059
1081
|
}
|
|
1060
1082
|
this.notificationTokens.delete(uuid);
|
|
1061
1083
|
try {
|
|
1062
|
-
yield ((
|
|
1084
|
+
yield ((_c = (_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) === null || _c === void 0 ? void 0 : _c.unsubscribe(uuid));
|
|
1063
1085
|
}
|
|
1064
1086
|
catch (error) {
|
|
1065
|
-
(
|
|
1087
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1066
1088
|
}
|
|
1067
1089
|
try {
|
|
1068
|
-
yield ((
|
|
1090
|
+
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.subscribe(uuid));
|
|
1069
1091
|
}
|
|
1070
1092
|
catch (error) {
|
|
1071
|
-
(
|
|
1093
|
+
(_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug(`[Electron BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1072
1094
|
throw error;
|
|
1073
1095
|
}
|
|
1074
1096
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
@@ -1151,10 +1173,12 @@ class ElectronBleTransport {
|
|
|
1151
1173
|
var _a, _b;
|
|
1152
1174
|
if (hexData === 'PAIRING_REJECTED') {
|
|
1153
1175
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Pairing rejection detected for device:', deviceId);
|
|
1154
|
-
|
|
1155
|
-
|
|
1176
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
|
|
1177
|
+
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
1178
|
+
this.rejectProtocolV2Frames(deviceId, error);
|
|
1179
|
+
}
|
|
1180
|
+
else if (this.runPromise) {
|
|
1156
1181
|
this.runPromise.reject(error);
|
|
1157
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1158
1182
|
}
|
|
1159
1183
|
return;
|
|
1160
1184
|
}
|
|
@@ -1170,13 +1194,8 @@ class ElectronBleTransport {
|
|
|
1170
1194
|
this.handleProtocolV1Notification(deviceId, hexData);
|
|
1171
1195
|
}
|
|
1172
1196
|
handleProtocolV2Notification(deviceId, hexData) {
|
|
1173
|
-
var _a
|
|
1197
|
+
var _a;
|
|
1174
1198
|
try {
|
|
1175
|
-
if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== deviceId) {
|
|
1176
|
-
(_b = this.v2Assemblers.get(deviceId)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1177
|
-
this.resetProtocolV2Frames(deviceId);
|
|
1178
|
-
return;
|
|
1179
|
-
}
|
|
1180
1199
|
const bytes = transport.hexToBytes(hexData);
|
|
1181
1200
|
if (bytes.length === 0)
|
|
1182
1201
|
return;
|
|
@@ -1188,12 +1207,9 @@ class ElectronBleTransport {
|
|
|
1188
1207
|
}
|
|
1189
1208
|
}
|
|
1190
1209
|
catch (error) {
|
|
1191
|
-
(
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
this.runPromise.reject(notifyError);
|
|
1195
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
1196
|
-
}
|
|
1210
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 notification error:', error);
|
|
1211
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1212
|
+
this.rejectProtocolV2Frames(deviceId, notifyError);
|
|
1197
1213
|
}
|
|
1198
1214
|
}
|
|
1199
1215
|
getProtocolV2FrameQueue(uuid) {
|
|
@@ -1224,9 +1240,13 @@ class ElectronBleTransport {
|
|
|
1224
1240
|
this.v2FrameQueues.delete(uuid);
|
|
1225
1241
|
this.v2FramePromises.delete(uuid);
|
|
1226
1242
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1243
|
+
rejectProtocolV2Frames(uuid, error) {
|
|
1244
|
+
this.v2FrameQueues.delete(uuid);
|
|
1245
|
+
const framePromise = this.v2FramePromises.get(uuid);
|
|
1246
|
+
if (framePromise) {
|
|
1247
|
+
this.v2FramePromises.delete(uuid);
|
|
1248
|
+
framePromise.reject(error);
|
|
1249
|
+
}
|
|
1230
1250
|
}
|
|
1231
1251
|
readProtocolV2Frame(uuid) {
|
|
1232
1252
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1349,76 +1369,60 @@ class ElectronBleTransport {
|
|
|
1349
1369
|
});
|
|
1350
1370
|
}
|
|
1351
1371
|
callProtocolV2(uuid, name, data, options) {
|
|
1352
|
-
var _a, _b
|
|
1372
|
+
var _a, _b;
|
|
1353
1373
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1354
1374
|
if (!this._messages || !this._messagesV2) {
|
|
1355
1375
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1356
1376
|
}
|
|
1357
|
-
const
|
|
1358
|
-
if (this.runPromise) {
|
|
1359
|
-
if (!forceRun) {
|
|
1360
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1361
|
-
}
|
|
1362
|
-
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1363
|
-
this.runPromise.reject(error);
|
|
1364
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1365
|
-
this.runPromise = null;
|
|
1366
|
-
this.activeProtocolV2Call = null;
|
|
1367
|
-
}
|
|
1368
|
-
const runPromise = hdShared.createDeferred();
|
|
1369
|
-
runPromise.promise.catch(() => undefined);
|
|
1370
|
-
this.runPromise = runPromise;
|
|
1371
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1372
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1373
|
-
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1374
|
-
this.resetProtocolV2Frames(uuid);
|
|
1375
|
-
let completed = false;
|
|
1376
|
-
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 });
|
|
1377
|
+
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 });
|
|
1377
1378
|
try {
|
|
1378
|
-
|
|
1379
|
-
schemas: {
|
|
1380
|
-
protocolV1: this._messages,
|
|
1381
|
-
protocolV2: this._messagesV2,
|
|
1382
|
-
},
|
|
1383
|
-
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1384
|
-
writeFrame: (frame) => this.writeWithChunking(uuid, transport.bytesToHex(frame)),
|
|
1385
|
-
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1386
|
-
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1387
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
1388
|
-
throw new Error('Response is not Uint8Array');
|
|
1389
|
-
}
|
|
1390
|
-
return rxFrame;
|
|
1391
|
-
}),
|
|
1392
|
-
logger: this.Log,
|
|
1393
|
-
logPrefix: 'ProtocolV2 BLE',
|
|
1394
|
-
createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
|
|
1395
|
-
});
|
|
1396
|
-
const result = yield session.call(name, data, callOptions);
|
|
1397
|
-
completed = true;
|
|
1398
|
-
return result;
|
|
1379
|
+
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1399
1380
|
}
|
|
1400
1381
|
catch (e) {
|
|
1401
|
-
|
|
1402
|
-
(_c = this.v2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1403
|
-
this.resetProtocolV2Frames(uuid);
|
|
1404
|
-
}
|
|
1405
|
-
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1382
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1406
1383
|
throw e;
|
|
1407
1384
|
}
|
|
1408
|
-
finally {
|
|
1409
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1410
|
-
if (!completed) {
|
|
1411
|
-
(_e = this.v2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
|
|
1412
|
-
}
|
|
1413
|
-
this.resetProtocolV2Frames(uuid);
|
|
1414
|
-
this.activeProtocolV2Call = null;
|
|
1415
|
-
}
|
|
1416
|
-
if (this.runPromise === runPromise) {
|
|
1417
|
-
this.runPromise = null;
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
1385
|
});
|
|
1421
1386
|
}
|
|
1387
|
+
createProtocolV2Adapter(uuid) {
|
|
1388
|
+
var _a;
|
|
1389
|
+
const generation = (_a = this.notificationTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1390
|
+
const assertCurrentGeneration = () => {
|
|
1391
|
+
if (this.notificationTokens.get(uuid) !== generation) {
|
|
1392
|
+
throw new Error(`Protocol V2 notification generation changed for ${uuid}`);
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
return {
|
|
1396
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1397
|
+
generation,
|
|
1398
|
+
prepareCall: () => {
|
|
1399
|
+
var _a;
|
|
1400
|
+
assertCurrentGeneration();
|
|
1401
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1402
|
+
this.resetProtocolV2Frames(uuid);
|
|
1403
|
+
},
|
|
1404
|
+
writeFrame: (frame) => {
|
|
1405
|
+
assertCurrentGeneration();
|
|
1406
|
+
return this.writeWithChunking(uuid, transport.bytesToHex(frame));
|
|
1407
|
+
},
|
|
1408
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1409
|
+
assertCurrentGeneration();
|
|
1410
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1411
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1412
|
+
throw new Error('Response is not Uint8Array');
|
|
1413
|
+
}
|
|
1414
|
+
return rxFrame;
|
|
1415
|
+
}),
|
|
1416
|
+
reset: (reason) => {
|
|
1417
|
+
var _a;
|
|
1418
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1419
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1420
|
+
},
|
|
1421
|
+
logger: this.Log,
|
|
1422
|
+
logPrefix: 'ProtocolV2 BLE',
|
|
1423
|
+
createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1422
1426
|
processProtocolV1Notification(deviceId, hexData) {
|
|
1423
1427
|
try {
|
|
1424
1428
|
if (typeof hexData !== 'string') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-web-device",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.9",
|
|
4
4
|
"author": "OneKey",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
"lint:fix": "eslint . --fix"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.9",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.9"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@onekeyfe/hd-transport-electron": "1.2.0-alpha.
|
|
27
|
+
"@onekeyfe/hd-transport-electron": "1.2.0-alpha.9",
|
|
28
28
|
"@types/w3c-web-usb": "^1.0.6",
|
|
29
29
|
"@types/web-bluetooth": "^0.0.17"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "f90ef9921b742f68cce9f4e7a0425e45e8ae7ec9"
|
|
32
32
|
}
|
|
@@ -3,7 +3,7 @@ import transport, {
|
|
|
3
3
|
PROTOCOL_V1_MESSAGE_HEADER_SIZE,
|
|
4
4
|
PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
5
5
|
ProtocolV2FrameAssembler,
|
|
6
|
-
|
|
6
|
+
ProtocolV2LinkManager,
|
|
7
7
|
bytesToHex,
|
|
8
8
|
hexToBytes,
|
|
9
9
|
probeProtocolV2 as probeProtocolV2Helper,
|
|
@@ -111,9 +111,26 @@ export default class ElectronBleTransport {
|
|
|
111
111
|
|
|
112
112
|
private v2FramePromises: Map<string, Deferred<Uint8Array>> = new Map();
|
|
113
113
|
|
|
114
|
-
private
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
private protocolV2Links = new ProtocolV2LinkManager<string>({
|
|
115
|
+
getSchemas: () => {
|
|
116
|
+
if (!this._messages || !this._messagesV2) {
|
|
117
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
protocolV1: this._messages,
|
|
121
|
+
protocolV2: this._messagesV2,
|
|
122
|
+
};
|
|
123
|
+
},
|
|
124
|
+
classifyError: () => 'link-fatal',
|
|
125
|
+
onLinkInvalidated: async (uuid, reason) => {
|
|
126
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
127
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
128
|
+
this.Log?.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
129
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
130
|
+
await this.release(uuid);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
});
|
|
117
134
|
|
|
118
135
|
private notificationCleanups: Map<string, () => void> = new Map();
|
|
119
136
|
|
|
@@ -155,6 +172,9 @@ export default class ElectronBleTransport {
|
|
|
155
172
|
}
|
|
156
173
|
|
|
157
174
|
private cleanupDeviceState(deviceId: string): void {
|
|
175
|
+
this.protocolV2Links
|
|
176
|
+
.invalidateLink(deviceId, 'Electron BLE device state cleaned')
|
|
177
|
+
.catch(error => this.Log?.debug('[Electron BLE] link cleanup failed:', error));
|
|
158
178
|
this.connectedDevices.delete(deviceId);
|
|
159
179
|
this.deviceProtocol.delete(deviceId);
|
|
160
180
|
// Keep deviceProtocolHints — it's inferred from device name (e.g. "Pro 2" → V2)
|
|
@@ -162,9 +182,6 @@ export default class ElectronBleTransport {
|
|
|
162
182
|
this.v1Buffers.delete(deviceId);
|
|
163
183
|
this.v2Assemblers.delete(deviceId);
|
|
164
184
|
this.resetProtocolV2Frames(deviceId);
|
|
165
|
-
if (this.activeProtocolV2Call?.uuid === deviceId) {
|
|
166
|
-
this.activeProtocolV2Call = null;
|
|
167
|
-
}
|
|
168
185
|
this.notificationTokens.delete(deviceId);
|
|
169
186
|
|
|
170
187
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
@@ -201,6 +218,9 @@ export default class ElectronBleTransport {
|
|
|
201
218
|
|
|
202
219
|
configureProtocolV2(signedData: any) {
|
|
203
220
|
this._messagesV2 = parseConfigure(signedData);
|
|
221
|
+
this.protocolV2Links
|
|
222
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
223
|
+
.catch(error => this.Log?.debug('[Electron BLE] schema link cleanup failed:', error));
|
|
204
224
|
this.Log?.debug('[Electron BLE] Protocol V2 schema configured');
|
|
205
225
|
}
|
|
206
226
|
|
|
@@ -236,12 +256,15 @@ export default class ElectronBleTransport {
|
|
|
236
256
|
throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
|
|
237
257
|
}
|
|
238
258
|
|
|
259
|
+
if (this.connectedDevices.has(uuid)) {
|
|
260
|
+
await this.release(uuid);
|
|
261
|
+
}
|
|
262
|
+
|
|
239
263
|
if (forceCleanRunPromise && this.runPromise) {
|
|
240
264
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
241
265
|
this.runPromise.reject(error);
|
|
242
266
|
this.rejectAllProtocolV2Frames(error);
|
|
243
267
|
this.runPromise = null;
|
|
244
|
-
this.activeProtocolV2Call = null;
|
|
245
268
|
}
|
|
246
269
|
|
|
247
270
|
try {
|
|
@@ -318,6 +341,7 @@ export default class ElectronBleTransport {
|
|
|
318
341
|
|
|
319
342
|
async release(id: string) {
|
|
320
343
|
try {
|
|
344
|
+
await this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
321
345
|
if (this.connectedDevices.has(id)) {
|
|
322
346
|
if (window.desktopApi?.nobleBle) {
|
|
323
347
|
await window.desktopApi.nobleBle.unsubscribe(id);
|
|
@@ -415,12 +439,13 @@ export default class ElectronBleTransport {
|
|
|
415
439
|
}
|
|
416
440
|
|
|
417
441
|
private async resetProbeStateAfterProtocolProbe(uuid: string, protocol: ProtocolType) {
|
|
442
|
+
await this.protocolV2Links.invalidateLink(
|
|
443
|
+
uuid,
|
|
444
|
+
`Reset notify state after Protocol ${protocol} probe`
|
|
445
|
+
);
|
|
418
446
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
419
447
|
this.v2Assemblers.get(uuid)?.reset();
|
|
420
448
|
this.resetProtocolV2Frames(uuid);
|
|
421
|
-
if (this.activeProtocolV2Call?.uuid === uuid) {
|
|
422
|
-
this.activeProtocolV2Call = null;
|
|
423
|
-
}
|
|
424
449
|
if (this.runPromise) {
|
|
425
450
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
426
451
|
this.runPromise.reject(error);
|
|
@@ -523,10 +548,11 @@ export default class ElectronBleTransport {
|
|
|
523
548
|
private handleNotification(deviceId: string, hexData: string): void {
|
|
524
549
|
if (hexData === 'PAIRING_REJECTED') {
|
|
525
550
|
this.Log?.debug('[Electron BLE] Pairing rejection detected for device:', deviceId);
|
|
526
|
-
|
|
527
|
-
|
|
551
|
+
const error = ERRORS.TypedError(HardwareErrorCode.BleDeviceBondedCanceled);
|
|
552
|
+
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
553
|
+
this.rejectProtocolV2Frames(deviceId, error);
|
|
554
|
+
} else if (this.runPromise) {
|
|
528
555
|
this.runPromise.reject(error);
|
|
529
|
-
this.rejectAllProtocolV2Frames(error);
|
|
530
556
|
}
|
|
531
557
|
return;
|
|
532
558
|
}
|
|
@@ -545,12 +571,6 @@ export default class ElectronBleTransport {
|
|
|
545
571
|
|
|
546
572
|
private handleProtocolV2Notification(deviceId: string, hexData: string): void {
|
|
547
573
|
try {
|
|
548
|
-
if (!this.runPromise || this.activeProtocolV2Call?.uuid !== deviceId) {
|
|
549
|
-
this.v2Assemblers.get(deviceId)?.reset();
|
|
550
|
-
this.resetProtocolV2Frames(deviceId);
|
|
551
|
-
return;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
574
|
const bytes = hexToBytes(hexData);
|
|
555
575
|
if (bytes.length === 0) return;
|
|
556
576
|
|
|
@@ -562,11 +582,8 @@ export default class ElectronBleTransport {
|
|
|
562
582
|
}
|
|
563
583
|
} catch (error) {
|
|
564
584
|
this.Log?.error('[Electron BLE] Protocol V2 notification error:', error);
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
this.runPromise.reject(notifyError);
|
|
568
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
569
|
-
}
|
|
585
|
+
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
586
|
+
this.rejectProtocolV2Frames(deviceId, notifyError);
|
|
570
587
|
}
|
|
571
588
|
}
|
|
572
589
|
|
|
@@ -602,8 +619,13 @@ export default class ElectronBleTransport {
|
|
|
602
619
|
this.v2FramePromises.delete(uuid);
|
|
603
620
|
}
|
|
604
621
|
|
|
605
|
-
private
|
|
606
|
-
|
|
622
|
+
private rejectProtocolV2Frames(uuid: string, error: Error) {
|
|
623
|
+
this.v2FrameQueues.delete(uuid);
|
|
624
|
+
const framePromise = this.v2FramePromises.get(uuid);
|
|
625
|
+
if (framePromise) {
|
|
626
|
+
this.v2FramePromises.delete(uuid);
|
|
627
|
+
framePromise.reject(error);
|
|
628
|
+
}
|
|
607
629
|
}
|
|
608
630
|
|
|
609
631
|
private async readProtocolV2Frame(uuid: string) {
|
|
@@ -755,79 +777,67 @@ export default class ElectronBleTransport {
|
|
|
755
777
|
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
756
778
|
}
|
|
757
779
|
|
|
758
|
-
const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'Ping';
|
|
759
|
-
if (this.runPromise) {
|
|
760
|
-
if (!forceRun) {
|
|
761
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
|
|
762
|
-
}
|
|
763
|
-
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
764
|
-
this.runPromise.reject(error);
|
|
765
|
-
this.rejectAllProtocolV2Frames(error);
|
|
766
|
-
this.runPromise = null;
|
|
767
|
-
this.activeProtocolV2Call = null;
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
const runPromise = createDeferred<Uint8Array | string>();
|
|
771
|
-
runPromise.promise.catch(() => undefined);
|
|
772
|
-
this.runPromise = runPromise;
|
|
773
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
774
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
775
|
-
this.v2Assemblers.get(uuid)?.reset();
|
|
776
|
-
this.resetProtocolV2Frames(uuid);
|
|
777
|
-
let completed = false;
|
|
778
780
|
const callOptions = {
|
|
779
781
|
...options,
|
|
780
782
|
timeoutMs: options?.timeoutMs ?? BLE_RESPONSE_TIMEOUT_MS,
|
|
781
783
|
};
|
|
782
784
|
|
|
783
785
|
try {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
readFrame: async () => {
|
|
792
|
-
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
793
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
794
|
-
throw new Error('Response is not Uint8Array');
|
|
795
|
-
}
|
|
796
|
-
return rxFrame;
|
|
797
|
-
},
|
|
798
|
-
logger: this.Log,
|
|
799
|
-
logPrefix: 'ProtocolV2 BLE',
|
|
800
|
-
createTimeoutError: (_messageName: string, timeout: number) =>
|
|
801
|
-
ERRORS.TypedError(
|
|
802
|
-
HardwareErrorCode.BleTimeoutError,
|
|
803
|
-
`BLE response timeout after ${timeout}ms for ${name}`
|
|
804
|
-
),
|
|
805
|
-
});
|
|
806
|
-
|
|
807
|
-
const result = await session.call(name, data, callOptions);
|
|
808
|
-
completed = true;
|
|
809
|
-
return result;
|
|
786
|
+
return await this.protocolV2Links.call(
|
|
787
|
+
uuid,
|
|
788
|
+
() => this.createProtocolV2Adapter(uuid),
|
|
789
|
+
name,
|
|
790
|
+
data,
|
|
791
|
+
callOptions
|
|
792
|
+
);
|
|
810
793
|
} catch (e) {
|
|
811
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
812
|
-
this.v2Assemblers.get(uuid)?.reset();
|
|
813
|
-
this.resetProtocolV2Frames(uuid);
|
|
814
|
-
}
|
|
815
794
|
this.Log?.error('[Electron BLE] Protocol V2 call error:', e);
|
|
816
795
|
throw e;
|
|
817
|
-
} finally {
|
|
818
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
819
|
-
if (!completed) {
|
|
820
|
-
this.v2Assemblers.get(uuid)?.reset();
|
|
821
|
-
}
|
|
822
|
-
this.resetProtocolV2Frames(uuid);
|
|
823
|
-
this.activeProtocolV2Call = null;
|
|
824
|
-
}
|
|
825
|
-
if (this.runPromise === runPromise) {
|
|
826
|
-
this.runPromise = null;
|
|
827
|
-
}
|
|
828
796
|
}
|
|
829
797
|
}
|
|
830
798
|
|
|
799
|
+
private createProtocolV2Adapter(uuid: string) {
|
|
800
|
+
const generation = this.notificationTokens.get(uuid) ?? 0;
|
|
801
|
+
const assertCurrentGeneration = () => {
|
|
802
|
+
if (this.notificationTokens.get(uuid) !== generation) {
|
|
803
|
+
throw new Error(`Protocol V2 notification generation changed for ${uuid}`);
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
|
|
807
|
+
return {
|
|
808
|
+
router: PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
809
|
+
generation,
|
|
810
|
+
prepareCall: () => {
|
|
811
|
+
assertCurrentGeneration();
|
|
812
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
813
|
+
this.resetProtocolV2Frames(uuid);
|
|
814
|
+
},
|
|
815
|
+
writeFrame: (frame: Uint8Array) => {
|
|
816
|
+
assertCurrentGeneration();
|
|
817
|
+
return this.writeWithChunking(uuid, bytesToHex(frame));
|
|
818
|
+
},
|
|
819
|
+
readFrame: async () => {
|
|
820
|
+
assertCurrentGeneration();
|
|
821
|
+
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
822
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
823
|
+
throw new Error('Response is not Uint8Array');
|
|
824
|
+
}
|
|
825
|
+
return rxFrame;
|
|
826
|
+
},
|
|
827
|
+
reset: (reason: string) => {
|
|
828
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
829
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
830
|
+
},
|
|
831
|
+
logger: this.Log,
|
|
832
|
+
logPrefix: 'ProtocolV2 BLE',
|
|
833
|
+
createTimeoutError: (messageName: string, timeout: number) =>
|
|
834
|
+
ERRORS.TypedError(
|
|
835
|
+
HardwareErrorCode.BleTimeoutError,
|
|
836
|
+
`BLE response timeout after ${timeout}ms for ${messageName}`
|
|
837
|
+
),
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
|
|
831
841
|
private processProtocolV1Notification(deviceId: string, hexData: string): PacketProcessResult {
|
|
832
842
|
try {
|
|
833
843
|
if (typeof hexData !== 'string') {
|