@onekeyfe/hd-transport-usb 1.1.28 → 1.2.0-alpha.1

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 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
- call(path: string, name: string, data: Record<string, unknown>): Promise<transport.MessageFromOneKey>;
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 { PACKET_SIZE, NodeUsbTransport as default };
64
+ export { NodeUsbTransport as default };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,SAA8B,MAAM,wBAAwB,CAAC;AAKpE,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AA0J7E,MAAM,CAAC,OAAO,OAAO,gBAAgB;IACnC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAElE,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,CAA0C;IAGhE,OAAO,CAAC,SAAS,CAAS;IAM1B,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY;IAMxC,SAAS,CAAC,UAAU,EAAE,GAAG;IAOzB,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;IA8B9C,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBvC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BxD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAkCpE,MAAM;IAWN,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,iBAAiB;YAmDX,sBAAsB;YAyCtB,mBAAmB;IAsCjC,OAAO,CAAC,UAAU;YAgEJ,WAAW;CAkC1B;AAED,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
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 PACKET_SIZE = 64;
65
- const REPORT_ID = 0x3f;
66
- const PAYLOAD_SIZE = PACKET_SIZE - 1;
67
- const HEADER_LENGTH = 6;
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 = buildEncodeBuffers(this.messages, name, data);
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 receiveOne(this.messages, resData);
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
- const path = (_a = input.path) !== null && _a !== void 0 ? _a : '';
242
- if (!path) {
243
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'No device path provided');
244
- }
245
- try {
246
- this.openDevice(path);
247
- return Promise.resolve(path);
248
- }
249
- catch (error) {
250
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('NodeUsbTransport acquire error: ', error);
251
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, (_c = error.message) !== null && _c !== void 0 ? _c : String(error));
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 { messages } = this;
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
- const encodeBuffers = buildEncodeBuffers(messages, name, data);
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 = receiveOne(messages, resData);
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.release(path);
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
- const existing = this.openDevices.get(path);
442
- if (existing)
443
- return;
444
- const busId = (_a = this.serialToBusId.get(path)) !== null && _a !== void 0 ? _a : path;
445
- const allDevices = usb__namespace.getDeviceList();
446
- const dev = allDevices.find(d => getBusId(d) === busId);
447
- if (!dev) {
448
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `USB device not found: ${path}`);
449
- }
450
- dev.open();
451
- try {
452
- dev.timeout = TRANSFER_TIMEOUT_MS;
453
- const iface = dev.interface(INTERFACE_NUMBER);
454
- if (process.platform === 'linux') {
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
- if (iface.isKernelDriverActive()) {
457
- iface.detachKernelDriver();
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
- catch (_b) {
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
- 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);
466
- if (!epIn || !epOut) {
467
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, 'USB endpoints not found (expected IN 0x81, OUT 0x01)');
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
- epIn.timeout = TRANSFER_TIMEOUT_MS;
470
- epOut.timeout = TRANSFER_TIMEOUT_MS;
471
- this.openDevices.set(path, { device: dev, iface, epIn, epOut });
472
- }
473
- catch (err) {
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
- dev.close();
792
+ return yield session.call(name, data, options);
476
793
  }
477
- catch (_c) {
794
+ finally {
795
+ this.protocolV2ReadTimeouts.delete(path);
478
796
  }
479
- throw err;
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 firstPacket = yield this.transferInWithRetry(path, dev, PACKET_SIZE);
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 } = decodeProtocol.decodeChunked(toArrayBuffer(firstData));
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 this.transferInWithRetry(path, this.getOpenDevice(path), PACKET_SIZE);
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.PACKET_SIZE = PACKET_SIZE;
513
- exports["default"] = NodeUsbTransport;
841
+ module.exports = NodeUsbTransport;