@onekeyfe/hd-transport-web-device 1.1.27-alpha.30 → 1.1.27-alpha.32
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/electron-auto-ble-transport.d.ts +12 -3
- package/dist/electron-auto-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.js +191 -81
- package/dist/webusb.d.ts +1 -0
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/electron-auto-ble-transport.ts +158 -54
- package/src/webusb.ts +38 -20
|
@@ -23,12 +23,17 @@ export default class ElectronAutoBleTransport {
|
|
|
23
23
|
emitter?: EventEmitter;
|
|
24
24
|
private connectedDevices;
|
|
25
25
|
private deviceProtocol;
|
|
26
|
+
private deviceProtocolHints;
|
|
26
27
|
private v1Buffers;
|
|
27
28
|
private v2Assemblers;
|
|
28
|
-
private
|
|
29
|
-
private
|
|
29
|
+
private v2FrameQueues;
|
|
30
|
+
private v2FramePromises;
|
|
31
|
+
private activeProtocolV2Call;
|
|
32
|
+
private nextProtocolV2CallToken;
|
|
30
33
|
private notificationCleanups;
|
|
31
34
|
private disconnectCleanups;
|
|
35
|
+
private notificationTokens;
|
|
36
|
+
private nextNotificationToken;
|
|
32
37
|
private handleBluetoothError;
|
|
33
38
|
private cleanupDeviceState;
|
|
34
39
|
init(logger: any, emitter?: EventEmitter): void;
|
|
@@ -50,15 +55,19 @@ export default class ElectronAutoBleTransport {
|
|
|
50
55
|
release(id: string): Promise<void>;
|
|
51
56
|
private createProtocolMismatchError;
|
|
52
57
|
private detectProtocol;
|
|
58
|
+
private createNotificationSubscription;
|
|
59
|
+
private resetProbeStateAfterProtocolProbe;
|
|
53
60
|
private probeProtocolV1;
|
|
54
61
|
private probeProtocolV2;
|
|
55
62
|
private writeWithChunking;
|
|
56
63
|
private writeWithRetry;
|
|
57
64
|
private handleNotification;
|
|
58
65
|
private handleProtocolV2Notification;
|
|
66
|
+
private getProtocolV2FrameQueue;
|
|
59
67
|
private resolveProtocolV2Frame;
|
|
60
|
-
private
|
|
68
|
+
private rejectAllProtocolV2Frames;
|
|
61
69
|
private resetProtocolV2Frames;
|
|
70
|
+
private isActiveProtocolV2Call;
|
|
62
71
|
private readProtocolV2Frame;
|
|
63
72
|
private handleProtocolV1Notification;
|
|
64
73
|
call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<import("@onekeyfe/hd-transport").MessageFromOneKey>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"electron-auto-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-auto-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;AAWvC,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;
|
|
1
|
+
{"version":3,"file":"electron-auto-ble-transport.d.ts","sourceRoot":"","sources":["../src/electron-auto-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;AAWvC,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;AAsCF,MAAM,CAAC,OAAO,OAAO,wBAAwB;IAC3C,OAAO,CAAC,SAAS,CAA0D;IAE3E,OAAO,CAAC,WAAW,CAA0D;IAE7E,IAAI,SAA8B;IAElC,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,oBAAoB,CAAgD;IAE5E,OAAO,CAAC,uBAAuB,CAAK;IAEpC,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;IAyB1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAcxC,SAAS,CAAC,UAAU,EAAE,GAAG;IAKzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAK7B,MAAM;IAIN,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAqBxC,OAAO,CAAC,KAAK,EAAE,eAAe;;;;;;;;;;;IAuF9B,OAAO,CAAC,EAAE,EAAE,MAAM;IAexB,OAAO,CAAC,2BAA2B;YAOrB,cAAc;IAgD5B,OAAO,CAAC,8BAA8B;YAgBxB,iCAAiC;YAoCjC,eAAe;YAef,eAAe;YAmBf,iBAAiB;YAsBjB,cAAc;IA4B5B,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,4BAA4B;IA6BpC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,sBAAsB;YAIhB,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;YAyBlB,cAAc;YAuEd,cAAc;IAmF5B,OAAO,CAAC,6BAA6B;IAgDrC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;CAG5C"}
|
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ declare class WebUsbTransport {
|
|
|
13
13
|
messages: ReturnType<typeof _onekeyfe_hd_transport__default.parseConfigure> | undefined;
|
|
14
14
|
messagesV2: ReturnType<typeof _onekeyfe_hd_transport__default.parseConfigure> | undefined;
|
|
15
15
|
private deviceProtocol;
|
|
16
|
+
private deviceProtocolHints;
|
|
16
17
|
private protocolV2Assemblers;
|
|
17
18
|
private deviceEndpoints;
|
|
18
19
|
name: string;
|
|
@@ -118,12 +119,17 @@ declare class ElectronAutoBleTransport {
|
|
|
118
119
|
emitter?: EventEmitter;
|
|
119
120
|
private connectedDevices;
|
|
120
121
|
private deviceProtocol;
|
|
122
|
+
private deviceProtocolHints;
|
|
121
123
|
private v1Buffers;
|
|
122
124
|
private v2Assemblers;
|
|
123
|
-
private
|
|
124
|
-
private
|
|
125
|
+
private v2FrameQueues;
|
|
126
|
+
private v2FramePromises;
|
|
127
|
+
private activeProtocolV2Call;
|
|
128
|
+
private nextProtocolV2CallToken;
|
|
125
129
|
private notificationCleanups;
|
|
126
130
|
private disconnectCleanups;
|
|
131
|
+
private notificationTokens;
|
|
132
|
+
private nextNotificationToken;
|
|
127
133
|
private handleBluetoothError;
|
|
128
134
|
private cleanupDeviceState;
|
|
129
135
|
init(logger: any, emitter?: EventEmitter): void;
|
|
@@ -145,15 +151,19 @@ declare class ElectronAutoBleTransport {
|
|
|
145
151
|
release(id: string): Promise<void>;
|
|
146
152
|
private createProtocolMismatchError;
|
|
147
153
|
private detectProtocol;
|
|
154
|
+
private createNotificationSubscription;
|
|
155
|
+
private resetProbeStateAfterProtocolProbe;
|
|
148
156
|
private probeProtocolV1;
|
|
149
157
|
private probeProtocolV2;
|
|
150
158
|
private writeWithChunking;
|
|
151
159
|
private writeWithRetry;
|
|
152
160
|
private handleNotification;
|
|
153
161
|
private handleProtocolV2Notification;
|
|
162
|
+
private getProtocolV2FrameQueue;
|
|
154
163
|
private resolveProtocolV2Frame;
|
|
155
|
-
private
|
|
164
|
+
private rejectAllProtocolV2Frames;
|
|
156
165
|
private resetProtocolV2Frames;
|
|
166
|
+
private isActiveProtocolV2Call;
|
|
157
167
|
private readProtocolV2Frame;
|
|
158
168
|
private handleProtocolV1Notification;
|
|
159
169
|
call(uuid: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<_onekeyfe_hd_transport.MessageFromOneKey>;
|
package/dist/index.js
CHANGED
|
@@ -61,12 +61,13 @@ function shouldBlockWebUsbCallDataLog(name) {
|
|
|
61
61
|
const normalized = name.replace(/[_\s-]/g, '');
|
|
62
62
|
return transport.LogBlockCommand.has(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
63
63
|
}
|
|
64
|
-
function
|
|
64
|
+
function inferProtocolHintFromDeviceName$1(name) {
|
|
65
65
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
66
66
|
}
|
|
67
67
|
class WebUsbTransport {
|
|
68
68
|
constructor() {
|
|
69
69
|
this.deviceProtocol = new Map();
|
|
70
|
+
this.deviceProtocolHints = new Map();
|
|
70
71
|
this.protocolV2Assemblers = new Map();
|
|
71
72
|
this.deviceEndpoints = new Map();
|
|
72
73
|
this.name = 'WebUsbTransport';
|
|
@@ -125,12 +126,18 @@ class WebUsbTransport {
|
|
|
125
126
|
const hasSerialNumber = typeof dev.serialNumber === 'string' && dev.serialNumber.length > 0;
|
|
126
127
|
return isOneKey && hasSerialNumber;
|
|
127
128
|
});
|
|
128
|
-
this.deviceList = onekeyDevices.map(device =>
|
|
129
|
-
path
|
|
130
|
-
device
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
this.deviceList = onekeyDevices.map(device => {
|
|
130
|
+
const path = device.serialNumber;
|
|
131
|
+
const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
|
|
132
|
+
if (protocolHint) {
|
|
133
|
+
this.deviceProtocolHints.set(path, protocolHint);
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
path,
|
|
137
|
+
device,
|
|
138
|
+
commType: 'webusb',
|
|
139
|
+
};
|
|
140
|
+
});
|
|
134
141
|
for (const dev of onekeyDevices) {
|
|
135
142
|
this.Log.debug(`[WebUSB] Device: name="${dev.productName}" serial="${dev.serialNumber}" ` +
|
|
136
143
|
`VID=0x${dev.vendorId.toString(16)} PID=0x${dev.productId.toString(16)}`);
|
|
@@ -139,13 +146,20 @@ class WebUsbTransport {
|
|
|
139
146
|
});
|
|
140
147
|
}
|
|
141
148
|
acquire(input) {
|
|
142
|
-
var _a;
|
|
149
|
+
var _a, _b, _c;
|
|
143
150
|
return __awaiter(this, void 0, void 0, function* () {
|
|
144
151
|
if (!input.path)
|
|
145
152
|
return;
|
|
146
153
|
try {
|
|
147
154
|
yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
|
|
148
|
-
|
|
155
|
+
const deviceName = (_b = this.deviceList.find(device => device.path === input.path)) === null || _b === void 0 ? void 0 : _b.device.productName;
|
|
156
|
+
const protocolHint = input.expectedProtocol
|
|
157
|
+
? undefined
|
|
158
|
+
: (_c = this.deviceProtocolHints.get(input.path)) !== null && _c !== void 0 ? _c : inferProtocolHintFromDeviceName$1(deviceName);
|
|
159
|
+
if (protocolHint) {
|
|
160
|
+
this.deviceProtocolHints.set(input.path, protocolHint);
|
|
161
|
+
}
|
|
162
|
+
yield this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
|
|
149
163
|
return yield Promise.resolve(input.path);
|
|
150
164
|
}
|
|
151
165
|
catch (e) {
|
|
@@ -157,8 +171,7 @@ class WebUsbTransport {
|
|
|
157
171
|
createProtocolMismatchError(expected) {
|
|
158
172
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
159
173
|
}
|
|
160
|
-
detectProtocol(path, expectedProtocol) {
|
|
161
|
-
var _a;
|
|
174
|
+
detectProtocol(path, expectedProtocol, protocolHint) {
|
|
162
175
|
return __awaiter(this, void 0, void 0, function* () {
|
|
163
176
|
if (expectedProtocol === 'V1') {
|
|
164
177
|
if (yield this.probeProtocolV1(path)) {
|
|
@@ -169,15 +182,6 @@ class WebUsbTransport {
|
|
|
169
182
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
170
183
|
}
|
|
171
184
|
if (expectedProtocol === 'V2') {
|
|
172
|
-
if (this.deviceProtocol.get(path) === 'V2') {
|
|
173
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (cached expected)`);
|
|
174
|
-
return 'V2';
|
|
175
|
-
}
|
|
176
|
-
if (((_a = this.deviceList.find(device => device.path === path)) === null || _a === void 0 ? void 0 : _a.protocolType) === 'V2') {
|
|
177
|
-
this.deviceProtocol.set(path, 'V2');
|
|
178
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (descriptor)`);
|
|
179
|
-
return 'V2';
|
|
180
|
-
}
|
|
181
185
|
if (yield this.probeProtocolV2(path)) {
|
|
182
186
|
this.deviceProtocol.set(path, 'V2');
|
|
183
187
|
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
@@ -185,6 +189,11 @@ class WebUsbTransport {
|
|
|
185
189
|
}
|
|
186
190
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
187
191
|
}
|
|
192
|
+
if (protocolHint === 'V2' && (yield this.probeProtocolV2(path))) {
|
|
193
|
+
this.deviceProtocol.set(path, 'V2');
|
|
194
|
+
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (hint)`);
|
|
195
|
+
return 'V2';
|
|
196
|
+
}
|
|
188
197
|
if (this.deviceProtocol.get(path) === 'V2' && (yield this.probeProtocolV2(path))) {
|
|
189
198
|
this.deviceProtocol.set(path, 'V2');
|
|
190
199
|
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (cached)`);
|
|
@@ -647,13 +656,16 @@ class WebUsbTransport {
|
|
|
647
656
|
});
|
|
648
657
|
}
|
|
649
658
|
release(path) {
|
|
650
|
-
var _a;
|
|
659
|
+
var _a, _b;
|
|
651
660
|
return __awaiter(this, void 0, void 0, function* () {
|
|
652
661
|
const device = yield this.findDevice(path);
|
|
653
662
|
const endpoints = this.deviceEndpoints.get(path);
|
|
654
663
|
const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
|
|
655
664
|
yield device.releaseInterface(ifaceNum);
|
|
656
665
|
yield device.close();
|
|
666
|
+
this.deviceProtocol.delete(path);
|
|
667
|
+
this.deviceProtocolHints.delete(path);
|
|
668
|
+
(_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
657
669
|
this.protocolV2Assemblers.delete(path);
|
|
658
670
|
this.deviceEndpoints.delete(path);
|
|
659
671
|
});
|
|
@@ -963,13 +975,10 @@ function shouldSuppressHighVolumeCallLog(name) {
|
|
|
963
975
|
return FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
964
976
|
}
|
|
965
977
|
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
966
|
-
function
|
|
978
|
+
function inferProtocolHintFromDeviceName(name) {
|
|
967
979
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
968
980
|
}
|
|
969
|
-
const toBleDescriptor = (device, protocolType) => {
|
|
970
|
-
const resolvedProtocolType = protocolType !== null && protocolType !== void 0 ? protocolType : inferProtocolTypeFromDeviceName(device.name);
|
|
971
|
-
return Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (resolvedProtocolType ? { protocolType: resolvedProtocolType } : {}));
|
|
972
|
-
};
|
|
981
|
+
const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
|
|
973
982
|
const BLE_PACKET_SIZE = 192;
|
|
974
983
|
const BLE_WRITE_DELAY_MS = 5;
|
|
975
984
|
const BLE_WRITE_MAX_RETRIES = 3;
|
|
@@ -983,12 +992,17 @@ class ElectronAutoBleTransport {
|
|
|
983
992
|
this.runPromise = null;
|
|
984
993
|
this.connectedDevices = new Set();
|
|
985
994
|
this.deviceProtocol = new Map();
|
|
995
|
+
this.deviceProtocolHints = new Map();
|
|
986
996
|
this.v1Buffers = new Map();
|
|
987
997
|
this.v2Assemblers = new Map();
|
|
988
|
-
this.
|
|
989
|
-
this.
|
|
998
|
+
this.v2FrameQueues = new Map();
|
|
999
|
+
this.v2FramePromises = new Map();
|
|
1000
|
+
this.activeProtocolV2Call = null;
|
|
1001
|
+
this.nextProtocolV2CallToken = 1;
|
|
990
1002
|
this.notificationCleanups = new Map();
|
|
991
1003
|
this.disconnectCleanups = new Map();
|
|
1004
|
+
this.notificationTokens = new Map();
|
|
1005
|
+
this.nextNotificationToken = 1;
|
|
992
1006
|
}
|
|
993
1007
|
handleBluetoothError(error) {
|
|
994
1008
|
if (error && typeof error === 'object') {
|
|
@@ -1020,10 +1034,17 @@ class ElectronAutoBleTransport {
|
|
|
1020
1034
|
throw error;
|
|
1021
1035
|
}
|
|
1022
1036
|
cleanupDeviceState(deviceId) {
|
|
1037
|
+
var _a;
|
|
1023
1038
|
this.connectedDevices.delete(deviceId);
|
|
1024
1039
|
this.deviceProtocol.delete(deviceId);
|
|
1040
|
+
this.deviceProtocolHints.delete(deviceId);
|
|
1025
1041
|
this.v1Buffers.delete(deviceId);
|
|
1026
1042
|
this.v2Assemblers.delete(deviceId);
|
|
1043
|
+
this.resetProtocolV2Frames(deviceId);
|
|
1044
|
+
if (((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === deviceId) {
|
|
1045
|
+
this.activeProtocolV2Call = null;
|
|
1046
|
+
}
|
|
1047
|
+
this.notificationTokens.delete(deviceId);
|
|
1027
1048
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
1028
1049
|
if (notifyCleanup) {
|
|
1029
1050
|
notifyCleanup();
|
|
@@ -1069,6 +1090,10 @@ class ElectronAutoBleTransport {
|
|
|
1069
1090
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Auto BLE] enumerate found ${devices.length} device(s):`);
|
|
1070
1091
|
for (const dev of devices) {
|
|
1071
1092
|
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Auto BLE] id="${dev.id}" name="${dev.name}"`);
|
|
1093
|
+
const protocolHint = inferProtocolHintFromDeviceName(dev.name);
|
|
1094
|
+
if (protocolHint) {
|
|
1095
|
+
this.deviceProtocolHints.set(dev.id, protocolHint);
|
|
1096
|
+
}
|
|
1072
1097
|
}
|
|
1073
1098
|
return devices.map(device => toBleDescriptor(device));
|
|
1074
1099
|
}
|
|
@@ -1079,7 +1104,7 @@ class ElectronAutoBleTransport {
|
|
|
1079
1104
|
});
|
|
1080
1105
|
}
|
|
1081
1106
|
acquire(input) {
|
|
1082
|
-
var _a, _b, _c, _d, _e;
|
|
1107
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1083
1108
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1084
1109
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
1085
1110
|
if (!uuid) {
|
|
@@ -1088,7 +1113,9 @@ class ElectronAutoBleTransport {
|
|
|
1088
1113
|
if (forceCleanRunPromise && this.runPromise) {
|
|
1089
1114
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1090
1115
|
this.runPromise.reject(error);
|
|
1091
|
-
this.
|
|
1116
|
+
this.rejectAllProtocolV2Frames(error);
|
|
1117
|
+
this.runPromise = null;
|
|
1118
|
+
this.activeProtocolV2Call = null;
|
|
1092
1119
|
}
|
|
1093
1120
|
try {
|
|
1094
1121
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
@@ -1098,6 +1125,12 @@ class ElectronAutoBleTransport {
|
|
|
1098
1125
|
if (!device) {
|
|
1099
1126
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
|
|
1100
1127
|
}
|
|
1128
|
+
const protocolHint = expectedProtocol
|
|
1129
|
+
? undefined
|
|
1130
|
+
: (_b = this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(device.name);
|
|
1131
|
+
if (protocolHint) {
|
|
1132
|
+
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
1133
|
+
}
|
|
1101
1134
|
try {
|
|
1102
1135
|
yield window.desktopApi.nobleBle.connect(uuid);
|
|
1103
1136
|
this.connectedDevices.add(uuid);
|
|
@@ -1108,11 +1141,7 @@ class ElectronAutoBleTransport {
|
|
|
1108
1141
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1109
1142
|
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
|
|
1110
1143
|
yield window.desktopApi.nobleBle.subscribe(uuid);
|
|
1111
|
-
const cleanup =
|
|
1112
|
-
if (deviceId === uuid) {
|
|
1113
|
-
this.handleNotification(uuid, data);
|
|
1114
|
-
}
|
|
1115
|
-
});
|
|
1144
|
+
const cleanup = this.createNotificationSubscription(uuid);
|
|
1116
1145
|
this.notificationCleanups.set(uuid, cleanup);
|
|
1117
1146
|
const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
|
|
1118
1147
|
var _a;
|
|
@@ -1126,8 +1155,8 @@ class ElectronAutoBleTransport {
|
|
|
1126
1155
|
}
|
|
1127
1156
|
});
|
|
1128
1157
|
this.disconnectCleanups.set(uuid, disconnectCleanup);
|
|
1129
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol);
|
|
1130
|
-
(
|
|
1158
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
1159
|
+
(_c = this.emitter) === null || _c === void 0 ? void 0 : _c.emit('device-connect', {
|
|
1131
1160
|
name: device.name,
|
|
1132
1161
|
id: device.id,
|
|
1133
1162
|
connectId: device.id,
|
|
@@ -1135,15 +1164,15 @@ class ElectronAutoBleTransport {
|
|
|
1135
1164
|
return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
|
|
1136
1165
|
}
|
|
1137
1166
|
catch (error) {
|
|
1138
|
-
(
|
|
1167
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Auto BLE] acquire failed:', error);
|
|
1139
1168
|
try {
|
|
1140
|
-
if (((
|
|
1169
|
+
if (((_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) && this.connectedDevices.has(uuid)) {
|
|
1141
1170
|
yield window.desktopApi.nobleBle.unsubscribe(uuid);
|
|
1142
1171
|
yield window.desktopApi.nobleBle.disconnect(uuid);
|
|
1143
1172
|
}
|
|
1144
1173
|
}
|
|
1145
1174
|
catch (cleanupError) {
|
|
1146
|
-
(
|
|
1175
|
+
(_f = this.Log) === null || _f === void 0 ? void 0 : _f.debug('[Auto BLE] acquire cleanup failed:', cleanupError);
|
|
1147
1176
|
}
|
|
1148
1177
|
this.cleanupDeviceState(uuid);
|
|
1149
1178
|
throw error;
|
|
@@ -1171,8 +1200,8 @@ class ElectronAutoBleTransport {
|
|
|
1171
1200
|
createProtocolMismatchError(expected) {
|
|
1172
1201
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1173
1202
|
}
|
|
1174
|
-
detectProtocol(uuid, expectedProtocol) {
|
|
1175
|
-
var _a, _b, _c, _d;
|
|
1203
|
+
detectProtocol(uuid, expectedProtocol, protocolHint) {
|
|
1204
|
+
var _a, _b, _c, _d, _e;
|
|
1176
1205
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1177
1206
|
if (expectedProtocol === 'V1') {
|
|
1178
1207
|
if (yield this.probeProtocolV1(uuid)) {
|
|
@@ -1190,20 +1219,80 @@ class ElectronAutoBleTransport {
|
|
|
1190
1219
|
}
|
|
1191
1220
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1192
1221
|
}
|
|
1222
|
+
if (protocolHint === 'V2' && (yield this.probeProtocolV2(uuid))) {
|
|
1223
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1224
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> V2 (hint)`);
|
|
1225
|
+
return 'V2';
|
|
1226
|
+
}
|
|
1193
1227
|
if (this.deviceProtocol.get(uuid) === 'V2' && (yield this.probeProtocolV2(uuid))) {
|
|
1194
1228
|
this.deviceProtocol.set(uuid, 'V2');
|
|
1195
|
-
(
|
|
1229
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> V2 (cached)`);
|
|
1196
1230
|
return 'V2';
|
|
1197
1231
|
}
|
|
1198
1232
|
let protocol = 'V1';
|
|
1199
|
-
|
|
1200
|
-
|
|
1233
|
+
const protocolV1Detected = yield this.probeProtocolV1(uuid);
|
|
1234
|
+
if (!protocolV1Detected) {
|
|
1235
|
+
yield this.resetProbeStateAfterProtocolProbe(uuid, 'V1');
|
|
1236
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1237
|
+
protocol = 'V2';
|
|
1238
|
+
}
|
|
1201
1239
|
}
|
|
1202
1240
|
this.deviceProtocol.set(uuid, protocol);
|
|
1203
|
-
(
|
|
1241
|
+
(_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> ${protocol}`);
|
|
1204
1242
|
return protocol;
|
|
1205
1243
|
});
|
|
1206
1244
|
}
|
|
1245
|
+
createNotificationSubscription(uuid) {
|
|
1246
|
+
var _a;
|
|
1247
|
+
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
1248
|
+
throw new Error('Noble BLE API not available');
|
|
1249
|
+
}
|
|
1250
|
+
const notificationToken = this.nextNotificationToken;
|
|
1251
|
+
this.nextNotificationToken += 1;
|
|
1252
|
+
this.notificationTokens.set(uuid, notificationToken);
|
|
1253
|
+
return window.desktopApi.nobleBle.onNotification((deviceId, data) => {
|
|
1254
|
+
if (deviceId === uuid && this.notificationTokens.get(uuid) === notificationToken) {
|
|
1255
|
+
this.handleNotification(uuid, data);
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1260
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1261
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1262
|
+
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1263
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1264
|
+
this.resetProtocolV2Frames(uuid);
|
|
1265
|
+
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
1266
|
+
this.activeProtocolV2Call = null;
|
|
1267
|
+
}
|
|
1268
|
+
if (this.runPromise) {
|
|
1269
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1270
|
+
this.runPromise.reject(error);
|
|
1271
|
+
this.runPromise = null;
|
|
1272
|
+
}
|
|
1273
|
+
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1274
|
+
if (notifyCleanup) {
|
|
1275
|
+
notifyCleanup();
|
|
1276
|
+
this.notificationCleanups.delete(uuid);
|
|
1277
|
+
}
|
|
1278
|
+
this.notificationTokens.delete(uuid);
|
|
1279
|
+
try {
|
|
1280
|
+
yield ((_d = (_c = window.desktopApi) === null || _c === void 0 ? void 0 : _c.nobleBle) === null || _d === void 0 ? void 0 : _d.unsubscribe(uuid));
|
|
1281
|
+
}
|
|
1282
|
+
catch (error) {
|
|
1283
|
+
(_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug(`[Auto BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1284
|
+
}
|
|
1285
|
+
try {
|
|
1286
|
+
yield ((_g = (_f = window.desktopApi) === null || _f === void 0 ? void 0 : _f.nobleBle) === null || _g === void 0 ? void 0 : _g.subscribe(uuid));
|
|
1287
|
+
}
|
|
1288
|
+
catch (error) {
|
|
1289
|
+
(_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug(`[Auto BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1290
|
+
throw error;
|
|
1291
|
+
}
|
|
1292
|
+
const cleanup = this.createNotificationSubscription(uuid);
|
|
1293
|
+
this.notificationCleanups.set(uuid, cleanup);
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1207
1296
|
probeProtocolV1(uuid) {
|
|
1208
1297
|
var _a;
|
|
1209
1298
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1237,7 +1326,7 @@ class ElectronAutoBleTransport {
|
|
|
1237
1326
|
onProbeFailed: () => {
|
|
1238
1327
|
var _a;
|
|
1239
1328
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1240
|
-
this.resetProtocolV2Frames();
|
|
1329
|
+
this.resetProtocolV2Frames(uuid);
|
|
1241
1330
|
},
|
|
1242
1331
|
});
|
|
1243
1332
|
});
|
|
@@ -1292,7 +1381,7 @@ class ElectronAutoBleTransport {
|
|
|
1292
1381
|
if (this.runPromise) {
|
|
1293
1382
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
|
|
1294
1383
|
this.runPromise.reject(error);
|
|
1295
|
-
this.
|
|
1384
|
+
this.rejectAllProtocolV2Frames(error);
|
|
1296
1385
|
}
|
|
1297
1386
|
return;
|
|
1298
1387
|
}
|
|
@@ -1304,11 +1393,11 @@ class ElectronAutoBleTransport {
|
|
|
1304
1393
|
this.handleProtocolV1Notification(deviceId, hexData);
|
|
1305
1394
|
}
|
|
1306
1395
|
handleProtocolV2Notification(deviceId, hexData) {
|
|
1307
|
-
var _a, _b;
|
|
1396
|
+
var _a, _b, _c;
|
|
1308
1397
|
try {
|
|
1309
|
-
if (!this.runPromise) {
|
|
1310
|
-
(
|
|
1311
|
-
this.resetProtocolV2Frames();
|
|
1398
|
+
if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== deviceId) {
|
|
1399
|
+
(_b = this.v2Assemblers.get(deviceId)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1400
|
+
this.resetProtocolV2Frames(deviceId);
|
|
1312
1401
|
return;
|
|
1313
1402
|
}
|
|
1314
1403
|
const bytes = transport.hexToBytes(hexData);
|
|
@@ -1319,52 +1408,65 @@ class ElectronAutoBleTransport {
|
|
|
1319
1408
|
return;
|
|
1320
1409
|
let frameData = assembler.push(bytes);
|
|
1321
1410
|
while (frameData) {
|
|
1322
|
-
this.resolveProtocolV2Frame(frameData);
|
|
1411
|
+
this.resolveProtocolV2Frame(deviceId, frameData);
|
|
1323
1412
|
frameData = assembler.push(new Uint8Array(0));
|
|
1324
1413
|
}
|
|
1325
1414
|
}
|
|
1326
1415
|
catch (error) {
|
|
1327
|
-
(
|
|
1416
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Auto BLE] Protocol V2 notification error:', error);
|
|
1328
1417
|
if (this.runPromise) {
|
|
1329
1418
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1330
1419
|
this.runPromise.reject(notifyError);
|
|
1331
|
-
this.
|
|
1420
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
1332
1421
|
}
|
|
1333
1422
|
}
|
|
1334
1423
|
}
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1424
|
+
getProtocolV2FrameQueue(uuid) {
|
|
1425
|
+
let queue = this.v2FrameQueues.get(uuid);
|
|
1426
|
+
if (!queue) {
|
|
1427
|
+
queue = [];
|
|
1428
|
+
this.v2FrameQueues.set(uuid, queue);
|
|
1429
|
+
}
|
|
1430
|
+
return queue;
|
|
1431
|
+
}
|
|
1432
|
+
resolveProtocolV2Frame(uuid, frame) {
|
|
1433
|
+
const framePromise = this.v2FramePromises.get(uuid);
|
|
1434
|
+
if (framePromise) {
|
|
1435
|
+
framePromise.resolve(frame);
|
|
1436
|
+
this.v2FramePromises.delete(uuid);
|
|
1339
1437
|
return;
|
|
1340
1438
|
}
|
|
1341
|
-
this.
|
|
1439
|
+
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1342
1440
|
}
|
|
1343
|
-
|
|
1344
|
-
this.
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
this.v2FramePromise = null;
|
|
1441
|
+
rejectAllProtocolV2Frames(error) {
|
|
1442
|
+
this.v2FrameQueues.clear();
|
|
1443
|
+
for (const framePromise of this.v2FramePromises.values()) {
|
|
1444
|
+
framePromise.reject(error);
|
|
1348
1445
|
}
|
|
1446
|
+
this.v2FramePromises.clear();
|
|
1349
1447
|
}
|
|
1350
|
-
resetProtocolV2Frames() {
|
|
1351
|
-
this.
|
|
1352
|
-
this.
|
|
1448
|
+
resetProtocolV2Frames(uuid) {
|
|
1449
|
+
this.v2FrameQueues.delete(uuid);
|
|
1450
|
+
this.v2FramePromises.delete(uuid);
|
|
1353
1451
|
}
|
|
1354
|
-
|
|
1452
|
+
isActiveProtocolV2Call(uuid, token) {
|
|
1453
|
+
var _a;
|
|
1454
|
+
return ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === uuid && this.activeProtocolV2Call.token === token;
|
|
1455
|
+
}
|
|
1456
|
+
readProtocolV2Frame(uuid) {
|
|
1355
1457
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1356
|
-
const queuedFrame = this.
|
|
1458
|
+
const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
|
|
1357
1459
|
if (queuedFrame) {
|
|
1358
1460
|
return queuedFrame;
|
|
1359
1461
|
}
|
|
1360
1462
|
const framePromise = hdShared.createDeferred();
|
|
1361
|
-
this.
|
|
1463
|
+
this.v2FramePromises.set(uuid, framePromise);
|
|
1362
1464
|
try {
|
|
1363
1465
|
return yield framePromise.promise;
|
|
1364
1466
|
}
|
|
1365
1467
|
finally {
|
|
1366
|
-
if (this.
|
|
1367
|
-
this.
|
|
1468
|
+
if (this.v2FramePromises.get(uuid) === framePromise) {
|
|
1469
|
+
this.v2FramePromises.delete(uuid);
|
|
1368
1470
|
}
|
|
1369
1471
|
}
|
|
1370
1472
|
});
|
|
@@ -1481,14 +1583,17 @@ class ElectronAutoBleTransport {
|
|
|
1481
1583
|
}
|
|
1482
1584
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1483
1585
|
this.runPromise.reject(error);
|
|
1484
|
-
this.
|
|
1586
|
+
this.rejectAllProtocolV2Frames(error);
|
|
1485
1587
|
this.runPromise = null;
|
|
1588
|
+
this.activeProtocolV2Call = null;
|
|
1486
1589
|
}
|
|
1487
1590
|
const runPromise = hdShared.createDeferred();
|
|
1488
1591
|
runPromise.promise.catch(() => undefined);
|
|
1489
1592
|
this.runPromise = runPromise;
|
|
1593
|
+
const callToken = this.nextProtocolV2CallToken++;
|
|
1594
|
+
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1490
1595
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1491
|
-
this.resetProtocolV2Frames();
|
|
1596
|
+
this.resetProtocolV2Frames(uuid);
|
|
1492
1597
|
let completed = false;
|
|
1493
1598
|
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 });
|
|
1494
1599
|
try {
|
|
@@ -1500,7 +1605,7 @@ class ElectronAutoBleTransport {
|
|
|
1500
1605
|
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1501
1606
|
writeFrame: (frame) => this.writeWithChunking(uuid, transport.bytesToHex(frame)),
|
|
1502
1607
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1503
|
-
const rxFrame = yield this.readProtocolV2Frame();
|
|
1608
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1504
1609
|
if (!(rxFrame instanceof Uint8Array)) {
|
|
1505
1610
|
throw new Error('Response is not Uint8Array');
|
|
1506
1611
|
}
|
|
@@ -1515,16 +1620,21 @@ class ElectronAutoBleTransport {
|
|
|
1515
1620
|
return result;
|
|
1516
1621
|
}
|
|
1517
1622
|
catch (e) {
|
|
1518
|
-
(
|
|
1519
|
-
|
|
1623
|
+
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1624
|
+
(_c = this.v2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1625
|
+
this.resetProtocolV2Frames(uuid);
|
|
1626
|
+
}
|
|
1520
1627
|
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Auto BLE] Protocol V2 call error:', e);
|
|
1521
1628
|
throw e;
|
|
1522
1629
|
}
|
|
1523
1630
|
finally {
|
|
1524
|
-
if (
|
|
1525
|
-
|
|
1631
|
+
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1632
|
+
if (!completed) {
|
|
1633
|
+
(_e = this.v2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
|
|
1634
|
+
}
|
|
1635
|
+
this.resetProtocolV2Frames(uuid);
|
|
1636
|
+
this.activeProtocolV2Call = null;
|
|
1526
1637
|
}
|
|
1527
|
-
this.resetProtocolV2Frames();
|
|
1528
1638
|
if (this.runPromise === runPromise) {
|
|
1529
1639
|
this.runPromise = null;
|
|
1530
1640
|
}
|
package/dist/webusb.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export default class WebUsbTransport {
|
|
|
10
10
|
messages: ReturnType<typeof transport.parseConfigure> | undefined;
|
|
11
11
|
messagesV2: ReturnType<typeof transport.parseConfigure> | undefined;
|
|
12
12
|
private deviceProtocol;
|
|
13
|
+
private deviceProtocolHints;
|
|
13
14
|
private protocolV2Assemblers;
|
|
14
15
|
private deviceEndpoints;
|
|
15
16
|
name: string;
|
package/dist/webusb.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":";AACA,OAAO,SAWN,MAAM,wBAAwB,CAAC;AAIhC,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAiChC,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAaD,MAAM,CAAC,OAAO,OAAO,eAAe;IAClC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGlE,UAAU,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGpE,OAAO,CAAC,cAAc,CAAwC;
|
|
1
|
+
{"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":";AACA,OAAO,SAWN,MAAM,wBAAwB,CAAC;AAIhC,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAiChC,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAaD,MAAM,CAAC,OAAO,OAAO,eAAe;IAClC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGlE,UAAU,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGpE,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,oBAAoB,CAAoD;IAGhF,OAAO,CAAC,eAAe,CAA2C;IAElE,IAAI,SAAqB;IAEzB,OAAO,UAAS;IAEhB,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,GAAG,CAAC,EAAE,GAAG,CAAC;IAMV,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAM;IAEnC,eAAe,SAAoB;IAEnC,UAAU,SAAe;IAEzB,WAAW,SAAgB;IAK3B,IAAI,CAAC,MAAM,EAAE,GAAG;IAgBhB,SAAS,CAAC,UAAU,EAAE,GAAG;IASzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAU7B,kBAAkB;IAmBlB,SAAS;IAQT,mBAAmB;IAwCnB,OAAO,CAAC,KAAK,EAAE,YAAY;IAyBjC,OAAO,CAAC,2BAA2B;YAOrB,cAAc;IA+CtB,UAAU,CAAC,IAAI,EAAE,MAAM;IAwBvB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;IAkB1C,OAAO,CAAC,iBAAiB;IAiCnB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;IAgC5C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIvE,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,wBAAwB;YAalB,yBAAyB;IAiCvC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;YASP,oBAAoB;YAoCpB,mBAAmB;YA2CnB,yBAAyB;YAuBzB,uBAAuB;YA4CvB,eAAe;YAcf,eAAe;IAiBvB,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA4BlB,cAAc;YAkCd,cAAc;YAmCd,sBAAsB;IA4C9B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAgD5C,OAAO,CAAC,IAAI,EAAE,MAAM;IAiB1B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;CAG5C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-web-device",
|
|
3
|
-
"version": "1.1.27-alpha.
|
|
3
|
+
"version": "1.1.27-alpha.32",
|
|
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.1.27-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.1.27-alpha.
|
|
23
|
+
"@onekeyfe/hd-shared": "1.1.27-alpha.32",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.1.27-alpha.32"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@onekeyfe/hd-transport-electron": "1.1.27-alpha.
|
|
27
|
+
"@onekeyfe/hd-transport-electron": "1.1.27-alpha.32",
|
|
28
28
|
"@types/w3c-web-usb": "^1.0.6",
|
|
29
29
|
"@types/web-bluetooth": "^0.0.17"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "04f92052a18dcf17e4a347f3003b4c4bbf062681"
|
|
32
32
|
}
|
|
@@ -49,25 +49,22 @@ interface PacketProcessResult {
|
|
|
49
49
|
error?: string;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
52
|
+
function inferProtocolHintFromDeviceName(name?: string | null): ProtocolType | undefined {
|
|
53
53
|
return /\bpro\s*2\b/i.test(name ?? '') ? 'V2' : undefined;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
const toBleDescriptor = (
|
|
57
57
|
device: { id: string; name: string | null },
|
|
58
58
|
protocolType?: ProtocolType
|
|
59
|
-
): OneKeyDeviceInfo =>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return {
|
|
59
|
+
): OneKeyDeviceInfo =>
|
|
60
|
+
({
|
|
63
61
|
id: device.id,
|
|
64
62
|
name: device.name,
|
|
65
63
|
path: device.id,
|
|
66
64
|
debug: false,
|
|
67
65
|
commType: 'electron-ble',
|
|
68
|
-
...(
|
|
69
|
-
} as OneKeyDeviceInfo;
|
|
70
|
-
};
|
|
66
|
+
...(protocolType ? { protocolType } : {}),
|
|
67
|
+
} as OneKeyDeviceInfo);
|
|
71
68
|
|
|
72
69
|
const BLE_PACKET_SIZE = 192;
|
|
73
70
|
const BLE_WRITE_DELAY_MS = 5;
|
|
@@ -101,18 +98,28 @@ export default class ElectronAutoBleTransport {
|
|
|
101
98
|
|
|
102
99
|
private deviceProtocol: Map<string, ProtocolType> = new Map();
|
|
103
100
|
|
|
101
|
+
private deviceProtocolHints: Map<string, ProtocolType> = new Map();
|
|
102
|
+
|
|
104
103
|
private v1Buffers: Map<string, { buffer: number[]; bufferLength: number }> = new Map();
|
|
105
104
|
|
|
106
105
|
private v2Assemblers: Map<string, ProtocolV2FrameAssembler> = new Map();
|
|
107
106
|
|
|
108
|
-
private
|
|
107
|
+
private v2FrameQueues: Map<string, Uint8Array[]> = new Map();
|
|
108
|
+
|
|
109
|
+
private v2FramePromises: Map<string, Deferred<Uint8Array>> = new Map();
|
|
109
110
|
|
|
110
|
-
private
|
|
111
|
+
private activeProtocolV2Call: { uuid: string; token: number } | null = null;
|
|
112
|
+
|
|
113
|
+
private nextProtocolV2CallToken = 1;
|
|
111
114
|
|
|
112
115
|
private notificationCleanups: Map<string, () => void> = new Map();
|
|
113
116
|
|
|
114
117
|
private disconnectCleanups: Map<string, () => void> = new Map();
|
|
115
118
|
|
|
119
|
+
private notificationTokens: Map<string, number> = new Map();
|
|
120
|
+
|
|
121
|
+
private nextNotificationToken = 1;
|
|
122
|
+
|
|
116
123
|
private handleBluetoothError(error: any): never {
|
|
117
124
|
if (error && typeof error === 'object') {
|
|
118
125
|
if ('code' in error) {
|
|
@@ -147,8 +154,14 @@ export default class ElectronAutoBleTransport {
|
|
|
147
154
|
private cleanupDeviceState(deviceId: string): void {
|
|
148
155
|
this.connectedDevices.delete(deviceId);
|
|
149
156
|
this.deviceProtocol.delete(deviceId);
|
|
157
|
+
this.deviceProtocolHints.delete(deviceId);
|
|
150
158
|
this.v1Buffers.delete(deviceId);
|
|
151
159
|
this.v2Assemblers.delete(deviceId);
|
|
160
|
+
this.resetProtocolV2Frames(deviceId);
|
|
161
|
+
if (this.activeProtocolV2Call?.uuid === deviceId) {
|
|
162
|
+
this.activeProtocolV2Call = null;
|
|
163
|
+
}
|
|
164
|
+
this.notificationTokens.delete(deviceId);
|
|
152
165
|
|
|
153
166
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
154
167
|
if (notifyCleanup) {
|
|
@@ -200,6 +213,10 @@ export default class ElectronAutoBleTransport {
|
|
|
200
213
|
this.Log?.debug(`[Auto BLE] enumerate found ${devices.length} device(s):`);
|
|
201
214
|
for (const dev of devices) {
|
|
202
215
|
this.Log?.debug(`[Auto BLE] id="${dev.id}" name="${dev.name}"`);
|
|
216
|
+
const protocolHint = inferProtocolHintFromDeviceName(dev.name);
|
|
217
|
+
if (protocolHint) {
|
|
218
|
+
this.deviceProtocolHints.set(dev.id, protocolHint);
|
|
219
|
+
}
|
|
203
220
|
}
|
|
204
221
|
return devices.map(device => toBleDescriptor(device));
|
|
205
222
|
} catch (error) {
|
|
@@ -218,7 +235,9 @@ export default class ElectronAutoBleTransport {
|
|
|
218
235
|
if (forceCleanRunPromise && this.runPromise) {
|
|
219
236
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
220
237
|
this.runPromise.reject(error);
|
|
221
|
-
this.
|
|
238
|
+
this.rejectAllProtocolV2Frames(error);
|
|
239
|
+
this.runPromise = null;
|
|
240
|
+
this.activeProtocolV2Call = null;
|
|
222
241
|
}
|
|
223
242
|
|
|
224
243
|
try {
|
|
@@ -230,6 +249,12 @@ export default class ElectronAutoBleTransport {
|
|
|
230
249
|
if (!device) {
|
|
231
250
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
|
|
232
251
|
}
|
|
252
|
+
const protocolHint = expectedProtocol
|
|
253
|
+
? undefined
|
|
254
|
+
: this.deviceProtocolHints.get(uuid) ?? inferProtocolHintFromDeviceName(device.name);
|
|
255
|
+
if (protocolHint) {
|
|
256
|
+
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
257
|
+
}
|
|
233
258
|
|
|
234
259
|
try {
|
|
235
260
|
await window.desktopApi.nobleBle.connect(uuid);
|
|
@@ -243,13 +268,7 @@ export default class ElectronAutoBleTransport {
|
|
|
243
268
|
|
|
244
269
|
await window.desktopApi.nobleBle.subscribe(uuid);
|
|
245
270
|
|
|
246
|
-
const cleanup =
|
|
247
|
-
(deviceId: string, data: string) => {
|
|
248
|
-
if (deviceId === uuid) {
|
|
249
|
-
this.handleNotification(uuid, data);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
);
|
|
271
|
+
const cleanup = this.createNotificationSubscription(uuid);
|
|
253
272
|
this.notificationCleanups.set(uuid, cleanup);
|
|
254
273
|
|
|
255
274
|
const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected(
|
|
@@ -266,7 +285,7 @@ export default class ElectronAutoBleTransport {
|
|
|
266
285
|
);
|
|
267
286
|
this.disconnectCleanups.set(uuid, disconnectCleanup);
|
|
268
287
|
|
|
269
|
-
const protocolType = await this.detectProtocol(uuid, expectedProtocol);
|
|
288
|
+
const protocolType = await this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
270
289
|
|
|
271
290
|
this.emitter?.emit('device-connect', {
|
|
272
291
|
name: device.name,
|
|
@@ -317,7 +336,8 @@ export default class ElectronAutoBleTransport {
|
|
|
317
336
|
|
|
318
337
|
private async detectProtocol(
|
|
319
338
|
uuid: string,
|
|
320
|
-
expectedProtocol?: ProtocolType
|
|
339
|
+
expectedProtocol?: ProtocolType,
|
|
340
|
+
protocolHint?: ProtocolType
|
|
321
341
|
): Promise<ProtocolType> {
|
|
322
342
|
if (expectedProtocol === 'V1') {
|
|
323
343
|
if (await this.probeProtocolV1(uuid)) {
|
|
@@ -337,6 +357,12 @@ export default class ElectronAutoBleTransport {
|
|
|
337
357
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
338
358
|
}
|
|
339
359
|
|
|
360
|
+
if (protocolHint === 'V2' && (await this.probeProtocolV2(uuid))) {
|
|
361
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
362
|
+
this.Log?.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> V2 (hint)`);
|
|
363
|
+
return 'V2';
|
|
364
|
+
}
|
|
365
|
+
|
|
340
366
|
if (this.deviceProtocol.get(uuid) === 'V2' && (await this.probeProtocolV2(uuid))) {
|
|
341
367
|
this.deviceProtocol.set(uuid, 'V2');
|
|
342
368
|
this.Log?.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> V2 (cached)`);
|
|
@@ -344,14 +370,70 @@ export default class ElectronAutoBleTransport {
|
|
|
344
370
|
}
|
|
345
371
|
|
|
346
372
|
let protocol: ProtocolType = 'V1';
|
|
347
|
-
|
|
348
|
-
|
|
373
|
+
const protocolV1Detected = await this.probeProtocolV1(uuid);
|
|
374
|
+
if (!protocolV1Detected) {
|
|
375
|
+
await this.resetProbeStateAfterProtocolProbe(uuid, 'V1');
|
|
376
|
+
if (await this.probeProtocolV2(uuid)) {
|
|
377
|
+
protocol = 'V2';
|
|
378
|
+
}
|
|
349
379
|
}
|
|
350
380
|
this.deviceProtocol.set(uuid, protocol);
|
|
351
381
|
this.Log?.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> ${protocol}`);
|
|
352
382
|
return protocol;
|
|
353
383
|
}
|
|
354
384
|
|
|
385
|
+
private createNotificationSubscription(uuid: string) {
|
|
386
|
+
if (!window.desktopApi?.nobleBle) {
|
|
387
|
+
throw new Error('Noble BLE API not available');
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const notificationToken = this.nextNotificationToken;
|
|
391
|
+
this.nextNotificationToken += 1;
|
|
392
|
+
this.notificationTokens.set(uuid, notificationToken);
|
|
393
|
+
|
|
394
|
+
return window.desktopApi.nobleBle.onNotification((deviceId: string, data: string) => {
|
|
395
|
+
if (deviceId === uuid && this.notificationTokens.get(uuid) === notificationToken) {
|
|
396
|
+
this.handleNotification(uuid, data);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private async resetProbeStateAfterProtocolProbe(uuid: string, protocol: ProtocolType) {
|
|
402
|
+
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
403
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
404
|
+
this.resetProtocolV2Frames(uuid);
|
|
405
|
+
if (this.activeProtocolV2Call?.uuid === uuid) {
|
|
406
|
+
this.activeProtocolV2Call = null;
|
|
407
|
+
}
|
|
408
|
+
if (this.runPromise) {
|
|
409
|
+
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
410
|
+
this.runPromise.reject(error);
|
|
411
|
+
this.runPromise = null;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
415
|
+
if (notifyCleanup) {
|
|
416
|
+
notifyCleanup();
|
|
417
|
+
this.notificationCleanups.delete(uuid);
|
|
418
|
+
}
|
|
419
|
+
this.notificationTokens.delete(uuid);
|
|
420
|
+
|
|
421
|
+
try {
|
|
422
|
+
await window.desktopApi?.nobleBle?.unsubscribe(uuid);
|
|
423
|
+
} catch (error) {
|
|
424
|
+
this.Log?.debug(`[Auto BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
425
|
+
}
|
|
426
|
+
try {
|
|
427
|
+
await window.desktopApi?.nobleBle?.subscribe(uuid);
|
|
428
|
+
} catch (error) {
|
|
429
|
+
this.Log?.debug(`[Auto BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
|
|
430
|
+
throw error;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const cleanup = this.createNotificationSubscription(uuid);
|
|
434
|
+
this.notificationCleanups.set(uuid, cleanup);
|
|
435
|
+
}
|
|
436
|
+
|
|
355
437
|
private async probeProtocolV1(uuid: string) {
|
|
356
438
|
if (!this._messages) {
|
|
357
439
|
return false;
|
|
@@ -381,7 +463,7 @@ export default class ElectronAutoBleTransport {
|
|
|
381
463
|
logPrefix: 'ProtocolV2 BLE',
|
|
382
464
|
onProbeFailed: () => {
|
|
383
465
|
this.v2Assemblers.get(uuid)?.reset();
|
|
384
|
-
this.resetProtocolV2Frames();
|
|
466
|
+
this.resetProtocolV2Frames(uuid);
|
|
385
467
|
},
|
|
386
468
|
});
|
|
387
469
|
}
|
|
@@ -442,7 +524,7 @@ export default class ElectronAutoBleTransport {
|
|
|
442
524
|
if (this.runPromise) {
|
|
443
525
|
const error = ERRORS.TypedError(HardwareErrorCode.BleDeviceBondedCanceled);
|
|
444
526
|
this.runPromise.reject(error);
|
|
445
|
-
this.
|
|
527
|
+
this.rejectAllProtocolV2Frames(error);
|
|
446
528
|
}
|
|
447
529
|
return;
|
|
448
530
|
}
|
|
@@ -457,9 +539,9 @@ export default class ElectronAutoBleTransport {
|
|
|
457
539
|
|
|
458
540
|
private handleProtocolV2Notification(deviceId: string, hexData: string): void {
|
|
459
541
|
try {
|
|
460
|
-
if (!this.runPromise) {
|
|
542
|
+
if (!this.runPromise || this.activeProtocolV2Call?.uuid !== deviceId) {
|
|
461
543
|
this.v2Assemblers.get(deviceId)?.reset();
|
|
462
|
-
this.resetProtocolV2Frames();
|
|
544
|
+
this.resetProtocolV2Frames(deviceId);
|
|
463
545
|
return;
|
|
464
546
|
}
|
|
465
547
|
|
|
@@ -471,7 +553,7 @@ export default class ElectronAutoBleTransport {
|
|
|
471
553
|
|
|
472
554
|
let frameData = assembler.push(bytes);
|
|
473
555
|
while (frameData) {
|
|
474
|
-
this.resolveProtocolV2Frame(frameData);
|
|
556
|
+
this.resolveProtocolV2Frame(deviceId, frameData);
|
|
475
557
|
frameData = assembler.push(new Uint8Array(0));
|
|
476
558
|
}
|
|
477
559
|
} catch (error) {
|
|
@@ -479,46 +561,60 @@ export default class ElectronAutoBleTransport {
|
|
|
479
561
|
if (this.runPromise) {
|
|
480
562
|
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
481
563
|
this.runPromise.reject(notifyError);
|
|
482
|
-
this.
|
|
564
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
483
565
|
}
|
|
484
566
|
}
|
|
485
567
|
}
|
|
486
568
|
|
|
487
|
-
private
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
569
|
+
private getProtocolV2FrameQueue(uuid: string) {
|
|
570
|
+
let queue = this.v2FrameQueues.get(uuid);
|
|
571
|
+
if (!queue) {
|
|
572
|
+
queue = [];
|
|
573
|
+
this.v2FrameQueues.set(uuid, queue);
|
|
574
|
+
}
|
|
575
|
+
return queue;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
private resolveProtocolV2Frame(uuid: string, frame: Uint8Array) {
|
|
579
|
+
const framePromise = this.v2FramePromises.get(uuid);
|
|
580
|
+
if (framePromise) {
|
|
581
|
+
framePromise.resolve(frame);
|
|
582
|
+
this.v2FramePromises.delete(uuid);
|
|
491
583
|
return;
|
|
492
584
|
}
|
|
493
|
-
this.
|
|
585
|
+
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
494
586
|
}
|
|
495
587
|
|
|
496
|
-
private
|
|
497
|
-
this.
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
this.v2FramePromise = null;
|
|
588
|
+
private rejectAllProtocolV2Frames(error: Error) {
|
|
589
|
+
this.v2FrameQueues.clear();
|
|
590
|
+
for (const framePromise of this.v2FramePromises.values()) {
|
|
591
|
+
framePromise.reject(error);
|
|
501
592
|
}
|
|
593
|
+
this.v2FramePromises.clear();
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
private resetProtocolV2Frames(uuid: string) {
|
|
597
|
+
this.v2FrameQueues.delete(uuid);
|
|
598
|
+
this.v2FramePromises.delete(uuid);
|
|
502
599
|
}
|
|
503
600
|
|
|
504
|
-
private
|
|
505
|
-
this.
|
|
506
|
-
this.v2FramePromise = null;
|
|
601
|
+
private isActiveProtocolV2Call(uuid: string, token: number) {
|
|
602
|
+
return this.activeProtocolV2Call?.uuid === uuid && this.activeProtocolV2Call.token === token;
|
|
507
603
|
}
|
|
508
604
|
|
|
509
|
-
private async readProtocolV2Frame() {
|
|
510
|
-
const queuedFrame = this.
|
|
605
|
+
private async readProtocolV2Frame(uuid: string) {
|
|
606
|
+
const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
|
|
511
607
|
if (queuedFrame) {
|
|
512
608
|
return queuedFrame;
|
|
513
609
|
}
|
|
514
610
|
|
|
515
611
|
const framePromise = createDeferred<Uint8Array>();
|
|
516
|
-
this.
|
|
612
|
+
this.v2FramePromises.set(uuid, framePromise);
|
|
517
613
|
try {
|
|
518
614
|
return await framePromise.promise;
|
|
519
615
|
} finally {
|
|
520
|
-
if (this.
|
|
521
|
-
this.
|
|
616
|
+
if (this.v2FramePromises.get(uuid) === framePromise) {
|
|
617
|
+
this.v2FramePromises.delete(uuid);
|
|
522
618
|
}
|
|
523
619
|
}
|
|
524
620
|
}
|
|
@@ -656,15 +752,18 @@ export default class ElectronAutoBleTransport {
|
|
|
656
752
|
}
|
|
657
753
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
658
754
|
this.runPromise.reject(error);
|
|
659
|
-
this.
|
|
755
|
+
this.rejectAllProtocolV2Frames(error);
|
|
660
756
|
this.runPromise = null;
|
|
757
|
+
this.activeProtocolV2Call = null;
|
|
661
758
|
}
|
|
662
759
|
|
|
663
760
|
const runPromise = createDeferred<Uint8Array | string>();
|
|
664
761
|
runPromise.promise.catch(() => undefined);
|
|
665
762
|
this.runPromise = runPromise;
|
|
763
|
+
const callToken = this.nextProtocolV2CallToken++;
|
|
764
|
+
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
666
765
|
this.v2Assemblers.get(uuid)?.reset();
|
|
667
|
-
this.resetProtocolV2Frames();
|
|
766
|
+
this.resetProtocolV2Frames(uuid);
|
|
668
767
|
let completed = false;
|
|
669
768
|
const callOptions = {
|
|
670
769
|
...options,
|
|
@@ -680,7 +779,7 @@ export default class ElectronAutoBleTransport {
|
|
|
680
779
|
router: PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
681
780
|
writeFrame: (frame: Uint8Array) => this.writeWithChunking(uuid, bytesToHex(frame)),
|
|
682
781
|
readFrame: async () => {
|
|
683
|
-
const rxFrame = await this.readProtocolV2Frame();
|
|
782
|
+
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
684
783
|
if (!(rxFrame instanceof Uint8Array)) {
|
|
685
784
|
throw new Error('Response is not Uint8Array');
|
|
686
785
|
}
|
|
@@ -699,15 +798,20 @@ export default class ElectronAutoBleTransport {
|
|
|
699
798
|
completed = true;
|
|
700
799
|
return result;
|
|
701
800
|
} catch (e) {
|
|
702
|
-
this.
|
|
703
|
-
|
|
801
|
+
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
802
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
803
|
+
this.resetProtocolV2Frames(uuid);
|
|
804
|
+
}
|
|
704
805
|
this.Log?.error('[Auto BLE] Protocol V2 call error:', e);
|
|
705
806
|
throw e;
|
|
706
807
|
} finally {
|
|
707
|
-
if (
|
|
708
|
-
|
|
808
|
+
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
809
|
+
if (!completed) {
|
|
810
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
811
|
+
}
|
|
812
|
+
this.resetProtocolV2Frames(uuid);
|
|
813
|
+
this.activeProtocolV2Call = null;
|
|
709
814
|
}
|
|
710
|
-
this.resetProtocolV2Frames();
|
|
711
815
|
if (this.runPromise === runPromise) {
|
|
712
816
|
this.runPromise = null;
|
|
713
817
|
}
|
package/src/webusb.ts
CHANGED
|
@@ -45,7 +45,7 @@ function shouldBlockWebUsbCallDataLog(name: string) {
|
|
|
45
45
|
return LogBlockCommand.has(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
function
|
|
48
|
+
function inferProtocolHintFromDeviceName(name?: string | null): ProtocolType | undefined {
|
|
49
49
|
return /\bpro\s*2\b/i.test(name ?? '') ? 'V2' : undefined;
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -78,6 +78,8 @@ export default class WebUsbTransport {
|
|
|
78
78
|
/** Per-path protocol type detected by active wire-level probe. */
|
|
79
79
|
private deviceProtocol: Map<string, ProtocolType> = new Map();
|
|
80
80
|
|
|
81
|
+
private deviceProtocolHints: Map<string, ProtocolType> = new Map();
|
|
82
|
+
|
|
81
83
|
/** 按设备缓存 Protocol V2 frame assembler,保留同一次读取里多出来的后续 frame。 */
|
|
82
84
|
private protocolV2Assemblers: Map<string, ProtocolV2FrameAssembler> = new Map();
|
|
83
85
|
|
|
@@ -183,12 +185,19 @@ export default class WebUsbTransport {
|
|
|
183
185
|
return isOneKey && hasSerialNumber;
|
|
184
186
|
});
|
|
185
187
|
|
|
186
|
-
this.deviceList = onekeyDevices.map(device =>
|
|
187
|
-
path
|
|
188
|
-
device
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
188
|
+
this.deviceList = onekeyDevices.map(device => {
|
|
189
|
+
const path = device.serialNumber as string;
|
|
190
|
+
const protocolHint = inferProtocolHintFromDeviceName(device.productName);
|
|
191
|
+
if (protocolHint) {
|
|
192
|
+
this.deviceProtocolHints.set(path, protocolHint);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
path,
|
|
197
|
+
device,
|
|
198
|
+
commType: 'webusb',
|
|
199
|
+
};
|
|
200
|
+
});
|
|
192
201
|
|
|
193
202
|
// Debug: log all discovered devices. Protocol is detected after acquire via wire probe.
|
|
194
203
|
for (const dev of onekeyDevices) {
|
|
@@ -208,7 +217,15 @@ export default class WebUsbTransport {
|
|
|
208
217
|
if (!input.path) return;
|
|
209
218
|
try {
|
|
210
219
|
await this.connect(input.path ?? '', true);
|
|
211
|
-
|
|
220
|
+
const deviceName = this.deviceList.find(device => device.path === input.path)?.device
|
|
221
|
+
.productName;
|
|
222
|
+
const protocolHint = input.expectedProtocol
|
|
223
|
+
? undefined
|
|
224
|
+
: this.deviceProtocolHints.get(input.path) ?? inferProtocolHintFromDeviceName(deviceName);
|
|
225
|
+
if (protocolHint) {
|
|
226
|
+
this.deviceProtocolHints.set(input.path, protocolHint);
|
|
227
|
+
}
|
|
228
|
+
await this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
|
|
212
229
|
return await Promise.resolve(input.path);
|
|
213
230
|
} catch (e) {
|
|
214
231
|
this.Log.debug('acquire error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
|
|
@@ -230,7 +247,8 @@ export default class WebUsbTransport {
|
|
|
230
247
|
|
|
231
248
|
private async detectProtocol(
|
|
232
249
|
path: string,
|
|
233
|
-
expectedProtocol?: ProtocolType
|
|
250
|
+
expectedProtocol?: ProtocolType,
|
|
251
|
+
protocolHint?: ProtocolType
|
|
234
252
|
): Promise<ProtocolType> {
|
|
235
253
|
if (expectedProtocol === 'V1') {
|
|
236
254
|
if (await this.probeProtocolV1(path)) {
|
|
@@ -242,15 +260,6 @@ export default class WebUsbTransport {
|
|
|
242
260
|
}
|
|
243
261
|
|
|
244
262
|
if (expectedProtocol === 'V2') {
|
|
245
|
-
if (this.deviceProtocol.get(path) === 'V2') {
|
|
246
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (cached expected)`);
|
|
247
|
-
return 'V2';
|
|
248
|
-
}
|
|
249
|
-
if (this.deviceList.find(device => device.path === path)?.protocolType === 'V2') {
|
|
250
|
-
this.deviceProtocol.set(path, 'V2');
|
|
251
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (descriptor)`);
|
|
252
|
-
return 'V2';
|
|
253
|
-
}
|
|
254
263
|
if (await this.probeProtocolV2(path)) {
|
|
255
264
|
this.deviceProtocol.set(path, 'V2');
|
|
256
265
|
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
@@ -259,6 +268,12 @@ export default class WebUsbTransport {
|
|
|
259
268
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
260
269
|
}
|
|
261
270
|
|
|
271
|
+
if (protocolHint === 'V2' && (await this.probeProtocolV2(path))) {
|
|
272
|
+
this.deviceProtocol.set(path, 'V2');
|
|
273
|
+
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (hint)`);
|
|
274
|
+
return 'V2';
|
|
275
|
+
}
|
|
276
|
+
|
|
262
277
|
if (this.deviceProtocol.get(path) === 'V2' && (await this.probeProtocolV2(path))) {
|
|
263
278
|
this.deviceProtocol.set(path, 'V2');
|
|
264
279
|
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (cached)`);
|
|
@@ -703,8 +718,8 @@ export default class WebUsbTransport {
|
|
|
703
718
|
/**
|
|
704
719
|
* Send/receive a single call over Protocol V2 (0x5A framing).
|
|
705
720
|
*
|
|
706
|
-
* Encoding: protobuf message → 2-byte LE
|
|
707
|
-
* Decoding: Protocol V2 frame →
|
|
721
|
+
* Encoding: protobuf message → 2-byte LE messageTypeId + pb bytes → Protocol V2 frame
|
|
722
|
+
* Decoding: Protocol V2 frame → messageTypeId + pb bytes → protobuf message
|
|
708
723
|
*/
|
|
709
724
|
private async callProtocolV2(
|
|
710
725
|
path: string,
|
|
@@ -839,6 +854,9 @@ export default class WebUsbTransport {
|
|
|
839
854
|
const ifaceNum = endpoints?.interfaceNumber ?? this.interfaceId;
|
|
840
855
|
await device.releaseInterface(ifaceNum);
|
|
841
856
|
await device.close();
|
|
857
|
+
this.deviceProtocol.delete(path);
|
|
858
|
+
this.deviceProtocolHints.delete(path);
|
|
859
|
+
this.protocolV2Assemblers.get(path)?.reset();
|
|
842
860
|
this.protocolV2Assemblers.delete(path);
|
|
843
861
|
this.deviceEndpoints.delete(path);
|
|
844
862
|
}
|