@onekeyfe/hd-transport-web-device 1.1.26 → 1.1.27-alpha.30

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.js CHANGED
@@ -41,16 +41,34 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
41
41
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
42
42
  };
43
43
 
44
- const { parseConfigure: parseConfigure$1, buildEncodeBuffers, decodeProtocol, receiveOne: receiveOne$1, check: check$1 } = transport__default["default"];
44
+ const { parseConfigure: parseConfigure$2, check: check$2, ProtocolV1: ProtocolV1$2 } = transport__default["default"];
45
45
  const CONFIGURATION_ID = 1;
46
46
  const INTERFACE_ID = 0;
47
47
  const ENDPOINT_ID = 1;
48
- const PACKET_SIZE = 64;
49
- const HEADER_LENGTH = 6;
48
+ const PACKET_SIZE = transport.PROTOCOL_V1_USB_PACKET_SIZE;
49
+ const PAYLOAD_SIZE = transport.PROTOCOL_V1_CHUNK_PAYLOAD_SIZE;
50
+ const REPORT_ID = transport.PROTOCOL_V1_REPORT_ID;
51
+ const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
50
52
  const PACKET_IO_MAX_RETRIES = 3;
51
53
  const PACKET_IO_RETRY_DELAY = 300;
54
+ const PROTOCOL_PROBE_TIMEOUT = 1000;
55
+ const WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
56
+ function shouldSuppressWebUsbCallLog(name) {
57
+ const normalized = name.replace(/[_\s-]/g, '');
58
+ return WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
59
+ }
60
+ function shouldBlockWebUsbCallDataLog(name) {
61
+ const normalized = name.replace(/[_\s-]/g, '');
62
+ return transport.LogBlockCommand.has(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
63
+ }
64
+ function inferProtocolTypeFromDeviceName$1(name) {
65
+ return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
66
+ }
52
67
  class WebUsbTransport {
53
68
  constructor() {
69
+ this.deviceProtocol = new Map();
70
+ this.protocolV2Assemblers = new Map();
71
+ this.deviceEndpoints = new Map();
54
72
  this.name = 'WebUsbTransport';
55
73
  this.stopped = false;
56
74
  this.configured = false;
@@ -68,10 +86,15 @@ class WebUsbTransport {
68
86
  this.usb = usb;
69
87
  }
70
88
  configure(signedData) {
71
- const messages = parseConfigure$1(signedData);
89
+ const messages = parseConfigure$2(signedData);
72
90
  this.configured = true;
73
91
  this.messages = messages;
74
92
  }
93
+ configureProtocolV2(signedData) {
94
+ var _a;
95
+ this.messagesV2 = parseConfigure$2(signedData);
96
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] Protocol V2 schema configured');
97
+ }
75
98
  promptDeviceAccess() {
76
99
  return __awaiter(this, void 0, void 0, function* () {
77
100
  if (!this.usb)
@@ -106,7 +129,12 @@ class WebUsbTransport {
106
129
  path: device.serialNumber,
107
130
  device,
108
131
  commType: 'webusb',
132
+ protocolType: inferProtocolTypeFromDeviceName$1(device.productName),
109
133
  }));
134
+ for (const dev of onekeyDevices) {
135
+ this.Log.debug(`[WebUSB] Device: name="${dev.productName}" serial="${dev.serialNumber}" ` +
136
+ `VID=0x${dev.vendorId.toString(16)} PID=0x${dev.productId.toString(16)}`);
137
+ }
110
138
  return this.deviceList;
111
139
  });
112
140
  }
@@ -117,6 +145,7 @@ class WebUsbTransport {
117
145
  return;
118
146
  try {
119
147
  yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
148
+ yield this.detectProtocol(input.path, input.expectedProtocol);
120
149
  return yield Promise.resolve(input.path);
121
150
  }
122
151
  catch (e) {
@@ -125,6 +154,51 @@ class WebUsbTransport {
125
154
  }
126
155
  });
127
156
  }
157
+ createProtocolMismatchError(expected) {
158
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
159
+ }
160
+ detectProtocol(path, expectedProtocol) {
161
+ var _a;
162
+ return __awaiter(this, void 0, void 0, function* () {
163
+ if (expectedProtocol === 'V1') {
164
+ if (yield this.probeProtocolV1(path)) {
165
+ this.deviceProtocol.set(path, 'V1');
166
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
167
+ return 'V1';
168
+ }
169
+ throw this.createProtocolMismatchError(expectedProtocol);
170
+ }
171
+ if (expectedProtocol === 'V2') {
172
+ if (this.deviceProtocol.get(path) === 'V2') {
173
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (cached expected)`);
174
+ return 'V2';
175
+ }
176
+ if (((_a = this.deviceList.find(device => device.path === path)) === null || _a === void 0 ? void 0 : _a.protocolType) === 'V2') {
177
+ this.deviceProtocol.set(path, 'V2');
178
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (descriptor)`);
179
+ return 'V2';
180
+ }
181
+ if (yield this.probeProtocolV2(path)) {
182
+ this.deviceProtocol.set(path, 'V2');
183
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
184
+ return 'V2';
185
+ }
186
+ throw this.createProtocolMismatchError(expectedProtocol);
187
+ }
188
+ if (this.deviceProtocol.get(path) === 'V2' && (yield this.probeProtocolV2(path))) {
189
+ this.deviceProtocol.set(path, 'V2');
190
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (cached)`);
191
+ return 'V2';
192
+ }
193
+ let protocol = 'V1';
194
+ if (!(yield this.probeProtocolV1(path)) && (yield this.probeProtocolV2(path))) {
195
+ protocol = 'V2';
196
+ }
197
+ this.deviceProtocol.set(path, protocol);
198
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> ${protocol}`);
199
+ return protocol;
200
+ });
201
+ }
128
202
  findDevice(path) {
129
203
  return __awaiter(this, void 0, void 0, function* () {
130
204
  if (this.deviceList.length === 0) {
@@ -157,19 +231,50 @@ class WebUsbTransport {
157
231
  }
158
232
  });
159
233
  }
234
+ discoverEndpoints(device) {
235
+ var _a, _b;
236
+ for (const config of device.configurations) {
237
+ for (const iface of config.interfaces) {
238
+ for (const alt of iface.alternates) {
239
+ if (alt.interfaceClass === 0xff) {
240
+ let endpointIn = this.endpointId;
241
+ let endpointOut = this.endpointId;
242
+ for (const ep of alt.endpoints) {
243
+ if (ep.direction === 'in')
244
+ endpointIn = ep.endpointNumber;
245
+ else
246
+ endpointOut = ep.endpointNumber;
247
+ }
248
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] discovered vendor interface ${iface.interfaceNumber}, ` +
249
+ `endpointIn=${endpointIn}, endpointOut=${endpointOut}`);
250
+ return { interfaceNumber: iface.interfaceNumber, endpointIn, endpointOut };
251
+ }
252
+ }
253
+ }
254
+ }
255
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[WebUsbTransport] no vendor interface found, using defaults');
256
+ return {
257
+ interfaceNumber: this.interfaceId,
258
+ endpointIn: this.endpointId,
259
+ endpointOut: this.endpointId,
260
+ };
261
+ }
160
262
  connectToDevice(path, first) {
161
263
  return __awaiter(this, void 0, void 0, function* () {
162
264
  const device = yield this.findDevice(path);
265
+ this.Log.debug('[WebUsbTransport] connecting to device:', device.productName, 'PID:', device.productId);
163
266
  yield device.open();
164
- if (first) {
267
+ if (first ||
268
+ !device.configuration ||
269
+ device.configuration.configurationValue !== this.configurationId) {
165
270
  yield device.selectConfiguration(this.configurationId);
166
- try {
167
- yield device.reset();
168
- }
169
- catch (error) {
170
- }
171
271
  }
172
- yield device.claimInterface(this.interfaceId);
272
+ const endpoints = this.discoverEndpoints(device);
273
+ this.deviceEndpoints.set(path, endpoints);
274
+ if (!this.protocolV2Assemblers.has(path)) {
275
+ this.protocolV2Assemblers.set(path, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES));
276
+ }
277
+ yield device.claimInterface(endpoints.interfaceNumber);
173
278
  });
174
279
  }
175
280
  post(session, name, data) {
@@ -199,14 +304,17 @@ class WebUsbTransport {
199
304
  message.includes('networkerror'));
200
305
  }
201
306
  reconnectForPacketIoRetry(path, direction, attempt, error) {
307
+ var _a;
202
308
  return __awaiter(this, void 0, void 0, function* () {
203
309
  this.Log.debug(`[WebUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
204
310
  yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
205
311
  try {
206
312
  const currentDevice = yield this.findDevice(path);
207
313
  if (currentDevice.opened) {
314
+ const endpoints = this.deviceEndpoints.get(path);
315
+ const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
208
316
  try {
209
- yield currentDevice.releaseInterface(this.interfaceId);
317
+ yield currentDevice.releaseInterface(ifaceNum);
210
318
  }
211
319
  catch (releaseError) {
212
320
  this.Log.debug('[WebUsbTransport] releaseInterface before retry error:', releaseError);
@@ -239,6 +347,7 @@ class WebUsbTransport {
239
347
  return copied.buffer;
240
348
  }
241
349
  transferOutWithRetry(path, packet) {
350
+ var _a;
242
351
  return __awaiter(this, void 0, void 0, function* () {
243
352
  let lastError;
244
353
  for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt += 1) {
@@ -247,8 +356,10 @@ class WebUsbTransport {
247
356
  if (!device.opened) {
248
357
  yield this.connect(path, false);
249
358
  }
359
+ const endpoints = this.deviceEndpoints.get(path);
360
+ const endpointOut = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointOut) !== null && _a !== void 0 ? _a : this.endpointId;
250
361
  const transferBuffer = this.toArrayBuffer(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
251
- yield device.transferOut(this.endpointId, transferBuffer);
362
+ yield device.transferOut(endpointOut, transferBuffer);
252
363
  return;
253
364
  }
254
365
  catch (error) {
@@ -269,20 +380,29 @@ class WebUsbTransport {
269
380
  throw lastError;
270
381
  });
271
382
  }
272
- transferInWithRetry(path, length) {
383
+ transferInWithRetry(path, length, cancelToken) {
384
+ var _a;
273
385
  return __awaiter(this, void 0, void 0, function* () {
274
386
  let lastError;
275
387
  for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt += 1) {
388
+ if (cancelToken === null || cancelToken === void 0 ? void 0 : cancelToken.cancelled) {
389
+ throw new Error('transferIn cancelled');
390
+ }
276
391
  try {
277
392
  const device = yield this.findDevice(path);
278
393
  if (!device.opened) {
279
394
  yield this.connect(path, false);
280
395
  }
281
- const result = yield device.transferIn(this.endpointId, length);
396
+ const endpoints = this.deviceEndpoints.get(path);
397
+ const endpointIn = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointIn) !== null && _a !== void 0 ? _a : this.endpointId;
398
+ const result = yield device.transferIn(endpointIn, length);
282
399
  return this.getTransferInData(result);
283
400
  }
284
401
  catch (error) {
285
402
  lastError = error;
403
+ if (cancelToken === null || cancelToken === void 0 ? void 0 : cancelToken.cancelled) {
404
+ throw error;
405
+ }
286
406
  const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryablePacketIoError(error);
287
407
  if (!shouldRetry) {
288
408
  throw error;
@@ -299,7 +419,99 @@ class WebUsbTransport {
299
419
  throw lastError;
300
420
  });
301
421
  }
302
- call(path, name, data) {
422
+ resetConnectionAfterProbe(path) {
423
+ var _a, _b;
424
+ return __awaiter(this, void 0, void 0, function* () {
425
+ (_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
426
+ try {
427
+ const device = yield this.findDevice(path);
428
+ if (device.opened) {
429
+ const endpoints = this.deviceEndpoints.get(path);
430
+ const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
431
+ try {
432
+ yield device.releaseInterface(ifaceNum);
433
+ }
434
+ catch (error) {
435
+ this.Log.debug('[WebUsbTransport] releaseInterface after protocol probe error:', error);
436
+ }
437
+ yield device.close();
438
+ }
439
+ }
440
+ catch (error) {
441
+ this.Log.debug('[WebUsbTransport] close after protocol probe error:', error);
442
+ }
443
+ yield this.getConnectedDevices();
444
+ yield this.connect(path, false);
445
+ });
446
+ }
447
+ withProtocolReadTimeout(path, promise, timeoutMs, protocol, onTimeout) {
448
+ return __awaiter(this, void 0, void 0, function* () {
449
+ let timer;
450
+ let timedOut = false;
451
+ const waitForeverAfterTimeout = () => new Promise(() => { });
452
+ const guardedPromise = promise.then(value => (timedOut ? waitForeverAfterTimeout() : value), error => {
453
+ if (timedOut) {
454
+ return waitForeverAfterTimeout();
455
+ }
456
+ throw error;
457
+ });
458
+ try {
459
+ return yield Promise.race([
460
+ guardedPromise,
461
+ new Promise((_, reject) => {
462
+ timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
463
+ timedOut = true;
464
+ onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout();
465
+ try {
466
+ yield this.resetConnectionAfterProbe(path);
467
+ }
468
+ catch (error) {
469
+ this.Log.debug(`[WebUsbTransport] reset after Protocol ${protocol} timeout failed:`, error);
470
+ }
471
+ finally {
472
+ reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
473
+ }
474
+ }), timeoutMs);
475
+ }),
476
+ ]);
477
+ }
478
+ finally {
479
+ if (timer)
480
+ clearTimeout(timer);
481
+ }
482
+ });
483
+ }
484
+ probeProtocolV1(path) {
485
+ return __awaiter(this, void 0, void 0, function* () {
486
+ if (!this.messages) {
487
+ return false;
488
+ }
489
+ try {
490
+ yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
491
+ return true;
492
+ }
493
+ catch (error) {
494
+ this.Log.debug('[WebUsbTransport] Protocol V1 Initialize probe failed:', error);
495
+ return false;
496
+ }
497
+ });
498
+ }
499
+ probeProtocolV2(path) {
500
+ return __awaiter(this, void 0, void 0, function* () {
501
+ if (!this.messages || !this.messagesV2) {
502
+ return false;
503
+ }
504
+ return transport.probeProtocolV2({
505
+ call: (name, data, options) => this.callProtocolV2(path, name, data, options),
506
+ timeoutMs: PROTOCOL_PROBE_TIMEOUT,
507
+ logger: this.Log,
508
+ logPrefix: 'ProtocolV2 WebUSB',
509
+ onProbeFailed: () => this.resetConnectionAfterProbe(path),
510
+ });
511
+ });
512
+ }
513
+ call(path, name, data, options) {
514
+ var _a;
303
515
  return __awaiter(this, void 0, void 0, function* () {
304
516
  if (this.messages == null) {
305
517
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
@@ -308,33 +520,110 @@ class WebUsbTransport {
308
520
  if (!device) {
309
521
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
310
522
  }
311
- const { messages } = this;
312
- if (transport.LogBlockCommand.has(name)) {
313
- this.Log.debug('call-', ' name: ', name);
523
+ const protocol = (_a = this.deviceProtocol.get(path)) !== null && _a !== void 0 ? _a : 'V1';
524
+ if (shouldSuppressWebUsbCallLog(name)) ;
525
+ else if (shouldBlockWebUsbCallDataLog(name)) {
526
+ this.Log.debug('call-', ' name: ', name, ' protocol: ', protocol);
314
527
  }
315
528
  else {
316
- this.Log.debug('call-', ' name: ', name, ' data: ', data);
529
+ this.Log.debug('call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
530
+ }
531
+ if (protocol === 'V2') {
532
+ return this.callProtocolV2(path, name, data, options);
533
+ }
534
+ return this.callProtocolV1(path, name, data, options);
535
+ });
536
+ }
537
+ callProtocolV1(path, name, data, options) {
538
+ return __awaiter(this, void 0, void 0, function* () {
539
+ const { messages } = this;
540
+ if (!messages) {
541
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
317
542
  }
318
- const encodeBuffers = buildEncodeBuffers(messages, name, data);
543
+ const encodeBuffers = ProtocolV1$2.encodeMessageChunks(messages, name, data);
319
544
  for (const buffer of encodeBuffers) {
320
545
  const newArray = new Uint8Array(PACKET_SIZE);
321
- newArray[0] = 63;
546
+ newArray[0] = REPORT_ID;
322
547
  newArray.set(new Uint8Array(buffer), 1);
323
548
  yield this.transferOutWithRetry(path, newArray);
324
549
  }
325
- const resData = yield this.receiveData(path);
550
+ const resData = yield this.receiveData(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
326
551
  if (typeof resData !== 'string') {
327
552
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Returning data is not string.');
328
553
  }
329
- const jsonData = receiveOne$1(messages, resData);
330
- return check$1.call(jsonData);
554
+ const jsonData = ProtocolV1$2.decodeMessage(messages, resData);
555
+ return check$2.call(jsonData);
556
+ });
557
+ }
558
+ callProtocolV2(path, name, data, options) {
559
+ var _a;
560
+ return __awaiter(this, void 0, void 0, function* () {
561
+ const protocolV1Messages = this.messages;
562
+ if (!this.messagesV2) {
563
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
564
+ }
565
+ if (!protocolV1Messages) {
566
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
567
+ }
568
+ const session = new transport.ProtocolV2Session({
569
+ schemas: {
570
+ protocolV1: protocolV1Messages,
571
+ protocolV2: this.messagesV2,
572
+ },
573
+ router: transport.PROTOCOL_V2_CHANNEL_USB,
574
+ writeFrame: (frame) => this.transferOutWithRetry(path, frame),
575
+ readFrame: () => this.receiveProtocolV2Frame(path, options === null || options === void 0 ? void 0 : options.timeoutMs),
576
+ logger: this.Log,
577
+ logPrefix: 'ProtocolV2 WebUSB',
578
+ createTimeoutError: (_messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${name}`),
579
+ });
580
+ (_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
581
+ return session.call(name, data, options);
331
582
  });
332
583
  }
333
- receiveData(path) {
584
+ receiveProtocolV2Frame(path, timeoutMs) {
334
585
  return __awaiter(this, void 0, void 0, function* () {
335
- const firstPacketData = yield this.transferInWithRetry(path, PACKET_SIZE);
586
+ let assembler = this.protocolV2Assemblers.get(path);
587
+ if (!assembler) {
588
+ assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
589
+ this.protocolV2Assemblers.set(path, assembler);
590
+ }
591
+ let frame = assembler.push(new Uint8Array(0));
592
+ const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
593
+ while (!frame) {
594
+ const cancelToken = { cancelled: false };
595
+ const transferIn = this.transferInWithRetry(path, transport.PROTOCOL_V2_FRAME_MAX_BYTES, cancelToken);
596
+ const dataView = deadline
597
+ ? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2', () => {
598
+ cancelToken.cancelled = true;
599
+ })
600
+ : yield transferIn;
601
+ const bytes = new Uint8Array(this.toArrayBuffer(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength)));
602
+ try {
603
+ frame = assembler.push(bytes);
604
+ }
605
+ catch (error) {
606
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
607
+ }
608
+ }
609
+ return frame;
610
+ });
611
+ }
612
+ receiveData(path, timeoutMs) {
613
+ return __awaiter(this, void 0, void 0, function* () {
614
+ const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
615
+ const readPacket = () => __awaiter(this, void 0, void 0, function* () {
616
+ const cancelToken = { cancelled: false };
617
+ const transferIn = this.transferInWithRetry(path, PACKET_SIZE, cancelToken);
618
+ return deadline
619
+ ? this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V1', () => {
620
+ cancelToken.cancelled = true;
621
+ })
622
+ : transferIn;
623
+ });
624
+ const firstPacketData = yield readPacket();
336
625
  const firstData = this.toArrayBuffer(firstPacketData.buffer.slice(1));
337
- const { length, typeId, restBuffer } = decodeProtocol.decodeChunked(firstData);
626
+ const { length, typeId, restBuffer } = ProtocolV1$2.decodeFirstChunk(firstData);
338
627
  const lengthWithHeader = Number(length + HEADER_LENGTH);
339
628
  const decoded = new ByteBuffer__default["default"](lengthWithHeader);
340
629
  decoded.writeUint16(typeId);
@@ -343,9 +632,9 @@ class WebUsbTransport {
343
632
  decoded.append(restBuffer);
344
633
  }
345
634
  while (decoded.offset < lengthWithHeader) {
346
- const packetData = yield this.transferInWithRetry(path, PACKET_SIZE);
635
+ const packetData = yield readPacket();
347
636
  const buffer = this.toArrayBuffer(packetData.buffer.slice(1));
348
- if (lengthWithHeader - decoded.offset >= PACKET_SIZE) {
637
+ if (lengthWithHeader - decoded.offset >= PAYLOAD_SIZE) {
349
638
  decoded.append(buffer);
350
639
  }
351
640
  else {
@@ -358,15 +647,24 @@ class WebUsbTransport {
358
647
  });
359
648
  }
360
649
  release(path) {
650
+ var _a;
361
651
  return __awaiter(this, void 0, void 0, function* () {
362
652
  const device = yield this.findDevice(path);
363
- yield device.releaseInterface(this.interfaceId);
653
+ const endpoints = this.deviceEndpoints.get(path);
654
+ const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
655
+ yield device.releaseInterface(ifaceNum);
364
656
  yield device.close();
657
+ this.protocolV2Assemblers.delete(path);
658
+ this.deviceEndpoints.delete(path);
365
659
  });
366
660
  }
661
+ getProtocolType(path) {
662
+ var _a;
663
+ return (_a = this.deviceProtocol.get(path)) !== null && _a !== void 0 ? _a : 'V1';
664
+ }
367
665
  }
368
666
 
369
- const { parseConfigure, buildBuffers, receiveOne, check } = transport__default["default"];
667
+ const { parseConfigure: parseConfigure$1, ProtocolV1: ProtocolV1$1, check: check$1 } = transport__default["default"];
370
668
  class ElectronBleTransport {
371
669
  constructor() {
372
670
  this.name = 'ElectronBleTransport';
@@ -377,6 +675,9 @@ class ElectronBleTransport {
377
675
  this.notificationCleanups = new Map();
378
676
  this.disconnectCleanups = new Map();
379
677
  }
678
+ getProtocolType(_path) {
679
+ return 'V1';
680
+ }
380
681
  handleBluetoothError(error) {
381
682
  if (error && typeof error === 'object') {
382
683
  if ('code' in error) {
@@ -430,7 +731,7 @@ class ElectronBleTransport {
430
731
  (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Transport] Noble BLE Transport initialized');
431
732
  }
432
733
  configure(signedData) {
433
- const messages = parseConfigure(signedData);
734
+ const messages = parseConfigure$1(signedData);
434
735
  this.configured = true;
435
736
  this._messages = messages;
436
737
  }
@@ -579,7 +880,7 @@ class ElectronBleTransport {
579
880
  else {
580
881
  (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[Transport] Noble BLE call', 'name:', name, 'data:', data);
581
882
  }
582
- const buffers = buildBuffers(messages, name, data);
883
+ const buffers = ProtocolV1$1.encodeTransportPackets(messages, name, data);
583
884
  try {
584
885
  if (!((_d = window.desktopApi) === null || _d === void 0 ? void 0 : _d.nobleBle)) {
585
886
  throw new Error('Noble BLE write API not available');
@@ -601,8 +902,8 @@ class ElectronBleTransport {
601
902
  if (typeof response !== 'string') {
602
903
  throw new Error('Returning data is not string.');
603
904
  }
604
- const jsonData = receiveOne(messages, response);
605
- return check.call(jsonData);
905
+ const jsonData = ProtocolV1$1.decodeMessage(messages, response);
906
+ return check$1.call(jsonData);
606
907
  }
607
908
  catch (e) {
608
909
  (_g = this.Log) === null || _g === void 0 ? void 0 : _g.error('[Transport] Noble BLE call error:', e);
@@ -639,7 +940,624 @@ class ElectronBleTransport {
639
940
  else {
640
941
  bufferState.buffer = bufferState.buffer.concat([...data]);
641
942
  }
642
- if (bufferState.buffer.length - transport.COMMON_HEADER_SIZE >= bufferState.bufferLength) {
943
+ if (bufferState.buffer.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferState.bufferLength) {
944
+ const completeBuffer = new Uint8Array(bufferState.buffer);
945
+ bufferState.bufferLength = 0;
946
+ bufferState.buffer = [];
947
+ const hexString = Array.from(completeBuffer)
948
+ .map(b => b.toString(16).padStart(2, '0'))
949
+ .join('');
950
+ return { isComplete: true, completePacket: hexString };
951
+ }
952
+ return { isComplete: false };
953
+ }
954
+ catch (error) {
955
+ return { isComplete: false, error: `Packet processing error: ${error}` };
956
+ }
957
+ }
958
+ }
959
+
960
+ const FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
961
+ function shouldSuppressHighVolumeCallLog(name) {
962
+ const normalized = name.replace(/[_\s-]/g, '');
963
+ return FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
964
+ }
965
+ const { parseConfigure, ProtocolV1, check } = transport__default["default"];
966
+ function inferProtocolTypeFromDeviceName(name) {
967
+ return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
968
+ }
969
+ const toBleDescriptor = (device, protocolType) => {
970
+ const resolvedProtocolType = protocolType !== null && protocolType !== void 0 ? protocolType : inferProtocolTypeFromDeviceName(device.name);
971
+ return Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (resolvedProtocolType ? { protocolType: resolvedProtocolType } : {}));
972
+ };
973
+ const BLE_PACKET_SIZE = 192;
974
+ const BLE_WRITE_DELAY_MS = 5;
975
+ const BLE_WRITE_MAX_RETRIES = 3;
976
+ const BLE_WRITE_RETRY_DELAY_MS = 300;
977
+ const BLE_RESPONSE_TIMEOUT_MS = 30000;
978
+ const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
979
+ class ElectronAutoBleTransport {
980
+ constructor() {
981
+ this.name = 'ElectronAutoBleTransport';
982
+ this.configured = false;
983
+ this.runPromise = null;
984
+ this.connectedDevices = new Set();
985
+ this.deviceProtocol = new Map();
986
+ this.v1Buffers = new Map();
987
+ this.v2Assemblers = new Map();
988
+ this.v2FrameQueue = [];
989
+ this.v2FramePromise = null;
990
+ this.notificationCleanups = new Map();
991
+ this.disconnectCleanups = new Map();
992
+ }
993
+ handleBluetoothError(error) {
994
+ if (error && typeof error === 'object') {
995
+ if ('code' in error) {
996
+ if (error.code === hdShared.HardwareErrorCode.BlePoweredOff) {
997
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
998
+ }
999
+ if (error.code === hdShared.HardwareErrorCode.BleUnsupported) {
1000
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
1001
+ }
1002
+ if (error.code === hdShared.HardwareErrorCode.BlePermissionError) {
1003
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
1004
+ }
1005
+ }
1006
+ const errorMessage = error.message || String(error);
1007
+ const poweredOffMessage = hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BlePoweredOff];
1008
+ const unsupportedMessage = hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BleUnsupported];
1009
+ const permissionMessage = hdShared.HardwareErrorCodeMessage[hdShared.HardwareErrorCode.BlePermissionError];
1010
+ if (errorMessage.includes(poweredOffMessage) || errorMessage.includes('poweredOff')) {
1011
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePoweredOff);
1012
+ }
1013
+ if (errorMessage.includes(unsupportedMessage) || errorMessage.includes('unsupported')) {
1014
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleUnsupported);
1015
+ }
1016
+ if (errorMessage.includes(permissionMessage) || errorMessage.includes('unauthorized')) {
1017
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError);
1018
+ }
1019
+ }
1020
+ throw error;
1021
+ }
1022
+ cleanupDeviceState(deviceId) {
1023
+ this.connectedDevices.delete(deviceId);
1024
+ this.deviceProtocol.delete(deviceId);
1025
+ this.v1Buffers.delete(deviceId);
1026
+ this.v2Assemblers.delete(deviceId);
1027
+ const notifyCleanup = this.notificationCleanups.get(deviceId);
1028
+ if (notifyCleanup) {
1029
+ notifyCleanup();
1030
+ this.notificationCleanups.delete(deviceId);
1031
+ }
1032
+ const disconnectCleanup = this.disconnectCleanups.get(deviceId);
1033
+ if (disconnectCleanup) {
1034
+ disconnectCleanup();
1035
+ this.disconnectCleanups.delete(deviceId);
1036
+ }
1037
+ }
1038
+ init(logger, emitter) {
1039
+ var _a, _b;
1040
+ this.Log = logger;
1041
+ this.emitter = emitter;
1042
+ if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
1043
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble BLE API is not available. Please ensure you are running in Electron with Noble support.');
1044
+ }
1045
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Auto BLE] Transport initialized');
1046
+ }
1047
+ configure(signedData) {
1048
+ this._messages = parseConfigure(signedData);
1049
+ this.configured = true;
1050
+ }
1051
+ configureProtocolV2(signedData) {
1052
+ var _a;
1053
+ this._messagesV2 = parseConfigure(signedData);
1054
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Auto BLE] Protocol V2 schema configured');
1055
+ }
1056
+ listen() {
1057
+ return __awaiter(this, void 0, void 0, function* () {
1058
+ return this.enumerate();
1059
+ });
1060
+ }
1061
+ enumerate() {
1062
+ var _a, _b, _c, _d;
1063
+ return __awaiter(this, void 0, void 0, function* () {
1064
+ try {
1065
+ if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
1066
+ throw new Error('Noble BLE API not available');
1067
+ }
1068
+ const devices = yield window.desktopApi.nobleBle.enumerate();
1069
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Auto BLE] enumerate found ${devices.length} device(s):`);
1070
+ for (const dev of devices) {
1071
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Auto BLE] id="${dev.id}" name="${dev.name}"`);
1072
+ }
1073
+ return devices.map(device => toBleDescriptor(device));
1074
+ }
1075
+ catch (error) {
1076
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Auto BLE] enumerate failed:', error);
1077
+ this.handleBluetoothError(error);
1078
+ }
1079
+ });
1080
+ }
1081
+ acquire(input) {
1082
+ var _a, _b, _c, _d, _e;
1083
+ return __awaiter(this, void 0, void 0, function* () {
1084
+ const { uuid, forceCleanRunPromise, expectedProtocol } = input;
1085
+ if (!uuid) {
1086
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
1087
+ }
1088
+ if (forceCleanRunPromise && this.runPromise) {
1089
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1090
+ this.runPromise.reject(error);
1091
+ this.rejectProtocolV2Frame(error);
1092
+ }
1093
+ try {
1094
+ if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
1095
+ throw new Error('Noble BLE API not available');
1096
+ }
1097
+ const device = yield window.desktopApi.nobleBle.getDevice(uuid);
1098
+ if (!device) {
1099
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
1100
+ }
1101
+ try {
1102
+ yield window.desktopApi.nobleBle.connect(uuid);
1103
+ this.connectedDevices.add(uuid);
1104
+ }
1105
+ catch (error) {
1106
+ this.handleBluetoothError(error);
1107
+ }
1108
+ this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
1109
+ this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
1110
+ yield window.desktopApi.nobleBle.subscribe(uuid);
1111
+ const cleanup = window.desktopApi.nobleBle.onNotification((deviceId, data) => {
1112
+ if (deviceId === uuid) {
1113
+ this.handleNotification(uuid, data);
1114
+ }
1115
+ });
1116
+ this.notificationCleanups.set(uuid, cleanup);
1117
+ const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
1118
+ var _a;
1119
+ if (disconnectedDevice.id === uuid) {
1120
+ this.cleanupDeviceState(uuid);
1121
+ (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
1122
+ name: disconnectedDevice.name,
1123
+ id: disconnectedDevice.id,
1124
+ connectId: disconnectedDevice.id,
1125
+ });
1126
+ }
1127
+ });
1128
+ this.disconnectCleanups.set(uuid, disconnectCleanup);
1129
+ const protocolType = yield this.detectProtocol(uuid, expectedProtocol);
1130
+ (_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
1131
+ name: device.name,
1132
+ id: device.id,
1133
+ connectId: device.id,
1134
+ });
1135
+ return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
1136
+ }
1137
+ catch (error) {
1138
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Auto BLE] acquire failed:', error);
1139
+ try {
1140
+ if (((_d = window.desktopApi) === null || _d === void 0 ? void 0 : _d.nobleBle) && this.connectedDevices.has(uuid)) {
1141
+ yield window.desktopApi.nobleBle.unsubscribe(uuid);
1142
+ yield window.desktopApi.nobleBle.disconnect(uuid);
1143
+ }
1144
+ }
1145
+ catch (cleanupError) {
1146
+ (_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug('[Auto BLE] acquire cleanup failed:', cleanupError);
1147
+ }
1148
+ this.cleanupDeviceState(uuid);
1149
+ throw error;
1150
+ }
1151
+ });
1152
+ }
1153
+ release(id) {
1154
+ var _a, _b;
1155
+ return __awaiter(this, void 0, void 0, function* () {
1156
+ try {
1157
+ if (this.connectedDevices.has(id)) {
1158
+ if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
1159
+ yield window.desktopApi.nobleBle.unsubscribe(id);
1160
+ yield window.desktopApi.nobleBle.disconnect(id);
1161
+ }
1162
+ this.cleanupDeviceState(id);
1163
+ }
1164
+ }
1165
+ catch (error) {
1166
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Auto BLE] release failed:', error);
1167
+ this.cleanupDeviceState(id);
1168
+ }
1169
+ });
1170
+ }
1171
+ createProtocolMismatchError(expected) {
1172
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
1173
+ }
1174
+ detectProtocol(uuid, expectedProtocol) {
1175
+ var _a, _b, _c, _d;
1176
+ return __awaiter(this, void 0, void 0, function* () {
1177
+ if (expectedProtocol === 'V1') {
1178
+ if (yield this.probeProtocolV1(uuid)) {
1179
+ this.deviceProtocol.set(uuid, 'V1');
1180
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> V1 (expected)`);
1181
+ return 'V1';
1182
+ }
1183
+ throw this.createProtocolMismatchError(expectedProtocol);
1184
+ }
1185
+ if (expectedProtocol === 'V2') {
1186
+ if (yield this.probeProtocolV2(uuid)) {
1187
+ this.deviceProtocol.set(uuid, 'V2');
1188
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
1189
+ return 'V2';
1190
+ }
1191
+ throw this.createProtocolMismatchError(expectedProtocol);
1192
+ }
1193
+ if (this.deviceProtocol.get(uuid) === 'V2' && (yield this.probeProtocolV2(uuid))) {
1194
+ this.deviceProtocol.set(uuid, 'V2');
1195
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> V2 (cached)`);
1196
+ return 'V2';
1197
+ }
1198
+ let protocol = 'V1';
1199
+ if (!(yield this.probeProtocolV1(uuid)) && (yield this.probeProtocolV2(uuid))) {
1200
+ protocol = 'V2';
1201
+ }
1202
+ this.deviceProtocol.set(uuid, protocol);
1203
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Auto BLE] detectProtocol: uuid=${uuid} -> ${protocol}`);
1204
+ return protocol;
1205
+ });
1206
+ }
1207
+ probeProtocolV1(uuid) {
1208
+ var _a;
1209
+ return __awaiter(this, void 0, void 0, function* () {
1210
+ if (!this._messages) {
1211
+ return false;
1212
+ }
1213
+ try {
1214
+ this.deviceProtocol.set(uuid, 'V1');
1215
+ yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
1216
+ return true;
1217
+ }
1218
+ catch (error) {
1219
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Auto BLE] Protocol V1 Initialize probe failed:', error);
1220
+ return false;
1221
+ }
1222
+ });
1223
+ }
1224
+ probeProtocolV2(uuid) {
1225
+ var _a;
1226
+ return __awaiter(this, void 0, void 0, function* () {
1227
+ if (!this._messages || !this._messagesV2) {
1228
+ return false;
1229
+ }
1230
+ this.deviceProtocol.set(uuid, 'V2');
1231
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1232
+ return transport.probeProtocolV2({
1233
+ call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
1234
+ timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS,
1235
+ logger: this.Log,
1236
+ logPrefix: 'ProtocolV2 BLE',
1237
+ onProbeFailed: () => {
1238
+ var _a;
1239
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1240
+ this.resetProtocolV2Frames();
1241
+ },
1242
+ });
1243
+ });
1244
+ }
1245
+ writeWithChunking(uuid, hexData) {
1246
+ return __awaiter(this, void 0, void 0, function* () {
1247
+ const totalBytes = hexData.length / 2;
1248
+ if (totalBytes <= BLE_PACKET_SIZE) {
1249
+ yield hdShared.wait(BLE_WRITE_DELAY_MS);
1250
+ yield this.writeWithRetry(uuid, hexData);
1251
+ return;
1252
+ }
1253
+ for (let offset = 0; offset < hexData.length;) {
1254
+ const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
1255
+ const chunkHex = hexData.substring(offset, offset + chunkHexLen);
1256
+ offset += chunkHexLen;
1257
+ yield this.writeWithRetry(uuid, chunkHex);
1258
+ if (offset < hexData.length) {
1259
+ yield hdShared.wait(BLE_WRITE_DELAY_MS);
1260
+ }
1261
+ }
1262
+ });
1263
+ }
1264
+ writeWithRetry(uuid, hexData) {
1265
+ var _a, _b, _c;
1266
+ return __awaiter(this, void 0, void 0, function* () {
1267
+ let lastError;
1268
+ const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
1269
+ if (!nobleBle) {
1270
+ throw new Error('Noble BLE API not available');
1271
+ }
1272
+ for (let attempt = 1; attempt <= BLE_WRITE_MAX_RETRIES; attempt++) {
1273
+ try {
1274
+ yield nobleBle.write(uuid, hexData);
1275
+ return;
1276
+ }
1277
+ catch (error) {
1278
+ lastError = error;
1279
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error(`[Auto BLE] write failed (attempt ${attempt}/${BLE_WRITE_MAX_RETRIES}):`, error);
1280
+ if (attempt < BLE_WRITE_MAX_RETRIES) {
1281
+ yield hdShared.wait(BLE_WRITE_RETRY_DELAY_MS);
1282
+ }
1283
+ }
1284
+ }
1285
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write failed after ${BLE_WRITE_MAX_RETRIES} attempts: ${(_c = lastError === null || lastError === void 0 ? void 0 : lastError.message) !== null && _c !== void 0 ? _c : lastError}`);
1286
+ });
1287
+ }
1288
+ handleNotification(deviceId, hexData) {
1289
+ var _a, _b;
1290
+ if (hexData === 'PAIRING_REJECTED') {
1291
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Auto BLE] Pairing rejection detected for device:', deviceId);
1292
+ if (this.runPromise) {
1293
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
1294
+ this.runPromise.reject(error);
1295
+ this.rejectProtocolV2Frame(error);
1296
+ }
1297
+ return;
1298
+ }
1299
+ const protocol = (_b = this.deviceProtocol.get(deviceId)) !== null && _b !== void 0 ? _b : 'V1';
1300
+ if (protocol === 'V2') {
1301
+ this.handleProtocolV2Notification(deviceId, hexData);
1302
+ return;
1303
+ }
1304
+ this.handleProtocolV1Notification(deviceId, hexData);
1305
+ }
1306
+ handleProtocolV2Notification(deviceId, hexData) {
1307
+ var _a, _b;
1308
+ try {
1309
+ if (!this.runPromise) {
1310
+ (_a = this.v2Assemblers.get(deviceId)) === null || _a === void 0 ? void 0 : _a.reset();
1311
+ this.resetProtocolV2Frames();
1312
+ return;
1313
+ }
1314
+ const bytes = transport.hexToBytes(hexData);
1315
+ if (bytes.length === 0)
1316
+ return;
1317
+ const assembler = this.v2Assemblers.get(deviceId);
1318
+ if (!assembler)
1319
+ return;
1320
+ let frameData = assembler.push(bytes);
1321
+ while (frameData) {
1322
+ this.resolveProtocolV2Frame(frameData);
1323
+ frameData = assembler.push(new Uint8Array(0));
1324
+ }
1325
+ }
1326
+ catch (error) {
1327
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Auto BLE] Protocol V2 notification error:', error);
1328
+ if (this.runPromise) {
1329
+ const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
1330
+ this.runPromise.reject(notifyError);
1331
+ this.rejectProtocolV2Frame(notifyError);
1332
+ }
1333
+ }
1334
+ }
1335
+ resolveProtocolV2Frame(frame) {
1336
+ if (this.v2FramePromise) {
1337
+ this.v2FramePromise.resolve(frame);
1338
+ this.v2FramePromise = null;
1339
+ return;
1340
+ }
1341
+ this.v2FrameQueue.push(frame);
1342
+ }
1343
+ rejectProtocolV2Frame(error) {
1344
+ this.v2FrameQueue = [];
1345
+ if (this.v2FramePromise) {
1346
+ this.v2FramePromise.reject(error);
1347
+ this.v2FramePromise = null;
1348
+ }
1349
+ }
1350
+ resetProtocolV2Frames() {
1351
+ this.v2FrameQueue = [];
1352
+ this.v2FramePromise = null;
1353
+ }
1354
+ readProtocolV2Frame() {
1355
+ return __awaiter(this, void 0, void 0, function* () {
1356
+ const queuedFrame = this.v2FrameQueue.shift();
1357
+ if (queuedFrame) {
1358
+ return queuedFrame;
1359
+ }
1360
+ const framePromise = hdShared.createDeferred();
1361
+ this.v2FramePromise = framePromise;
1362
+ try {
1363
+ return yield framePromise.promise;
1364
+ }
1365
+ finally {
1366
+ if (this.v2FramePromise === framePromise) {
1367
+ this.v2FramePromise = null;
1368
+ }
1369
+ }
1370
+ });
1371
+ }
1372
+ handleProtocolV1Notification(deviceId, hexData) {
1373
+ var _a;
1374
+ const result = this.processProtocolV1Notification(deviceId, hexData);
1375
+ if (result.error) {
1376
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Auto BLE] Protocol V1 packet processing error:', result.error);
1377
+ if (this.runPromise) {
1378
+ this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
1379
+ }
1380
+ return;
1381
+ }
1382
+ if (result.isComplete && result.completePacket && this.runPromise) {
1383
+ this.runPromise.resolve(result.completePacket);
1384
+ }
1385
+ }
1386
+ call(uuid, name, data, options) {
1387
+ var _a, _b, _c;
1388
+ return __awaiter(this, void 0, void 0, function* () {
1389
+ if (!this._messages) {
1390
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1391
+ }
1392
+ if (!this.connectedDevices.has(uuid)) {
1393
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound, `Device ${uuid} not connected`);
1394
+ }
1395
+ const protocol = (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : 'V1';
1396
+ if (shouldSuppressHighVolumeCallLog(name)) ;
1397
+ else if (transport.LogBlockCommand.has(name)) {
1398
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Auto BLE] call', 'name:', name, 'protocol:', protocol);
1399
+ }
1400
+ else {
1401
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[Auto BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
1402
+ }
1403
+ if (protocol === 'V2') {
1404
+ return this.callProtocolV2(uuid, name, data, options);
1405
+ }
1406
+ return this.callProtocolV1(uuid, name, data, options);
1407
+ });
1408
+ }
1409
+ callProtocolV1(uuid, name, data, options) {
1410
+ var _a, _b;
1411
+ return __awaiter(this, void 0, void 0, function* () {
1412
+ if (!this._messages) {
1413
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1414
+ }
1415
+ const forceRun = name === 'Initialize' || name === 'Cancel';
1416
+ if (this.runPromise && !forceRun) {
1417
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1418
+ }
1419
+ const runPromise = hdShared.createDeferred();
1420
+ runPromise.promise.catch(() => undefined);
1421
+ this.runPromise = runPromise;
1422
+ const messages = this._messages;
1423
+ const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
1424
+ let timeout;
1425
+ try {
1426
+ if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
1427
+ throw new Error('Noble BLE write API not available');
1428
+ }
1429
+ for (let i = 0; i < buffers.length; i++) {
1430
+ const buffer = buffers[i];
1431
+ if (!buffer || typeof buffer.toString !== 'function') {
1432
+ throw new Error(`Buffer ${i + 1} is invalid`);
1433
+ }
1434
+ const hexString = buffer.toString('hex');
1435
+ if (hexString.length === 0) {
1436
+ throw new Error(`Buffer ${i + 1} is empty`);
1437
+ }
1438
+ yield window.desktopApi.nobleBle.write(uuid, hexString);
1439
+ }
1440
+ const response = yield Promise.race([
1441
+ runPromise.promise,
1442
+ new Promise((_, reject) => {
1443
+ if (options === null || options === void 0 ? void 0 : options.timeoutMs) {
1444
+ timeout = setTimeout(() => {
1445
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${options.timeoutMs}ms for ${name}`);
1446
+ runPromise.reject(error);
1447
+ reject(error);
1448
+ }, options.timeoutMs);
1449
+ }
1450
+ }),
1451
+ ]);
1452
+ if (typeof response !== 'string') {
1453
+ throw new Error('Returning data is not string.');
1454
+ }
1455
+ const jsonData = ProtocolV1.decodeMessage(messages, response);
1456
+ return check.call(jsonData);
1457
+ }
1458
+ catch (e) {
1459
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Auto BLE] Protocol V1 call error:', e);
1460
+ throw e;
1461
+ }
1462
+ finally {
1463
+ if (timeout)
1464
+ clearTimeout(timeout);
1465
+ if (this.runPromise === runPromise) {
1466
+ this.runPromise = null;
1467
+ }
1468
+ }
1469
+ });
1470
+ }
1471
+ callProtocolV2(uuid, name, data, options) {
1472
+ var _a, _b, _c, _d, _e;
1473
+ return __awaiter(this, void 0, void 0, function* () {
1474
+ if (!this._messages || !this._messagesV2) {
1475
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1476
+ }
1477
+ const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'GetProtoVersion';
1478
+ if (this.runPromise) {
1479
+ if (!forceRun) {
1480
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1481
+ }
1482
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1483
+ this.runPromise.reject(error);
1484
+ this.rejectProtocolV2Frame(error);
1485
+ this.runPromise = null;
1486
+ }
1487
+ const runPromise = hdShared.createDeferred();
1488
+ runPromise.promise.catch(() => undefined);
1489
+ this.runPromise = runPromise;
1490
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1491
+ this.resetProtocolV2Frames();
1492
+ let completed = false;
1493
+ const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
1494
+ try {
1495
+ const session = new transport.ProtocolV2Session({
1496
+ schemas: {
1497
+ protocolV1: this._messages,
1498
+ protocolV2: this._messagesV2,
1499
+ },
1500
+ router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1501
+ writeFrame: (frame) => this.writeWithChunking(uuid, transport.bytesToHex(frame)),
1502
+ readFrame: () => __awaiter(this, void 0, void 0, function* () {
1503
+ const rxFrame = yield this.readProtocolV2Frame();
1504
+ if (!(rxFrame instanceof Uint8Array)) {
1505
+ throw new Error('Response is not Uint8Array');
1506
+ }
1507
+ return rxFrame;
1508
+ }),
1509
+ logger: this.Log,
1510
+ logPrefix: 'ProtocolV2 BLE',
1511
+ createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
1512
+ });
1513
+ const result = yield session.call(name, data, callOptions);
1514
+ completed = true;
1515
+ return result;
1516
+ }
1517
+ catch (e) {
1518
+ (_c = this.v2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
1519
+ this.resetProtocolV2Frames();
1520
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Auto BLE] Protocol V2 call error:', e);
1521
+ throw e;
1522
+ }
1523
+ finally {
1524
+ if (!completed) {
1525
+ (_e = this.v2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
1526
+ }
1527
+ this.resetProtocolV2Frames();
1528
+ if (this.runPromise === runPromise) {
1529
+ this.runPromise = null;
1530
+ }
1531
+ }
1532
+ });
1533
+ }
1534
+ processProtocolV1Notification(deviceId, hexData) {
1535
+ try {
1536
+ if (typeof hexData !== 'string') {
1537
+ return { isComplete: false, error: 'Invalid hexData type' };
1538
+ }
1539
+ const cleanHexData = hexData.replace(/\s+/g, '');
1540
+ if (!/^[0-9A-Fa-f]*$/.test(cleanHexData)) {
1541
+ return { isComplete: false, error: 'Invalid hex data format' };
1542
+ }
1543
+ const hexMatch = cleanHexData.match(/.{1,2}/g);
1544
+ if (!hexMatch) {
1545
+ return { isComplete: false, error: 'Failed to parse hex data' };
1546
+ }
1547
+ const data = new Uint8Array(hexMatch.map(byte => parseInt(byte, 16)));
1548
+ const bufferState = this.v1Buffers.get(deviceId);
1549
+ if (!bufferState) {
1550
+ return { isComplete: false, error: 'No buffer state for device' };
1551
+ }
1552
+ if (hdShared.isHeaderChunk(data)) {
1553
+ const dataView = new DataView(data.buffer);
1554
+ bufferState.bufferLength = dataView.getInt32(5, false);
1555
+ bufferState.buffer = [...data.subarray(3)];
1556
+ }
1557
+ else {
1558
+ bufferState.buffer = bufferState.buffer.concat([...data]);
1559
+ }
1560
+ if (bufferState.buffer.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferState.bufferLength) {
643
1561
  const completeBuffer = new Uint8Array(bufferState.buffer);
644
1562
  bufferState.bufferLength = 0;
645
1563
  bufferState.buffer = [];
@@ -654,7 +1572,12 @@ class ElectronBleTransport {
654
1572
  return { isComplete: false, error: `Packet processing error: ${error}` };
655
1573
  }
656
1574
  }
1575
+ getProtocolType(path) {
1576
+ var _a;
1577
+ return (_a = this.deviceProtocol.get(path)) !== null && _a !== void 0 ? _a : 'V1';
1578
+ }
657
1579
  }
658
1580
 
1581
+ exports.ElectronAutoBleTransport = ElectronAutoBleTransport;
659
1582
  exports.ElectronBleTransport = ElectronBleTransport;
660
1583
  exports.WebUsbTransport = WebUsbTransport;