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

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