@onekeyfe/hd-transport-usb 1.1.27-alpha.4 → 1.1.27-alpha.41
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 +21 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +302 -42
- package/package.json +4 -4
- package/src/index.ts +385 -31
- 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,13 @@ declare class NodeUsbTransport {
|
|
|
14
13
|
emitter?: EventEmitter;
|
|
15
14
|
private serialToBusId;
|
|
16
15
|
private openDevices;
|
|
16
|
+
private deviceProtocol;
|
|
17
|
+
private protocolV2Assemblers;
|
|
17
18
|
private reconnectLocks;
|
|
18
19
|
private cancelled;
|
|
19
20
|
init(logger: any, emitter?: EventEmitter): Promise<string>;
|
|
20
21
|
configure(signedData: any): Promise<void>;
|
|
22
|
+
configureProtocolV2(signedData: any): void;
|
|
21
23
|
listen(): void;
|
|
22
24
|
stop(): void;
|
|
23
25
|
post(path: string, name: string, data: Record<string, unknown>): Promise<void>;
|
|
@@ -30,16 +32,30 @@ declare class NodeUsbTransport {
|
|
|
30
32
|
enumerate(): Promise<OneKeyDeviceInfo[]>;
|
|
31
33
|
acquire(input: AcquireInput): Promise<string>;
|
|
32
34
|
release(path: string, _onclose?: boolean): Promise<void>;
|
|
33
|
-
|
|
35
|
+
private closeOpenDevice;
|
|
36
|
+
call(path: string, name: string, data: Record<string, unknown>, options?: TransportCallOptions): Promise<transport.MessageFromOneKey>;
|
|
37
|
+
private callProtocolV1;
|
|
34
38
|
cancel(): void;
|
|
35
39
|
private getOpenDevice;
|
|
36
40
|
private getErrorMessage;
|
|
37
41
|
private isRetryableError;
|
|
42
|
+
private getDeviceInterface;
|
|
38
43
|
private reconnectForRetry;
|
|
39
44
|
private sendAllChunksWithRetry;
|
|
40
45
|
private transferInWithRetry;
|
|
41
46
|
private openDevice;
|
|
47
|
+
private createProtocolMismatchError;
|
|
48
|
+
private createProtocolDetectionError;
|
|
49
|
+
private detectProtocol;
|
|
50
|
+
private resetConnectionAfterProbe;
|
|
51
|
+
private withProtocolReadTimeout;
|
|
52
|
+
private probeProtocolV1;
|
|
53
|
+
private probeProtocolV2;
|
|
54
|
+
private writeProtocolV2Frame;
|
|
55
|
+
private receiveProtocolV2Frame;
|
|
56
|
+
private callProtocolV2;
|
|
42
57
|
private receiveData;
|
|
58
|
+
getProtocolType(path: string): ProtocolType | undefined;
|
|
43
59
|
}
|
|
44
60
|
|
|
45
|
-
export {
|
|
61
|
+
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;AAgKhC,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,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;IAKnC,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;IAqB7C,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;IAsCjC,OAAO,CAAC,UAAU;IA8DlB,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;YAOtB,cAAc;YA4Cd,yBAAyB;YAazB,uBAAuB;YA0CvB,eAAe;YAcf,eAAe;YAcf,oBAAoB;YA+BpB,sBAAsB;YAuCtB,cAAc;YAuCd,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
|
}
|
|
@@ -171,6 +169,8 @@ class NodeUsbTransport {
|
|
|
171
169
|
this.isOutdated = false;
|
|
172
170
|
this.serialToBusId = new Map();
|
|
173
171
|
this.openDevices = new Map();
|
|
172
|
+
this.deviceProtocol = new Map();
|
|
173
|
+
this.protocolV2Assemblers = new Map();
|
|
174
174
|
this.reconnectLocks = new Map();
|
|
175
175
|
this.cancelled = false;
|
|
176
176
|
}
|
|
@@ -185,6 +185,11 @@ class NodeUsbTransport {
|
|
|
185
185
|
this.messages = messages;
|
|
186
186
|
return Promise.resolve();
|
|
187
187
|
}
|
|
188
|
+
configureProtocolV2(signedData) {
|
|
189
|
+
var _a;
|
|
190
|
+
this.messagesV2 = parseConfigure(signedData);
|
|
191
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V2 schema configured');
|
|
192
|
+
}
|
|
188
193
|
listen() {
|
|
189
194
|
}
|
|
190
195
|
stop() {
|
|
@@ -194,7 +199,7 @@ class NodeUsbTransport {
|
|
|
194
199
|
if (!this.messages) {
|
|
195
200
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
196
201
|
}
|
|
197
|
-
const encodeBuffers =
|
|
202
|
+
const encodeBuffers = ProtocolV1.encodeMessageChunks(this.messages, name, data);
|
|
198
203
|
yield this.sendAllChunksWithRetry(path, encodeBuffers);
|
|
199
204
|
});
|
|
200
205
|
}
|
|
@@ -208,7 +213,7 @@ class NodeUsbTransport {
|
|
|
208
213
|
if (!this.messages) {
|
|
209
214
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
210
215
|
}
|
|
211
|
-
return
|
|
216
|
+
return ProtocolV1.decodeMessage(this.messages, resData);
|
|
212
217
|
});
|
|
213
218
|
}
|
|
214
219
|
enumerate() {
|
|
@@ -238,20 +243,31 @@ class NodeUsbTransport {
|
|
|
238
243
|
}
|
|
239
244
|
acquire(input) {
|
|
240
245
|
var _a, _b, _c;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
246
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
247
|
+
this.cancelled = false;
|
|
248
|
+
const path = (_a = input.path) !== null && _a !== void 0 ? _a : '';
|
|
249
|
+
if (!path) {
|
|
250
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'No device path provided');
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
253
|
+
this.openDevice(path);
|
|
254
|
+
yield this.detectProtocol(path, input.expectedProtocol);
|
|
255
|
+
return path;
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport acquire error: ', error);
|
|
259
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, (_c = error.message) !== null && _c !== void 0 ? _c : String(error));
|
|
260
|
+
}
|
|
261
|
+
});
|
|
253
262
|
}
|
|
254
263
|
release(path, _onclose) {
|
|
264
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
yield this.closeOpenDevice(path);
|
|
266
|
+
this.deviceProtocol.delete(path);
|
|
267
|
+
this.protocolV2Assemblers.delete(path);
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
closeOpenDevice(path) {
|
|
255
271
|
return __awaiter(this, void 0, void 0, function* () {
|
|
256
272
|
const openDev = this.openDevices.get(path);
|
|
257
273
|
if (!openDev)
|
|
@@ -278,7 +294,7 @@ class NodeUsbTransport {
|
|
|
278
294
|
this.openDevices.delete(path);
|
|
279
295
|
});
|
|
280
296
|
}
|
|
281
|
-
call(path, name, data) {
|
|
297
|
+
call(path, name, data, options) {
|
|
282
298
|
var _a, _b;
|
|
283
299
|
return __awaiter(this, void 0, void 0, function* () {
|
|
284
300
|
this.cancelled = false;
|
|
@@ -288,20 +304,35 @@ class NodeUsbTransport {
|
|
|
288
304
|
if (!this.openDevices.get(path)) {
|
|
289
305
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device not acquired: ${path}`);
|
|
290
306
|
}
|
|
291
|
-
const
|
|
307
|
+
const protocol = this.deviceProtocol.get(path);
|
|
308
|
+
if (!protocol) {
|
|
309
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
310
|
+
}
|
|
292
311
|
if (transport.LogBlockCommand.has(name)) {
|
|
293
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport call-', ' name: ', name);
|
|
312
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('NodeUsbTransport call-', ' name: ', name, ' protocol: ', protocol);
|
|
294
313
|
}
|
|
295
314
|
else {
|
|
296
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport call-', ' name: ', name, ' data: ', data);
|
|
315
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
316
|
+
}
|
|
317
|
+
if (protocol === 'V2') {
|
|
318
|
+
return this.callProtocolV2(path, name, data, options);
|
|
319
|
+
}
|
|
320
|
+
return this.callProtocolV1(path, name, data, options);
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
callProtocolV1(path, name, data, options) {
|
|
324
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
325
|
+
const { messages } = this;
|
|
326
|
+
if (!messages) {
|
|
327
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
297
328
|
}
|
|
298
|
-
const encodeBuffers =
|
|
329
|
+
const encodeBuffers = ProtocolV1.encodeMessageChunks(messages, name, data);
|
|
299
330
|
yield this.sendAllChunksWithRetry(path, encodeBuffers);
|
|
300
|
-
const resData = yield this.receiveData(path, this.getOpenDevice(path));
|
|
331
|
+
const resData = yield this.receiveData(path, this.getOpenDevice(path), options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
301
332
|
if (typeof resData !== 'string') {
|
|
302
333
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Returning data is not string.');
|
|
303
334
|
}
|
|
304
|
-
const jsonData =
|
|
335
|
+
const jsonData = ProtocolV1.decodeMessage(messages, resData);
|
|
305
336
|
return check.call(jsonData);
|
|
306
337
|
});
|
|
307
338
|
}
|
|
@@ -341,6 +372,17 @@ class NodeUsbTransport {
|
|
|
341
372
|
message.includes('timeout') ||
|
|
342
373
|
message.includes('interrupt'));
|
|
343
374
|
}
|
|
375
|
+
getDeviceInterface(dev) {
|
|
376
|
+
var _a;
|
|
377
|
+
const { interfaces } = dev;
|
|
378
|
+
if (!(interfaces === null || interfaces === void 0 ? void 0 : interfaces.length)) {
|
|
379
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'USB interface not found');
|
|
380
|
+
}
|
|
381
|
+
const vendorInterface = interfaces.find(iface => iface.descriptor.bInterfaceClass === 0xff);
|
|
382
|
+
const defaultInterface = interfaces.find(iface => iface.descriptor.bInterfaceNumber === INTERFACE_NUMBER);
|
|
383
|
+
const iface = (_a = vendorInterface !== null && vendorInterface !== void 0 ? vendorInterface : defaultInterface) !== null && _a !== void 0 ? _a : interfaces[0];
|
|
384
|
+
return iface;
|
|
385
|
+
}
|
|
344
386
|
reconnectForRetry(path, direction, attempt, error) {
|
|
345
387
|
const existing = this.reconnectLocks.get(path);
|
|
346
388
|
if (existing)
|
|
@@ -350,7 +392,7 @@ class NodeUsbTransport {
|
|
|
350
392
|
(_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
393
|
yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
|
|
352
394
|
try {
|
|
353
|
-
yield this.
|
|
395
|
+
yield this.closeOpenDevice(path);
|
|
354
396
|
}
|
|
355
397
|
catch (releaseError) {
|
|
356
398
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[NodeUsbTransport] release before retry error:', releaseError);
|
|
@@ -437,7 +479,7 @@ class NodeUsbTransport {
|
|
|
437
479
|
});
|
|
438
480
|
}
|
|
439
481
|
openDevice(path) {
|
|
440
|
-
var _a;
|
|
482
|
+
var _a, _b, _c;
|
|
441
483
|
const existing = this.openDevices.get(path);
|
|
442
484
|
if (existing)
|
|
443
485
|
return;
|
|
@@ -450,19 +492,19 @@ class NodeUsbTransport {
|
|
|
450
492
|
dev.open();
|
|
451
493
|
try {
|
|
452
494
|
dev.timeout = TRANSFER_TIMEOUT_MS;
|
|
453
|
-
const iface =
|
|
495
|
+
const iface = this.getDeviceInterface(dev);
|
|
454
496
|
if (process.platform === 'linux') {
|
|
455
497
|
try {
|
|
456
498
|
if (iface.isKernelDriverActive()) {
|
|
457
499
|
iface.detachKernelDriver();
|
|
458
500
|
}
|
|
459
501
|
}
|
|
460
|
-
catch (
|
|
502
|
+
catch (_d) {
|
|
461
503
|
}
|
|
462
504
|
}
|
|
463
505
|
iface.claim();
|
|
464
|
-
const epIn = iface.endpoints.find((e) => e.direction === 'in' && e.address === ENDPOINT_IN);
|
|
465
|
-
const epOut = iface.endpoints.find((e) => e.direction === 'out' && e.address === ENDPOINT_OUT);
|
|
506
|
+
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');
|
|
507
|
+
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');
|
|
466
508
|
if (!epIn || !epOut) {
|
|
467
509
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'USB endpoints not found (expected IN 0x81, OUT 0x01)');
|
|
468
510
|
}
|
|
@@ -474,16 +516,232 @@ class NodeUsbTransport {
|
|
|
474
516
|
try {
|
|
475
517
|
dev.close();
|
|
476
518
|
}
|
|
477
|
-
catch (
|
|
519
|
+
catch (_e) {
|
|
478
520
|
}
|
|
479
521
|
throw err;
|
|
480
522
|
}
|
|
481
523
|
}
|
|
482
|
-
|
|
524
|
+
createProtocolMismatchError(expected) {
|
|
525
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
526
|
+
}
|
|
527
|
+
createProtocolDetectionError() {
|
|
528
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Unable to detect USB protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
|
|
529
|
+
}
|
|
530
|
+
detectProtocol(path, expectedProtocol) {
|
|
531
|
+
var _a, _b, _c, _d, _e;
|
|
532
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
533
|
+
if (expectedProtocol === 'V1') {
|
|
534
|
+
if (yield this.probeProtocolV1(path)) {
|
|
535
|
+
this.deviceProtocol.set(path, 'V1');
|
|
536
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
537
|
+
return 'V1';
|
|
538
|
+
}
|
|
539
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
540
|
+
}
|
|
541
|
+
if (expectedProtocol === 'V2') {
|
|
542
|
+
if (yield this.probeProtocolV2(path)) {
|
|
543
|
+
this.deviceProtocol.set(path, 'V2');
|
|
544
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
545
|
+
return 'V2';
|
|
546
|
+
}
|
|
547
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
548
|
+
}
|
|
549
|
+
if (this.deviceProtocol.get(path) === 'V2' && (yield this.probeProtocolV2(path))) {
|
|
550
|
+
this.deviceProtocol.set(path, 'V2');
|
|
551
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (cached)`);
|
|
552
|
+
return 'V2';
|
|
553
|
+
}
|
|
554
|
+
if (yield this.probeProtocolV1(path)) {
|
|
555
|
+
this.deviceProtocol.set(path, 'V1');
|
|
556
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1`);
|
|
557
|
+
return 'V1';
|
|
558
|
+
}
|
|
559
|
+
if (yield this.probeProtocolV2(path)) {
|
|
560
|
+
this.deviceProtocol.set(path, 'V2');
|
|
561
|
+
(_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2`);
|
|
562
|
+
return 'V2';
|
|
563
|
+
}
|
|
564
|
+
this.deviceProtocol.delete(path);
|
|
565
|
+
throw this.createProtocolDetectionError();
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
resetConnectionAfterProbe(path) {
|
|
569
|
+
var _a, _b;
|
|
483
570
|
return __awaiter(this, void 0, void 0, function* () {
|
|
484
|
-
|
|
571
|
+
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
572
|
+
try {
|
|
573
|
+
yield this.closeOpenDevice(path);
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[NodeUsbTransport] close after protocol probe error:', error);
|
|
577
|
+
}
|
|
578
|
+
yield this.enumerate();
|
|
579
|
+
this.openDevice(path);
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
withProtocolReadTimeout(path, promise, timeoutMs, protocol) {
|
|
583
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
584
|
+
let timer;
|
|
585
|
+
let timedOut = false;
|
|
586
|
+
const waitForeverAfterTimeout = () => new Promise(() => { });
|
|
587
|
+
const guardedPromise = promise.then(value => (timedOut ? waitForeverAfterTimeout() : value), error => {
|
|
588
|
+
if (timedOut) {
|
|
589
|
+
return waitForeverAfterTimeout();
|
|
590
|
+
}
|
|
591
|
+
throw error;
|
|
592
|
+
});
|
|
593
|
+
try {
|
|
594
|
+
return yield Promise.race([
|
|
595
|
+
guardedPromise,
|
|
596
|
+
new Promise((_, reject) => {
|
|
597
|
+
timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
598
|
+
var _a;
|
|
599
|
+
timedOut = true;
|
|
600
|
+
try {
|
|
601
|
+
yield this.resetConnectionAfterProbe(path);
|
|
602
|
+
}
|
|
603
|
+
catch (error) {
|
|
604
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[NodeUsbTransport] reset after Protocol ${protocol} timeout failed:`, error);
|
|
605
|
+
}
|
|
606
|
+
finally {
|
|
607
|
+
reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
|
|
608
|
+
}
|
|
609
|
+
}), timeoutMs);
|
|
610
|
+
}),
|
|
611
|
+
]);
|
|
612
|
+
}
|
|
613
|
+
finally {
|
|
614
|
+
if (timer)
|
|
615
|
+
clearTimeout(timer);
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
probeProtocolV1(path) {
|
|
620
|
+
var _a;
|
|
621
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
622
|
+
if (!this.messages) {
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[NodeUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
probeProtocolV2(path) {
|
|
636
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
637
|
+
if (!this.messages || !this.messagesV2) {
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
return transport.probeProtocolV2({
|
|
641
|
+
call: (name, data, options) => this.callProtocolV2(path, name, data, options),
|
|
642
|
+
timeoutMs: PROTOCOL_PROBE_TIMEOUT,
|
|
643
|
+
logger: this.Log,
|
|
644
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
645
|
+
onProbeFailed: () => this.resetConnectionAfterProbe(path),
|
|
646
|
+
});
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
writeProtocolV2Frame(path, frame) {
|
|
650
|
+
var _a;
|
|
651
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
652
|
+
let lastError;
|
|
653
|
+
for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt++) {
|
|
654
|
+
if (this.cancelled) {
|
|
655
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
656
|
+
}
|
|
657
|
+
try {
|
|
658
|
+
yield transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(frame));
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
catch (error) {
|
|
662
|
+
lastError = error;
|
|
663
|
+
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
664
|
+
if (!shouldRetry) {
|
|
665
|
+
throw error;
|
|
666
|
+
}
|
|
667
|
+
try {
|
|
668
|
+
yield this.reconnectForRetry(path, 'out', attempt, error);
|
|
669
|
+
}
|
|
670
|
+
catch (reconnectError) {
|
|
671
|
+
lastError = reconnectError;
|
|
672
|
+
(_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)}`);
|
|
673
|
+
break;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
throw lastError;
|
|
678
|
+
});
|
|
679
|
+
}
|
|
680
|
+
receiveProtocolV2Frame(path, timeoutMs) {
|
|
681
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
682
|
+
let assembler = this.protocolV2Assemblers.get(path);
|
|
683
|
+
if (!assembler) {
|
|
684
|
+
assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
685
|
+
this.protocolV2Assemblers.set(path, assembler);
|
|
686
|
+
}
|
|
687
|
+
let frame = assembler.push(new Uint8Array(0));
|
|
688
|
+
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
689
|
+
while (!frame) {
|
|
690
|
+
const transferIn = this.transferInWithRetry(path, this.getOpenDevice(path), transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
691
|
+
const packet = deadline
|
|
692
|
+
? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2')
|
|
693
|
+
: yield transferIn;
|
|
694
|
+
const bytes = new Uint8Array(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
|
|
695
|
+
try {
|
|
696
|
+
frame = assembler.push(bytes);
|
|
697
|
+
}
|
|
698
|
+
catch (error) {
|
|
699
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return frame;
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
callProtocolV2(path, name, data, options) {
|
|
706
|
+
var _a;
|
|
707
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
708
|
+
const protocolV1Messages = this.messages;
|
|
709
|
+
if (!this.messagesV2) {
|
|
710
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
|
|
711
|
+
}
|
|
712
|
+
if (!protocolV1Messages) {
|
|
713
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
714
|
+
}
|
|
715
|
+
const session = new transport.ProtocolV2Session({
|
|
716
|
+
schemas: {
|
|
717
|
+
protocolV1: protocolV1Messages,
|
|
718
|
+
protocolV2: this.messagesV2,
|
|
719
|
+
},
|
|
720
|
+
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
721
|
+
writeFrame: (frame) => this.writeProtocolV2Frame(path, frame),
|
|
722
|
+
readFrame: () => this.receiveProtocolV2Frame(path, options === null || options === void 0 ? void 0 : options.timeoutMs),
|
|
723
|
+
logger: this.Log,
|
|
724
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
725
|
+
createTimeoutError: (_messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${name}`),
|
|
726
|
+
});
|
|
727
|
+
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
728
|
+
return session.call(name, data, options);
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
receiveData(path, dev, timeoutMs) {
|
|
732
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
733
|
+
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
734
|
+
const readPacket = () => __awaiter(this, void 0, void 0, function* () {
|
|
735
|
+
const transferIn = this.transferInWithRetry(path, this.getOpenDevice(path), PACKET_SIZE);
|
|
736
|
+
return deadline
|
|
737
|
+
? this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V1')
|
|
738
|
+
: transferIn;
|
|
739
|
+
});
|
|
740
|
+
const firstPacket = timeoutMs
|
|
741
|
+
? yield readPacket()
|
|
742
|
+
: yield this.transferInWithRetry(path, dev, PACKET_SIZE);
|
|
485
743
|
const firstData = skipReportByte(firstPacket);
|
|
486
|
-
const { length, typeId, restBuffer } =
|
|
744
|
+
const { length, typeId, restBuffer } = ProtocolV1.decodeFirstChunk(toArrayBuffer(firstData));
|
|
487
745
|
const lengthWithHeader = Number(length) + HEADER_LENGTH;
|
|
488
746
|
const decoded = new ByteBuffer__default["default"](lengthWithHeader);
|
|
489
747
|
decoded.writeUint16(typeId);
|
|
@@ -492,7 +750,7 @@ class NodeUsbTransport {
|
|
|
492
750
|
decoded.append(restBuffer);
|
|
493
751
|
}
|
|
494
752
|
while (decoded.offset < lengthWithHeader) {
|
|
495
|
-
const packet = yield
|
|
753
|
+
const packet = yield readPacket();
|
|
496
754
|
const pktData = skipReportByte(packet);
|
|
497
755
|
const buf = toArrayBuffer(pktData);
|
|
498
756
|
if (lengthWithHeader - decoded.offset >= PAYLOAD_SIZE) {
|
|
@@ -507,7 +765,9 @@ class NodeUsbTransport {
|
|
|
507
765
|
return Buffer.from(result).toString('hex');
|
|
508
766
|
});
|
|
509
767
|
}
|
|
768
|
+
getProtocolType(path) {
|
|
769
|
+
return this.deviceProtocol.get(path);
|
|
770
|
+
}
|
|
510
771
|
}
|
|
511
772
|
|
|
512
|
-
exports
|
|
513
|
-
exports["default"] = NodeUsbTransport;
|
|
773
|
+
module.exports = NodeUsbTransport;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-usb",
|
|
3
|
-
"version": "1.1.27-alpha.
|
|
3
|
+
"version": "1.1.27-alpha.41",
|
|
4
4
|
"description": "OneKey hardware wallet direct USB transport plugin (libusb)",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,10 +20,10 @@
|
|
|
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.41",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.1.27-alpha.41",
|
|
25
25
|
"bytebuffer": "^5.0.1",
|
|
26
26
|
"usb": "^2.14.0"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "09cece9f0c9d85f55ae2f7f0458ed7d8833483d2"
|
|
29
29
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,33 @@
|
|
|
1
1
|
import ByteBuffer from 'bytebuffer';
|
|
2
2
|
import * as usb from 'usb';
|
|
3
|
-
import transport, {
|
|
3
|
+
import transport, {
|
|
4
|
+
LogBlockCommand,
|
|
5
|
+
PROTOCOL_V1_CHUNK_PAYLOAD_SIZE,
|
|
6
|
+
PROTOCOL_V1_MESSAGE_HEADER_SIZE,
|
|
7
|
+
PROTOCOL_V1_REPORT_ID,
|
|
8
|
+
PROTOCOL_V1_USB_PACKET_SIZE,
|
|
9
|
+
PROTOCOL_V2_CHANNEL_USB,
|
|
10
|
+
PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
11
|
+
ProtocolV2FrameAssembler,
|
|
12
|
+
ProtocolV2Session,
|
|
13
|
+
probeProtocolV2 as probeProtocolV2Helper,
|
|
14
|
+
} from '@onekeyfe/hd-transport';
|
|
4
15
|
import { ERRORS, HardwareErrorCode, ONEKEY_WEBUSB_FILTER, wait } from '@onekeyfe/hd-shared';
|
|
5
16
|
|
|
6
|
-
import { HEADER_LENGTH, PACKET_SIZE, PAYLOAD_SIZE, REPORT_ID } from './constants';
|
|
7
|
-
|
|
8
17
|
import type EventEmitter from 'events';
|
|
9
|
-
import type {
|
|
18
|
+
import type {
|
|
19
|
+
AcquireInput,
|
|
20
|
+
OneKeyDeviceInfo,
|
|
21
|
+
ProtocolType,
|
|
22
|
+
TransportCallOptions,
|
|
23
|
+
} from '@onekeyfe/hd-transport';
|
|
24
|
+
|
|
25
|
+
const { parseConfigure, ProtocolV1, check } = transport;
|
|
10
26
|
|
|
11
|
-
const
|
|
27
|
+
const PACKET_SIZE = PROTOCOL_V1_USB_PACKET_SIZE;
|
|
28
|
+
const REPORT_ID = PROTOCOL_V1_REPORT_ID;
|
|
29
|
+
const PAYLOAD_SIZE = PROTOCOL_V1_CHUNK_PAYLOAD_SIZE;
|
|
30
|
+
const HEADER_LENGTH = PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
12
31
|
|
|
13
32
|
/** USB interface number for vendor-specific communication */
|
|
14
33
|
const INTERFACE_NUMBER = 0;
|
|
@@ -25,6 +44,7 @@ const SERIAL_READ_TIMEOUT_MS = 5000;
|
|
|
25
44
|
/** Packet I/O retry configuration (matches WebUsbTransport) */
|
|
26
45
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
27
46
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
47
|
+
const PROTOCOL_PROBE_TIMEOUT = 1000;
|
|
28
48
|
|
|
29
49
|
/**
|
|
30
50
|
* Opened device state — holds the USB device, claimed interface, and endpoints.
|
|
@@ -163,6 +183,9 @@ function toArrayBuffer(buf: Buffer): ArrayBuffer {
|
|
|
163
183
|
export default class NodeUsbTransport {
|
|
164
184
|
messages: ReturnType<typeof transport.parseConfigure> | undefined;
|
|
165
185
|
|
|
186
|
+
/** Protobuf schema for Protocol V2 transports. */
|
|
187
|
+
messagesV2: ReturnType<typeof transport.parseConfigure> | undefined;
|
|
188
|
+
|
|
166
189
|
name = 'NodeUsbTransport';
|
|
167
190
|
|
|
168
191
|
version = '';
|
|
@@ -181,6 +204,12 @@ export default class NodeUsbTransport {
|
|
|
181
204
|
/** path → opened device state */
|
|
182
205
|
private openDevices = new Map<string, OpenDevice>();
|
|
183
206
|
|
|
207
|
+
/** Per-path protocol type detected by active wire-level probe. */
|
|
208
|
+
private deviceProtocol: Map<string, ProtocolType> = new Map();
|
|
209
|
+
|
|
210
|
+
/** Per-path Protocol V2 frame assembler, preserving buffered frames during reads. */
|
|
211
|
+
private protocolV2Assemblers: Map<string, ProtocolV2FrameAssembler> = new Map();
|
|
212
|
+
|
|
184
213
|
/** per-path reconnect lock to prevent concurrent reconnects */
|
|
185
214
|
private reconnectLocks = new Map<string, Promise<OpenDevice>>();
|
|
186
215
|
|
|
@@ -204,6 +233,11 @@ export default class NodeUsbTransport {
|
|
|
204
233
|
return Promise.resolve();
|
|
205
234
|
}
|
|
206
235
|
|
|
236
|
+
configureProtocolV2(signedData: any) {
|
|
237
|
+
this.messagesV2 = parseConfigure(signedData);
|
|
238
|
+
this.Log?.debug('[NodeUsbTransport] Protocol V2 schema configured');
|
|
239
|
+
}
|
|
240
|
+
|
|
207
241
|
listen() {
|
|
208
242
|
// empty — could add hotplug events via usb.on('attach'/'detach')
|
|
209
243
|
}
|
|
@@ -220,7 +254,7 @@ export default class NodeUsbTransport {
|
|
|
220
254
|
if (!this.messages) {
|
|
221
255
|
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
222
256
|
}
|
|
223
|
-
const encodeBuffers =
|
|
257
|
+
const encodeBuffers = ProtocolV1.encodeMessageChunks(this.messages, name, data);
|
|
224
258
|
await this.sendAllChunksWithRetry(path, encodeBuffers);
|
|
225
259
|
}
|
|
226
260
|
|
|
@@ -237,7 +271,7 @@ export default class NodeUsbTransport {
|
|
|
237
271
|
if (!this.messages) {
|
|
238
272
|
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
239
273
|
}
|
|
240
|
-
return
|
|
274
|
+
return ProtocolV1.decodeMessage(this.messages, resData);
|
|
241
275
|
}
|
|
242
276
|
|
|
243
277
|
/**
|
|
@@ -275,7 +309,9 @@ export default class NodeUsbTransport {
|
|
|
275
309
|
/**
|
|
276
310
|
* Acquire device — open USB device, claim interface, return path (string).
|
|
277
311
|
*/
|
|
278
|
-
acquire(input: AcquireInput): Promise<string> {
|
|
312
|
+
async acquire(input: AcquireInput): Promise<string> {
|
|
313
|
+
this.cancelled = false;
|
|
314
|
+
|
|
279
315
|
const path = input.path ?? '';
|
|
280
316
|
if (!path) {
|
|
281
317
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, 'No device path provided');
|
|
@@ -283,7 +319,8 @@ export default class NodeUsbTransport {
|
|
|
283
319
|
|
|
284
320
|
try {
|
|
285
321
|
this.openDevice(path);
|
|
286
|
-
|
|
322
|
+
await this.detectProtocol(path, input.expectedProtocol);
|
|
323
|
+
return path;
|
|
287
324
|
} catch (error: any) {
|
|
288
325
|
this.Log?.debug('NodeUsbTransport acquire error: ', error);
|
|
289
326
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, error.message ?? String(error));
|
|
@@ -294,6 +331,12 @@ export default class NodeUsbTransport {
|
|
|
294
331
|
* Release device — release interface and close.
|
|
295
332
|
*/
|
|
296
333
|
async release(path: string, _onclose?: boolean): Promise<void> {
|
|
334
|
+
await this.closeOpenDevice(path);
|
|
335
|
+
this.deviceProtocol.delete(path);
|
|
336
|
+
this.protocolV2Assemblers.delete(path);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
private async closeOpenDevice(path: string): Promise<void> {
|
|
297
340
|
const openDev = this.openDevices.get(path);
|
|
298
341
|
if (!openDev) return;
|
|
299
342
|
|
|
@@ -322,7 +365,12 @@ export default class NodeUsbTransport {
|
|
|
322
365
|
* Call device method — encode protobuf, send packets, receive response.
|
|
323
366
|
* This is the core method that replaces LowlevelTransport's call + UsbPlugin's send/receive.
|
|
324
367
|
*/
|
|
325
|
-
async call(
|
|
368
|
+
async call(
|
|
369
|
+
path: string,
|
|
370
|
+
name: string,
|
|
371
|
+
data: Record<string, unknown>,
|
|
372
|
+
options?: TransportCallOptions
|
|
373
|
+
) {
|
|
326
374
|
this.cancelled = false;
|
|
327
375
|
|
|
328
376
|
if (!this.messages) {
|
|
@@ -333,26 +381,57 @@ export default class NodeUsbTransport {
|
|
|
333
381
|
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, `Device not acquired: ${path}`);
|
|
334
382
|
}
|
|
335
383
|
|
|
336
|
-
const
|
|
384
|
+
const protocol = this.deviceProtocol.get(path);
|
|
385
|
+
if (!protocol) {
|
|
386
|
+
throw ERRORS.TypedError(
|
|
387
|
+
HardwareErrorCode.RuntimeError,
|
|
388
|
+
`Device protocol has not been detected for ${path}`
|
|
389
|
+
);
|
|
390
|
+
}
|
|
337
391
|
if (LogBlockCommand.has(name)) {
|
|
338
|
-
this.Log?.debug('NodeUsbTransport call-', ' name: ', name);
|
|
392
|
+
this.Log?.debug('NodeUsbTransport call-', ' name: ', name, ' protocol: ', protocol);
|
|
339
393
|
} else {
|
|
340
|
-
this.Log?.debug(
|
|
394
|
+
this.Log?.debug(
|
|
395
|
+
'NodeUsbTransport call-',
|
|
396
|
+
' name: ',
|
|
397
|
+
name,
|
|
398
|
+
' data: ',
|
|
399
|
+
data,
|
|
400
|
+
' protocol: ',
|
|
401
|
+
protocol
|
|
402
|
+
);
|
|
341
403
|
}
|
|
342
404
|
|
|
405
|
+
if (protocol === 'V2') {
|
|
406
|
+
return this.callProtocolV2(path, name, data, options);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return this.callProtocolV1(path, name, data, options);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private async callProtocolV1(
|
|
413
|
+
path: string,
|
|
414
|
+
name: string,
|
|
415
|
+
data: Record<string, unknown>,
|
|
416
|
+
options?: TransportCallOptions
|
|
417
|
+
) {
|
|
418
|
+
const { messages } = this;
|
|
419
|
+
if (!messages) {
|
|
420
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
421
|
+
}
|
|
343
422
|
// Encode protobuf message into 63-byte chunks (same as WebUsbTransport)
|
|
344
|
-
const encodeBuffers =
|
|
423
|
+
const encodeBuffers = ProtocolV1.encodeMessageChunks(messages, name, data);
|
|
345
424
|
|
|
346
425
|
// Send all chunks with retry — if any chunk fails and reconnects,
|
|
347
426
|
// restart the entire send sequence from chunk 0 (device resets state on reconnect)
|
|
348
427
|
await this.sendAllChunksWithRetry(path, encodeBuffers);
|
|
349
428
|
|
|
350
429
|
// Receive response — re-resolve in case reconnect happened during send
|
|
351
|
-
const resData = await this.receiveData(path, this.getOpenDevice(path));
|
|
430
|
+
const resData = await this.receiveData(path, this.getOpenDevice(path), options?.timeoutMs);
|
|
352
431
|
if (typeof resData !== 'string') {
|
|
353
432
|
throw ERRORS.TypedError(HardwareErrorCode.NetworkError, 'Returning data is not string.');
|
|
354
433
|
}
|
|
355
|
-
const jsonData =
|
|
434
|
+
const jsonData = ProtocolV1.decodeMessage(messages, resData);
|
|
356
435
|
return check.call(jsonData);
|
|
357
436
|
}
|
|
358
437
|
|
|
@@ -401,6 +480,21 @@ export default class NodeUsbTransport {
|
|
|
401
480
|
);
|
|
402
481
|
}
|
|
403
482
|
|
|
483
|
+
private getDeviceInterface(dev: usb.Device): usb.Interface {
|
|
484
|
+
const { interfaces } = dev;
|
|
485
|
+
if (!interfaces?.length) {
|
|
486
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotFound, 'USB interface not found');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const vendorInterface = interfaces.find(iface => iface.descriptor.bInterfaceClass === 0xff);
|
|
490
|
+
const defaultInterface = interfaces.find(
|
|
491
|
+
iface => iface.descriptor.bInterfaceNumber === INTERFACE_NUMBER
|
|
492
|
+
);
|
|
493
|
+
const iface = vendorInterface ?? defaultInterface ?? interfaces[0];
|
|
494
|
+
|
|
495
|
+
return iface;
|
|
496
|
+
}
|
|
497
|
+
|
|
404
498
|
/**
|
|
405
499
|
* Reconnect device before retrying a failed transfer (aligned with WebUsbTransport).
|
|
406
500
|
* Uses per-path lock to prevent concurrent reconnects to the same device.
|
|
@@ -423,9 +517,9 @@ export default class NodeUsbTransport {
|
|
|
423
517
|
);
|
|
424
518
|
await wait(attempt * PACKET_IO_RETRY_DELAY);
|
|
425
519
|
|
|
426
|
-
// Close the existing device
|
|
520
|
+
// Close the existing device without clearing the detected protocol cache.
|
|
427
521
|
try {
|
|
428
|
-
await this.
|
|
522
|
+
await this.closeOpenDevice(path);
|
|
429
523
|
} catch (releaseError) {
|
|
430
524
|
this.Log?.debug('[NodeUsbTransport] release before retry error:', releaseError);
|
|
431
525
|
}
|
|
@@ -552,7 +646,7 @@ export default class NodeUsbTransport {
|
|
|
552
646
|
try {
|
|
553
647
|
dev.timeout = TRANSFER_TIMEOUT_MS;
|
|
554
648
|
|
|
555
|
-
const iface =
|
|
649
|
+
const iface = this.getDeviceInterface(dev);
|
|
556
650
|
|
|
557
651
|
// On Linux, detach kernel driver if active
|
|
558
652
|
if (process.platform === 'linux') {
|
|
@@ -567,12 +661,14 @@ export default class NodeUsbTransport {
|
|
|
567
661
|
|
|
568
662
|
iface.claim();
|
|
569
663
|
|
|
570
|
-
const epIn =
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
664
|
+
const epIn =
|
|
665
|
+
iface.endpoints.find(
|
|
666
|
+
(e): e is usb.InEndpoint => e.direction === 'in' && e.address === ENDPOINT_IN
|
|
667
|
+
) ?? iface.endpoints.find((e): e is usb.InEndpoint => e.direction === 'in');
|
|
668
|
+
const epOut =
|
|
669
|
+
iface.endpoints.find(
|
|
670
|
+
(e): e is usb.OutEndpoint => e.direction === 'out' && e.address === ENDPOINT_OUT
|
|
671
|
+
) ?? iface.endpoints.find((e): e is usb.OutEndpoint => e.direction === 'out');
|
|
576
672
|
|
|
577
673
|
if (!epIn || !epOut) {
|
|
578
674
|
throw ERRORS.TypedError(
|
|
@@ -595,17 +691,273 @@ export default class NodeUsbTransport {
|
|
|
595
691
|
}
|
|
596
692
|
}
|
|
597
693
|
|
|
694
|
+
private createProtocolMismatchError(expected: ProtocolType) {
|
|
695
|
+
return ERRORS.TypedError(
|
|
696
|
+
HardwareErrorCode.RuntimeError,
|
|
697
|
+
`Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`
|
|
698
|
+
);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
private createProtocolDetectionError() {
|
|
702
|
+
return ERRORS.TypedError(
|
|
703
|
+
HardwareErrorCode.RuntimeError,
|
|
704
|
+
'Unable to detect USB protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping'
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
private async detectProtocol(
|
|
709
|
+
path: string,
|
|
710
|
+
expectedProtocol?: ProtocolType
|
|
711
|
+
): Promise<ProtocolType> {
|
|
712
|
+
if (expectedProtocol === 'V1') {
|
|
713
|
+
if (await this.probeProtocolV1(path)) {
|
|
714
|
+
this.deviceProtocol.set(path, 'V1');
|
|
715
|
+
this.Log?.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
716
|
+
return 'V1';
|
|
717
|
+
}
|
|
718
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
if (expectedProtocol === 'V2') {
|
|
722
|
+
if (await this.probeProtocolV2(path)) {
|
|
723
|
+
this.deviceProtocol.set(path, 'V2');
|
|
724
|
+
this.Log?.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
|
|
725
|
+
return 'V2';
|
|
726
|
+
}
|
|
727
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
if (this.deviceProtocol.get(path) === 'V2' && (await this.probeProtocolV2(path))) {
|
|
731
|
+
this.deviceProtocol.set(path, 'V2');
|
|
732
|
+
this.Log?.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2 (cached)`);
|
|
733
|
+
return 'V2';
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
if (await this.probeProtocolV1(path)) {
|
|
737
|
+
this.deviceProtocol.set(path, 'V1');
|
|
738
|
+
this.Log?.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V1`);
|
|
739
|
+
return 'V1';
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (await this.probeProtocolV2(path)) {
|
|
743
|
+
this.deviceProtocol.set(path, 'V2');
|
|
744
|
+
this.Log?.debug(`[NodeUsbTransport] detectProtocol: path=${path} -> V2`);
|
|
745
|
+
return 'V2';
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
this.deviceProtocol.delete(path);
|
|
749
|
+
throw this.createProtocolDetectionError();
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
private async resetConnectionAfterProbe(path: string) {
|
|
753
|
+
this.protocolV2Assemblers.get(path)?.reset();
|
|
754
|
+
|
|
755
|
+
try {
|
|
756
|
+
await this.closeOpenDevice(path);
|
|
757
|
+
} catch (error) {
|
|
758
|
+
this.Log?.debug('[NodeUsbTransport] close after protocol probe error:', error);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
await this.enumerate();
|
|
762
|
+
this.openDevice(path);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
private async withProtocolReadTimeout<T>(
|
|
766
|
+
path: string,
|
|
767
|
+
promise: Promise<T>,
|
|
768
|
+
timeoutMs: number,
|
|
769
|
+
protocol: ProtocolType
|
|
770
|
+
): Promise<T> {
|
|
771
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
772
|
+
let timedOut = false;
|
|
773
|
+
const waitForeverAfterTimeout = () => new Promise<never>(() => {});
|
|
774
|
+
const guardedPromise = promise.then(
|
|
775
|
+
value => (timedOut ? waitForeverAfterTimeout() : value),
|
|
776
|
+
error => {
|
|
777
|
+
if (timedOut) {
|
|
778
|
+
return waitForeverAfterTimeout();
|
|
779
|
+
}
|
|
780
|
+
throw error;
|
|
781
|
+
}
|
|
782
|
+
);
|
|
783
|
+
try {
|
|
784
|
+
return await Promise.race([
|
|
785
|
+
guardedPromise,
|
|
786
|
+
new Promise<never>((_, reject) => {
|
|
787
|
+
timer = setTimeout(async () => {
|
|
788
|
+
timedOut = true;
|
|
789
|
+
try {
|
|
790
|
+
await this.resetConnectionAfterProbe(path);
|
|
791
|
+
} catch (error) {
|
|
792
|
+
this.Log?.debug(
|
|
793
|
+
`[NodeUsbTransport] reset after Protocol ${protocol} timeout failed:`,
|
|
794
|
+
error
|
|
795
|
+
);
|
|
796
|
+
} finally {
|
|
797
|
+
reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
|
|
798
|
+
}
|
|
799
|
+
}, timeoutMs);
|
|
800
|
+
}),
|
|
801
|
+
]);
|
|
802
|
+
} finally {
|
|
803
|
+
if (timer) clearTimeout(timer);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
private async probeProtocolV1(path: string) {
|
|
808
|
+
if (!this.messages) {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
try {
|
|
813
|
+
await this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
|
|
814
|
+
return true;
|
|
815
|
+
} catch (error) {
|
|
816
|
+
this.Log?.debug('[NodeUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
817
|
+
return false;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
private async probeProtocolV2(path: string) {
|
|
822
|
+
if (!this.messages || !this.messagesV2) {
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
return probeProtocolV2Helper({
|
|
827
|
+
call: (name, data, options) => this.callProtocolV2(path, name, data, options),
|
|
828
|
+
timeoutMs: PROTOCOL_PROBE_TIMEOUT,
|
|
829
|
+
logger: this.Log,
|
|
830
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
831
|
+
onProbeFailed: () => this.resetConnectionAfterProbe(path),
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
private async writeProtocolV2Frame(path: string, frame: Uint8Array) {
|
|
836
|
+
let lastError: unknown;
|
|
837
|
+
for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt++) {
|
|
838
|
+
if (this.cancelled) {
|
|
839
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromOutside, 'Cancelled');
|
|
840
|
+
}
|
|
841
|
+
try {
|
|
842
|
+
await transferOutOnce(this.getOpenDevice(path).epOut, Buffer.from(frame));
|
|
843
|
+
return;
|
|
844
|
+
} catch (error) {
|
|
845
|
+
lastError = error;
|
|
846
|
+
const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryableError(error);
|
|
847
|
+
if (!shouldRetry) {
|
|
848
|
+
throw error;
|
|
849
|
+
}
|
|
850
|
+
try {
|
|
851
|
+
await this.reconnectForRetry(path, 'out', attempt, error);
|
|
852
|
+
} catch (reconnectError) {
|
|
853
|
+
lastError = reconnectError;
|
|
854
|
+
this.Log?.debug(
|
|
855
|
+
`[NodeUsbTransport] Protocol V2 write reconnect failed on retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(
|
|
856
|
+
reconnectError
|
|
857
|
+
)}`
|
|
858
|
+
);
|
|
859
|
+
break;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
throw lastError;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
private async receiveProtocolV2Frame(path: string, timeoutMs?: number): Promise<Uint8Array> {
|
|
867
|
+
let assembler = this.protocolV2Assemblers.get(path);
|
|
868
|
+
if (!assembler) {
|
|
869
|
+
assembler = new ProtocolV2FrameAssembler(PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
870
|
+
this.protocolV2Assemblers.set(path, assembler);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
let frame: Uint8Array | undefined = assembler.push(new Uint8Array(0));
|
|
874
|
+
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
875
|
+
|
|
876
|
+
while (!frame) {
|
|
877
|
+
const transferIn = this.transferInWithRetry(
|
|
878
|
+
path,
|
|
879
|
+
this.getOpenDevice(path),
|
|
880
|
+
PROTOCOL_V2_FRAME_MAX_BYTES
|
|
881
|
+
);
|
|
882
|
+
const packet = deadline
|
|
883
|
+
? await this.withProtocolReadTimeout(
|
|
884
|
+
path,
|
|
885
|
+
transferIn,
|
|
886
|
+
Math.max(deadline - Date.now(), 1),
|
|
887
|
+
'V2'
|
|
888
|
+
)
|
|
889
|
+
: await transferIn;
|
|
890
|
+
const bytes = new Uint8Array(
|
|
891
|
+
packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength)
|
|
892
|
+
);
|
|
893
|
+
try {
|
|
894
|
+
frame = assembler.push(bytes);
|
|
895
|
+
} catch (error) {
|
|
896
|
+
throw ERRORS.TypedError(
|
|
897
|
+
HardwareErrorCode.NetworkError,
|
|
898
|
+
error instanceof Error ? error.message : String(error)
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return frame;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
private async callProtocolV2(
|
|
906
|
+
path: string,
|
|
907
|
+
name: string,
|
|
908
|
+
data: Record<string, unknown>,
|
|
909
|
+
options?: TransportCallOptions
|
|
910
|
+
) {
|
|
911
|
+
const protocolV1Messages = this.messages;
|
|
912
|
+
if (!this.messagesV2) {
|
|
913
|
+
throw ERRORS.TypedError(
|
|
914
|
+
HardwareErrorCode.TransportNotConfigured,
|
|
915
|
+
'Protocol V2 schema not configured'
|
|
916
|
+
);
|
|
917
|
+
}
|
|
918
|
+
if (!protocolV1Messages) {
|
|
919
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
const session = new ProtocolV2Session({
|
|
923
|
+
schemas: {
|
|
924
|
+
protocolV1: protocolV1Messages,
|
|
925
|
+
protocolV2: this.messagesV2,
|
|
926
|
+
},
|
|
927
|
+
router: PROTOCOL_V2_CHANNEL_USB,
|
|
928
|
+
writeFrame: (frame: Uint8Array) => this.writeProtocolV2Frame(path, frame),
|
|
929
|
+
readFrame: () => this.receiveProtocolV2Frame(path, options?.timeoutMs),
|
|
930
|
+
logger: this.Log,
|
|
931
|
+
logPrefix: 'ProtocolV2 NodeUSB',
|
|
932
|
+
createTimeoutError: (_messageName: string, timeoutMs: number) =>
|
|
933
|
+
new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${name}`),
|
|
934
|
+
});
|
|
935
|
+
|
|
936
|
+
this.protocolV2Assemblers.get(path)?.reset();
|
|
937
|
+
return session.call(name, data, options);
|
|
938
|
+
}
|
|
939
|
+
|
|
598
940
|
/**
|
|
599
941
|
* Receive a complete protobuf response from the device.
|
|
600
942
|
* Reads 64-byte packets, strips 0x3F marker, reassembles into hex string.
|
|
601
943
|
*/
|
|
602
|
-
private async receiveData(path: string, dev: OpenDevice): Promise<string> {
|
|
944
|
+
private async receiveData(path: string, dev: OpenDevice, timeoutMs?: number): Promise<string> {
|
|
945
|
+
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
946
|
+
const readPacket = async () => {
|
|
947
|
+
const transferIn = this.transferInWithRetry(path, this.getOpenDevice(path), PACKET_SIZE);
|
|
948
|
+
return deadline
|
|
949
|
+
? this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V1')
|
|
950
|
+
: transferIn;
|
|
951
|
+
};
|
|
952
|
+
|
|
603
953
|
// Read first packet, skip report byte
|
|
604
|
-
const firstPacket =
|
|
954
|
+
const firstPacket = timeoutMs
|
|
955
|
+
? await readPacket()
|
|
956
|
+
: await this.transferInWithRetry(path, dev, PACKET_SIZE);
|
|
605
957
|
const firstData = skipReportByte(firstPacket);
|
|
606
958
|
|
|
607
959
|
// Decode header: ## marker → { typeId, length, restBuffer }
|
|
608
|
-
const { length, typeId, restBuffer } =
|
|
960
|
+
const { length, typeId, restBuffer } = ProtocolV1.decodeFirstChunk(toArrayBuffer(firstData));
|
|
609
961
|
|
|
610
962
|
// Allocate result: typeId(2) + length(4) + payload(length)
|
|
611
963
|
const lengthWithHeader = Number(length) + HEADER_LENGTH;
|
|
@@ -619,7 +971,7 @@ export default class NodeUsbTransport {
|
|
|
619
971
|
// Read subsequent packets until complete
|
|
620
972
|
// Re-resolve device on each iteration so we use a fresh handle after any reconnect
|
|
621
973
|
while (decoded.offset < lengthWithHeader) {
|
|
622
|
-
const packet = await
|
|
974
|
+
const packet = await readPacket();
|
|
623
975
|
const pktData = skipReportByte(packet);
|
|
624
976
|
const buf = toArrayBuffer(pktData);
|
|
625
977
|
if (lengthWithHeader - decoded.offset >= PAYLOAD_SIZE) {
|
|
@@ -633,6 +985,8 @@ export default class NodeUsbTransport {
|
|
|
633
985
|
const result = decoded.toBuffer();
|
|
634
986
|
return Buffer.from(result as unknown as ArrayBuffer).toString('hex');
|
|
635
987
|
}
|
|
636
|
-
}
|
|
637
988
|
|
|
638
|
-
|
|
989
|
+
getProtocolType(path: string): ProtocolType | undefined {
|
|
990
|
+
return this.deviceProtocol.get(path);
|
|
991
|
+
}
|
|
992
|
+
}
|
package/dist/constants.d.ts
DELETED
package/dist/constants.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,WAAW,KAAK,CAAC;AAG9B,eAAO,MAAM,SAAS,KAAO,CAAC;AAG9B,eAAO,MAAM,YAAY,QAAkB,CAAC;AAG5C,eAAO,MAAM,aAAa,IAAI,CAAC"}
|
package/src/constants.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/** USB packet size in bytes */
|
|
2
|
-
export const PACKET_SIZE = 64;
|
|
3
|
-
|
|
4
|
-
/** Protocol marker byte (0x3F = '?') — first byte of every packet */
|
|
5
|
-
export const REPORT_ID = 0x3f;
|
|
6
|
-
|
|
7
|
-
/** Usable payload per packet after stripping the 0x3F report byte */
|
|
8
|
-
export const PAYLOAD_SIZE = PACKET_SIZE - 1;
|
|
9
|
-
|
|
10
|
-
/** Protocol header length: typeId (2 bytes) + length (4 bytes) */
|
|
11
|
-
export const HEADER_LENGTH = 6;
|