@onekeyfe/hd-transport-web-device 1.1.27-patch.1 → 1.2.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -41,16 +41,43 @@ 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$1, check: check$1, ProtocolV1: ProtocolV1$1 } = 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 isLogBlockCommand$1(name) {
61
+ var _a, _b;
62
+ return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
63
+ }
64
+ function shouldBlockWebUsbCallDataLog(name) {
65
+ const normalized = name.replace(/[_\s-]/g, '');
66
+ return isLogBlockCommand$1(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
67
+ }
68
+ function inferProtocolHintFromDeviceName$1(name) {
69
+ return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
70
+ }
52
71
  class WebUsbTransport {
53
72
  constructor() {
73
+ this.deviceProtocol = new Map();
74
+ this.deviceProtocolHints = new Map();
75
+ this.protocolV2Assemblers = new Map();
76
+ this.protocolV2Sessions = new Map();
77
+ this.protocolV2ReadTimeouts = new Map();
78
+ this.deviceEndpoints = new Map();
79
+ this.mockSerialPaths = new WeakMap();
80
+ this.mockSerialCounter = 0;
54
81
  this.name = 'WebUsbTransport';
55
82
  this.stopped = false;
56
83
  this.configured = false;
@@ -72,6 +99,13 @@ class WebUsbTransport {
72
99
  this.configured = true;
73
100
  this.messages = messages;
74
101
  }
102
+ configureProtocolV2(signedData) {
103
+ var _a;
104
+ this.messagesV2 = parseConfigure$1(signedData);
105
+ this.protocolV2Sessions.clear();
106
+ this.protocolV2ReadTimeouts.clear();
107
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] Protocol V2 schema configured');
108
+ }
75
109
  promptDeviceAccess() {
76
110
  return __awaiter(this, void 0, void 0, function* () {
77
111
  if (!this.usb)
@@ -92,31 +126,61 @@ class WebUsbTransport {
92
126
  return this.deviceList;
93
127
  });
94
128
  }
129
+ getDevicePath(device) {
130
+ var _a;
131
+ if (typeof device.serialNumber === 'string' && device.serialNumber.length > 0) {
132
+ return device.serialNumber;
133
+ }
134
+ let path = this.mockSerialPaths.get(device);
135
+ if (!path) {
136
+ this.mockSerialCounter += 1;
137
+ path = `mock-serial:${device.vendorId.toString(16)}:${device.productId.toString(16)}:${this.mockSerialCounter}`;
138
+ this.mockSerialPaths.set(device, path);
139
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUSB] device has no serial number, using mock path: ${path}`);
140
+ }
141
+ return path;
142
+ }
95
143
  getConnectedDevices() {
96
144
  return __awaiter(this, void 0, void 0, function* () {
97
145
  if (!this.usb)
98
146
  return [];
99
147
  const devices = yield this.usb.getDevices();
100
- const onekeyDevices = devices.filter(dev => {
101
- const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some(desc => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
102
- const hasSerialNumber = typeof dev.serialNumber === 'string' && dev.serialNumber.length > 0;
103
- return isOneKey && hasSerialNumber;
148
+ const onekeyDevices = devices.filter(dev => hdShared.ONEKEY_WEBUSB_FILTER.some(desc => dev.vendorId === desc.vendorId && dev.productId === desc.productId));
149
+ this.deviceList = onekeyDevices.map(device => {
150
+ const path = this.getDevicePath(device);
151
+ const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
152
+ if (protocolHint) {
153
+ this.deviceProtocolHints.set(path, protocolHint);
154
+ }
155
+ return {
156
+ path,
157
+ device,
158
+ commType: 'webusb',
159
+ };
104
160
  });
105
- this.deviceList = onekeyDevices.map(device => ({
106
- path: device.serialNumber,
107
- device,
108
- commType: 'webusb',
109
- }));
161
+ for (const dev of onekeyDevices) {
162
+ this.Log.debug(`[WebUSB] Device: name="${dev.productName}" serial="${dev.serialNumber}" ` +
163
+ `VID=0x${dev.vendorId.toString(16)} PID=0x${dev.productId.toString(16)}`);
164
+ }
110
165
  return this.deviceList;
111
166
  });
112
167
  }
113
168
  acquire(input) {
114
- var _a;
169
+ var _a, _b, _c;
115
170
  return __awaiter(this, void 0, void 0, function* () {
116
171
  if (!input.path)
117
172
  return;
118
173
  try {
174
+ yield this.closeOpenDevice(input.path);
119
175
  yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
176
+ const deviceName = (_b = this.deviceList.find(device => device.path === input.path)) === null || _b === void 0 ? void 0 : _b.device.productName;
177
+ const protocolHint = input.expectedProtocol
178
+ ? undefined
179
+ : (_c = this.deviceProtocolHints.get(input.path)) !== null && _c !== void 0 ? _c : inferProtocolHintFromDeviceName$1(deviceName);
180
+ if (protocolHint) {
181
+ this.deviceProtocolHints.set(input.path, protocolHint);
182
+ }
183
+ yield this.detectProtocol(input.path, input.expectedProtocol, protocolHint);
120
184
  return yield Promise.resolve(input.path);
121
185
  }
122
186
  catch (e) {
@@ -125,6 +189,40 @@ class WebUsbTransport {
125
189
  }
126
190
  });
127
191
  }
192
+ createProtocolMismatchError(expected) {
193
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
194
+ }
195
+ createProtocolDetectionError() {
196
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Unable to detect USB protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
197
+ }
198
+ detectProtocol(path, expectedProtocol, protocolHint) {
199
+ return __awaiter(this, void 0, void 0, function* () {
200
+ if (expectedProtocol === 'V1') {
201
+ if (yield this.probeProtocolV1(path)) {
202
+ this.deviceProtocol.set(path, 'V1');
203
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
204
+ return 'V1';
205
+ }
206
+ throw this.createProtocolMismatchError(expectedProtocol);
207
+ }
208
+ if (expectedProtocol === 'V2') {
209
+ this.deviceProtocol.set(path, 'V2');
210
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V2 (expected)`);
211
+ return 'V2';
212
+ }
213
+ const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
214
+ for (const protocol of probeOrder) {
215
+ const detected = protocol === 'V1' ? yield this.probeProtocolV1(path) : yield this.probeProtocolV2(path);
216
+ if (detected) {
217
+ this.deviceProtocol.set(path, protocol);
218
+ this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> ${protocol}`);
219
+ return protocol;
220
+ }
221
+ }
222
+ this.deviceProtocol.delete(path);
223
+ throw this.createProtocolDetectionError();
224
+ });
225
+ }
128
226
  findDevice(path) {
129
227
  return __awaiter(this, void 0, void 0, function* () {
130
228
  if (this.deviceList.length === 0) {
@@ -157,19 +255,99 @@ class WebUsbTransport {
157
255
  }
158
256
  });
159
257
  }
258
+ discoverEndpoints(device) {
259
+ var _a, _b;
260
+ for (const config of device.configurations) {
261
+ for (const iface of config.interfaces) {
262
+ for (const alt of iface.alternates) {
263
+ if (alt.interfaceClass === 0xff) {
264
+ let endpointIn = this.endpointId;
265
+ let endpointOut = this.endpointId;
266
+ for (const ep of alt.endpoints) {
267
+ if (ep.direction === 'in')
268
+ endpointIn = ep.endpointNumber;
269
+ else
270
+ endpointOut = ep.endpointNumber;
271
+ }
272
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] discovered vendor interface ${iface.interfaceNumber}, ` +
273
+ `endpointIn=${endpointIn}, endpointOut=${endpointOut}`);
274
+ return { interfaceNumber: iface.interfaceNumber, endpointIn, endpointOut };
275
+ }
276
+ }
277
+ }
278
+ }
279
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[WebUsbTransport] no vendor interface found, using defaults');
280
+ return {
281
+ interfaceNumber: this.interfaceId,
282
+ endpointIn: this.endpointId,
283
+ endpointOut: this.endpointId,
284
+ };
285
+ }
160
286
  connectToDevice(path, first) {
287
+ var _a, _b;
161
288
  return __awaiter(this, void 0, void 0, function* () {
162
- const device = yield this.findDevice(path);
163
- yield device.open();
164
- if (first) {
289
+ let device = yield this.findDevice(path);
290
+ this.Log.debug('[WebUsbTransport] connecting to device:', device.productName, 'PID:', device.productId);
291
+ if (!device.opened) {
292
+ yield device.open();
293
+ }
294
+ try {
295
+ yield device.reset();
296
+ }
297
+ catch (error) {
298
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] reset before claim failed, continuing:', error);
299
+ }
300
+ yield this.getConnectedDevices();
301
+ device = yield this.findDevice(path);
302
+ if (!device.opened) {
303
+ yield device.open();
304
+ }
305
+ if (first ||
306
+ !device.configuration ||
307
+ device.configuration.configurationValue !== this.configurationId) {
165
308
  yield device.selectConfiguration(this.configurationId);
166
- try {
167
- yield device.reset();
168
- }
169
- catch (error) {
170
- }
171
309
  }
172
- yield device.claimInterface(this.interfaceId);
310
+ const endpoints = this.discoverEndpoints(device);
311
+ this.deviceEndpoints.set(path, endpoints);
312
+ (_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
313
+ this.protocolV2Assemblers.set(path, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES));
314
+ yield device.claimInterface(endpoints.interfaceNumber);
315
+ yield this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
316
+ yield this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
317
+ });
318
+ }
319
+ closeOpenDevice(path) {
320
+ var _a, _b, _c, _d, _e;
321
+ return __awaiter(this, void 0, void 0, function* () {
322
+ (_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
323
+ const current = (_b = this.deviceList.find(device => device.path === path)) === null || _b === void 0 ? void 0 : _b.device;
324
+ if (!(current === null || current === void 0 ? void 0 : current.opened))
325
+ return;
326
+ const endpoints = this.deviceEndpoints.get(path);
327
+ const ifaceNum = (_c = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _c !== void 0 ? _c : this.interfaceId;
328
+ try {
329
+ yield current.releaseInterface(ifaceNum);
330
+ }
331
+ catch (error) {
332
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
333
+ }
334
+ try {
335
+ yield current.close();
336
+ }
337
+ catch (error) {
338
+ (_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug('[WebUsbTransport] close before reconnect failed:', error);
339
+ }
340
+ });
341
+ }
342
+ clearEndpointHalt(device, direction, endpointNumber) {
343
+ var _a;
344
+ return __awaiter(this, void 0, void 0, function* () {
345
+ try {
346
+ yield device.clearHalt(direction, endpointNumber);
347
+ }
348
+ catch (error) {
349
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] clearHalt ${direction} endpoint ${endpointNumber} failed, continuing:`, error);
350
+ }
173
351
  });
174
352
  }
175
353
  post(session, name, data) {
@@ -199,14 +377,17 @@ class WebUsbTransport {
199
377
  message.includes('networkerror'));
200
378
  }
201
379
  reconnectForPacketIoRetry(path, direction, attempt, error) {
380
+ var _a;
202
381
  return __awaiter(this, void 0, void 0, function* () {
203
382
  this.Log.debug(`[WebUsbTransport] transfer${direction} failed, retry ${attempt}/${PACKET_IO_MAX_RETRIES}: ${this.getErrorMessage(error)}`);
204
383
  yield hdShared.wait(attempt * PACKET_IO_RETRY_DELAY);
205
384
  try {
206
385
  const currentDevice = yield this.findDevice(path);
207
386
  if (currentDevice.opened) {
387
+ const endpoints = this.deviceEndpoints.get(path);
388
+ const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
208
389
  try {
209
- yield currentDevice.releaseInterface(this.interfaceId);
390
+ yield currentDevice.releaseInterface(ifaceNum);
210
391
  }
211
392
  catch (releaseError) {
212
393
  this.Log.debug('[WebUsbTransport] releaseInterface before retry error:', releaseError);
@@ -239,6 +420,7 @@ class WebUsbTransport {
239
420
  return copied.buffer;
240
421
  }
241
422
  transferOutWithRetry(path, packet) {
423
+ var _a;
242
424
  return __awaiter(this, void 0, void 0, function* () {
243
425
  let lastError;
244
426
  for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt += 1) {
@@ -247,8 +429,10 @@ class WebUsbTransport {
247
429
  if (!device.opened) {
248
430
  yield this.connect(path, false);
249
431
  }
432
+ const endpoints = this.deviceEndpoints.get(path);
433
+ const endpointOut = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointOut) !== null && _a !== void 0 ? _a : this.endpointId;
250
434
  const transferBuffer = this.toArrayBuffer(packet.buffer.slice(packet.byteOffset, packet.byteOffset + packet.byteLength));
251
- yield device.transferOut(this.endpointId, transferBuffer);
435
+ yield device.transferOut(endpointOut, transferBuffer);
252
436
  return;
253
437
  }
254
438
  catch (error) {
@@ -269,20 +453,29 @@ class WebUsbTransport {
269
453
  throw lastError;
270
454
  });
271
455
  }
272
- transferInWithRetry(path, length) {
456
+ transferInWithRetry(path, length, cancelToken) {
457
+ var _a;
273
458
  return __awaiter(this, void 0, void 0, function* () {
274
459
  let lastError;
275
460
  for (let attempt = 1; attempt <= PACKET_IO_MAX_RETRIES; attempt += 1) {
461
+ if (cancelToken === null || cancelToken === void 0 ? void 0 : cancelToken.cancelled) {
462
+ throw new Error('transferIn cancelled');
463
+ }
276
464
  try {
277
465
  const device = yield this.findDevice(path);
278
466
  if (!device.opened) {
279
467
  yield this.connect(path, false);
280
468
  }
281
- const result = yield device.transferIn(this.endpointId, length);
469
+ const endpoints = this.deviceEndpoints.get(path);
470
+ const endpointIn = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointIn) !== null && _a !== void 0 ? _a : this.endpointId;
471
+ const result = yield device.transferIn(endpointIn, length);
282
472
  return this.getTransferInData(result);
283
473
  }
284
474
  catch (error) {
285
475
  lastError = error;
476
+ if (cancelToken === null || cancelToken === void 0 ? void 0 : cancelToken.cancelled) {
477
+ throw error;
478
+ }
286
479
  const shouldRetry = attempt < PACKET_IO_MAX_RETRIES && this.isRetryablePacketIoError(error);
287
480
  if (!shouldRetry) {
288
481
  throw error;
@@ -299,7 +492,92 @@ class WebUsbTransport {
299
492
  throw lastError;
300
493
  });
301
494
  }
302
- call(path, name, data) {
495
+ resetConnectionAfterProbe(path) {
496
+ var _a, _b;
497
+ return __awaiter(this, void 0, void 0, function* () {
498
+ (_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
499
+ this.protocolV2Sessions.delete(path);
500
+ this.protocolV2ReadTimeouts.delete(path);
501
+ try {
502
+ const device = yield this.findDevice(path);
503
+ if (device.opened) {
504
+ const endpoints = this.deviceEndpoints.get(path);
505
+ const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
506
+ try {
507
+ yield device.releaseInterface(ifaceNum);
508
+ }
509
+ catch (error) {
510
+ this.Log.debug('[WebUsbTransport] releaseInterface after protocol probe error:', error);
511
+ }
512
+ yield device.close();
513
+ }
514
+ }
515
+ catch (error) {
516
+ this.Log.debug('[WebUsbTransport] close after protocol probe error:', error);
517
+ }
518
+ yield this.getConnectedDevices();
519
+ yield this.connect(path, false);
520
+ });
521
+ }
522
+ withProtocolReadTimeout(path, promise, timeoutMs, protocol, onTimeout) {
523
+ return __awaiter(this, void 0, void 0, function* () {
524
+ let timer;
525
+ let timedOut = false;
526
+ const waitForeverAfterTimeout = () => new Promise(() => { });
527
+ const guardedPromise = promise.then(value => (timedOut ? waitForeverAfterTimeout() : value), error => {
528
+ if (timedOut) {
529
+ return waitForeverAfterTimeout();
530
+ }
531
+ throw error;
532
+ });
533
+ try {
534
+ return yield Promise.race([
535
+ guardedPromise,
536
+ new Promise((_, reject) => {
537
+ timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
538
+ timedOut = true;
539
+ onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout();
540
+ reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
541
+ }), timeoutMs);
542
+ }),
543
+ ]);
544
+ }
545
+ finally {
546
+ if (timer)
547
+ clearTimeout(timer);
548
+ }
549
+ });
550
+ }
551
+ probeProtocolV1(path) {
552
+ return __awaiter(this, void 0, void 0, function* () {
553
+ if (!this.messages) {
554
+ return false;
555
+ }
556
+ try {
557
+ yield this.callProtocolV1(path, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT });
558
+ return true;
559
+ }
560
+ catch (error) {
561
+ this.Log.debug('[WebUsbTransport] Protocol V1 Initialize probe failed:', error);
562
+ return false;
563
+ }
564
+ });
565
+ }
566
+ probeProtocolV2(path) {
567
+ return __awaiter(this, void 0, void 0, function* () {
568
+ if (!this.messages || !this.messagesV2) {
569
+ return false;
570
+ }
571
+ return transport.probeProtocolV2({
572
+ call: (name, data, options) => this.callProtocolV2(path, name, data, options),
573
+ timeoutMs: PROTOCOL_PROBE_TIMEOUT,
574
+ logger: this.Log,
575
+ logPrefix: 'ProtocolV2 WebUSB',
576
+ onProbeFailed: () => this.resetConnectionAfterProbe(path),
577
+ });
578
+ });
579
+ }
580
+ call(path, name, data, options) {
303
581
  return __awaiter(this, void 0, void 0, function* () {
304
582
  if (this.messages == null) {
305
583
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
@@ -308,33 +586,123 @@ class WebUsbTransport {
308
586
  if (!device) {
309
587
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
310
588
  }
311
- const { messages } = this;
312
- if (transport.LogBlockCommand.has(name)) {
313
- this.Log.debug('call-', ' name: ', name);
589
+ const protocol = this.deviceProtocol.get(path);
590
+ if (!protocol) {
591
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
592
+ }
593
+ if (shouldSuppressWebUsbCallLog(name)) ;
594
+ else if (shouldBlockWebUsbCallDataLog(name)) {
595
+ this.Log.debug('call-', ' name: ', name, ' protocol: ', protocol);
314
596
  }
315
597
  else {
316
- this.Log.debug('call-', ' name: ', name, ' data: ', data);
598
+ this.Log.debug('call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
599
+ }
600
+ if (protocol === 'V2') {
601
+ return this.callProtocolV2(path, name, data, options);
602
+ }
603
+ return this.callProtocolV1(path, name, data, options);
604
+ });
605
+ }
606
+ callProtocolV1(path, name, data, options) {
607
+ return __awaiter(this, void 0, void 0, function* () {
608
+ const { messages } = this;
609
+ if (!messages) {
610
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
317
611
  }
318
- const encodeBuffers = buildEncodeBuffers(messages, name, data);
612
+ const encodeBuffers = ProtocolV1$1.encodeMessageChunks(messages, name, data);
319
613
  for (const buffer of encodeBuffers) {
320
614
  const newArray = new Uint8Array(PACKET_SIZE);
321
- newArray[0] = 63;
615
+ newArray[0] = REPORT_ID;
322
616
  newArray.set(new Uint8Array(buffer), 1);
323
617
  yield this.transferOutWithRetry(path, newArray);
324
618
  }
325
- const resData = yield this.receiveData(path);
619
+ const resData = yield this.receiveData(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
326
620
  if (typeof resData !== 'string') {
327
621
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, 'Returning data is not string.');
328
622
  }
329
- const jsonData = receiveOne$1(messages, resData);
623
+ const jsonData = ProtocolV1$1.decodeMessage(messages, resData);
330
624
  return check$1.call(jsonData);
331
625
  });
332
626
  }
333
- receiveData(path) {
627
+ callProtocolV2(path, name, data, options) {
628
+ var _a;
334
629
  return __awaiter(this, void 0, void 0, function* () {
335
- const firstPacketData = yield this.transferInWithRetry(path, PACKET_SIZE);
630
+ const protocolV1Messages = this.messages;
631
+ if (!this.messagesV2) {
632
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
633
+ }
634
+ if (!protocolV1Messages) {
635
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
636
+ }
637
+ let session = this.protocolV2Sessions.get(path);
638
+ if (!session) {
639
+ session = new transport.ProtocolV2Session({
640
+ schemas: {
641
+ protocolV1: protocolV1Messages,
642
+ protocolV2: this.messagesV2,
643
+ },
644
+ router: transport.PROTOCOL_V2_CHANNEL_USB,
645
+ writeFrame: (frame) => this.transferOutWithRetry(path, frame),
646
+ readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
647
+ logger: this.Log,
648
+ logPrefix: 'ProtocolV2 WebUSB',
649
+ createTimeoutError: (messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
650
+ });
651
+ this.protocolV2Sessions.set(path, session);
652
+ }
653
+ this.protocolV2ReadTimeouts.set(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
654
+ (_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
655
+ try {
656
+ return yield session.call(name, data, options);
657
+ }
658
+ finally {
659
+ this.protocolV2ReadTimeouts.delete(path);
660
+ }
661
+ });
662
+ }
663
+ receiveProtocolV2Frame(path, timeoutMs) {
664
+ return __awaiter(this, void 0, void 0, function* () {
665
+ let assembler = this.protocolV2Assemblers.get(path);
666
+ if (!assembler) {
667
+ assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
668
+ this.protocolV2Assemblers.set(path, assembler);
669
+ }
670
+ let frame = assembler.push(new Uint8Array(0));
671
+ const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
672
+ while (!frame) {
673
+ const cancelToken = { cancelled: false };
674
+ const transferIn = this.transferInWithRetry(path, transport.PROTOCOL_V2_FRAME_MAX_BYTES, cancelToken);
675
+ const dataView = deadline
676
+ ? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2', () => {
677
+ cancelToken.cancelled = true;
678
+ })
679
+ : yield transferIn;
680
+ const bytes = new Uint8Array(this.toArrayBuffer(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength)));
681
+ try {
682
+ frame = assembler.push(bytes);
683
+ }
684
+ catch (error) {
685
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
686
+ }
687
+ }
688
+ return frame;
689
+ });
690
+ }
691
+ receiveData(path, timeoutMs) {
692
+ return __awaiter(this, void 0, void 0, function* () {
693
+ const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
694
+ const readPacket = () => __awaiter(this, void 0, void 0, function* () {
695
+ const cancelToken = { cancelled: false };
696
+ const transferIn = this.transferInWithRetry(path, PACKET_SIZE, cancelToken);
697
+ return deadline
698
+ ? this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V1', () => {
699
+ cancelToken.cancelled = true;
700
+ })
701
+ : transferIn;
702
+ });
703
+ const firstPacketData = yield readPacket();
336
704
  const firstData = this.toArrayBuffer(firstPacketData.buffer.slice(1));
337
- const { length, typeId, restBuffer } = decodeProtocol.decodeChunked(firstData);
705
+ const { length, typeId, restBuffer } = ProtocolV1$1.decodeFirstChunk(firstData);
338
706
  const lengthWithHeader = Number(length + HEADER_LENGTH);
339
707
  const decoded = new ByteBuffer__default["default"](lengthWithHeader);
340
708
  decoded.writeUint16(typeId);
@@ -343,9 +711,9 @@ class WebUsbTransport {
343
711
  decoded.append(restBuffer);
344
712
  }
345
713
  while (decoded.offset < lengthWithHeader) {
346
- const packetData = yield this.transferInWithRetry(path, PACKET_SIZE);
714
+ const packetData = yield readPacket();
347
715
  const buffer = this.toArrayBuffer(packetData.buffer.slice(1));
348
- if (lengthWithHeader - decoded.offset >= PACKET_SIZE) {
716
+ if (lengthWithHeader - decoded.offset >= PAYLOAD_SIZE) {
349
717
  decoded.append(buffer);
350
718
  }
351
719
  else {
@@ -358,24 +726,64 @@ class WebUsbTransport {
358
726
  });
359
727
  }
360
728
  release(path) {
729
+ var _a, _b;
361
730
  return __awaiter(this, void 0, void 0, function* () {
362
731
  const device = yield this.findDevice(path);
363
- yield device.releaseInterface(this.interfaceId);
732
+ const endpoints = this.deviceEndpoints.get(path);
733
+ const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
734
+ yield device.releaseInterface(ifaceNum);
364
735
  yield device.close();
736
+ this.deviceProtocol.delete(path);
737
+ this.deviceProtocolHints.delete(path);
738
+ (_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
739
+ this.protocolV2Assemblers.delete(path);
740
+ this.deviceEndpoints.delete(path);
365
741
  });
366
742
  }
743
+ getProtocolType(path) {
744
+ return this.deviceProtocol.get(path);
745
+ }
367
746
  }
368
747
 
369
- const { parseConfigure, buildBuffers, receiveOne, check } = transport__default["default"];
748
+ const FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
749
+ function shouldSuppressHighVolumeCallLog(name) {
750
+ const normalized = name.replace(/[_\s-]/g, '');
751
+ return FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
752
+ }
753
+ function isLogBlockCommand(name) {
754
+ var _a, _b;
755
+ return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
756
+ }
757
+ const { parseConfigure, ProtocolV1, check } = transport__default["default"];
758
+ function inferProtocolHintFromDeviceName(name) {
759
+ return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
760
+ }
761
+ const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
762
+ const BLE_PACKET_SIZE = 192;
763
+ const BLE_WRITE_DELAY_MS = 5;
764
+ const BLE_WRITE_MAX_RETRIES = 3;
765
+ const BLE_WRITE_RETRY_DELAY_MS = 300;
766
+ const BLE_RESPONSE_TIMEOUT_MS = 30000;
767
+ const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
768
+ const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
370
769
  class ElectronBleTransport {
371
770
  constructor() {
372
771
  this.name = 'ElectronBleTransport';
373
772
  this.configured = false;
374
773
  this.runPromise = null;
375
774
  this.connectedDevices = new Set();
376
- this.dataBuffers = new Map();
775
+ this.deviceProtocol = new Map();
776
+ this.deviceProtocolHints = new Map();
777
+ this.v1Buffers = new Map();
778
+ this.v2Assemblers = new Map();
779
+ this.v2FrameQueues = new Map();
780
+ this.v2FramePromises = new Map();
781
+ this.activeProtocolV2Call = null;
782
+ this.nextProtocolV2CallToken = 1;
377
783
  this.notificationCleanups = new Map();
378
784
  this.disconnectCleanups = new Map();
785
+ this.notificationTokens = new Map();
786
+ this.nextNotificationToken = 1;
379
787
  }
380
788
  handleBluetoothError(error) {
381
789
  if (error && typeof error === 'object') {
@@ -407,8 +815,16 @@ class ElectronBleTransport {
407
815
  throw error;
408
816
  }
409
817
  cleanupDeviceState(deviceId) {
818
+ var _a;
410
819
  this.connectedDevices.delete(deviceId);
411
- this.dataBuffers.delete(deviceId);
820
+ this.deviceProtocol.delete(deviceId);
821
+ this.v1Buffers.delete(deviceId);
822
+ this.v2Assemblers.delete(deviceId);
823
+ this.resetProtocolV2Frames(deviceId);
824
+ if (((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === deviceId) {
825
+ this.activeProtocolV2Call = null;
826
+ }
827
+ this.notificationTokens.delete(deviceId);
412
828
  const notifyCleanup = this.notificationCleanups.get(deviceId);
413
829
  if (notifyCleanup) {
414
830
  notifyCleanup();
@@ -427,39 +843,59 @@ class ElectronBleTransport {
427
843
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
428
844
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Noble BLE API is not available. Please ensure you are running in Electron with Noble support.');
429
845
  }
430
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Transport] Noble BLE Transport initialized');
846
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Transport initialized');
431
847
  }
432
848
  configure(signedData) {
433
- const messages = parseConfigure(signedData);
849
+ this._messages = parseConfigure(signedData);
434
850
  this.configured = true;
435
- this._messages = messages;
436
851
  }
437
- listen() { }
852
+ configureProtocolV2(signedData) {
853
+ var _a;
854
+ this._messagesV2 = parseConfigure(signedData);
855
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V2 schema configured');
856
+ }
857
+ listen() {
858
+ return __awaiter(this, void 0, void 0, function* () {
859
+ return this.enumerate();
860
+ });
861
+ }
438
862
  enumerate() {
439
- var _a, _b;
863
+ var _a, _b, _c, _d;
440
864
  return __awaiter(this, void 0, void 0, function* () {
441
865
  try {
442
866
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
443
867
  throw new Error('Noble BLE API not available');
444
868
  }
445
869
  const devices = yield window.desktopApi.nobleBle.enumerate();
446
- return devices;
870
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] enumerate found ${devices.length} device(s):`);
871
+ for (const dev of devices) {
872
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Electron BLE] id="${dev.id}" name="${dev.name}"`);
873
+ const protocolHint = inferProtocolHintFromDeviceName(dev.name);
874
+ if (protocolHint) {
875
+ this.deviceProtocolHints.set(dev.id, protocolHint);
876
+ }
877
+ }
878
+ return devices.map(device => toBleDescriptor(device));
447
879
  }
448
880
  catch (error) {
449
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Transport] Noble BLE enumerate failed:', error);
881
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] enumerate failed:', error);
450
882
  this.handleBluetoothError(error);
451
883
  }
452
884
  });
453
885
  }
454
886
  acquire(input) {
455
- var _a, _b, _c;
887
+ var _a, _b, _c, _d, _e, _f;
456
888
  return __awaiter(this, void 0, void 0, function* () {
457
- const { uuid, forceCleanRunPromise } = input;
889
+ const { uuid, forceCleanRunPromise, expectedProtocol } = input;
458
890
  if (!uuid) {
459
891
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
460
892
  }
461
893
  if (forceCleanRunPromise && this.runPromise) {
462
- this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
894
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
895
+ this.runPromise.reject(error);
896
+ this.rejectAllProtocolV2Frames(error);
897
+ this.runPromise = null;
898
+ this.activeProtocolV2Call = null;
463
899
  }
464
900
  try {
465
901
  if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
@@ -469,6 +905,12 @@ class ElectronBleTransport {
469
905
  if (!device) {
470
906
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound, `Device ${uuid} not found`);
471
907
  }
908
+ const protocolHint = expectedProtocol
909
+ ? undefined
910
+ : (_b = this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(device.name);
911
+ if (protocolHint) {
912
+ this.deviceProtocolHints.set(uuid, protocolHint);
913
+ }
472
914
  try {
473
915
  yield window.desktopApi.nobleBle.connect(uuid);
474
916
  this.connectedDevices.add(uuid);
@@ -476,13 +918,10 @@ class ElectronBleTransport {
476
918
  catch (error) {
477
919
  this.handleBluetoothError(error);
478
920
  }
479
- this.dataBuffers.set(uuid, { buffer: [], bufferLength: 0 });
921
+ this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
922
+ this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
480
923
  yield window.desktopApi.nobleBle.subscribe(uuid);
481
- const cleanup = window.desktopApi.nobleBle.onNotification((deviceId, data) => {
482
- if (deviceId === uuid) {
483
- this.handleNotificationData(uuid, data);
484
- }
485
- });
924
+ const cleanup = this.createNotificationSubscription(uuid);
486
925
  this.notificationCleanups.set(uuid, cleanup);
487
926
  const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
488
927
  var _a;
@@ -496,138 +935,511 @@ class ElectronBleTransport {
496
935
  }
497
936
  });
498
937
  this.disconnectCleanups.set(uuid, disconnectCleanup);
499
- (_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
938
+ const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
939
+ (_c = this.emitter) === null || _c === void 0 ? void 0 : _c.emit('device-connect', {
500
940
  name: device.name,
501
941
  id: device.id,
502
942
  connectId: device.id,
503
943
  });
504
- return { uuid, path: uuid };
944
+ return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
505
945
  }
506
946
  catch (error) {
507
- (_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Transport] Noble BLE acquire failed:', error);
947
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] acquire failed:', error);
948
+ try {
949
+ if (((_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) && this.connectedDevices.has(uuid)) {
950
+ yield window.desktopApi.nobleBle.unsubscribe(uuid);
951
+ yield window.desktopApi.nobleBle.disconnect(uuid);
952
+ }
953
+ }
954
+ catch (cleanupError) {
955
+ (_f = this.Log) === null || _f === void 0 ? void 0 : _f.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
956
+ }
957
+ this.cleanupDeviceState(uuid);
508
958
  throw error;
509
959
  }
510
960
  });
511
961
  }
512
962
  release(id) {
513
- var _a, _b, _c;
963
+ var _a, _b;
514
964
  return __awaiter(this, void 0, void 0, function* () {
515
965
  try {
516
966
  if (this.connectedDevices.has(id)) {
517
967
  if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
518
968
  yield window.desktopApi.nobleBle.unsubscribe(id);
519
- }
520
- if ((_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) {
521
969
  yield window.desktopApi.nobleBle.disconnect(id);
522
970
  }
523
971
  this.cleanupDeviceState(id);
524
972
  }
525
973
  }
526
974
  catch (error) {
527
- (_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Transport] Noble BLE release failed:', error);
975
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] release failed:', error);
528
976
  this.cleanupDeviceState(id);
529
977
  }
530
978
  });
531
979
  }
532
- handleNotificationData(deviceId, hexData) {
980
+ createProtocolMismatchError(expected) {
981
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
982
+ }
983
+ createProtocolDetectionError() {
984
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
985
+ }
986
+ clearProbeProtocol(uuid, protocol) {
987
+ if (this.deviceProtocol.get(uuid) === protocol) {
988
+ this.deviceProtocol.delete(uuid);
989
+ }
990
+ }
991
+ detectProtocol(uuid, expectedProtocol, protocolHint) {
992
+ var _a, _b, _c;
993
+ return __awaiter(this, void 0, void 0, function* () {
994
+ if (expectedProtocol === 'V1') {
995
+ if (yield this.probeProtocolV1(uuid)) {
996
+ this.deviceProtocol.set(uuid, 'V1');
997
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V1 (expected)`);
998
+ return 'V1';
999
+ }
1000
+ throw this.createProtocolMismatchError(expectedProtocol);
1001
+ }
1002
+ if (expectedProtocol === 'V2') {
1003
+ this.deviceProtocol.set(uuid, 'V2');
1004
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
1005
+ return 'V2';
1006
+ }
1007
+ const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
1008
+ for (let i = 0; i < probeOrder.length; i += 1) {
1009
+ const protocol = probeOrder[i];
1010
+ if (i > 0) {
1011
+ yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
1012
+ }
1013
+ const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
1014
+ if (detected) {
1015
+ this.deviceProtocol.set(uuid, protocol);
1016
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> ${protocol}`);
1017
+ return protocol;
1018
+ }
1019
+ }
1020
+ this.deviceProtocol.delete(uuid);
1021
+ throw this.createProtocolDetectionError();
1022
+ });
1023
+ }
1024
+ createNotificationSubscription(uuid) {
1025
+ var _a;
1026
+ if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
1027
+ throw new Error('Noble BLE API not available');
1028
+ }
1029
+ const notificationToken = this.nextNotificationToken;
1030
+ this.nextNotificationToken += 1;
1031
+ this.notificationTokens.set(uuid, notificationToken);
1032
+ return window.desktopApi.nobleBle.onNotification((deviceId, data) => {
1033
+ if (deviceId === uuid && this.notificationTokens.get(uuid) === notificationToken) {
1034
+ this.handleNotification(uuid, data);
1035
+ }
1036
+ });
1037
+ }
1038
+ resetProbeStateAfterProtocolProbe(uuid, protocol) {
1039
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1040
+ return __awaiter(this, void 0, void 0, function* () {
1041
+ this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
1042
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1043
+ this.resetProtocolV2Frames(uuid);
1044
+ if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
1045
+ this.activeProtocolV2Call = null;
1046
+ }
1047
+ if (this.runPromise) {
1048
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1049
+ this.runPromise.reject(error);
1050
+ this.runPromise = null;
1051
+ }
1052
+ const notifyCleanup = this.notificationCleanups.get(uuid);
1053
+ if (notifyCleanup) {
1054
+ notifyCleanup();
1055
+ this.notificationCleanups.delete(uuid);
1056
+ }
1057
+ this.notificationTokens.delete(uuid);
1058
+ try {
1059
+ yield ((_d = (_c = window.desktopApi) === null || _c === void 0 ? void 0 : _c.nobleBle) === null || _d === void 0 ? void 0 : _d.unsubscribe(uuid));
1060
+ }
1061
+ catch (error) {
1062
+ (_e = this.Log) === null || _e === void 0 ? void 0 : _e.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
1063
+ }
1064
+ try {
1065
+ yield ((_g = (_f = window.desktopApi) === null || _f === void 0 ? void 0 : _f.nobleBle) === null || _g === void 0 ? void 0 : _g.subscribe(uuid));
1066
+ }
1067
+ catch (error) {
1068
+ (_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug(`[Electron BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
1069
+ throw error;
1070
+ }
1071
+ const cleanup = this.createNotificationSubscription(uuid);
1072
+ this.notificationCleanups.set(uuid, cleanup);
1073
+ });
1074
+ }
1075
+ probeProtocolV1(uuid) {
1076
+ var _a;
1077
+ return __awaiter(this, void 0, void 0, function* () {
1078
+ if (!this._messages) {
1079
+ return false;
1080
+ }
1081
+ try {
1082
+ this.deviceProtocol.set(uuid, 'V1');
1083
+ yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
1084
+ return true;
1085
+ }
1086
+ catch (error) {
1087
+ this.clearProbeProtocol(uuid, 'V1');
1088
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1 Initialize probe failed:', error);
1089
+ return false;
1090
+ }
1091
+ });
1092
+ }
1093
+ probeProtocolV2(uuid) {
1094
+ var _a;
1095
+ return __awaiter(this, void 0, void 0, function* () {
1096
+ if (!this._messages || !this._messagesV2) {
1097
+ return false;
1098
+ }
1099
+ this.deviceProtocol.set(uuid, 'V2');
1100
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1101
+ const detected = yield transport.probeProtocolV2({
1102
+ call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
1103
+ timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
1104
+ logger: this.Log,
1105
+ logPrefix: 'ProtocolV2 BLE',
1106
+ onProbeFailed: () => {
1107
+ var _a;
1108
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1109
+ this.resetProtocolV2Frames(uuid);
1110
+ },
1111
+ });
1112
+ if (!detected) {
1113
+ this.clearProbeProtocol(uuid, 'V2');
1114
+ }
1115
+ return detected;
1116
+ });
1117
+ }
1118
+ writeWithChunking(uuid, hexData) {
1119
+ return __awaiter(this, void 0, void 0, function* () {
1120
+ const totalBytes = hexData.length / 2;
1121
+ if (totalBytes <= BLE_PACKET_SIZE) {
1122
+ yield hdShared.wait(BLE_WRITE_DELAY_MS);
1123
+ yield this.writeWithRetry(uuid, hexData);
1124
+ return;
1125
+ }
1126
+ for (let offset = 0; offset < hexData.length;) {
1127
+ const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
1128
+ const chunkHex = hexData.substring(offset, offset + chunkHexLen);
1129
+ offset += chunkHexLen;
1130
+ yield this.writeWithRetry(uuid, chunkHex);
1131
+ if (offset < hexData.length) {
1132
+ yield hdShared.wait(BLE_WRITE_DELAY_MS);
1133
+ }
1134
+ }
1135
+ });
1136
+ }
1137
+ writeWithRetry(uuid, hexData) {
1138
+ var _a, _b, _c;
1139
+ return __awaiter(this, void 0, void 0, function* () {
1140
+ let lastError;
1141
+ const nobleBle = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle;
1142
+ if (!nobleBle) {
1143
+ throw new Error('Noble BLE API not available');
1144
+ }
1145
+ for (let attempt = 1; attempt <= BLE_WRITE_MAX_RETRIES; attempt++) {
1146
+ try {
1147
+ yield nobleBle.write(uuid, hexData);
1148
+ return;
1149
+ }
1150
+ catch (error) {
1151
+ lastError = error;
1152
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error(`[Electron BLE] write failed (attempt ${attempt}/${BLE_WRITE_MAX_RETRIES}):`, error);
1153
+ if (attempt < BLE_WRITE_MAX_RETRIES) {
1154
+ yield hdShared.wait(BLE_WRITE_RETRY_DELAY_MS);
1155
+ }
1156
+ }
1157
+ }
1158
+ 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}`);
1159
+ });
1160
+ }
1161
+ handleNotification(deviceId, hexData) {
533
1162
  var _a, _b;
534
1163
  if (hexData === 'PAIRING_REJECTED') {
535
- (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Transport] Pairing rejection detected for device:', deviceId);
1164
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Pairing rejection detected for device:', deviceId);
536
1165
  if (this.runPromise) {
537
- this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled));
1166
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
1167
+ this.runPromise.reject(error);
1168
+ this.rejectAllProtocolV2Frames(error);
538
1169
  }
539
1170
  return;
540
1171
  }
541
- const result = this.processNotificationPacket(deviceId, hexData);
542
- if (result.error) {
543
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Transport] Packet processing error:', result.error);
1172
+ const protocol = this.deviceProtocol.get(deviceId);
1173
+ if (!protocol) {
1174
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Ignore notification before protocol detection:', deviceId);
1175
+ return;
1176
+ }
1177
+ if (protocol === 'V2') {
1178
+ this.handleProtocolV2Notification(deviceId, hexData);
1179
+ return;
1180
+ }
1181
+ this.handleProtocolV1Notification(deviceId, hexData);
1182
+ }
1183
+ handleProtocolV2Notification(deviceId, hexData) {
1184
+ var _a, _b, _c;
1185
+ try {
1186
+ if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== deviceId) {
1187
+ (_b = this.v2Assemblers.get(deviceId)) === null || _b === void 0 ? void 0 : _b.reset();
1188
+ this.resetProtocolV2Frames(deviceId);
1189
+ return;
1190
+ }
1191
+ const bytes = transport.hexToBytes(hexData);
1192
+ if (bytes.length === 0)
1193
+ return;
1194
+ const assembler = this.v2Assemblers.get(deviceId);
1195
+ if (!assembler)
1196
+ return;
1197
+ for (const frameData of assembler.drain(bytes)) {
1198
+ this.resolveProtocolV2Frame(deviceId, frameData);
1199
+ }
1200
+ }
1201
+ catch (error) {
1202
+ (_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Electron BLE] Protocol V2 notification error:', error);
544
1203
  if (this.runPromise) {
545
- this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
1204
+ const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
1205
+ this.runPromise.reject(notifyError);
1206
+ this.rejectAllProtocolV2Frames(notifyError);
546
1207
  }
1208
+ }
1209
+ }
1210
+ getProtocolV2FrameQueue(uuid) {
1211
+ let queue = this.v2FrameQueues.get(uuid);
1212
+ if (!queue) {
1213
+ queue = [];
1214
+ this.v2FrameQueues.set(uuid, queue);
1215
+ }
1216
+ return queue;
1217
+ }
1218
+ resolveProtocolV2Frame(uuid, frame) {
1219
+ const framePromise = this.v2FramePromises.get(uuid);
1220
+ if (framePromise) {
1221
+ framePromise.resolve(frame);
1222
+ this.v2FramePromises.delete(uuid);
547
1223
  return;
548
1224
  }
549
- if (result.isComplete && result.completePacket) {
1225
+ this.getProtocolV2FrameQueue(uuid).push(frame);
1226
+ }
1227
+ rejectAllProtocolV2Frames(error) {
1228
+ this.v2FrameQueues.clear();
1229
+ for (const framePromise of this.v2FramePromises.values()) {
1230
+ framePromise.reject(error);
1231
+ }
1232
+ this.v2FramePromises.clear();
1233
+ }
1234
+ resetProtocolV2Frames(uuid) {
1235
+ this.v2FrameQueues.delete(uuid);
1236
+ this.v2FramePromises.delete(uuid);
1237
+ }
1238
+ isActiveProtocolV2Call(uuid, token) {
1239
+ var _a;
1240
+ return ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === uuid && this.activeProtocolV2Call.token === token;
1241
+ }
1242
+ readProtocolV2Frame(uuid) {
1243
+ return __awaiter(this, void 0, void 0, function* () {
1244
+ const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
1245
+ if (queuedFrame) {
1246
+ return queuedFrame;
1247
+ }
1248
+ const framePromise = hdShared.createDeferred();
1249
+ this.v2FramePromises.set(uuid, framePromise);
1250
+ try {
1251
+ return yield framePromise.promise;
1252
+ }
1253
+ finally {
1254
+ if (this.v2FramePromises.get(uuid) === framePromise) {
1255
+ this.v2FramePromises.delete(uuid);
1256
+ }
1257
+ }
1258
+ });
1259
+ }
1260
+ handleProtocolV1Notification(deviceId, hexData) {
1261
+ var _a;
1262
+ const result = this.processProtocolV1Notification(deviceId, hexData);
1263
+ if (result.error) {
1264
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V1 packet processing error:', result.error);
550
1265
  if (this.runPromise) {
551
- this.runPromise.resolve(result.completePacket);
1266
+ this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
552
1267
  }
1268
+ return;
1269
+ }
1270
+ if (result.isComplete && result.completePacket && this.runPromise) {
1271
+ this.runPromise.resolve(result.completePacket);
553
1272
  }
554
1273
  }
555
- call(uuid, name, data) {
556
- var _a, _b, _c, _d, _e, _f, _g;
1274
+ call(uuid, name, data, options) {
1275
+ var _a, _b;
557
1276
  return __awaiter(this, void 0, void 0, function* () {
558
- if (this._messages == null) {
1277
+ if (!this._messages) {
559
1278
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
560
1279
  }
561
- const forceRun = name === 'Initialize' || name === 'Cancel';
562
- if (this.runPromise && !forceRun) {
563
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
564
- }
565
1280
  if (!this.connectedDevices.has(uuid)) {
566
1281
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound, `Device ${uuid} not connected`);
567
1282
  }
568
- this.runPromise = hdShared.createDeferred();
569
- const messages = this._messages;
570
- if (name === 'ResourceUpdate' || name === 'ResourceAck') {
571
- (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Transport] Noble BLE call', 'name:', name, 'data:', {
572
- file_name: data === null || data === void 0 ? void 0 : data.file_name,
573
- hash: data === null || data === void 0 ? void 0 : data.hash,
574
- });
1283
+ const protocol = this.deviceProtocol.get(uuid);
1284
+ if (!protocol) {
1285
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
575
1286
  }
576
- else if (transport.LogBlockCommand.has(name)) {
577
- (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Transport] Noble BLE call', 'name:', name);
1287
+ if (shouldSuppressHighVolumeCallLog(name)) ;
1288
+ else if (isLogBlockCommand(name)) {
1289
+ (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] call', 'name:', name, 'protocol:', protocol);
578
1290
  }
579
1291
  else {
580
- (_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[Transport] Noble BLE call', 'name:', name, 'data:', data);
1292
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
1293
+ }
1294
+ if (protocol === 'V2') {
1295
+ return this.callProtocolV2(uuid, name, data, options);
1296
+ }
1297
+ return this.callProtocolV1(uuid, name, data, options);
1298
+ });
1299
+ }
1300
+ callProtocolV1(uuid, name, data, options) {
1301
+ var _a, _b;
1302
+ return __awaiter(this, void 0, void 0, function* () {
1303
+ if (!this._messages) {
1304
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1305
+ }
1306
+ const forceRun = name === 'Initialize' || name === 'Cancel';
1307
+ if (this.runPromise && !forceRun) {
1308
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
581
1309
  }
582
- const buffers = buildBuffers(messages, name, data);
1310
+ const runPromise = hdShared.createDeferred();
1311
+ runPromise.promise.catch(() => undefined);
1312
+ this.runPromise = runPromise;
1313
+ const messages = this._messages;
1314
+ const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
1315
+ let timeout;
583
1316
  try {
584
- if (!((_d = window.desktopApi) === null || _d === void 0 ? void 0 : _d.nobleBle)) {
1317
+ if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
585
1318
  throw new Error('Noble BLE write API not available');
586
1319
  }
587
1320
  for (let i = 0; i < buffers.length; i++) {
588
1321
  const buffer = buffers[i];
589
1322
  if (!buffer || typeof buffer.toString !== 'function') {
590
- (_e = this.Log) === null || _e === void 0 ? void 0 : _e.error(`[Transport] Noble BLE buffer ${i + 1} is invalid:`, buffer);
591
1323
  throw new Error(`Buffer ${i + 1} is invalid`);
592
1324
  }
593
1325
  const hexString = buffer.toString('hex');
594
1326
  if (hexString.length === 0) {
595
- (_f = this.Log) === null || _f === void 0 ? void 0 : _f.error(`[Transport] Noble BLE buffer ${i + 1} generated empty hex string`);
596
1327
  throw new Error(`Buffer ${i + 1} is empty`);
597
1328
  }
598
1329
  yield window.desktopApi.nobleBle.write(uuid, hexString);
599
1330
  }
600
- const response = yield this.runPromise.promise;
1331
+ const response = yield Promise.race([
1332
+ runPromise.promise,
1333
+ new Promise((_, reject) => {
1334
+ if (options === null || options === void 0 ? void 0 : options.timeoutMs) {
1335
+ timeout = setTimeout(() => {
1336
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${options.timeoutMs}ms for ${name}`);
1337
+ runPromise.reject(error);
1338
+ reject(error);
1339
+ }, options.timeoutMs);
1340
+ }
1341
+ }),
1342
+ ]);
601
1343
  if (typeof response !== 'string') {
602
1344
  throw new Error('Returning data is not string.');
603
1345
  }
604
- const jsonData = receiveOne(messages, response);
1346
+ const jsonData = ProtocolV1.decodeMessage(messages, response);
605
1347
  return check.call(jsonData);
606
1348
  }
607
1349
  catch (e) {
608
- (_g = this.Log) === null || _g === void 0 ? void 0 : _g.error('[Transport] Noble BLE call error:', e);
1350
+ (_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V1 call error:', e);
609
1351
  throw e;
610
1352
  }
611
1353
  finally {
1354
+ if (timeout)
1355
+ clearTimeout(timeout);
1356
+ if (this.runPromise === runPromise) {
1357
+ this.runPromise = null;
1358
+ }
1359
+ }
1360
+ });
1361
+ }
1362
+ callProtocolV2(uuid, name, data, options) {
1363
+ var _a, _b, _c, _d, _e;
1364
+ return __awaiter(this, void 0, void 0, function* () {
1365
+ if (!this._messages || !this._messagesV2) {
1366
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1367
+ }
1368
+ const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'GetProtoVersion';
1369
+ if (this.runPromise) {
1370
+ if (!forceRun) {
1371
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1372
+ }
1373
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1374
+ this.runPromise.reject(error);
1375
+ this.rejectAllProtocolV2Frames(error);
612
1376
  this.runPromise = null;
1377
+ this.activeProtocolV2Call = null;
1378
+ }
1379
+ const runPromise = hdShared.createDeferred();
1380
+ runPromise.promise.catch(() => undefined);
1381
+ this.runPromise = runPromise;
1382
+ const callToken = this.nextProtocolV2CallToken++;
1383
+ this.activeProtocolV2Call = { uuid, token: callToken };
1384
+ (_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1385
+ this.resetProtocolV2Frames(uuid);
1386
+ let completed = false;
1387
+ 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 });
1388
+ try {
1389
+ const session = new transport.ProtocolV2Session({
1390
+ schemas: {
1391
+ protocolV1: this._messages,
1392
+ protocolV2: this._messagesV2,
1393
+ },
1394
+ router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1395
+ writeFrame: (frame) => this.writeWithChunking(uuid, transport.bytesToHex(frame)),
1396
+ readFrame: () => __awaiter(this, void 0, void 0, function* () {
1397
+ const rxFrame = yield this.readProtocolV2Frame(uuid);
1398
+ if (!(rxFrame instanceof Uint8Array)) {
1399
+ throw new Error('Response is not Uint8Array');
1400
+ }
1401
+ return rxFrame;
1402
+ }),
1403
+ logger: this.Log,
1404
+ logPrefix: 'ProtocolV2 BLE',
1405
+ createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
1406
+ });
1407
+ const result = yield session.call(name, data, callOptions);
1408
+ completed = true;
1409
+ return result;
1410
+ }
1411
+ catch (e) {
1412
+ if (this.isActiveProtocolV2Call(uuid, callToken)) {
1413
+ (_c = this.v2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
1414
+ this.resetProtocolV2Frames(uuid);
1415
+ }
1416
+ (_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] Protocol V2 call error:', e);
1417
+ throw e;
1418
+ }
1419
+ finally {
1420
+ if (this.isActiveProtocolV2Call(uuid, callToken)) {
1421
+ if (!completed) {
1422
+ (_e = this.v2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
1423
+ }
1424
+ this.resetProtocolV2Frames(uuid);
1425
+ this.activeProtocolV2Call = null;
1426
+ }
1427
+ if (this.runPromise === runPromise) {
1428
+ this.runPromise = null;
1429
+ }
613
1430
  }
614
1431
  });
615
1432
  }
616
- processNotificationPacket(deviceId, hexData) {
1433
+ processProtocolV1Notification(deviceId, hexData) {
617
1434
  try {
618
1435
  if (typeof hexData !== 'string') {
619
1436
  return { isComplete: false, error: 'Invalid hexData type' };
620
1437
  }
621
- const cleanHexData = hexData.replace(/\s+/g, '');
622
- if (!/^[0-9A-Fa-f]*$/.test(cleanHexData)) {
623
- return { isComplete: false, error: 'Invalid hex data format' };
1438
+ const data = transport.hexToBytes(hexData);
1439
+ if (data.length === 0) {
1440
+ return { isComplete: false, error: 'Empty or invalid hex data' };
624
1441
  }
625
- const hexMatch = cleanHexData.match(/.{1,2}/g);
626
- if (!hexMatch) {
627
- return { isComplete: false, error: 'Failed to parse hex data' };
628
- }
629
- const data = new Uint8Array(hexMatch.map(byte => parseInt(byte, 16)));
630
- const bufferState = this.dataBuffers.get(deviceId);
1442
+ const bufferState = this.v1Buffers.get(deviceId);
631
1443
  if (!bufferState) {
632
1444
  return { isComplete: false, error: 'No buffer state for device' };
633
1445
  }
@@ -639,14 +1451,11 @@ class ElectronBleTransport {
639
1451
  else {
640
1452
  bufferState.buffer = bufferState.buffer.concat([...data]);
641
1453
  }
642
- if (bufferState.buffer.length - transport.COMMON_HEADER_SIZE >= bufferState.bufferLength) {
1454
+ if (bufferState.buffer.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferState.bufferLength) {
643
1455
  const completeBuffer = new Uint8Array(bufferState.buffer);
644
1456
  bufferState.bufferLength = 0;
645
1457
  bufferState.buffer = [];
646
- const hexString = Array.from(completeBuffer)
647
- .map(b => b.toString(16).padStart(2, '0'))
648
- .join('');
649
- return { isComplete: true, completePacket: hexString };
1458
+ return { isComplete: true, completePacket: transport.bytesToHex(completeBuffer) };
650
1459
  }
651
1460
  return { isComplete: false };
652
1461
  }
@@ -654,6 +1463,9 @@ class ElectronBleTransport {
654
1463
  return { isComplete: false, error: `Packet processing error: ${error}` };
655
1464
  }
656
1465
  }
1466
+ getProtocolType(path) {
1467
+ return this.deviceProtocol.get(path);
1468
+ }
657
1469
  }
658
1470
 
659
1471
  exports.ElectronBleTransport = ElectronBleTransport;