@onekeyfe/hd-transport-web-device 1.2.0-alpha.13 → 1.2.0-alpha.131
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/__tests__/electron-ble-transport.test.ts +377 -22
- package/__tests__/webusb-protocol-v2-timeout.test.ts +357 -11
- package/dist/ble-packet-capacity.d.ts +2 -0
- package/dist/ble-packet-capacity.d.ts.map +1 -0
- package/dist/electron-ble-transport.d.ts +16 -3
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +110 -12
- package/dist/index.js +345 -255
- package/dist/transportLog.d.ts +1 -6
- package/dist/transportLog.d.ts.map +1 -1
- package/dist/webusb.d.ts +15 -10
- package/dist/webusb.d.ts.map +1 -1
- package/jest.config.js +5 -0
- package/package.json +6 -5
- package/src/ble-packet-capacity.ts +13 -0
- package/src/electron-ble-transport.ts +241 -104
- package/src/transportLog.ts +1 -11
- package/src/webusb.ts +173 -189
package/dist/index.js
CHANGED
|
@@ -41,14 +41,6 @@ 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 HIGH_VOLUME_CALLS = new Set(['FileWrite', 'FilesystemFileWrite', 'EmmcFileWrite']);
|
|
45
|
-
function shouldSuppressHighVolumeCallLog(name) {
|
|
46
|
-
return HIGH_VOLUME_CALLS.has(name);
|
|
47
|
-
}
|
|
48
|
-
function createTransportCallLog(name, protocol) {
|
|
49
|
-
return { name, protocol };
|
|
50
|
-
}
|
|
51
|
-
|
|
52
44
|
const { parseConfigure: parseConfigure$1, check: check$1, ProtocolV1: ProtocolV1$1 } = transport__default["default"];
|
|
53
45
|
const CONFIGURATION_ID = 1;
|
|
54
46
|
const INTERFACE_ID = 0;
|
|
@@ -59,20 +51,22 @@ const REPORT_ID = transport.PROTOCOL_V1_REPORT_ID;
|
|
|
59
51
|
const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
60
52
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
61
53
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
62
|
-
const
|
|
54
|
+
const PROTOCOL_V1_PROBE_TIMEOUT = 5000;
|
|
55
|
+
const PROTOCOL_V2_PROBE_TIMEOUT = 1000;
|
|
56
|
+
const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
|
|
63
57
|
function inferProtocolHintFromDeviceName$1(name) {
|
|
64
58
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
65
59
|
}
|
|
66
|
-
class WebUsbTransport {
|
|
60
|
+
class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
67
61
|
constructor() {
|
|
62
|
+
super({
|
|
63
|
+
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
64
|
+
maxFrameBytes: transport.PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
65
|
+
logPrefix: 'ProtocolV2 WebUSB',
|
|
66
|
+
});
|
|
68
67
|
this.deviceProtocol = new Map();
|
|
69
68
|
this.deviceProtocolHints = new Map();
|
|
70
|
-
this.protocolV2Assemblers = new Map();
|
|
71
|
-
this.protocolV2Sessions = new Map();
|
|
72
|
-
this.protocolV2ReadTimeouts = new Map();
|
|
73
69
|
this.deviceEndpoints = new Map();
|
|
74
|
-
this.mockSerialPaths = new WeakMap();
|
|
75
|
-
this.mockSerialCounter = 0;
|
|
76
70
|
this.name = 'WebUsbTransport';
|
|
77
71
|
this.stopped = false;
|
|
78
72
|
this.configured = false;
|
|
@@ -95,9 +89,18 @@ class WebUsbTransport {
|
|
|
95
89
|
this.messages = messages;
|
|
96
90
|
}
|
|
97
91
|
configureProtocolV2(signedData) {
|
|
92
|
+
var _a;
|
|
93
|
+
const schemaSource = typeof signedData === 'string'
|
|
94
|
+
? signedData
|
|
95
|
+
: (_a = JSON.stringify(signedData)) !== null && _a !== void 0 ? _a : String(signedData);
|
|
96
|
+
if (schemaSource === this.protocolV2SchemaSource)
|
|
97
|
+
return;
|
|
98
|
+
const hadProtocolV2Schema = this.protocolV2SchemaSource !== undefined;
|
|
98
99
|
this.messagesV2 = parseConfigure$1(signedData);
|
|
99
|
-
this.
|
|
100
|
-
|
|
100
|
+
this.protocolV2SchemaSource = schemaSource;
|
|
101
|
+
if (!hadProtocolV2Schema)
|
|
102
|
+
return;
|
|
103
|
+
this.invalidateAllProtocolV2UsbLinks('Protocol V2 schema reconfigured').catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[WebUsbTransport] schema link cleanup failed:', error); });
|
|
101
104
|
}
|
|
102
105
|
promptDeviceAccess() {
|
|
103
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -119,20 +122,6 @@ class WebUsbTransport {
|
|
|
119
122
|
return this.deviceList;
|
|
120
123
|
});
|
|
121
124
|
}
|
|
122
|
-
getDevicePath(device) {
|
|
123
|
-
var _a;
|
|
124
|
-
if (typeof device.serialNumber === 'string' && device.serialNumber.length > 0) {
|
|
125
|
-
return device.serialNumber;
|
|
126
|
-
}
|
|
127
|
-
let path = this.mockSerialPaths.get(device);
|
|
128
|
-
if (!path) {
|
|
129
|
-
this.mockSerialCounter += 1;
|
|
130
|
-
path = `mock-serial:${device.vendorId.toString(16)}:${device.productId.toString(16)}:${this.mockSerialCounter}`;
|
|
131
|
-
this.mockSerialPaths.set(device, path);
|
|
132
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUSB] device has no serial number, using mock path: ${path}`);
|
|
133
|
-
}
|
|
134
|
-
return path;
|
|
135
|
-
}
|
|
136
125
|
getConnectedDevices() {
|
|
137
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
138
127
|
if (!this.usb)
|
|
@@ -140,10 +129,11 @@ class WebUsbTransport {
|
|
|
140
129
|
const devices = yield this.usb.getDevices();
|
|
141
130
|
const onekeyDevices = devices.filter(dev => {
|
|
142
131
|
const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some((desc) => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
|
|
143
|
-
|
|
132
|
+
const hasSerialNumber = typeof dev.serialNumber === 'string' && dev.serialNumber.length > 0;
|
|
133
|
+
return isOneKey && hasSerialNumber && !hdShared.isKnownTrezorWebUsbDevice(dev);
|
|
144
134
|
});
|
|
145
135
|
this.deviceList = onekeyDevices.map(device => {
|
|
146
|
-
const path =
|
|
136
|
+
const path = device.serialNumber;
|
|
147
137
|
const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
|
|
148
138
|
if (protocolHint) {
|
|
149
139
|
this.deviceProtocolHints.set(path, protocolHint);
|
|
@@ -158,17 +148,18 @@ class WebUsbTransport {
|
|
|
158
148
|
});
|
|
159
149
|
}
|
|
160
150
|
acquire(input) {
|
|
161
|
-
var _a, _b, _c;
|
|
151
|
+
var _a, _b, _c, _d;
|
|
162
152
|
return __awaiter(this, void 0, void 0, function* () {
|
|
163
153
|
if (!input.path)
|
|
164
154
|
return;
|
|
165
155
|
try {
|
|
156
|
+
yield this.rotateProtocolV2UsbGeneration(input.path, 'WebUSB transport acquired');
|
|
166
157
|
yield this.closeOpenDevice(input.path);
|
|
167
158
|
yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
|
|
168
159
|
const deviceName = (_b = this.deviceList.find(device => device.path === input.path)) === null || _b === void 0 ? void 0 : _b.device.productName;
|
|
169
160
|
const protocolHint = input.expectedProtocol
|
|
170
161
|
? undefined
|
|
171
|
-
: (_c = this.deviceProtocolHints.get(input.path)) !== null &&
|
|
162
|
+
: (_d = (_c = input.protocolHint) !== null && _c !== void 0 ? _c : this.deviceProtocolHints.get(input.path)) !== null && _d !== void 0 ? _d : inferProtocolHintFromDeviceName$1(deviceName);
|
|
172
163
|
if (protocolHint) {
|
|
173
164
|
this.deviceProtocolHints.set(input.path, protocolHint);
|
|
174
165
|
}
|
|
@@ -177,6 +168,7 @@ class WebUsbTransport {
|
|
|
177
168
|
}
|
|
178
169
|
catch (e) {
|
|
179
170
|
this.Log.debug('acquire error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
|
|
171
|
+
yield this.closeOpenDevice(input.path);
|
|
180
172
|
throw e;
|
|
181
173
|
}
|
|
182
174
|
});
|
|
@@ -184,29 +176,53 @@ class WebUsbTransport {
|
|
|
184
176
|
createProtocolMismatchError(expected) {
|
|
185
177
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
186
178
|
}
|
|
179
|
+
createProtocolProbeTimeoutError(expected, attempts) {
|
|
180
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceInitializeFailed, `Protocol ${expected} probe timeout after ${attempts} attempts`);
|
|
181
|
+
}
|
|
187
182
|
createProtocolDetectionError() {
|
|
188
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.
|
|
183
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
|
|
189
184
|
}
|
|
190
185
|
detectProtocol(path, expectedProtocol, protocolHint) {
|
|
186
|
+
var _a;
|
|
191
187
|
return __awaiter(this, void 0, void 0, function* () {
|
|
192
188
|
if (expectedProtocol === 'V1') {
|
|
193
189
|
if (yield this.probeProtocolV1(path)) {
|
|
194
190
|
this.deviceProtocol.set(path, 'V1');
|
|
195
191
|
return 'V1';
|
|
196
192
|
}
|
|
193
|
+
yield this.closeConnectionAfterProbe(path);
|
|
197
194
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
198
195
|
}
|
|
199
196
|
if (expectedProtocol === 'V2') {
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
for (let attempt = 1; attempt <= EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS; attempt += 1) {
|
|
198
|
+
if (yield this.probeProtocolV2(path)) {
|
|
199
|
+
this.deviceProtocol.set(path, 'V2');
|
|
200
|
+
return 'V2';
|
|
201
|
+
}
|
|
202
|
+
if (attempt < EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS) {
|
|
203
|
+
yield this.resetConnectionAfterProbe(path);
|
|
204
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] Protocol V2 probe timed out, retrying ${attempt + 1}/${EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS}`);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
yield this.closeConnectionAfterProbe(path);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
this.deviceProtocol.delete(path);
|
|
211
|
+
throw this.createProtocolProbeTimeoutError(expectedProtocol, EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS);
|
|
202
212
|
}
|
|
203
213
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
204
|
-
for (const protocol of probeOrder) {
|
|
214
|
+
for (const [index, protocol] of probeOrder.entries()) {
|
|
205
215
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(path) : yield this.probeProtocolV2(path);
|
|
206
216
|
if (detected) {
|
|
207
217
|
this.deviceProtocol.set(path, protocol);
|
|
208
218
|
return protocol;
|
|
209
219
|
}
|
|
220
|
+
if (index < probeOrder.length - 1) {
|
|
221
|
+
yield this.resetConnectionAfterProbe(path);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
yield this.closeConnectionAfterProbe(path);
|
|
225
|
+
}
|
|
210
226
|
}
|
|
211
227
|
this.deviceProtocol.delete(path);
|
|
212
228
|
throw this.createProtocolDetectionError();
|
|
@@ -273,7 +289,7 @@ class WebUsbTransport {
|
|
|
273
289
|
};
|
|
274
290
|
}
|
|
275
291
|
connectToDevice(path, first) {
|
|
276
|
-
var _a
|
|
292
|
+
var _a;
|
|
277
293
|
return __awaiter(this, void 0, void 0, function* () {
|
|
278
294
|
let device = yield this.findDevice(path);
|
|
279
295
|
if (!device.opened) {
|
|
@@ -297,33 +313,30 @@ class WebUsbTransport {
|
|
|
297
313
|
}
|
|
298
314
|
const endpoints = this.discoverEndpoints(device);
|
|
299
315
|
this.deviceEndpoints.set(path, endpoints);
|
|
300
|
-
(_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
301
|
-
this.protocolV2Assemblers.set(path, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES));
|
|
302
316
|
yield device.claimInterface(endpoints.interfaceNumber);
|
|
303
317
|
yield this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
|
|
304
318
|
yield this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
|
|
305
319
|
});
|
|
306
320
|
}
|
|
307
321
|
closeOpenDevice(path) {
|
|
308
|
-
var _a, _b, _c, _d
|
|
322
|
+
var _a, _b, _c, _d;
|
|
309
323
|
return __awaiter(this, void 0, void 0, function* () {
|
|
310
|
-
(_a = this.
|
|
311
|
-
const current = (_b = this.deviceList.find(device => device.path === path)) === null || _b === void 0 ? void 0 : _b.device;
|
|
324
|
+
const current = (_a = this.deviceList.find(device => device.path === path)) === null || _a === void 0 ? void 0 : _a.device;
|
|
312
325
|
if (!(current === null || current === void 0 ? void 0 : current.opened))
|
|
313
326
|
return;
|
|
314
327
|
const endpoints = this.deviceEndpoints.get(path);
|
|
315
|
-
const ifaceNum = (
|
|
328
|
+
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
316
329
|
try {
|
|
317
330
|
yield current.releaseInterface(ifaceNum);
|
|
318
331
|
}
|
|
319
332
|
catch (error) {
|
|
320
|
-
(
|
|
333
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
321
334
|
}
|
|
322
335
|
try {
|
|
323
336
|
yield current.close();
|
|
324
337
|
}
|
|
325
338
|
catch (error) {
|
|
326
|
-
(
|
|
339
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[WebUsbTransport] close before reconnect failed:', error);
|
|
327
340
|
}
|
|
328
341
|
});
|
|
329
342
|
}
|
|
@@ -340,6 +353,10 @@ class WebUsbTransport {
|
|
|
340
353
|
}
|
|
341
354
|
post(session, name, data) {
|
|
342
355
|
return __awaiter(this, void 0, void 0, function* () {
|
|
356
|
+
if (this.deviceProtocol.get(session) === 'V2') {
|
|
357
|
+
yield this.sendProtocolV2UsbFlowControl(session, name, data);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
343
360
|
yield this.call(session, name, data);
|
|
344
361
|
});
|
|
345
362
|
}
|
|
@@ -485,34 +502,33 @@ class WebUsbTransport {
|
|
|
485
502
|
throw lastError;
|
|
486
503
|
});
|
|
487
504
|
}
|
|
488
|
-
|
|
489
|
-
var _a
|
|
505
|
+
transferInOnce(path, length) {
|
|
506
|
+
var _a;
|
|
490
507
|
return __awaiter(this, void 0, void 0, function* () {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
try {
|
|
495
|
-
const device = yield this.findDevice(path);
|
|
496
|
-
if (device.opened) {
|
|
497
|
-
const endpoints = this.deviceEndpoints.get(path);
|
|
498
|
-
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
499
|
-
try {
|
|
500
|
-
yield device.releaseInterface(ifaceNum);
|
|
501
|
-
}
|
|
502
|
-
catch (error) {
|
|
503
|
-
this.Log.debug('[WebUsbTransport] releaseInterface after protocol probe error:', error);
|
|
504
|
-
}
|
|
505
|
-
yield device.close();
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
catch (error) {
|
|
509
|
-
this.Log.debug('[WebUsbTransport] close after protocol probe error:', error);
|
|
508
|
+
const device = yield this.findDevice(path);
|
|
509
|
+
if (!device.opened) {
|
|
510
|
+
throw new Error('USBDevice is not open for transferIn');
|
|
510
511
|
}
|
|
512
|
+
const endpoints = this.deviceEndpoints.get(path);
|
|
513
|
+
const endpointIn = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointIn) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
514
|
+
const result = yield device.transferIn(endpointIn, length);
|
|
515
|
+
return this.getTransferInData(result);
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
closeConnectionAfterProbe(path) {
|
|
519
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
520
|
+
yield this.rotateProtocolV2UsbGeneration(path, 'WebUSB protocol probe reset');
|
|
521
|
+
yield this.closeOpenDevice(path);
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
resetConnectionAfterProbe(path) {
|
|
525
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
526
|
+
yield this.closeConnectionAfterProbe(path);
|
|
511
527
|
yield this.getConnectedDevices();
|
|
512
528
|
yield this.connect(path, false);
|
|
513
529
|
});
|
|
514
530
|
}
|
|
515
|
-
withProtocolReadTimeout(
|
|
531
|
+
withProtocolReadTimeout(path, promise, timeoutMs, protocol, onTimeout) {
|
|
516
532
|
return __awaiter(this, void 0, void 0, function* () {
|
|
517
533
|
let timer;
|
|
518
534
|
let timedOut = false;
|
|
@@ -527,11 +543,19 @@ class WebUsbTransport {
|
|
|
527
543
|
return yield Promise.race([
|
|
528
544
|
guardedPromise,
|
|
529
545
|
new Promise((_, reject) => {
|
|
530
|
-
timer = setTimeout(() => {
|
|
546
|
+
timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
531
547
|
timedOut = true;
|
|
532
548
|
onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout();
|
|
549
|
+
if (protocol === 'V1') {
|
|
550
|
+
try {
|
|
551
|
+
yield this.resetConnectionAfterProbe(path);
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
this.Log.debug('[WebUsbTransport] reset after Protocol V1 timeout failed:', error);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
533
557
|
reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
|
|
534
|
-
}, timeoutMs);
|
|
558
|
+
}), timeoutMs);
|
|
535
559
|
}),
|
|
536
560
|
]);
|
|
537
561
|
}
|
|
@@ -547,7 +571,9 @@ class WebUsbTransport {
|
|
|
547
571
|
return false;
|
|
548
572
|
}
|
|
549
573
|
try {
|
|
550
|
-
yield this.callProtocolV1(path, 'Initialize', {}, {
|
|
574
|
+
yield this.callProtocolV1(path, 'Initialize', {}, {
|
|
575
|
+
timeoutMs: PROTOCOL_V1_PROBE_TIMEOUT,
|
|
576
|
+
});
|
|
551
577
|
return true;
|
|
552
578
|
}
|
|
553
579
|
catch (_error) {
|
|
@@ -562,10 +588,9 @@ class WebUsbTransport {
|
|
|
562
588
|
}
|
|
563
589
|
return transport.probeProtocolV2({
|
|
564
590
|
call: (name, data, options) => this.callProtocolV2(path, name, data, options),
|
|
565
|
-
timeoutMs:
|
|
591
|
+
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT,
|
|
566
592
|
logger: this.Log,
|
|
567
593
|
logPrefix: 'ProtocolV2 WebUSB',
|
|
568
|
-
onProbeFailed: () => this.resetConnectionAfterProbe(path),
|
|
569
594
|
});
|
|
570
595
|
});
|
|
571
596
|
}
|
|
@@ -582,9 +607,6 @@ class WebUsbTransport {
|
|
|
582
607
|
if (!protocol) {
|
|
583
608
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
584
609
|
}
|
|
585
|
-
if (!shouldSuppressHighVolumeCallLog(name)) {
|
|
586
|
-
this.Log.debug('transport call', createTransportCallLog(name, protocol));
|
|
587
|
-
}
|
|
588
610
|
if (protocol === 'V2') {
|
|
589
611
|
return this.callProtocolV2(path, name, data, options);
|
|
590
612
|
}
|
|
@@ -613,79 +635,8 @@ class WebUsbTransport {
|
|
|
613
635
|
});
|
|
614
636
|
}
|
|
615
637
|
callProtocolV2(path, name, data, options) {
|
|
616
|
-
var _a;
|
|
617
638
|
return __awaiter(this, void 0, void 0, function* () {
|
|
618
|
-
|
|
619
|
-
if (!this.messagesV2) {
|
|
620
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
|
|
621
|
-
}
|
|
622
|
-
if (!protocolV1Messages) {
|
|
623
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
624
|
-
}
|
|
625
|
-
let session = this.protocolV2Sessions.get(path);
|
|
626
|
-
if (!session) {
|
|
627
|
-
session = new transport.ProtocolV2Session({
|
|
628
|
-
schemas: {
|
|
629
|
-
protocolV1: protocolV1Messages,
|
|
630
|
-
protocolV2: this.messagesV2,
|
|
631
|
-
},
|
|
632
|
-
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
633
|
-
writeFrame: (frame) => this.transferOutOnce(path, frame),
|
|
634
|
-
readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
|
|
635
|
-
logger: this.Log,
|
|
636
|
-
logPrefix: 'ProtocolV2 WebUSB',
|
|
637
|
-
createTimeoutError: (messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
|
|
638
|
-
});
|
|
639
|
-
this.protocolV2Sessions.set(path, session);
|
|
640
|
-
}
|
|
641
|
-
this.protocolV2ReadTimeouts.set(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
642
|
-
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
643
|
-
try {
|
|
644
|
-
return yield session.call(name, data, options);
|
|
645
|
-
}
|
|
646
|
-
catch (error) {
|
|
647
|
-
const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
648
|
-
if (message.includes('protocol v2 read timeout') || message.includes('response timeout')) {
|
|
649
|
-
try {
|
|
650
|
-
yield this.resetConnectionAfterProbe(path);
|
|
651
|
-
}
|
|
652
|
-
catch (resetError) {
|
|
653
|
-
this.Log.debug('[WebUsbTransport] Protocol V2 timeout reset failed:', resetError);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
throw error;
|
|
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;
|
|
639
|
+
return this.callProtocolV2Usb(path, name, data, options);
|
|
689
640
|
});
|
|
690
641
|
}
|
|
691
642
|
receiveData(path, timeoutMs) {
|
|
@@ -726,45 +677,84 @@ class WebUsbTransport {
|
|
|
726
677
|
});
|
|
727
678
|
}
|
|
728
679
|
release(path) {
|
|
729
|
-
var _a, _b;
|
|
730
680
|
return __awaiter(this, void 0, void 0, function* () {
|
|
731
|
-
|
|
732
|
-
|
|
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);
|
|
735
|
-
yield device.close();
|
|
681
|
+
yield this.invalidateProtocolV2UsbLink(path, 'WebUSB transport released');
|
|
682
|
+
yield this.closeOpenDevice(path);
|
|
736
683
|
this.deviceProtocol.delete(path);
|
|
737
684
|
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.protocolV2Sessions.delete(path);
|
|
741
|
-
this.protocolV2ReadTimeouts.delete(path);
|
|
742
685
|
this.deviceEndpoints.delete(path);
|
|
743
686
|
});
|
|
744
687
|
}
|
|
688
|
+
getProtocolV2UsbSchemas() {
|
|
689
|
+
if (!this.messages || !this.messagesV2) {
|
|
690
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
691
|
+
}
|
|
692
|
+
return {
|
|
693
|
+
protocolV1: this.messages,
|
|
694
|
+
protocolV2: this.messagesV2,
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
getProtocolV2UsbLogger() {
|
|
698
|
+
return this.Log;
|
|
699
|
+
}
|
|
700
|
+
writeProtocolV2UsbPacket(path, frame, _context) {
|
|
701
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
702
|
+
yield this.transferOutOnce(path, frame);
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
readProtocolV2UsbPacket(path, _context) {
|
|
706
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
707
|
+
const dataView = yield this.transferInOnce(path, transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
708
|
+
return new Uint8Array(this.toArrayBuffer(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength)));
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
resetProtocolV2UsbNativeLink(path, _reason) {
|
|
712
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
713
|
+
yield this.closeOpenDevice(path);
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
onProtocolV2UsbLinkInvalidated(path, reason) {
|
|
717
|
+
var _a;
|
|
718
|
+
this.deviceProtocol.delete(path);
|
|
719
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] Protocol V2 link invalidated: ${path}`, reason);
|
|
720
|
+
}
|
|
721
|
+
createProtocolV2UsbTimeoutError(name, timeoutMs) {
|
|
722
|
+
return new transport.ProtocolV2LinkError('response-timeout', `Protocol V2 response timeout after ${timeoutMs}ms for ${name}`);
|
|
723
|
+
}
|
|
745
724
|
getProtocolType(path) {
|
|
746
725
|
return this.deviceProtocol.get(path);
|
|
747
726
|
}
|
|
748
727
|
}
|
|
749
728
|
|
|
729
|
+
const BLE_ATT_HEADER_BYTES = 3;
|
|
730
|
+
function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapacity) {
|
|
731
|
+
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= BLE_ATT_HEADER_BYTES) {
|
|
732
|
+
return fallbackPacketCapacity;
|
|
733
|
+
}
|
|
734
|
+
return Math.min(maximumPacketCapacity, Math.floor(mtu) - BLE_ATT_HEADER_BYTES);
|
|
735
|
+
}
|
|
736
|
+
|
|
750
737
|
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
751
738
|
function inferProtocolHintFromDeviceName(name) {
|
|
752
739
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
753
740
|
}
|
|
754
741
|
const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
|
|
755
|
-
const
|
|
742
|
+
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
743
|
+
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
756
744
|
const BLE_WRITE_DELAY_MS = 5;
|
|
757
|
-
const
|
|
758
|
-
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
745
|
+
const PROTOCOL_PROBE_TIMEOUT_MS = 3000;
|
|
759
746
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
|
|
760
747
|
class ElectronBleTransport {
|
|
761
748
|
constructor() {
|
|
762
749
|
this.name = 'ElectronBleTransport';
|
|
763
750
|
this.configured = false;
|
|
764
751
|
this.runPromise = null;
|
|
752
|
+
this.runPromiseDeviceId = null;
|
|
765
753
|
this.connectedDevices = new Set();
|
|
766
754
|
this.deviceProtocol = new Map();
|
|
767
755
|
this.deviceProtocolHints = new Map();
|
|
756
|
+
this.deviceMtus = new Map();
|
|
757
|
+
this.devicePacketCapacities = new Map();
|
|
768
758
|
this.v1Buffers = new Map();
|
|
769
759
|
this.v2Assemblers = new Map();
|
|
770
760
|
this.v2FrameQueues = new Map();
|
|
@@ -786,11 +776,13 @@ class ElectronBleTransport {
|
|
|
786
776
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
787
777
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
788
778
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
789
|
-
yield this.
|
|
779
|
+
yield this.releaseNative(uuid);
|
|
790
780
|
}
|
|
791
781
|
}),
|
|
792
782
|
});
|
|
783
|
+
this.warnedMissingRelease = false;
|
|
793
784
|
this.notificationCleanups = new Map();
|
|
785
|
+
this.mtuCleanups = new Map();
|
|
794
786
|
this.disconnectCleanups = new Map();
|
|
795
787
|
this.notificationTokens = new Map();
|
|
796
788
|
this.nextNotificationToken = 1;
|
|
@@ -830,15 +822,27 @@ class ElectronBleTransport {
|
|
|
830
822
|
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
|
|
831
823
|
this.connectedDevices.delete(deviceId);
|
|
832
824
|
this.deviceProtocol.delete(deviceId);
|
|
825
|
+
this.deviceMtus.delete(deviceId);
|
|
826
|
+
this.devicePacketCapacities.delete(deviceId);
|
|
833
827
|
this.v1Buffers.delete(deviceId);
|
|
834
828
|
this.v2Assemblers.delete(deviceId);
|
|
835
829
|
this.resetProtocolV2Frames(deviceId);
|
|
836
830
|
this.notificationTokens.delete(deviceId);
|
|
831
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
832
|
+
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
833
|
+
this.runPromise = null;
|
|
834
|
+
this.runPromiseDeviceId = null;
|
|
835
|
+
}
|
|
837
836
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
838
837
|
if (notifyCleanup) {
|
|
839
838
|
notifyCleanup();
|
|
840
839
|
this.notificationCleanups.delete(deviceId);
|
|
841
840
|
}
|
|
841
|
+
const mtuCleanup = this.mtuCleanups.get(deviceId);
|
|
842
|
+
if (mtuCleanup) {
|
|
843
|
+
mtuCleanup();
|
|
844
|
+
this.mtuCleanups.delete(deviceId);
|
|
845
|
+
}
|
|
842
846
|
const disconnectCleanup = this.disconnectCleanups.get(deviceId);
|
|
843
847
|
if (disconnectCleanup) {
|
|
844
848
|
disconnectCleanup();
|
|
@@ -859,10 +863,18 @@ class ElectronBleTransport {
|
|
|
859
863
|
this.configured = true;
|
|
860
864
|
}
|
|
861
865
|
configureProtocolV2(signedData) {
|
|
866
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
867
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
862
871
|
this._messagesV2 = parseConfigure(signedData);
|
|
863
|
-
this.
|
|
864
|
-
|
|
865
|
-
|
|
872
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
873
|
+
if (isReconfiguration) {
|
|
874
|
+
this.protocolV2Links
|
|
875
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
876
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] schema link cleanup failed:', error); });
|
|
877
|
+
}
|
|
866
878
|
}
|
|
867
879
|
listen() {
|
|
868
880
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -894,7 +906,7 @@ class ElectronBleTransport {
|
|
|
894
906
|
});
|
|
895
907
|
}
|
|
896
908
|
acquire(input) {
|
|
897
|
-
var _a, _b, _c, _d, _e, _f;
|
|
909
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
898
910
|
return __awaiter(this, void 0, void 0, function* () {
|
|
899
911
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
900
912
|
if (!uuid) {
|
|
@@ -906,8 +918,8 @@ class ElectronBleTransport {
|
|
|
906
918
|
if (forceCleanRunPromise && this.runPromise) {
|
|
907
919
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
908
920
|
this.runPromise.reject(error);
|
|
909
|
-
this.rejectAllProtocolV2Frames(error);
|
|
910
921
|
this.runPromise = null;
|
|
922
|
+
this.runPromiseDeviceId = null;
|
|
911
923
|
}
|
|
912
924
|
try {
|
|
913
925
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
@@ -919,7 +931,7 @@ class ElectronBleTransport {
|
|
|
919
931
|
}
|
|
920
932
|
const protocolHint = expectedProtocol
|
|
921
933
|
? undefined
|
|
922
|
-
: (_b = this.deviceProtocolHints.get(uuid)) !== null &&
|
|
934
|
+
: (_c = (_b = input.protocolHint) !== null && _b !== void 0 ? _b : this.deviceProtocolHints.get(uuid)) !== null && _c !== void 0 ? _c : inferProtocolHintFromDeviceName(device.name);
|
|
923
935
|
if (protocolHint) {
|
|
924
936
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
925
937
|
}
|
|
@@ -930,16 +942,31 @@ class ElectronBleTransport {
|
|
|
930
942
|
catch (error) {
|
|
931
943
|
this.handleBluetoothError(error);
|
|
932
944
|
}
|
|
945
|
+
const mtuCleanup = this.createMtuSubscription(uuid);
|
|
946
|
+
if (mtuCleanup) {
|
|
947
|
+
this.mtuCleanups.set(uuid, mtuCleanup);
|
|
948
|
+
}
|
|
933
949
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
934
|
-
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
|
|
950
|
+
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
935
951
|
yield window.desktopApi.nobleBle.subscribe(uuid);
|
|
952
|
+
yield this.refreshBlePacketCapacity(uuid);
|
|
936
953
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
937
954
|
this.notificationCleanups.set(uuid, cleanup);
|
|
955
|
+
const connectionToken = this.notificationTokens.get(uuid);
|
|
956
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
957
|
+
if (protocolType === 'V2') {
|
|
958
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[Electron BLE] Protocol V2 write configured', {
|
|
959
|
+
writeMode: 'withoutResponse',
|
|
960
|
+
negotiatedMtu: this.deviceMtus.get(uuid),
|
|
961
|
+
packetCapacity: (_e = this.devicePacketCapacities.get(uuid)) !== null && _e !== void 0 ? _e : BLE_PACKET_SIZE_FALLBACK,
|
|
962
|
+
});
|
|
963
|
+
}
|
|
938
964
|
const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
|
|
939
965
|
var _a;
|
|
940
|
-
if (disconnectedDevice.id === uuid
|
|
966
|
+
if (disconnectedDevice.id === uuid &&
|
|
967
|
+
this.notificationTokens.get(uuid) === connectionToken) {
|
|
941
968
|
this.cleanupDeviceState(uuid);
|
|
942
|
-
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(
|
|
969
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
943
970
|
name: disconnectedDevice.name,
|
|
944
971
|
id: disconnectedDevice.id,
|
|
945
972
|
connectId: disconnectedDevice.id,
|
|
@@ -947,35 +974,46 @@ class ElectronBleTransport {
|
|
|
947
974
|
}
|
|
948
975
|
});
|
|
949
976
|
this.disconnectCleanups.set(uuid, disconnectCleanup);
|
|
950
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
951
|
-
(_c = this.emitter) === null || _c === void 0 ? void 0 : _c.emit('device-connect', {
|
|
952
|
-
name: device.name,
|
|
953
|
-
id: device.id,
|
|
954
|
-
connectId: device.id,
|
|
955
|
-
});
|
|
956
977
|
return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
|
|
957
978
|
}
|
|
958
979
|
catch (error) {
|
|
959
|
-
(
|
|
980
|
+
(_f = this.Log) === null || _f === void 0 ? void 0 : _f.error('[Electron BLE] acquire failed:', error);
|
|
960
981
|
try {
|
|
961
|
-
if (((
|
|
982
|
+
if (((_g = window.desktopApi) === null || _g === void 0 ? void 0 : _g.nobleBle) && this.connectedDevices.has(uuid)) {
|
|
962
983
|
yield window.desktopApi.nobleBle.unsubscribe(uuid);
|
|
963
984
|
yield window.desktopApi.nobleBle.disconnect(uuid);
|
|
964
985
|
}
|
|
965
986
|
}
|
|
966
987
|
catch (cleanupError) {
|
|
967
|
-
(
|
|
988
|
+
(_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
|
|
968
989
|
}
|
|
969
990
|
this.cleanupDeviceState(uuid);
|
|
970
991
|
throw error;
|
|
971
992
|
}
|
|
972
993
|
});
|
|
973
994
|
}
|
|
974
|
-
release(id) {
|
|
975
|
-
var _a
|
|
995
|
+
release(id, _onclose, keepSession) {
|
|
996
|
+
var _a;
|
|
976
997
|
return __awaiter(this, void 0, void 0, function* () {
|
|
977
998
|
try {
|
|
978
999
|
yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
1000
|
+
yield this.releaseLogical(id, keepSession);
|
|
1001
|
+
}
|
|
1002
|
+
catch (error) {
|
|
1003
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] release failed:', error);
|
|
1004
|
+
this.cleanupDeviceState(id);
|
|
1005
|
+
}
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
disconnect(id) {
|
|
1009
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1010
|
+
return this.releaseNative(id);
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
releaseNative(id) {
|
|
1014
|
+
var _a, _b;
|
|
1015
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1016
|
+
try {
|
|
979
1017
|
if (this.connectedDevices.has(id)) {
|
|
980
1018
|
if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
|
|
981
1019
|
yield window.desktopApi.nobleBle.unsubscribe(id);
|
|
@@ -990,11 +1028,35 @@ class ElectronBleTransport {
|
|
|
990
1028
|
}
|
|
991
1029
|
});
|
|
992
1030
|
}
|
|
1031
|
+
releaseLogical(id, keepSession) {
|
|
1032
|
+
var _a, _b, _c, _d;
|
|
1033
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1034
|
+
try {
|
|
1035
|
+
if (!this.connectedDevices.has(id))
|
|
1036
|
+
return;
|
|
1037
|
+
this.cleanupDeviceState(id);
|
|
1038
|
+
const release = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.release;
|
|
1039
|
+
if (!release) {
|
|
1040
|
+
if (!this.warnedMissingRelease) {
|
|
1041
|
+
this.warnedMissingRelease = true;
|
|
1042
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Electron BLE] desktopApi.nobleBle.release is missing from the preload bridge; ' +
|
|
1043
|
+
'keep-alive idle countdown will never start — map NOBLE_BLE_RELEASE in the desktop preload');
|
|
1044
|
+
}
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
yield release(id, keepSession);
|
|
1048
|
+
}
|
|
1049
|
+
catch (error) {
|
|
1050
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] logical release failed:', error);
|
|
1051
|
+
this.cleanupDeviceState(id);
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
993
1055
|
createProtocolMismatchError(expected) {
|
|
994
1056
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
995
1057
|
}
|
|
996
1058
|
createProtocolDetectionError() {
|
|
997
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1059
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
998
1060
|
}
|
|
999
1061
|
clearProbeProtocol(uuid, protocol) {
|
|
1000
1062
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
@@ -1013,9 +1075,12 @@ class ElectronBleTransport {
|
|
|
1013
1075
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1014
1076
|
}
|
|
1015
1077
|
if (expectedProtocol === 'V2') {
|
|
1016
|
-
this.
|
|
1017
|
-
|
|
1018
|
-
|
|
1078
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1079
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1080
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
|
|
1081
|
+
return 'V2';
|
|
1082
|
+
}
|
|
1083
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1019
1084
|
}
|
|
1020
1085
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1021
1086
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
@@ -1049,38 +1114,22 @@ class ElectronBleTransport {
|
|
|
1049
1114
|
});
|
|
1050
1115
|
}
|
|
1051
1116
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1052
|
-
var _a
|
|
1117
|
+
var _a;
|
|
1053
1118
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1054
1119
|
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1055
1120
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1056
1121
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1057
1122
|
this.resetProtocolV2Frames(uuid);
|
|
1058
|
-
if (this.runPromise) {
|
|
1123
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
1059
1124
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1060
1125
|
this.runPromise.reject(error);
|
|
1061
1126
|
this.runPromise = null;
|
|
1127
|
+
this.runPromiseDeviceId = null;
|
|
1062
1128
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
this.notificationCleanups.delete(uuid);
|
|
1067
|
-
}
|
|
1068
|
-
this.notificationTokens.delete(uuid);
|
|
1069
|
-
try {
|
|
1070
|
-
yield ((_c = (_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) === null || _c === void 0 ? void 0 : _c.unsubscribe(uuid));
|
|
1071
|
-
}
|
|
1072
|
-
catch (error) {
|
|
1073
|
-
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1074
|
-
}
|
|
1075
|
-
try {
|
|
1076
|
-
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.subscribe(uuid));
|
|
1077
|
-
}
|
|
1078
|
-
catch (error) {
|
|
1079
|
-
(_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug(`[Electron BLE] resubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1080
|
-
throw error;
|
|
1129
|
+
if (!this.notificationCleanups.has(uuid)) {
|
|
1130
|
+
const cleanup = this.createNotificationSubscription(uuid);
|
|
1131
|
+
this.notificationCleanups.set(uuid, cleanup);
|
|
1081
1132
|
}
|
|
1082
|
-
const cleanup = this.createNotificationSubscription(uuid);
|
|
1083
|
-
this.notificationCleanups.set(uuid, cleanup);
|
|
1084
1133
|
});
|
|
1085
1134
|
}
|
|
1086
1135
|
probeProtocolV1(uuid) {
|
|
@@ -1091,12 +1140,12 @@ class ElectronBleTransport {
|
|
|
1091
1140
|
}
|
|
1092
1141
|
try {
|
|
1093
1142
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1094
|
-
yield this.callProtocolV1(uuid, '
|
|
1143
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1095
1144
|
return true;
|
|
1096
1145
|
}
|
|
1097
1146
|
catch (error) {
|
|
1098
1147
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1099
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1
|
|
1148
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1 GetFeatures probe failed:', error);
|
|
1100
1149
|
return false;
|
|
1101
1150
|
}
|
|
1102
1151
|
});
|
|
@@ -1126,25 +1175,6 @@ class ElectronBleTransport {
|
|
|
1126
1175
|
return detected;
|
|
1127
1176
|
});
|
|
1128
1177
|
}
|
|
1129
|
-
writeWithChunking(uuid, hexData) {
|
|
1130
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1131
|
-
const totalBytes = hexData.length / 2;
|
|
1132
|
-
if (totalBytes <= BLE_PACKET_SIZE) {
|
|
1133
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1134
|
-
yield this.writeOnce(uuid, hexData);
|
|
1135
|
-
return;
|
|
1136
|
-
}
|
|
1137
|
-
for (let offset = 0; offset < hexData.length;) {
|
|
1138
|
-
const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
|
|
1139
|
-
const chunkHex = hexData.substring(offset, offset + chunkHexLen);
|
|
1140
|
-
offset += chunkHexLen;
|
|
1141
|
-
yield this.writeOnce(uuid, chunkHex);
|
|
1142
|
-
if (offset < hexData.length) {
|
|
1143
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
});
|
|
1147
|
-
}
|
|
1148
1178
|
writeOnce(uuid, hexData) {
|
|
1149
1179
|
var _a;
|
|
1150
1180
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1152,7 +1182,51 @@ class ElectronBleTransport {
|
|
|
1152
1182
|
if (!nobleBle) {
|
|
1153
1183
|
throw new Error('Noble BLE API not available');
|
|
1154
1184
|
}
|
|
1155
|
-
yield nobleBle.write(uuid, hexData);
|
|
1185
|
+
yield nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
|
|
1186
|
+
});
|
|
1187
|
+
}
|
|
1188
|
+
refreshBlePacketCapacity(uuid) {
|
|
1189
|
+
var _a, _b;
|
|
1190
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1191
|
+
const device = yield ((_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.getDevice(uuid));
|
|
1192
|
+
this.updateBlePacketCapacity(uuid, device === null || device === void 0 ? void 0 : device.mtu);
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
updateBlePacketCapacity(uuid, mtu) {
|
|
1196
|
+
const packetCapacity = resolveBlePacketCapacity(mtu, BLE_PACKET_SIZE_MAXIMUM, BLE_PACKET_SIZE_FALLBACK);
|
|
1197
|
+
if (typeof mtu === 'number') {
|
|
1198
|
+
this.deviceMtus.set(uuid, mtu);
|
|
1199
|
+
}
|
|
1200
|
+
else {
|
|
1201
|
+
this.deviceMtus.delete(uuid);
|
|
1202
|
+
}
|
|
1203
|
+
this.devicePacketCapacities.set(uuid, packetCapacity);
|
|
1204
|
+
}
|
|
1205
|
+
createMtuSubscription(uuid) {
|
|
1206
|
+
var _a, _b;
|
|
1207
|
+
const onMtuChanged = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.onMtuChanged;
|
|
1208
|
+
if (!onMtuChanged)
|
|
1209
|
+
return undefined;
|
|
1210
|
+
return onMtuChanged(device => {
|
|
1211
|
+
if (device.id === uuid) {
|
|
1212
|
+
this.updateBlePacketCapacity(uuid, device.mtu);
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration) {
|
|
1217
|
+
var _a;
|
|
1218
|
+
const packetCapacity = (_a = this.devicePacketCapacities.get(uuid)) !== null && _a !== void 0 ? _a : BLE_PACKET_SIZE_FALLBACK;
|
|
1219
|
+
const shouldPace = !context.highThroughput;
|
|
1220
|
+
return transport.writeProtocolV2BleFrame({
|
|
1221
|
+
frame,
|
|
1222
|
+
packetCapacity,
|
|
1223
|
+
assertActive: assertCurrentGeneration,
|
|
1224
|
+
signal: context.signal,
|
|
1225
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1226
|
+
initialDelayMs: shouldPace && frame.length <= packetCapacity ? BLE_WRITE_DELAY_MS : 0,
|
|
1227
|
+
burstSize: shouldPace ? 1 : undefined,
|
|
1228
|
+
burstPauseMs: shouldPace ? BLE_WRITE_DELAY_MS : 0,
|
|
1229
|
+
writePacket: packet => this.writeOnce(uuid, transport.bytesToHex(packet)),
|
|
1156
1230
|
});
|
|
1157
1231
|
}
|
|
1158
1232
|
handleNotification(deviceId, hexData) {
|
|
@@ -1163,7 +1237,7 @@ class ElectronBleTransport {
|
|
|
1163
1237
|
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
1164
1238
|
this.rejectProtocolV2Frames(deviceId, error);
|
|
1165
1239
|
}
|
|
1166
|
-
else if (this.runPromise) {
|
|
1240
|
+
else if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1167
1241
|
this.runPromise.reject(error);
|
|
1168
1242
|
}
|
|
1169
1243
|
return;
|
|
@@ -1215,16 +1289,8 @@ class ElectronBleTransport {
|
|
|
1215
1289
|
}
|
|
1216
1290
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1217
1291
|
}
|
|
1218
|
-
rejectAllProtocolV2Frames(error) {
|
|
1219
|
-
this.v2FrameQueues.clear();
|
|
1220
|
-
for (const framePromise of this.v2FramePromises.values()) {
|
|
1221
|
-
framePromise.reject(error);
|
|
1222
|
-
}
|
|
1223
|
-
this.v2FramePromises.clear();
|
|
1224
|
-
}
|
|
1225
1292
|
resetProtocolV2Frames(uuid) {
|
|
1226
|
-
this.
|
|
1227
|
-
this.v2FramePromises.delete(uuid);
|
|
1293
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1228
1294
|
}
|
|
1229
1295
|
rejectProtocolV2Frames(uuid, error) {
|
|
1230
1296
|
this.v2FrameQueues.delete(uuid);
|
|
@@ -1257,17 +1323,19 @@ class ElectronBleTransport {
|
|
|
1257
1323
|
const result = this.processProtocolV1Notification(deviceId, hexData);
|
|
1258
1324
|
if (result.error) {
|
|
1259
1325
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V1 packet processing error:', result.error);
|
|
1260
|
-
if (this.runPromise) {
|
|
1326
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1261
1327
|
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
|
|
1262
1328
|
}
|
|
1263
1329
|
return;
|
|
1264
1330
|
}
|
|
1265
|
-
if (result.isComplete &&
|
|
1331
|
+
if (result.isComplete &&
|
|
1332
|
+
result.completePacket &&
|
|
1333
|
+
this.runPromise &&
|
|
1334
|
+
this.runPromiseDeviceId === deviceId) {
|
|
1266
1335
|
this.runPromise.resolve(result.completePacket);
|
|
1267
1336
|
}
|
|
1268
1337
|
}
|
|
1269
1338
|
call(uuid, name, data, options) {
|
|
1270
|
-
var _a;
|
|
1271
1339
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1272
1340
|
if (!this._messages) {
|
|
1273
1341
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
@@ -1279,15 +1347,21 @@ class ElectronBleTransport {
|
|
|
1279
1347
|
if (!protocol) {
|
|
1280
1348
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1281
1349
|
}
|
|
1282
|
-
if (!shouldSuppressHighVolumeCallLog(name)) {
|
|
1283
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('transport call', createTransportCallLog(name, protocol));
|
|
1284
|
-
}
|
|
1285
1350
|
if (protocol === 'V2') {
|
|
1286
1351
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1287
1352
|
}
|
|
1288
1353
|
return this.callProtocolV1(uuid, name, data, options);
|
|
1289
1354
|
});
|
|
1290
1355
|
}
|
|
1356
|
+
post(uuid, name, data) {
|
|
1357
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1358
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
1359
|
+
yield this.protocolV2Links.sendFlowControl(uuid, () => this.createProtocolV2Adapter(uuid), name, data);
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
yield this.callProtocolV1(uuid, name, data);
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1291
1365
|
callProtocolV1(uuid, name, data, options) {
|
|
1292
1366
|
var _a, _b;
|
|
1293
1367
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1301,6 +1375,7 @@ class ElectronBleTransport {
|
|
|
1301
1375
|
const runPromise = hdShared.createDeferred();
|
|
1302
1376
|
runPromise.promise.catch(() => undefined);
|
|
1303
1377
|
this.runPromise = runPromise;
|
|
1378
|
+
this.runPromiseDeviceId = uuid;
|
|
1304
1379
|
const messages = this._messages;
|
|
1305
1380
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1306
1381
|
let timeout;
|
|
@@ -1339,6 +1414,17 @@ class ElectronBleTransport {
|
|
|
1339
1414
|
}
|
|
1340
1415
|
catch (e) {
|
|
1341
1416
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V1 call error:', e);
|
|
1417
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1418
|
+
if ((e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1419
|
+
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1420
|
+
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1421
|
+
notifyCleanup === null || notifyCleanup === void 0 ? void 0 : notifyCleanup();
|
|
1422
|
+
this.notificationCleanups.delete(uuid);
|
|
1423
|
+
this.notificationTokens.delete(uuid);
|
|
1424
|
+
if (!isProbeTimeout) {
|
|
1425
|
+
yield this.releaseNative(uuid);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1342
1428
|
throw e;
|
|
1343
1429
|
}
|
|
1344
1430
|
finally {
|
|
@@ -1346,22 +1432,23 @@ class ElectronBleTransport {
|
|
|
1346
1432
|
clearTimeout(timeout);
|
|
1347
1433
|
if (this.runPromise === runPromise) {
|
|
1348
1434
|
this.runPromise = null;
|
|
1435
|
+
this.runPromiseDeviceId = null;
|
|
1349
1436
|
}
|
|
1350
1437
|
}
|
|
1351
1438
|
});
|
|
1352
1439
|
}
|
|
1353
1440
|
callProtocolV2(uuid, name, data, options) {
|
|
1354
|
-
var _a
|
|
1441
|
+
var _a;
|
|
1355
1442
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1356
1443
|
if (!this._messages || !this._messagesV2) {
|
|
1357
1444
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1358
1445
|
}
|
|
1359
|
-
const callOptions =
|
|
1446
|
+
const callOptions = options;
|
|
1360
1447
|
try {
|
|
1361
1448
|
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1362
1449
|
}
|
|
1363
1450
|
catch (e) {
|
|
1364
|
-
(
|
|
1451
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1365
1452
|
throw e;
|
|
1366
1453
|
}
|
|
1367
1454
|
});
|
|
@@ -1376,6 +1463,7 @@ class ElectronBleTransport {
|
|
|
1376
1463
|
};
|
|
1377
1464
|
return {
|
|
1378
1465
|
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1466
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1379
1467
|
generation,
|
|
1380
1468
|
prepareCall: () => {
|
|
1381
1469
|
var _a;
|
|
@@ -1383,10 +1471,7 @@ class ElectronBleTransport {
|
|
|
1383
1471
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1384
1472
|
this.resetProtocolV2Frames(uuid);
|
|
1385
1473
|
},
|
|
1386
|
-
writeFrame: (frame) =>
|
|
1387
|
-
assertCurrentGeneration();
|
|
1388
|
-
return this.writeWithChunking(uuid, transport.bytesToHex(frame));
|
|
1389
|
-
},
|
|
1474
|
+
writeFrame: (frame, context) => this.writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration),
|
|
1390
1475
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1391
1476
|
assertCurrentGeneration();
|
|
1392
1477
|
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
@@ -1406,6 +1491,7 @@ class ElectronBleTransport {
|
|
|
1406
1491
|
};
|
|
1407
1492
|
}
|
|
1408
1493
|
processProtocolV1Notification(deviceId, hexData) {
|
|
1494
|
+
var _a;
|
|
1409
1495
|
try {
|
|
1410
1496
|
if (typeof hexData !== 'string') {
|
|
1411
1497
|
return { isComplete: false, error: 'Invalid hexData type' };
|
|
@@ -1424,6 +1510,10 @@ class ElectronBleTransport {
|
|
|
1424
1510
|
bufferState.buffer = [...data.subarray(3)];
|
|
1425
1511
|
}
|
|
1426
1512
|
else {
|
|
1513
|
+
if (bufferState.buffer.length === 0) {
|
|
1514
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Orphan continuation chunk discarded');
|
|
1515
|
+
return { isComplete: false };
|
|
1516
|
+
}
|
|
1427
1517
|
bufferState.buffer = bufferState.buffer.concat([...data]);
|
|
1428
1518
|
}
|
|
1429
1519
|
if (bufferState.buffer.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferState.bufferLength) {
|