@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/electron-auto-ble-transport.d.ts +70 -0
- package/dist/electron-auto-ble-transport.d.ts.map +1 -0
- package/dist/electron-ble-transport.d.ts +2 -0
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +93 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +948 -37
- package/dist/webusb.d.ts +20 -3
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/electron-auto-ble-transport.ts +768 -0
- package/src/electron-ble-transport.ts +14 -5
- package/src/index.ts +2 -1
- package/src/webusb.ts +455 -35
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$
|
|
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 =
|
|
49
|
-
const
|
|
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$
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
312
|
-
if (
|
|
313
|
-
|
|
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
|
-
|
|
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] =
|
|
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 =
|
|
330
|
-
return check$
|
|
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
|
|
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 } =
|
|
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
|
|
621
|
+
const packetData = yield readPacket();
|
|
347
622
|
const buffer = this.toArrayBuffer(packetData.buffer.slice(1));
|
|
348
|
-
if (lengthWithHeader - decoded.offset >=
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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.
|
|
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;
|