@onekeyfe/hd-transport-usb 1.1.27 → 1.2.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +24 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +396 -68
- package/package.json +4 -4
- package/src/index.ts +465 -36
- package/dist/constants.d.ts +0 -5
- package/dist/constants.d.ts.map +0 -1
- package/src/constants.ts +0 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as transport from '@onekeyfe/hd-transport';
|
|
2
|
-
import transport__default, { OneKeyDeviceInfo, AcquireInput } from '@onekeyfe/hd-transport';
|
|
2
|
+
import transport__default, { OneKeyDeviceInfo, AcquireInput, TransportCallOptions, ProtocolType } from '@onekeyfe/hd-transport';
|
|
3
3
|
import EventEmitter from 'events';
|
|
4
4
|
|
|
5
|
-
declare const PACKET_SIZE = 64;
|
|
6
|
-
|
|
7
5
|
declare class NodeUsbTransport {
|
|
8
6
|
messages: ReturnType<typeof transport__default.parseConfigure> | undefined;
|
|
7
|
+
messagesV2: ReturnType<typeof transport__default.parseConfigure> | undefined;
|
|
9
8
|
name: string;
|
|
10
9
|
version: string;
|
|
11
10
|
configured: boolean;
|
|
@@ -14,10 +13,15 @@ declare class NodeUsbTransport {
|
|
|
14
13
|
emitter?: EventEmitter;
|
|
15
14
|
private serialToBusId;
|
|
16
15
|
private openDevices;
|
|
16
|
+
private deviceProtocol;
|
|
17
|
+
private protocolV2Assemblers;
|
|
18
|
+
private protocolV2Sessions;
|
|
19
|
+
private protocolV2ReadTimeouts;
|
|
17
20
|
private reconnectLocks;
|
|
18
21
|
private cancelled;
|
|
19
22
|
init(logger: any, emitter?: EventEmitter): Promise<string>;
|
|
20
23
|
configure(signedData: any): Promise<void>;
|
|
24
|
+
configureProtocolV2(signedData: any): void;
|
|
21
25
|
listen(): void;
|
|
22
26
|
stop(): void;
|
|
23
27
|
post(path: string, name: string, data: Record<string, unknown>): Promise<void>;
|
|
@@ -30,16 +34,31 @@ declare class NodeUsbTransport {
|
|
|
30
34
|
enumerate(): Promise<OneKeyDeviceInfo[]>;
|
|
31
35
|
acquire(input: AcquireInput): Promise<string>;
|
|
32
36
|
release(path: string, _onclose?: boolean): Promise<void>;
|
|
33
|
-
|
|
37
|
+
private closeOpenDevice;
|
|
38
|
+
call(path: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<transport.MessageFromOneKey>;
|
|
39
|
+
private callProtocolV1;
|
|
34
40
|
cancel(): void;
|
|
35
41
|
private getOpenDevice;
|
|
36
42
|
private getErrorMessage;
|
|
37
43
|
private isRetryableError;
|
|
44
|
+
private getDeviceInterface;
|
|
38
45
|
private reconnectForRetry;
|
|
39
46
|
private sendAllChunksWithRetry;
|
|
40
47
|
private transferInWithRetry;
|
|
41
48
|
private openDevice;
|
|
49
|
+
private drainStaleInput;
|
|
50
|
+
private createProtocolMismatchError;
|
|
51
|
+
private createProtocolDetectionError;
|
|
52
|
+
private detectProtocol;
|
|
53
|
+
private resetConnectionAfterProbe;
|
|
54
|
+
private withProtocolReadTimeout;
|
|
55
|
+
private probeProtocolV1;
|
|
56
|
+
private probeProtocolV2;
|
|
57
|
+
private writeProtocolV2Frame;
|
|
58
|
+
private receiveProtocolV2Frame;
|
|
59
|
+
private callProtocolV2;
|
|
42
60
|
private receiveData;
|
|
61
|
+
getProtocolType(path: string): ProtocolType | undefined;
|
|
43
62
|
}
|
|
44
63
|
|
|
45
|
-
export {
|
|
64
|
+
export { NodeUsbTransport as default };
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,SAWN,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AA0LhC,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,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;IAEpE,IAAI,SAAsB;IAE1B,OAAO,SAAM;IAEb,UAAU,UAAS;IAEnB,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,OAAO,CAAC,EAAE,YAAY,CAAC;IAGvB,OAAO,CAAC,aAAa,CAA6B;IAGlD,OAAO,CAAC,WAAW,CAAiC;IAGpD,OAAO,CAAC,cAAc,CAAwC;IAG9D,OAAO,CAAC,oBAAoB,CAAoD;IAGhF,OAAO,CAAC,kBAAkB,CAA6C;IAGvE,OAAO,CAAC,sBAAsB,CAA8C;IAG5E,OAAO,CAAC,cAAc,CAA0C;IAGhE,OAAO,CAAC,SAAS,CAAS;IAM1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAMxC,SAAS,CAAC,UAAU,EAAE,GAAG;IAOzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAOnC,MAAM;IAIN,IAAI;IAQE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAY9E,IAAI,CAAC,IAAI,EAAE,MAAM;;;;;;IAiBjB,SAAS,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IA8BxC,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAsB7C,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;YAMhD,eAAe;IA6BvB,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YAwClB,cAAc;IA0B5B,MAAM;IAWN,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,kBAAkB;IAmB1B,OAAO,CAAC,iBAAiB;YAmDX,sBAAsB;YAyCtB,mBAAmB;YAsCnB,UAAU;YA0EV,eAAe;IAiB7B,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;YAOtB,cAAc;YA4Cd,yBAAyB;YAezB,uBAAuB;YA0CvB,eAAe;YAcf,eAAe;YAcf,oBAAoB;YA+BpB,sBAAsB;YAuCtB,cAAc;YAgDd,WAAW;IA6CzB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
3
|
var ByteBuffer = require('bytebuffer');
|
|
6
4
|
var usb = require('usb');
|
|
7
5
|
var transport = require('@onekeyfe/hd-transport');
|
|
@@ -61,12 +59,11 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
61
59
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
62
60
|
};
|
|
63
61
|
|
|
64
|
-
const
|
|
65
|
-
const
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
const { parseConfigure, buildEncodeBuffers, decodeProtocol, receiveOne, check } = transport__default["default"];
|
|
62
|
+
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
63
|
+
const PACKET_SIZE = transport.PROTOCOL_V1_USB_PACKET_SIZE;
|
|
64
|
+
const REPORT_ID = transport.PROTOCOL_V1_REPORT_ID;
|
|
65
|
+
const PAYLOAD_SIZE = transport.PROTOCOL_V1_CHUNK_PAYLOAD_SIZE;
|
|
66
|
+
const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
70
67
|
const INTERFACE_NUMBER = 0;
|
|
71
68
|
const ENDPOINT_IN = 0x81;
|
|
72
69
|
const ENDPOINT_OUT = 0x01;
|
|
@@ -74,6 +71,7 @@ const TRANSFER_TIMEOUT_MS = 30000;
|
|
|
74
71
|
const SERIAL_READ_TIMEOUT_MS = 5000;
|
|
75
72
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
76
73
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
74
|
+
const PROTOCOL_PROBE_TIMEOUT = 1000;
|
|
77
75
|
function getBusId(dev) {
|
|
78
76
|
return `usb:${dev.busNumber}:${dev.deviceAddress}`;
|
|
79
77
|
}
|
|
@@ -154,6 +152,26 @@ function transferOutOnce(ep, data) {
|
|
|
154
152
|
});
|
|
155
153
|
});
|
|
156
154
|
}
|
|
155
|
+
function resetUsbDevice(dev) {
|
|
156
|
+
return new Promise(resolve => {
|
|
157
|
+
const reset = dev.reset;
|
|
158
|
+
if (typeof reset !== 'function') {
|
|
159
|
+
resolve();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
reset.call(dev, () => resolve());
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function clearEndpointHalt(ep) {
|
|
166
|
+
return new Promise(resolve => {
|
|
167
|
+
const clearHalt = ep.clearHalt;
|
|
168
|
+
if (typeof clearHalt !== 'function') {
|
|
169
|
+
resolve();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
clearHalt.call(ep, () => resolve());
|
|
173
|
+
});
|
|
174
|
+
}
|
|
157
175
|
function skipReportByte(packet) {
|
|
158
176
|
if (packet[0] === REPORT_ID) {
|
|
159
177
|
return packet.subarray(1);
|
|
@@ -171,6 +189,10 @@ class NodeUsbTransport {
|
|
|
171
189
|
this.isOutdated = false;
|
|
172
190
|
this.serialToBusId = new Map();
|
|
173
191
|
this.openDevices = new Map();
|
|
192
|
+
this.deviceProtocol = new Map();
|
|
193
|
+
this.protocolV2Assemblers = new Map();
|
|
194
|
+
this.protocolV2Sessions = new Map();
|
|
195
|
+
this.protocolV2ReadTimeouts = new Map();
|
|
174
196
|
this.reconnectLocks = new Map();
|
|
175
197
|
this.cancelled = false;
|
|
176
198
|
}
|
|
@@ -185,6 +207,13 @@ class NodeUsbTransport {
|
|
|
185
207
|
this.messages = messages;
|
|
186
208
|
return Promise.resolve();
|
|
187
209
|
}
|
|
210
|
+
configureProtocolV2(signedData) {
|
|
211
|
+
var _a;
|
|
212
|
+
this.messagesV2 = parseConfigure(signedData);
|
|
213
|
+
this.protocolV2Sessions.clear();
|
|
214
|
+
this.protocolV2ReadTimeouts.clear();
|
|
215
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V2 schema configured');
|
|
216
|
+
}
|
|
188
217
|
listen() {
|
|
189
218
|
}
|
|
190
219
|
stop() {
|
|
@@ -194,7 +223,7 @@ class NodeUsbTransport {
|
|
|
194
223
|
if (!this.messages) {
|
|
195
224
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
196
225
|
}
|
|
197
|
-
const encodeBuffers =
|
|
226
|
+
const encodeBuffers = ProtocolV1.encodeMessageChunks(this.messages, name, data);
|
|
198
227
|
yield this.sendAllChunksWithRetry(path, encodeBuffers);
|
|
199
228
|
});
|
|
200
229
|
}
|
|
@@ -208,7 +237,7 @@ class NodeUsbTransport {
|
|
|
208
237
|
if (!this.messages) {
|
|
209
238
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
210
239
|
}
|
|
211
|
-
return
|
|
240
|
+
return ProtocolV1.decodeMessage(this.messages, resData);
|
|
212
241
|
});
|
|
213
242
|
}
|
|
214
243
|
enumerate() {
|
|
@@ -238,20 +267,32 @@ class NodeUsbTransport {
|
|
|
238
267
|
}
|
|
239
268
|
acquire(input) {
|
|
240
269
|
var _a, _b, _c;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
270
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
271
|
+
this.cancelled = false;
|
|
272
|
+
const path = (_a = input.path) !== null && _a !== void 0 ? _a : '';
|
|
273
|
+
if (!path) {
|
|
274
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'No device path provided');
|
|
275
|
+
}
|
|
276
|
+
try {
|
|
277
|
+
yield this.closeOpenDevice(path);
|
|
278
|
+
yield this.openDevice(path);
|
|
279
|
+
yield this.detectProtocol(path, input.expectedProtocol);
|
|
280
|
+
return path;
|
|
281
|
+
}
|
|
282
|
+
catch (error) {
|
|
283
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport acquire error: ', error);
|
|
284
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, (_c = error.message) !== null && _c !== void 0 ? _c : String(error));
|
|
285
|
+
}
|
|
286
|
+
});
|
|
253
287
|
}
|
|
254
288
|
release(path, _onclose) {
|
|
289
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
290
|
+
yield this.closeOpenDevice(path);
|
|
291
|
+
this.deviceProtocol.delete(path);
|
|
292
|
+
this.protocolV2Assemblers.delete(path);
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
closeOpenDevice(path) {
|
|
255
296
|
return __awaiter(this, void 0, void 0, function* () {
|
|
256
297
|
const openDev = this.openDevices.get(path);
|
|
257
298
|
if (!openDev)
|
|
@@ -278,7 +319,7 @@ class NodeUsbTransport {
|
|
|
278
319
|
this.openDevices.delete(path);
|
|
279
320
|
});
|
|
280
321
|
}
|
|
281
|
-
call(path, name, data) {
|
|
322
|
+
call(path, name, data, options) {
|
|
282
323
|
var _a, _b;
|
|
283
324
|
return __awaiter(this, void 0, void 0, function* () {
|
|
284
325
|
this.cancelled = false;
|
|
@@ -288,20 +329,35 @@ class NodeUsbTransport {
|
|
|
288
329
|
if (!this.openDevices.get(path)) {
|
|
289
330
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device not acquired: ${path}`);
|
|
290
331
|
}
|
|
291
|
-
const
|
|
332
|
+
const protocol = this.deviceProtocol.get(path);
|
|
333
|
+
if (!protocol) {
|
|
334
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
335
|
+
}
|
|
292
336
|
if (transport.LogBlockCommand.has(name)) {
|
|
293
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport call-', ' name: ', name);
|
|
337
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport call-', ' name: ', name, ' protocol: ', protocol);
|
|
294
338
|
}
|
|
295
339
|
else {
|
|
296
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport call-', ' name: ', name, ' data: ', data);
|
|
340
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
341
|
+
}
|
|
342
|
+
if (protocol === 'V2') {
|
|
343
|
+
return this.callProtocolV2(path, name, data, options);
|
|
297
344
|
}
|
|
298
|
-
|
|
345
|
+
return this.callProtocolV1(path, name, data, options);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
callProtocolV1(path, name, data, options) {
|
|
349
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
350
|
+
const { messages } = this;
|
|
351
|
+
if (!messages) {
|
|
352
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
353
|
+
}
|
|
354
|
+
const encodeBuffers = ProtocolV1.encodeMessageChunks(messages, name, data);
|
|
299
355
|
yield this.sendAllChunksWithRetry(path, encodeBuffers);
|
|
300
|
-
const resData = yield this.receiveData(path, this.getOpenDevice(path));
|
|
356
|
+
const resData = yield this.receiveData(path, this.getOpenDevice(path), options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
301
357
|
if (typeof resData !== 'string') {
|
|
302
358
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Returning data is not string.');
|
|
303
359
|
}
|
|
304
|
-
const jsonData =
|
|
360
|
+
const jsonData = ProtocolV1.decodeMessage(messages, resData);
|
|
305
361
|
return check.call(jsonData);
|
|
306
362
|
});
|
|
307
363
|
}
|
|
@@ -341,6 +397,17 @@ class NodeUsbTransport {
|
|
|
341
397
|
message.includes('timeout') ||
|
|
342
398
|
message.includes('interrupt'));
|
|
343
399
|
}
|
|
400
|
+
getDeviceInterface(dev) {
|
|
401
|
+
var _a;
|
|
402
|
+
const { interfaces } = dev;
|
|
403
|
+
if (!(interfaces === null || interfaces === void 0 ? void 0 : interfaces.length)) {
|
|
404
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'USB interface not found');
|
|
405
|
+
}
|
|
406
|
+
const vendorInterface = interfaces.find(iface => iface.descriptor.bInterfaceClass === 0xff);
|
|
407
|
+
const defaultInterface = interfaces.find(iface => iface.descriptor.bInterfaceNumber === INTERFACE_NUMBER);
|
|
408
|
+
const iface = (_a = vendorInterface !== null && vendorInterface !== void 0 ? vendorInterface : defaultInterface) !== null && _a !== void 0 ? _a : interfaces[0];
|
|
409
|
+
return iface;
|
|
410
|
+
}
|
|
344
411
|
reconnectForRetry(path, direction, attempt, error) {
|
|
345
412
|
const existing = this.reconnectLocks.get(path);
|
|
346
413
|
if (existing)
|
|
@@ -350,13 +417,13 @@ class NodeUsbTransport {
|
|
|
350
417
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
|
|
351
418
|
yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
|
|
352
419
|
try {
|
|
353
|
-
yield this.
|
|
420
|
+
yield this.closeOpenDevice(path);
|
|
354
421
|
}
|
|
355
422
|
catch (releaseError) {
|
|
356
423
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[NodeUsbTransport] release before retry error:', releaseError);
|
|
357
424
|
}
|
|
358
425
|
yield this.enumerate();
|
|
359
|
-
this.openDevice(path);
|
|
426
|
+
yield this.openDevice(path);
|
|
360
427
|
const openDev = this.openDevices.get(path);
|
|
361
428
|
if (!openDev) {
|
|
362
429
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device not found after reconnect: ${path}`);
|
|
@@ -437,53 +504,312 @@ class NodeUsbTransport {
|
|
|
437
504
|
});
|
|
438
505
|
}
|
|
439
506
|
openDevice(path) {
|
|
507
|
+
var _a, _b, _c;
|
|
508
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
509
|
+
const existing = this.openDevices.get(path);
|
|
510
|
+
if (existing)
|
|
511
|
+
return;
|
|
512
|
+
const busId = (_a = this.serialToBusId.get(path)) !== null && _a !== void 0 ? _a : path;
|
|
513
|
+
const allDevices = usb__namespace.getDeviceList();
|
|
514
|
+
const dev = allDevices.find(d => getBusId(d) === busId);
|
|
515
|
+
if (!dev) {
|
|
516
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `USB device not found: ${path}`);
|
|
517
|
+
}
|
|
518
|
+
try {
|
|
519
|
+
dev.open();
|
|
520
|
+
dev.timeout = TRANSFER_TIMEOUT_MS;
|
|
521
|
+
yield resetUsbDevice(dev);
|
|
522
|
+
try {
|
|
523
|
+
dev.open();
|
|
524
|
+
}
|
|
525
|
+
catch (_d) {
|
|
526
|
+
}
|
|
527
|
+
dev.timeout = TRANSFER_TIMEOUT_MS;
|
|
528
|
+
const iface = this.getDeviceInterface(dev);
|
|
529
|
+
if (process.platform === 'linux') {
|
|
530
|
+
try {
|
|
531
|
+
if (iface.isKernelDriverActive()) {
|
|
532
|
+
iface.detachKernelDriver();
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
catch (_e) {
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
iface.claim();
|
|
539
|
+
const epIn = (_b = iface.endpoints.find((e) => e.direction === 'in' && e.address === ENDPOINT_IN)) !== null && _b !== void 0 ? _b : iface.endpoints.find((e) => e.direction === 'in');
|
|
540
|
+
const epOut = (_c = iface.endpoints.find((e) => e.direction === 'out' && e.address === ENDPOINT_OUT)) !== null && _c !== void 0 ? _c : iface.endpoints.find((e) => e.direction === 'out');
|
|
541
|
+
if (!epIn || !epOut) {
|
|
542
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'USB endpoints not found (expected IN 0x81, OUT 0x01)');
|
|
543
|
+
}
|
|
544
|
+
epIn.timeout = TRANSFER_TIMEOUT_MS;
|
|
545
|
+
epOut.timeout = TRANSFER_TIMEOUT_MS;
|
|
546
|
+
yield clearEndpointHalt(epIn);
|
|
547
|
+
yield clearEndpointHalt(epOut);
|
|
548
|
+
yield this.drainStaleInput(epIn);
|
|
549
|
+
this.openDevices.set(path, { device: dev, iface, epIn, epOut });
|
|
550
|
+
}
|
|
551
|
+
catch (err) {
|
|
552
|
+
try {
|
|
553
|
+
dev.close();
|
|
554
|
+
}
|
|
555
|
+
catch (_f) {
|
|
556
|
+
}
|
|
557
|
+
throw err;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
drainStaleInput(epIn) {
|
|
562
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
563
|
+
const originalTimeout = epIn.timeout;
|
|
564
|
+
epIn.timeout = 50;
|
|
565
|
+
try {
|
|
566
|
+
for (let index = 0; index < 16; index += 1) {
|
|
567
|
+
try {
|
|
568
|
+
yield transferInOnce(epIn, PACKET_SIZE);
|
|
569
|
+
}
|
|
570
|
+
catch (_a) {
|
|
571
|
+
break;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
finally {
|
|
576
|
+
epIn.timeout = originalTimeout;
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
createProtocolMismatchError(expected) {
|
|
581
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
582
|
+
}
|
|
583
|
+
createProtocolDetectionError() {
|
|
584
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Unable to detect USB protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
|
|
585
|
+
}
|
|
586
|
+
detectProtocol(path, expectedProtocol) {
|
|
587
|
+
var _a, _b, _c, _d, _e;
|
|
588
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
589
|
+
if (expectedProtocol === 'V1') {
|
|
590
|
+
if (yield this.probeProtocolV1(path)) {
|
|
591
|
+
this.deviceProtocol.set(path, 'V1');
|
|
592
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
593
|
+
return 'V1';
|
|
594
|
+
}
|
|
595
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
596
|
+
}
|
|
597
|
+
if (expectedProtocol === 'V2') {
|
|
598
|
+
if (yield this.probeProtocolV2(path)) {
|
|
599
|
+
this.deviceProtocol.set(path, 'V2');
|
|
600
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
601
|
+
return 'V2';
|
|
602
|
+
}
|
|
603
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
604
|
+
}
|
|
605
|
+
if (this.deviceProtocol.get(path) === 'V2' && (yield this.probeProtocolV2(path))) {
|
|
606
|
+
this.deviceProtocol.set(path, 'V2');
|
|
607
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (cached)`);
|
|
608
|
+
return 'V2';
|
|
609
|
+
}
|
|
610
|
+
if (yield this.probeProtocolV1(path)) {
|
|
611
|
+
this.deviceProtocol.set(path, 'V1');
|
|
612
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1`);
|
|
613
|
+
return 'V1';
|
|
614
|
+
}
|
|
615
|
+
if (yield this.probeProtocolV2(path)) {
|
|
616
|
+
this.deviceProtocol.set(path, 'V2');
|
|
617
|
+
(_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2`);
|
|
618
|
+
return 'V2';
|
|
619
|
+
}
|
|
620
|
+
this.deviceProtocol.delete(path);
|
|
621
|
+
throw this.createProtocolDetectionError();
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
resetConnectionAfterProbe(path) {
|
|
625
|
+
var _a, _b;
|
|
626
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
627
|
+
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
628
|
+
this.protocolV2Sessions.delete(path);
|
|
629
|
+
this.protocolV2ReadTimeouts.delete(path);
|
|
630
|
+
try {
|
|
631
|
+
yield this.closeOpenDevice(path);
|
|
632
|
+
}
|
|
633
|
+
catch (error) {
|
|
634
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[NodeUsbTransport] close after protocol probe error:', error);
|
|
635
|
+
}
|
|
636
|
+
yield this.enumerate();
|
|
637
|
+
yield this.openDevice(path);
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
withProtocolReadTimeout(path, promise, timeoutMs, protocol) {
|
|
641
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
642
|
+
let timer;
|
|
643
|
+
let timedOut = false;
|
|
644
|
+
const waitForeverAfterTimeout = () => new Promise(() => { });
|
|
645
|
+
const guardedPromise = promise.then(value => (timedOut ? waitForeverAfterTimeout() : value), error => {
|
|
646
|
+
if (timedOut) {
|
|
647
|
+
return waitForeverAfterTimeout();
|
|
648
|
+
}
|
|
649
|
+
throw error;
|
|
650
|
+
});
|
|
651
|
+
try {
|
|
652
|
+
return yield Promise.race([
|
|
653
|
+
guardedPromise,
|
|
654
|
+
new Promise((_, reject) => {
|
|
655
|
+
timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
656
|
+
var _a;
|
|
657
|
+
timedOut = true;
|
|
658
|
+
try {
|
|
659
|
+
yield this.resetConnectionAfterProbe(path);
|
|
660
|
+
}
|
|
661
|
+
catch (error) {
|
|
662
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reset after Protocol ${protocol} timeout failed:`, error);
|
|
663
|
+
}
|
|
664
|
+
finally {
|
|
665
|
+
reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
|
|
666
|
+
}
|
|
667
|
+
}), timeoutMs);
|
|
668
|
+
}),
|
|
669
|
+
]);
|
|
670
|
+
}
|
|
671
|
+
finally {
|
|
672
|
+
if (timer)
|
|
673
|
+
clearTimeout(timer);
|
|
674
|
+
}
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
probeProtocolV1(path) {
|
|
440
678
|
var _a;
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
679
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
680
|
+
if (!this.messages) {
|
|
681
|
+
return false;
|
|
682
|
+
}
|
|
683
|
+
try {
|
|
684
|
+
yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
|
|
685
|
+
return true;
|
|
686
|
+
}
|
|
687
|
+
catch (error) {
|
|
688
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
probeProtocolV2(path) {
|
|
694
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
695
|
+
if (!this.messages || !this.messagesV2) {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
return transport.probeProtocolV2({
|
|
699
|
+
call: (name, data, options) => this.callProtocolV2(path, name, data, options),
|
|
700
|
+
timeoutMs: PROTOCOL_PROBE_TIMEOUT,
|
|
701
|
+
logger: this.Log,
|
|
702
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
703
|
+
onProbeFailed: () => this.resetConnectionAfterProbe(path),
|
|
704
|
+
});
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
writeProtocolV2Frame(path, frame) {
|
|
708
|
+
var _a;
|
|
709
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
710
|
+
let lastError;
|
|
711
|
+
for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt++) {
|
|
712
|
+
if (this.cancelled) {
|
|
713
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
714
|
+
}
|
|
455
715
|
try {
|
|
456
|
-
|
|
457
|
-
|
|
716
|
+
yield transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(frame));
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
catch (error) {
|
|
720
|
+
lastError = error;
|
|
721
|
+
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
722
|
+
if (!shouldRetry) {
|
|
723
|
+
throw error;
|
|
724
|
+
}
|
|
725
|
+
try {
|
|
726
|
+
yield this.reconnectForRetry(path, 'out', attempt, error);
|
|
727
|
+
}
|
|
728
|
+
catch (reconnectError) {
|
|
729
|
+
lastError = reconnectError;
|
|
730
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] Protocol V2 write reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(reconnectError)}`);
|
|
731
|
+
break;
|
|
458
732
|
}
|
|
459
733
|
}
|
|
460
|
-
|
|
734
|
+
}
|
|
735
|
+
throw lastError;
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
receiveProtocolV2Frame(path, timeoutMs) {
|
|
739
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
740
|
+
let assembler = this.protocolV2Assemblers.get(path);
|
|
741
|
+
if (!assembler) {
|
|
742
|
+
assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
743
|
+
this.protocolV2Assemblers.set(path, assembler);
|
|
744
|
+
}
|
|
745
|
+
let frame = assembler.push(new Uint8Array(0));
|
|
746
|
+
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
747
|
+
while (!frame) {
|
|
748
|
+
const transferIn = this.transferInWithRetry(path, this.getOpenDevice(path), transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
749
|
+
const packet = deadline
|
|
750
|
+
? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2')
|
|
751
|
+
: yield transferIn;
|
|
752
|
+
const bytes = new Uint8Array(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
753
|
+
try {
|
|
754
|
+
frame = assembler.push(bytes);
|
|
755
|
+
}
|
|
756
|
+
catch (error) {
|
|
757
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
|
|
461
758
|
}
|
|
462
759
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
760
|
+
return frame;
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
callProtocolV2(path, name, data, options) {
|
|
764
|
+
var _a;
|
|
765
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
766
|
+
const protocolV1Messages = this.messages;
|
|
767
|
+
if (!this.messagesV2) {
|
|
768
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
|
|
468
769
|
}
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
770
|
+
if (!protocolV1Messages) {
|
|
771
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
772
|
+
}
|
|
773
|
+
let session = this.protocolV2Sessions.get(path);
|
|
774
|
+
if (!session) {
|
|
775
|
+
session = new transport.ProtocolV2Session({
|
|
776
|
+
schemas: {
|
|
777
|
+
protocolV1: protocolV1Messages,
|
|
778
|
+
protocolV2: this.messagesV2,
|
|
779
|
+
},
|
|
780
|
+
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
781
|
+
writeFrame: (frame) => this.writeProtocolV2Frame(path, frame),
|
|
782
|
+
readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
|
|
783
|
+
logger: this.Log,
|
|
784
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
785
|
+
createTimeoutError: (messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
|
|
786
|
+
});
|
|
787
|
+
this.protocolV2Sessions.set(path, session);
|
|
788
|
+
}
|
|
789
|
+
this.protocolV2ReadTimeouts.set(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
790
|
+
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
474
791
|
try {
|
|
475
|
-
|
|
792
|
+
return yield session.call(name, data, options);
|
|
476
793
|
}
|
|
477
|
-
|
|
794
|
+
finally {
|
|
795
|
+
this.protocolV2ReadTimeouts.delete(path);
|
|
478
796
|
}
|
|
479
|
-
|
|
480
|
-
}
|
|
797
|
+
});
|
|
481
798
|
}
|
|
482
|
-
receiveData(path, dev) {
|
|
799
|
+
receiveData(path, dev, timeoutMs) {
|
|
483
800
|
return __awaiter(this, void 0, void 0, function* () {
|
|
484
|
-
const
|
|
801
|
+
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
802
|
+
const readPacket = () => __awaiter(this, void 0, void 0, function* () {
|
|
803
|
+
const transferIn = this.transferInWithRetry(path, this.getOpenDevice(path), PACKET_SIZE);
|
|
804
|
+
return deadline
|
|
805
|
+
? this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V1')
|
|
806
|
+
: transferIn;
|
|
807
|
+
});
|
|
808
|
+
const firstPacket = timeoutMs
|
|
809
|
+
? yield readPacket()
|
|
810
|
+
: yield this.transferInWithRetry(path, dev, PACKET_SIZE);
|
|
485
811
|
const firstData = skipReportByte(firstPacket);
|
|
486
|
-
const { length, typeId, restBuffer } =
|
|
812
|
+
const { length, typeId, restBuffer } = ProtocolV1.decodeFirstChunk(toArrayBuffer(firstData));
|
|
487
813
|
const lengthWithHeader = Number(length) + HEADER_LENGTH;
|
|
488
814
|
const decoded = new ByteBuffer__default["default"](lengthWithHeader);
|
|
489
815
|
decoded.writeUint16(typeId);
|
|
@@ -492,7 +818,7 @@ class NodeUsbTransport {
|
|
|
492
818
|
decoded.append(restBuffer);
|
|
493
819
|
}
|
|
494
820
|
while (decoded.offset < lengthWithHeader) {
|
|
495
|
-
const packet = yield
|
|
821
|
+
const packet = yield readPacket();
|
|
496
822
|
const pktData = skipReportByte(packet);
|
|
497
823
|
const buf = toArrayBuffer(pktData);
|
|
498
824
|
if (lengthWithHeader - decoded.offset >= PAYLOAD_SIZE) {
|
|
@@ -507,7 +833,9 @@ class NodeUsbTransport {
|
|
|
507
833
|
return Buffer.from(result).toString('hex');
|
|
508
834
|
});
|
|
509
835
|
}
|
|
836
|
+
getProtocolType(path) {
|
|
837
|
+
return this.deviceProtocol.get(path);
|
|
838
|
+
}
|
|
510
839
|
}
|
|
511
840
|
|
|
512
|
-
exports
|
|
513
|
-
exports["default"] = NodeUsbTransport;
|
|
841
|
+
module.exports = NodeUsbTransport;
|