@onekeyfe/hd-transport-web-device 1.2.0-alpha.9 → 1.2.0-alpha.91
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 +373 -22
- package/__tests__/webusb-protocol-v2-timeout.test.ts +385 -0
- 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 +15 -3
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +109 -12
- package/dist/index.js +344 -251
- package/dist/transportLog.d.ts +2 -0
- package/dist/transportLog.d.ts.map +1 -0
- 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 +234 -98
- package/src/transportLog.ts +1 -0
- package/src/webusb.ts +184 -217
package/dist/index.js
CHANGED
|
@@ -51,33 +51,22 @@ const REPORT_ID = transport.PROTOCOL_V1_REPORT_ID;
|
|
|
51
51
|
const HEADER_LENGTH = transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE;
|
|
52
52
|
const PACKET_IO_MAX_RETRIES = 3;
|
|
53
53
|
const PACKET_IO_RETRY_DELAY = 300;
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
58
|
-
return WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
59
|
-
}
|
|
60
|
-
function isLogBlockCommand$1(name) {
|
|
61
|
-
var _a, _b;
|
|
62
|
-
return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
|
|
63
|
-
}
|
|
64
|
-
function shouldBlockWebUsbCallDataLog(name) {
|
|
65
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
66
|
-
return isLogBlockCommand$1(name) || WEBUSB_FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
67
|
-
}
|
|
54
|
+
const PROTOCOL_V1_PROBE_TIMEOUT = 5000;
|
|
55
|
+
const PROTOCOL_V2_PROBE_TIMEOUT = 1000;
|
|
56
|
+
const EXPECTED_PROTOCOL_V2_PROBE_ATTEMPTS = 2;
|
|
68
57
|
function inferProtocolHintFromDeviceName$1(name) {
|
|
69
58
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
70
59
|
}
|
|
71
|
-
class WebUsbTransport {
|
|
60
|
+
class WebUsbTransport extends transport.ProtocolV2UsbTransportBase {
|
|
72
61
|
constructor() {
|
|
62
|
+
super({
|
|
63
|
+
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
64
|
+
maxFrameBytes: transport.PROTOCOL_V2_FRAME_MAX_BYTES,
|
|
65
|
+
logPrefix: 'ProtocolV2 WebUSB',
|
|
66
|
+
});
|
|
73
67
|
this.deviceProtocol = new Map();
|
|
74
68
|
this.deviceProtocolHints = new Map();
|
|
75
|
-
this.protocolV2Assemblers = new Map();
|
|
76
|
-
this.protocolV2Sessions = new Map();
|
|
77
|
-
this.protocolV2ReadTimeouts = new Map();
|
|
78
69
|
this.deviceEndpoints = new Map();
|
|
79
|
-
this.mockSerialPaths = new WeakMap();
|
|
80
|
-
this.mockSerialCounter = 0;
|
|
81
70
|
this.name = 'WebUsbTransport';
|
|
82
71
|
this.stopped = false;
|
|
83
72
|
this.configured = false;
|
|
@@ -101,10 +90,17 @@ class WebUsbTransport {
|
|
|
101
90
|
}
|
|
102
91
|
configureProtocolV2(signedData) {
|
|
103
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;
|
|
104
99
|
this.messagesV2 = parseConfigure$1(signedData);
|
|
105
|
-
this.
|
|
106
|
-
|
|
107
|
-
|
|
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); });
|
|
108
104
|
}
|
|
109
105
|
promptDeviceAccess() {
|
|
110
106
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -126,28 +122,18 @@ class WebUsbTransport {
|
|
|
126
122
|
return this.deviceList;
|
|
127
123
|
});
|
|
128
124
|
}
|
|
129
|
-
getDevicePath(device) {
|
|
130
|
-
var _a;
|
|
131
|
-
if (typeof device.serialNumber === 'string' && device.serialNumber.length > 0) {
|
|
132
|
-
return device.serialNumber;
|
|
133
|
-
}
|
|
134
|
-
let path = this.mockSerialPaths.get(device);
|
|
135
|
-
if (!path) {
|
|
136
|
-
this.mockSerialCounter += 1;
|
|
137
|
-
path = `mock-serial:${device.vendorId.toString(16)}:${device.productId.toString(16)}:${this.mockSerialCounter}`;
|
|
138
|
-
this.mockSerialPaths.set(device, path);
|
|
139
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUSB] device has no serial number, using mock path: ${path}`);
|
|
140
|
-
}
|
|
141
|
-
return path;
|
|
142
|
-
}
|
|
143
125
|
getConnectedDevices() {
|
|
144
126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
145
127
|
if (!this.usb)
|
|
146
128
|
return [];
|
|
147
129
|
const devices = yield this.usb.getDevices();
|
|
148
|
-
const onekeyDevices = devices.filter(dev =>
|
|
130
|
+
const onekeyDevices = devices.filter(dev => {
|
|
131
|
+
const isOneKey = hdShared.ONEKEY_WEBUSB_FILTER.some((desc) => dev.vendorId === desc.vendorId && dev.productId === desc.productId);
|
|
132
|
+
const hasSerialNumber = typeof dev.serialNumber === 'string' && dev.serialNumber.length > 0;
|
|
133
|
+
return isOneKey && hasSerialNumber && !hdShared.isKnownTrezorWebUsbDevice(dev);
|
|
134
|
+
});
|
|
149
135
|
this.deviceList = onekeyDevices.map(device => {
|
|
150
|
-
const path =
|
|
136
|
+
const path = device.serialNumber;
|
|
151
137
|
const protocolHint = inferProtocolHintFromDeviceName$1(device.productName);
|
|
152
138
|
if (protocolHint) {
|
|
153
139
|
this.deviceProtocolHints.set(path, protocolHint);
|
|
@@ -158,25 +144,22 @@ class WebUsbTransport {
|
|
|
158
144
|
commType: 'webusb',
|
|
159
145
|
};
|
|
160
146
|
});
|
|
161
|
-
for (const dev of onekeyDevices) {
|
|
162
|
-
this.Log.debug(`[WebUSB] Device: name="${dev.productName}" serial="${dev.serialNumber}" ` +
|
|
163
|
-
`VID=0x${dev.vendorId.toString(16)} PID=0x${dev.productId.toString(16)}`);
|
|
164
|
-
}
|
|
165
147
|
return this.deviceList;
|
|
166
148
|
});
|
|
167
149
|
}
|
|
168
150
|
acquire(input) {
|
|
169
|
-
var _a, _b, _c;
|
|
151
|
+
var _a, _b, _c, _d;
|
|
170
152
|
return __awaiter(this, void 0, void 0, function* () {
|
|
171
153
|
if (!input.path)
|
|
172
154
|
return;
|
|
173
155
|
try {
|
|
156
|
+
yield this.rotateProtocolV2UsbGeneration(input.path, 'WebUSB transport acquired');
|
|
174
157
|
yield this.closeOpenDevice(input.path);
|
|
175
158
|
yield this.connect((_a = input.path) !== null && _a !== void 0 ? _a : '', true);
|
|
176
159
|
const deviceName = (_b = this.deviceList.find(device => device.path === input.path)) === null || _b === void 0 ? void 0 : _b.device.productName;
|
|
177
160
|
const protocolHint = input.expectedProtocol
|
|
178
161
|
? undefined
|
|
179
|
-
: (_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);
|
|
180
163
|
if (protocolHint) {
|
|
181
164
|
this.deviceProtocolHints.set(input.path, protocolHint);
|
|
182
165
|
}
|
|
@@ -185,6 +168,7 @@ class WebUsbTransport {
|
|
|
185
168
|
}
|
|
186
169
|
catch (e) {
|
|
187
170
|
this.Log.debug('acquire error: ', e instanceof Error ? `${e.name}: ${e.message}` : String(e));
|
|
171
|
+
yield this.closeOpenDevice(input.path);
|
|
188
172
|
throw e;
|
|
189
173
|
}
|
|
190
174
|
});
|
|
@@ -192,32 +176,53 @@ class WebUsbTransport {
|
|
|
192
176
|
createProtocolMismatchError(expected) {
|
|
193
177
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
194
178
|
}
|
|
179
|
+
createProtocolProbeTimeoutError(expected, attempts) {
|
|
180
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol ${expected} probe timeout after ${attempts} attempts`);
|
|
181
|
+
}
|
|
195
182
|
createProtocolDetectionError() {
|
|
196
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.
|
|
183
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.DeviceNotFound);
|
|
197
184
|
}
|
|
198
185
|
detectProtocol(path, expectedProtocol, protocolHint) {
|
|
186
|
+
var _a;
|
|
199
187
|
return __awaiter(this, void 0, void 0, function* () {
|
|
200
188
|
if (expectedProtocol === 'V1') {
|
|
201
189
|
if (yield this.probeProtocolV1(path)) {
|
|
202
190
|
this.deviceProtocol.set(path, 'V1');
|
|
203
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> V1 (expected)`);
|
|
204
191
|
return 'V1';
|
|
205
192
|
}
|
|
193
|
+
yield this.closeConnectionAfterProbe(path);
|
|
206
194
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
207
195
|
}
|
|
208
196
|
if (expectedProtocol === 'V2') {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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);
|
|
212
212
|
}
|
|
213
213
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(path) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
214
|
-
for (const protocol of probeOrder) {
|
|
214
|
+
for (const [index, protocol] of probeOrder.entries()) {
|
|
215
215
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(path) : yield this.probeProtocolV2(path);
|
|
216
216
|
if (detected) {
|
|
217
217
|
this.deviceProtocol.set(path, protocol);
|
|
218
|
-
this.Log.debug(`[WebUsbTransport] detectProtocol: path=${path} -> ${protocol}`);
|
|
219
218
|
return protocol;
|
|
220
219
|
}
|
|
220
|
+
if (index < probeOrder.length - 1) {
|
|
221
|
+
yield this.resetConnectionAfterProbe(path);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
yield this.closeConnectionAfterProbe(path);
|
|
225
|
+
}
|
|
221
226
|
}
|
|
222
227
|
this.deviceProtocol.delete(path);
|
|
223
228
|
throw this.createProtocolDetectionError();
|
|
@@ -284,10 +289,9 @@ class WebUsbTransport {
|
|
|
284
289
|
};
|
|
285
290
|
}
|
|
286
291
|
connectToDevice(path, first) {
|
|
287
|
-
var _a
|
|
292
|
+
var _a;
|
|
288
293
|
return __awaiter(this, void 0, void 0, function* () {
|
|
289
294
|
let device = yield this.findDevice(path);
|
|
290
|
-
this.Log.debug('[WebUsbTransport] connecting to device:', device.productName, 'PID:', device.productId);
|
|
291
295
|
if (!device.opened) {
|
|
292
296
|
yield device.open();
|
|
293
297
|
}
|
|
@@ -309,33 +313,30 @@ class WebUsbTransport {
|
|
|
309
313
|
}
|
|
310
314
|
const endpoints = this.discoverEndpoints(device);
|
|
311
315
|
this.deviceEndpoints.set(path, endpoints);
|
|
312
|
-
(_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
313
|
-
this.protocolV2Assemblers.set(path, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES));
|
|
314
316
|
yield device.claimInterface(endpoints.interfaceNumber);
|
|
315
317
|
yield this.clearEndpointHalt(device, 'in', endpoints.endpointIn);
|
|
316
318
|
yield this.clearEndpointHalt(device, 'out', endpoints.endpointOut);
|
|
317
319
|
});
|
|
318
320
|
}
|
|
319
321
|
closeOpenDevice(path) {
|
|
320
|
-
var _a, _b, _c, _d
|
|
322
|
+
var _a, _b, _c, _d;
|
|
321
323
|
return __awaiter(this, void 0, void 0, function* () {
|
|
322
|
-
(_a = this.
|
|
323
|
-
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;
|
|
324
325
|
if (!(current === null || current === void 0 ? void 0 : current.opened))
|
|
325
326
|
return;
|
|
326
327
|
const endpoints = this.deviceEndpoints.get(path);
|
|
327
|
-
const ifaceNum = (
|
|
328
|
+
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
328
329
|
try {
|
|
329
330
|
yield current.releaseInterface(ifaceNum);
|
|
330
331
|
}
|
|
331
332
|
catch (error) {
|
|
332
|
-
(
|
|
333
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.debug('[WebUsbTransport] releaseInterface before reconnect failed:', error);
|
|
333
334
|
}
|
|
334
335
|
try {
|
|
335
336
|
yield current.close();
|
|
336
337
|
}
|
|
337
338
|
catch (error) {
|
|
338
|
-
(
|
|
339
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[WebUsbTransport] close before reconnect failed:', error);
|
|
339
340
|
}
|
|
340
341
|
});
|
|
341
342
|
}
|
|
@@ -497,29 +498,28 @@ class WebUsbTransport {
|
|
|
497
498
|
throw lastError;
|
|
498
499
|
});
|
|
499
500
|
}
|
|
500
|
-
|
|
501
|
-
var _a
|
|
501
|
+
transferInOnce(path, length) {
|
|
502
|
+
var _a;
|
|
502
503
|
return __awaiter(this, void 0, void 0, function* () {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
try {
|
|
507
|
-
const device = yield this.findDevice(path);
|
|
508
|
-
if (device.opened) {
|
|
509
|
-
const endpoints = this.deviceEndpoints.get(path);
|
|
510
|
-
const ifaceNum = (_b = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _b !== void 0 ? _b : this.interfaceId;
|
|
511
|
-
try {
|
|
512
|
-
yield device.releaseInterface(ifaceNum);
|
|
513
|
-
}
|
|
514
|
-
catch (error) {
|
|
515
|
-
this.Log.debug('[WebUsbTransport] releaseInterface after protocol probe error:', error);
|
|
516
|
-
}
|
|
517
|
-
yield device.close();
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
catch (error) {
|
|
521
|
-
this.Log.debug('[WebUsbTransport] close after protocol probe error:', error);
|
|
504
|
+
const device = yield this.findDevice(path);
|
|
505
|
+
if (!device.opened) {
|
|
506
|
+
throw new Error('USBDevice is not open for transferIn');
|
|
522
507
|
}
|
|
508
|
+
const endpoints = this.deviceEndpoints.get(path);
|
|
509
|
+
const endpointIn = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.endpointIn) !== null && _a !== void 0 ? _a : this.endpointId;
|
|
510
|
+
const result = yield device.transferIn(endpointIn, length);
|
|
511
|
+
return this.getTransferInData(result);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
closeConnectionAfterProbe(path) {
|
|
515
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
516
|
+
yield this.rotateProtocolV2UsbGeneration(path, 'WebUSB protocol probe reset');
|
|
517
|
+
yield this.closeOpenDevice(path);
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
resetConnectionAfterProbe(path) {
|
|
521
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
522
|
+
yield this.closeConnectionAfterProbe(path);
|
|
523
523
|
yield this.getConnectedDevices();
|
|
524
524
|
yield this.connect(path, false);
|
|
525
525
|
});
|
|
@@ -542,6 +542,14 @@ class WebUsbTransport {
|
|
|
542
542
|
timer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
543
543
|
timedOut = true;
|
|
544
544
|
onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout();
|
|
545
|
+
if (protocol === 'V1') {
|
|
546
|
+
try {
|
|
547
|
+
yield this.resetConnectionAfterProbe(path);
|
|
548
|
+
}
|
|
549
|
+
catch (error) {
|
|
550
|
+
this.Log.debug('[WebUsbTransport] reset after Protocol V1 timeout failed:', error);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
545
553
|
reject(new Error(`Protocol ${protocol} read timeout after ${timeoutMs}ms`));
|
|
546
554
|
}), timeoutMs);
|
|
547
555
|
}),
|
|
@@ -559,11 +567,12 @@ class WebUsbTransport {
|
|
|
559
567
|
return false;
|
|
560
568
|
}
|
|
561
569
|
try {
|
|
562
|
-
yield this.callProtocolV1(path, 'Initialize', {}, {
|
|
570
|
+
yield this.callProtocolV1(path, 'Initialize', {}, {
|
|
571
|
+
timeoutMs: PROTOCOL_V1_PROBE_TIMEOUT,
|
|
572
|
+
});
|
|
563
573
|
return true;
|
|
564
574
|
}
|
|
565
|
-
catch (
|
|
566
|
-
this.Log.debug('[WebUsbTransport] Protocol V1 Initialize probe failed:', error);
|
|
575
|
+
catch (_error) {
|
|
567
576
|
return false;
|
|
568
577
|
}
|
|
569
578
|
});
|
|
@@ -575,10 +584,9 @@ class WebUsbTransport {
|
|
|
575
584
|
}
|
|
576
585
|
return transport.probeProtocolV2({
|
|
577
586
|
call: (name, data, options) => this.callProtocolV2(path, name, data, options),
|
|
578
|
-
timeoutMs:
|
|
587
|
+
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT,
|
|
579
588
|
logger: this.Log,
|
|
580
589
|
logPrefix: 'ProtocolV2 WebUSB',
|
|
581
|
-
onProbeFailed: () => this.resetConnectionAfterProbe(path),
|
|
582
590
|
});
|
|
583
591
|
});
|
|
584
592
|
}
|
|
@@ -595,12 +603,8 @@ class WebUsbTransport {
|
|
|
595
603
|
if (!protocol) {
|
|
596
604
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${path}`);
|
|
597
605
|
}
|
|
598
|
-
if (
|
|
599
|
-
|
|
600
|
-
this.Log.debug('call-', ' name: ', name, ' protocol: ', protocol);
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
this.Log.debug('call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
606
|
+
if (!transport.shouldSuppressHighVolumeCallLog(name)) {
|
|
607
|
+
this.Log.debug('transport call', transport.createTransportCallLog(name, protocol, data));
|
|
604
608
|
}
|
|
605
609
|
if (protocol === 'V2') {
|
|
606
610
|
return this.callProtocolV2(path, name, data, options);
|
|
@@ -630,67 +634,8 @@ class WebUsbTransport {
|
|
|
630
634
|
});
|
|
631
635
|
}
|
|
632
636
|
callProtocolV2(path, name, data, options) {
|
|
633
|
-
var _a;
|
|
634
637
|
return __awaiter(this, void 0, void 0, function* () {
|
|
635
|
-
|
|
636
|
-
if (!this.messagesV2) {
|
|
637
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured, 'Protocol V2 schema not configured');
|
|
638
|
-
}
|
|
639
|
-
if (!protocolV1Messages) {
|
|
640
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
641
|
-
}
|
|
642
|
-
let session = this.protocolV2Sessions.get(path);
|
|
643
|
-
if (!session) {
|
|
644
|
-
session = new transport.ProtocolV2Session({
|
|
645
|
-
schemas: {
|
|
646
|
-
protocolV1: protocolV1Messages,
|
|
647
|
-
protocolV2: this.messagesV2,
|
|
648
|
-
},
|
|
649
|
-
router: transport.PROTOCOL_V2_CHANNEL_USB,
|
|
650
|
-
writeFrame: (frame) => this.transferOutOnce(path, frame),
|
|
651
|
-
readFrame: () => this.receiveProtocolV2Frame(path, this.protocolV2ReadTimeouts.get(path)),
|
|
652
|
-
logger: this.Log,
|
|
653
|
-
logPrefix: 'ProtocolV2 WebUSB',
|
|
654
|
-
createTimeoutError: (messageName, timeoutMs) => new Error(`Protocol V2 response timeout after ${timeoutMs}ms for ${messageName}`),
|
|
655
|
-
});
|
|
656
|
-
this.protocolV2Sessions.set(path, session);
|
|
657
|
-
}
|
|
658
|
-
this.protocolV2ReadTimeouts.set(path, options === null || options === void 0 ? void 0 : options.timeoutMs);
|
|
659
|
-
(_a = this.protocolV2Assemblers.get(path)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
660
|
-
try {
|
|
661
|
-
return yield session.call(name, data, options);
|
|
662
|
-
}
|
|
663
|
-
finally {
|
|
664
|
-
this.protocolV2ReadTimeouts.delete(path);
|
|
665
|
-
}
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
receiveProtocolV2Frame(path, timeoutMs) {
|
|
669
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
670
|
-
let assembler = this.protocolV2Assemblers.get(path);
|
|
671
|
-
if (!assembler) {
|
|
672
|
-
assembler = new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
673
|
-
this.protocolV2Assemblers.set(path, assembler);
|
|
674
|
-
}
|
|
675
|
-
let frame = assembler.push(new Uint8Array(0));
|
|
676
|
-
const deadline = timeoutMs ? Date.now() + timeoutMs : undefined;
|
|
677
|
-
while (!frame) {
|
|
678
|
-
const cancelToken = { cancelled: false };
|
|
679
|
-
const transferIn = this.transferInWithRetry(path, transport.PROTOCOL_V2_FRAME_MAX_BYTES, cancelToken);
|
|
680
|
-
const dataView = deadline
|
|
681
|
-
? yield this.withProtocolReadTimeout(path, transferIn, Math.max(deadline - Date.now(), 1), 'V2', () => {
|
|
682
|
-
cancelToken.cancelled = true;
|
|
683
|
-
})
|
|
684
|
-
: yield transferIn;
|
|
685
|
-
const bytes = new Uint8Array(this.toArrayBuffer(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength)));
|
|
686
|
-
try {
|
|
687
|
-
frame = assembler.push(bytes);
|
|
688
|
-
}
|
|
689
|
-
catch (error) {
|
|
690
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.NetworkError, error instanceof Error ? error.message : String(error));
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
return frame;
|
|
638
|
+
return this.callProtocolV2Usb(path, name, data, options);
|
|
694
639
|
});
|
|
695
640
|
}
|
|
696
641
|
receiveData(path, timeoutMs) {
|
|
@@ -731,42 +676,71 @@ class WebUsbTransport {
|
|
|
731
676
|
});
|
|
732
677
|
}
|
|
733
678
|
release(path) {
|
|
734
|
-
var _a, _b;
|
|
735
679
|
return __awaiter(this, void 0, void 0, function* () {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const ifaceNum = (_a = endpoints === null || endpoints === void 0 ? void 0 : endpoints.interfaceNumber) !== null && _a !== void 0 ? _a : this.interfaceId;
|
|
739
|
-
yield device.releaseInterface(ifaceNum);
|
|
740
|
-
yield device.close();
|
|
680
|
+
yield this.invalidateProtocolV2UsbLink(path, 'WebUSB transport released');
|
|
681
|
+
yield this.closeOpenDevice(path);
|
|
741
682
|
this.deviceProtocol.delete(path);
|
|
742
683
|
this.deviceProtocolHints.delete(path);
|
|
743
|
-
(_b = this.protocolV2Assemblers.get(path)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
744
|
-
this.protocolV2Assemblers.delete(path);
|
|
745
684
|
this.deviceEndpoints.delete(path);
|
|
746
685
|
});
|
|
747
686
|
}
|
|
687
|
+
getProtocolV2UsbSchemas() {
|
|
688
|
+
if (!this.messages || !this.messagesV2) {
|
|
689
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
690
|
+
}
|
|
691
|
+
return {
|
|
692
|
+
protocolV1: this.messages,
|
|
693
|
+
protocolV2: this.messagesV2,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
getProtocolV2UsbLogger() {
|
|
697
|
+
return this.Log;
|
|
698
|
+
}
|
|
699
|
+
writeProtocolV2UsbPacket(path, frame, _context) {
|
|
700
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
701
|
+
yield this.transferOutOnce(path, frame);
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
readProtocolV2UsbPacket(path, _context) {
|
|
705
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
706
|
+
const dataView = yield this.transferInOnce(path, transport.PROTOCOL_V2_FRAME_MAX_BYTES);
|
|
707
|
+
return new Uint8Array(this.toArrayBuffer(dataView.buffer.slice(dataView.byteOffset, dataView.byteOffset + dataView.byteLength)));
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
resetProtocolV2UsbNativeLink(path, _reason) {
|
|
711
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
712
|
+
yield this.closeOpenDevice(path);
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
onProtocolV2UsbLinkInvalidated(path, reason) {
|
|
716
|
+
var _a;
|
|
717
|
+
this.deviceProtocol.delete(path);
|
|
718
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug(`[WebUsbTransport] Protocol V2 link invalidated: ${path}`, reason);
|
|
719
|
+
}
|
|
720
|
+
createProtocolV2UsbTimeoutError(name, timeoutMs) {
|
|
721
|
+
return new transport.ProtocolV2LinkError('response-timeout', `Protocol V2 response timeout after ${timeoutMs}ms for ${name}`);
|
|
722
|
+
}
|
|
748
723
|
getProtocolType(path) {
|
|
749
724
|
return this.deviceProtocol.get(path);
|
|
750
725
|
}
|
|
751
726
|
}
|
|
752
727
|
|
|
753
|
-
const
|
|
754
|
-
function
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
var _a, _b;
|
|
760
|
-
return (_b = (_a = transport.LogBlockCommand === null || transport.LogBlockCommand === void 0 ? void 0 : transport.LogBlockCommand.has) === null || _a === void 0 ? void 0 : _a.call(transport.LogBlockCommand, name)) !== null && _b !== void 0 ? _b : false;
|
|
728
|
+
const BLE_ATT_HEADER_BYTES = 3;
|
|
729
|
+
function resolveBlePacketCapacity(mtu, maximumPacketCapacity, fallbackPacketCapacity) {
|
|
730
|
+
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= BLE_ATT_HEADER_BYTES) {
|
|
731
|
+
return fallbackPacketCapacity;
|
|
732
|
+
}
|
|
733
|
+
return Math.min(maximumPacketCapacity, Math.floor(mtu) - BLE_ATT_HEADER_BYTES);
|
|
761
734
|
}
|
|
735
|
+
|
|
762
736
|
const { parseConfigure, ProtocolV1, check } = transport__default["default"];
|
|
763
737
|
function inferProtocolHintFromDeviceName(name) {
|
|
764
738
|
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
765
739
|
}
|
|
766
740
|
const toBleDescriptor = (device, protocolType) => (Object.assign({ id: device.id, name: device.name, path: device.id, debug: false, commType: 'electron-ble' }, (protocolType ? { protocolType } : {})));
|
|
767
|
-
const
|
|
741
|
+
const BLE_PACKET_SIZE_FALLBACK = 192;
|
|
742
|
+
const BLE_PACKET_SIZE_MAXIMUM = 244;
|
|
768
743
|
const BLE_WRITE_DELAY_MS = 5;
|
|
769
|
-
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
770
744
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
771
745
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
|
|
772
746
|
class ElectronBleTransport {
|
|
@@ -774,9 +748,12 @@ class ElectronBleTransport {
|
|
|
774
748
|
this.name = 'ElectronBleTransport';
|
|
775
749
|
this.configured = false;
|
|
776
750
|
this.runPromise = null;
|
|
751
|
+
this.runPromiseDeviceId = null;
|
|
777
752
|
this.connectedDevices = new Set();
|
|
778
753
|
this.deviceProtocol = new Map();
|
|
779
754
|
this.deviceProtocolHints = new Map();
|
|
755
|
+
this.deviceMtus = new Map();
|
|
756
|
+
this.devicePacketCapacities = new Map();
|
|
780
757
|
this.v1Buffers = new Map();
|
|
781
758
|
this.v2Assemblers = new Map();
|
|
782
759
|
this.v2FrameQueues = new Map();
|
|
@@ -798,11 +775,13 @@ class ElectronBleTransport {
|
|
|
798
775
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
799
776
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
800
777
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
801
|
-
yield this.
|
|
778
|
+
yield this.releaseNative(uuid);
|
|
802
779
|
}
|
|
803
780
|
}),
|
|
804
781
|
});
|
|
782
|
+
this.warnedMissingRelease = false;
|
|
805
783
|
this.notificationCleanups = new Map();
|
|
784
|
+
this.mtuCleanups = new Map();
|
|
806
785
|
this.disconnectCleanups = new Map();
|
|
807
786
|
this.notificationTokens = new Map();
|
|
808
787
|
this.nextNotificationToken = 1;
|
|
@@ -842,15 +821,27 @@ class ElectronBleTransport {
|
|
|
842
821
|
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
|
|
843
822
|
this.connectedDevices.delete(deviceId);
|
|
844
823
|
this.deviceProtocol.delete(deviceId);
|
|
824
|
+
this.deviceMtus.delete(deviceId);
|
|
825
|
+
this.devicePacketCapacities.delete(deviceId);
|
|
845
826
|
this.v1Buffers.delete(deviceId);
|
|
846
827
|
this.v2Assemblers.delete(deviceId);
|
|
847
828
|
this.resetProtocolV2Frames(deviceId);
|
|
848
829
|
this.notificationTokens.delete(deviceId);
|
|
830
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
831
|
+
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
832
|
+
this.runPromise = null;
|
|
833
|
+
this.runPromiseDeviceId = null;
|
|
834
|
+
}
|
|
849
835
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
850
836
|
if (notifyCleanup) {
|
|
851
837
|
notifyCleanup();
|
|
852
838
|
this.notificationCleanups.delete(deviceId);
|
|
853
839
|
}
|
|
840
|
+
const mtuCleanup = this.mtuCleanups.get(deviceId);
|
|
841
|
+
if (mtuCleanup) {
|
|
842
|
+
mtuCleanup();
|
|
843
|
+
this.mtuCleanups.delete(deviceId);
|
|
844
|
+
}
|
|
854
845
|
const disconnectCleanup = this.disconnectCleanups.get(deviceId);
|
|
855
846
|
if (disconnectCleanup) {
|
|
856
847
|
disconnectCleanup();
|
|
@@ -871,12 +862,18 @@ class ElectronBleTransport {
|
|
|
871
862
|
this.configured = true;
|
|
872
863
|
}
|
|
873
864
|
configureProtocolV2(signedData) {
|
|
874
|
-
|
|
865
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
866
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
875
870
|
this._messagesV2 = parseConfigure(signedData);
|
|
876
|
-
this.
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
871
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
872
|
+
if (isReconfiguration) {
|
|
873
|
+
this.protocolV2Links
|
|
874
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
875
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] schema link cleanup failed:', error); });
|
|
876
|
+
}
|
|
880
877
|
}
|
|
881
878
|
listen() {
|
|
882
879
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -908,7 +905,7 @@ class ElectronBleTransport {
|
|
|
908
905
|
});
|
|
909
906
|
}
|
|
910
907
|
acquire(input) {
|
|
911
|
-
var _a, _b, _c, _d, _e, _f;
|
|
908
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
912
909
|
return __awaiter(this, void 0, void 0, function* () {
|
|
913
910
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
914
911
|
if (!uuid) {
|
|
@@ -920,8 +917,8 @@ class ElectronBleTransport {
|
|
|
920
917
|
if (forceCleanRunPromise && this.runPromise) {
|
|
921
918
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
922
919
|
this.runPromise.reject(error);
|
|
923
|
-
this.rejectAllProtocolV2Frames(error);
|
|
924
920
|
this.runPromise = null;
|
|
921
|
+
this.runPromiseDeviceId = null;
|
|
925
922
|
}
|
|
926
923
|
try {
|
|
927
924
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
@@ -933,7 +930,7 @@ class ElectronBleTransport {
|
|
|
933
930
|
}
|
|
934
931
|
const protocolHint = expectedProtocol
|
|
935
932
|
? undefined
|
|
936
|
-
: (_b = this.deviceProtocolHints.get(uuid)) !== null &&
|
|
933
|
+
: (_c = (_b = input.protocolHint) !== null && _b !== void 0 ? _b : this.deviceProtocolHints.get(uuid)) !== null && _c !== void 0 ? _c : inferProtocolHintFromDeviceName(device.name);
|
|
937
934
|
if (protocolHint) {
|
|
938
935
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
939
936
|
}
|
|
@@ -944,16 +941,31 @@ class ElectronBleTransport {
|
|
|
944
941
|
catch (error) {
|
|
945
942
|
this.handleBluetoothError(error);
|
|
946
943
|
}
|
|
944
|
+
const mtuCleanup = this.createMtuSubscription(uuid);
|
|
945
|
+
if (mtuCleanup) {
|
|
946
|
+
this.mtuCleanups.set(uuid, mtuCleanup);
|
|
947
|
+
}
|
|
947
948
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
948
|
-
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
|
|
949
|
+
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
949
950
|
yield window.desktopApi.nobleBle.subscribe(uuid);
|
|
951
|
+
yield this.refreshBlePacketCapacity(uuid);
|
|
950
952
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
951
953
|
this.notificationCleanups.set(uuid, cleanup);
|
|
954
|
+
const connectionToken = this.notificationTokens.get(uuid);
|
|
955
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
956
|
+
if (protocolType === 'V2') {
|
|
957
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[Electron BLE] Protocol V2 write configured', {
|
|
958
|
+
writeMode: 'withoutResponse',
|
|
959
|
+
negotiatedMtu: this.deviceMtus.get(uuid),
|
|
960
|
+
packetCapacity: (_e = this.devicePacketCapacities.get(uuid)) !== null && _e !== void 0 ? _e : BLE_PACKET_SIZE_FALLBACK,
|
|
961
|
+
});
|
|
962
|
+
}
|
|
952
963
|
const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
|
|
953
964
|
var _a;
|
|
954
|
-
if (disconnectedDevice.id === uuid
|
|
965
|
+
if (disconnectedDevice.id === uuid &&
|
|
966
|
+
this.notificationTokens.get(uuid) === connectionToken) {
|
|
955
967
|
this.cleanupDeviceState(uuid);
|
|
956
|
-
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(
|
|
968
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
957
969
|
name: disconnectedDevice.name,
|
|
958
970
|
id: disconnectedDevice.id,
|
|
959
971
|
connectId: disconnectedDevice.id,
|
|
@@ -961,35 +973,46 @@ class ElectronBleTransport {
|
|
|
961
973
|
}
|
|
962
974
|
});
|
|
963
975
|
this.disconnectCleanups.set(uuid, disconnectCleanup);
|
|
964
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
965
|
-
(_c = this.emitter) === null || _c === void 0 ? void 0 : _c.emit('device-connect', {
|
|
966
|
-
name: device.name,
|
|
967
|
-
id: device.id,
|
|
968
|
-
connectId: device.id,
|
|
969
|
-
});
|
|
970
976
|
return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
|
|
971
977
|
}
|
|
972
978
|
catch (error) {
|
|
973
|
-
(
|
|
979
|
+
(_f = this.Log) === null || _f === void 0 ? void 0 : _f.error('[Electron BLE] acquire failed:', error);
|
|
974
980
|
try {
|
|
975
|
-
if (((
|
|
981
|
+
if (((_g = window.desktopApi) === null || _g === void 0 ? void 0 : _g.nobleBle) && this.connectedDevices.has(uuid)) {
|
|
976
982
|
yield window.desktopApi.nobleBle.unsubscribe(uuid);
|
|
977
983
|
yield window.desktopApi.nobleBle.disconnect(uuid);
|
|
978
984
|
}
|
|
979
985
|
}
|
|
980
986
|
catch (cleanupError) {
|
|
981
|
-
(
|
|
987
|
+
(_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
|
|
982
988
|
}
|
|
983
989
|
this.cleanupDeviceState(uuid);
|
|
984
990
|
throw error;
|
|
985
991
|
}
|
|
986
992
|
});
|
|
987
993
|
}
|
|
988
|
-
release(id) {
|
|
989
|
-
var _a
|
|
994
|
+
release(id, _onclose, keepSession) {
|
|
995
|
+
var _a;
|
|
990
996
|
return __awaiter(this, void 0, void 0, function* () {
|
|
991
997
|
try {
|
|
992
998
|
yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
999
|
+
yield this.releaseLogical(id, keepSession);
|
|
1000
|
+
}
|
|
1001
|
+
catch (error) {
|
|
1002
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] release failed:', error);
|
|
1003
|
+
this.cleanupDeviceState(id);
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
disconnect(id) {
|
|
1008
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1009
|
+
return this.releaseNative(id);
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
releaseNative(id) {
|
|
1013
|
+
var _a, _b;
|
|
1014
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1015
|
+
try {
|
|
993
1016
|
if (this.connectedDevices.has(id)) {
|
|
994
1017
|
if ((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) {
|
|
995
1018
|
yield window.desktopApi.nobleBle.unsubscribe(id);
|
|
@@ -1004,11 +1027,35 @@ class ElectronBleTransport {
|
|
|
1004
1027
|
}
|
|
1005
1028
|
});
|
|
1006
1029
|
}
|
|
1030
|
+
releaseLogical(id, keepSession) {
|
|
1031
|
+
var _a, _b, _c, _d;
|
|
1032
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1033
|
+
try {
|
|
1034
|
+
if (!this.connectedDevices.has(id))
|
|
1035
|
+
return;
|
|
1036
|
+
this.cleanupDeviceState(id);
|
|
1037
|
+
const release = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.release;
|
|
1038
|
+
if (!release) {
|
|
1039
|
+
if (!this.warnedMissingRelease) {
|
|
1040
|
+
this.warnedMissingRelease = true;
|
|
1041
|
+
(_c = this.Log) === null || _c === void 0 ? void 0 : _c.error('[Electron BLE] desktopApi.nobleBle.release is missing from the preload bridge; ' +
|
|
1042
|
+
'keep-alive idle countdown will never start — map NOBLE_BLE_RELEASE in the desktop preload');
|
|
1043
|
+
}
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
yield release(id, keepSession);
|
|
1047
|
+
}
|
|
1048
|
+
catch (error) {
|
|
1049
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] logical release failed:', error);
|
|
1050
|
+
this.cleanupDeviceState(id);
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1007
1054
|
createProtocolMismatchError(expected) {
|
|
1008
1055
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1009
1056
|
}
|
|
1010
1057
|
createProtocolDetectionError() {
|
|
1011
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1058
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
1012
1059
|
}
|
|
1013
1060
|
clearProbeProtocol(uuid, protocol) {
|
|
1014
1061
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
@@ -1027,9 +1074,12 @@ class ElectronBleTransport {
|
|
|
1027
1074
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1028
1075
|
}
|
|
1029
1076
|
if (expectedProtocol === 'V2') {
|
|
1030
|
-
this.
|
|
1031
|
-
|
|
1032
|
-
|
|
1077
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1078
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1079
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
|
|
1080
|
+
return 'V2';
|
|
1081
|
+
}
|
|
1082
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1033
1083
|
}
|
|
1034
1084
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1035
1085
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
@@ -1063,16 +1113,17 @@ class ElectronBleTransport {
|
|
|
1063
1113
|
});
|
|
1064
1114
|
}
|
|
1065
1115
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1066
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1116
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
1067
1117
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1068
1118
|
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1069
1119
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1070
1120
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1071
1121
|
this.resetProtocolV2Frames(uuid);
|
|
1072
|
-
if (this.runPromise) {
|
|
1122
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
1073
1123
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1074
1124
|
this.runPromise.reject(error);
|
|
1075
1125
|
this.runPromise = null;
|
|
1126
|
+
this.runPromiseDeviceId = null;
|
|
1076
1127
|
}
|
|
1077
1128
|
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1078
1129
|
if (notifyCleanup) {
|
|
@@ -1087,10 +1138,20 @@ class ElectronBleTransport {
|
|
|
1087
1138
|
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1088
1139
|
}
|
|
1089
1140
|
try {
|
|
1090
|
-
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.
|
|
1141
|
+
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.disconnect(uuid));
|
|
1142
|
+
}
|
|
1143
|
+
catch (error) {
|
|
1144
|
+
(_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug(`[Electron BLE] disconnect after Protocol ${protocol} probe failed:`, error);
|
|
1145
|
+
}
|
|
1146
|
+
this.connectedDevices.delete(uuid);
|
|
1147
|
+
try {
|
|
1148
|
+
yield ((_j = (_h = window.desktopApi) === null || _h === void 0 ? void 0 : _h.nobleBle) === null || _j === void 0 ? void 0 : _j.connect(uuid));
|
|
1149
|
+
this.connectedDevices.add(uuid);
|
|
1150
|
+
yield ((_l = (_k = window.desktopApi) === null || _k === void 0 ? void 0 : _k.nobleBle) === null || _l === void 0 ? void 0 : _l.subscribe(uuid));
|
|
1151
|
+
yield this.refreshBlePacketCapacity(uuid);
|
|
1091
1152
|
}
|
|
1092
1153
|
catch (error) {
|
|
1093
|
-
(
|
|
1154
|
+
(_m = this.Log) === null || _m === void 0 ? void 0 : _m.debug(`[Electron BLE] reconnect after Protocol ${protocol} probe failed:`, error);
|
|
1094
1155
|
throw error;
|
|
1095
1156
|
}
|
|
1096
1157
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
@@ -1105,12 +1166,12 @@ class ElectronBleTransport {
|
|
|
1105
1166
|
}
|
|
1106
1167
|
try {
|
|
1107
1168
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1108
|
-
yield this.callProtocolV1(uuid, '
|
|
1169
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1109
1170
|
return true;
|
|
1110
1171
|
}
|
|
1111
1172
|
catch (error) {
|
|
1112
1173
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1113
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1
|
|
1174
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1 GetFeatures probe failed:', error);
|
|
1114
1175
|
return false;
|
|
1115
1176
|
}
|
|
1116
1177
|
});
|
|
@@ -1140,25 +1201,6 @@ class ElectronBleTransport {
|
|
|
1140
1201
|
return detected;
|
|
1141
1202
|
});
|
|
1142
1203
|
}
|
|
1143
|
-
writeWithChunking(uuid, hexData) {
|
|
1144
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1145
|
-
const totalBytes = hexData.length / 2;
|
|
1146
|
-
if (totalBytes <= BLE_PACKET_SIZE) {
|
|
1147
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1148
|
-
yield this.writeOnce(uuid, hexData);
|
|
1149
|
-
return;
|
|
1150
|
-
}
|
|
1151
|
-
for (let offset = 0; offset < hexData.length;) {
|
|
1152
|
-
const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
|
|
1153
|
-
const chunkHex = hexData.substring(offset, offset + chunkHexLen);
|
|
1154
|
-
offset += chunkHexLen;
|
|
1155
|
-
yield this.writeOnce(uuid, chunkHex);
|
|
1156
|
-
if (offset < hexData.length) {
|
|
1157
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
});
|
|
1161
|
-
}
|
|
1162
1204
|
writeOnce(uuid, hexData) {
|
|
1163
1205
|
var _a;
|
|
1164
1206
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1166,7 +1208,51 @@ class ElectronBleTransport {
|
|
|
1166
1208
|
if (!nobleBle) {
|
|
1167
1209
|
throw new Error('Noble BLE API not available');
|
|
1168
1210
|
}
|
|
1169
|
-
yield nobleBle.write(uuid, hexData);
|
|
1211
|
+
yield nobleBle.write(uuid, hexData, { pacingDelayMs: 0 });
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
refreshBlePacketCapacity(uuid) {
|
|
1215
|
+
var _a, _b;
|
|
1216
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1217
|
+
const device = yield ((_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.getDevice(uuid));
|
|
1218
|
+
this.updateBlePacketCapacity(uuid, device === null || device === void 0 ? void 0 : device.mtu);
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
updateBlePacketCapacity(uuid, mtu) {
|
|
1222
|
+
const packetCapacity = resolveBlePacketCapacity(mtu, BLE_PACKET_SIZE_MAXIMUM, BLE_PACKET_SIZE_FALLBACK);
|
|
1223
|
+
if (typeof mtu === 'number') {
|
|
1224
|
+
this.deviceMtus.set(uuid, mtu);
|
|
1225
|
+
}
|
|
1226
|
+
else {
|
|
1227
|
+
this.deviceMtus.delete(uuid);
|
|
1228
|
+
}
|
|
1229
|
+
this.devicePacketCapacities.set(uuid, packetCapacity);
|
|
1230
|
+
}
|
|
1231
|
+
createMtuSubscription(uuid) {
|
|
1232
|
+
var _a, _b;
|
|
1233
|
+
const onMtuChanged = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.onMtuChanged;
|
|
1234
|
+
if (!onMtuChanged)
|
|
1235
|
+
return undefined;
|
|
1236
|
+
return onMtuChanged(device => {
|
|
1237
|
+
if (device.id === uuid) {
|
|
1238
|
+
this.updateBlePacketCapacity(uuid, device.mtu);
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration) {
|
|
1243
|
+
var _a;
|
|
1244
|
+
const packetCapacity = (_a = this.devicePacketCapacities.get(uuid)) !== null && _a !== void 0 ? _a : BLE_PACKET_SIZE_FALLBACK;
|
|
1245
|
+
const shouldPace = !context.highThroughput;
|
|
1246
|
+
return transport.writeProtocolV2BleFrame({
|
|
1247
|
+
frame,
|
|
1248
|
+
packetCapacity,
|
|
1249
|
+
assertActive: assertCurrentGeneration,
|
|
1250
|
+
signal: context.signal,
|
|
1251
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1252
|
+
initialDelayMs: shouldPace && frame.length <= packetCapacity ? BLE_WRITE_DELAY_MS : 0,
|
|
1253
|
+
burstSize: shouldPace ? 1 : undefined,
|
|
1254
|
+
burstPauseMs: shouldPace ? BLE_WRITE_DELAY_MS : 0,
|
|
1255
|
+
writePacket: packet => this.writeOnce(uuid, transport.bytesToHex(packet)),
|
|
1170
1256
|
});
|
|
1171
1257
|
}
|
|
1172
1258
|
handleNotification(deviceId, hexData) {
|
|
@@ -1177,7 +1263,7 @@ class ElectronBleTransport {
|
|
|
1177
1263
|
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
1178
1264
|
this.rejectProtocolV2Frames(deviceId, error);
|
|
1179
1265
|
}
|
|
1180
|
-
else if (this.runPromise) {
|
|
1266
|
+
else if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1181
1267
|
this.runPromise.reject(error);
|
|
1182
1268
|
}
|
|
1183
1269
|
return;
|
|
@@ -1229,16 +1315,8 @@ class ElectronBleTransport {
|
|
|
1229
1315
|
}
|
|
1230
1316
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1231
1317
|
}
|
|
1232
|
-
rejectAllProtocolV2Frames(error) {
|
|
1233
|
-
this.v2FrameQueues.clear();
|
|
1234
|
-
for (const framePromise of this.v2FramePromises.values()) {
|
|
1235
|
-
framePromise.reject(error);
|
|
1236
|
-
}
|
|
1237
|
-
this.v2FramePromises.clear();
|
|
1238
|
-
}
|
|
1239
1318
|
resetProtocolV2Frames(uuid) {
|
|
1240
|
-
this.
|
|
1241
|
-
this.v2FramePromises.delete(uuid);
|
|
1319
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1242
1320
|
}
|
|
1243
1321
|
rejectProtocolV2Frames(uuid, error) {
|
|
1244
1322
|
this.v2FrameQueues.delete(uuid);
|
|
@@ -1271,17 +1349,20 @@ class ElectronBleTransport {
|
|
|
1271
1349
|
const result = this.processProtocolV1Notification(deviceId, hexData);
|
|
1272
1350
|
if (result.error) {
|
|
1273
1351
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V1 packet processing error:', result.error);
|
|
1274
|
-
if (this.runPromise) {
|
|
1352
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1275
1353
|
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
|
|
1276
1354
|
}
|
|
1277
1355
|
return;
|
|
1278
1356
|
}
|
|
1279
|
-
if (result.isComplete &&
|
|
1357
|
+
if (result.isComplete &&
|
|
1358
|
+
result.completePacket &&
|
|
1359
|
+
this.runPromise &&
|
|
1360
|
+
this.runPromiseDeviceId === deviceId) {
|
|
1280
1361
|
this.runPromise.resolve(result.completePacket);
|
|
1281
1362
|
}
|
|
1282
1363
|
}
|
|
1283
1364
|
call(uuid, name, data, options) {
|
|
1284
|
-
var _a
|
|
1365
|
+
var _a;
|
|
1285
1366
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1286
1367
|
if (!this._messages) {
|
|
1287
1368
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
@@ -1293,12 +1374,8 @@ class ElectronBleTransport {
|
|
|
1293
1374
|
if (!protocol) {
|
|
1294
1375
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1295
1376
|
}
|
|
1296
|
-
if (shouldSuppressHighVolumeCallLog(name))
|
|
1297
|
-
|
|
1298
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] call', 'name:', name, 'protocol:', protocol);
|
|
1299
|
-
}
|
|
1300
|
-
else {
|
|
1301
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
|
|
1377
|
+
if (!transport.shouldSuppressHighVolumeCallLog(name)) {
|
|
1378
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('transport call', transport.createTransportCallLog(name, protocol, data));
|
|
1302
1379
|
}
|
|
1303
1380
|
if (protocol === 'V2') {
|
|
1304
1381
|
return this.callProtocolV2(uuid, name, data, options);
|
|
@@ -1319,6 +1396,7 @@ class ElectronBleTransport {
|
|
|
1319
1396
|
const runPromise = hdShared.createDeferred();
|
|
1320
1397
|
runPromise.promise.catch(() => undefined);
|
|
1321
1398
|
this.runPromise = runPromise;
|
|
1399
|
+
this.runPromiseDeviceId = uuid;
|
|
1322
1400
|
const messages = this._messages;
|
|
1323
1401
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1324
1402
|
let timeout;
|
|
@@ -1357,6 +1435,17 @@ class ElectronBleTransport {
|
|
|
1357
1435
|
}
|
|
1358
1436
|
catch (e) {
|
|
1359
1437
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V1 call error:', e);
|
|
1438
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1439
|
+
if ((e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1440
|
+
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1441
|
+
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1442
|
+
notifyCleanup === null || notifyCleanup === void 0 ? void 0 : notifyCleanup();
|
|
1443
|
+
this.notificationCleanups.delete(uuid);
|
|
1444
|
+
this.notificationTokens.delete(uuid);
|
|
1445
|
+
if (!isProbeTimeout) {
|
|
1446
|
+
yield this.releaseNative(uuid);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1360
1449
|
throw e;
|
|
1361
1450
|
}
|
|
1362
1451
|
finally {
|
|
@@ -1364,22 +1453,23 @@ class ElectronBleTransport {
|
|
|
1364
1453
|
clearTimeout(timeout);
|
|
1365
1454
|
if (this.runPromise === runPromise) {
|
|
1366
1455
|
this.runPromise = null;
|
|
1456
|
+
this.runPromiseDeviceId = null;
|
|
1367
1457
|
}
|
|
1368
1458
|
}
|
|
1369
1459
|
});
|
|
1370
1460
|
}
|
|
1371
1461
|
callProtocolV2(uuid, name, data, options) {
|
|
1372
|
-
var _a
|
|
1462
|
+
var _a;
|
|
1373
1463
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1374
1464
|
if (!this._messages || !this._messagesV2) {
|
|
1375
1465
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1376
1466
|
}
|
|
1377
|
-
const callOptions =
|
|
1467
|
+
const callOptions = options;
|
|
1378
1468
|
try {
|
|
1379
1469
|
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1380
1470
|
}
|
|
1381
1471
|
catch (e) {
|
|
1382
|
-
(
|
|
1472
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1383
1473
|
throw e;
|
|
1384
1474
|
}
|
|
1385
1475
|
});
|
|
@@ -1394,6 +1484,7 @@ class ElectronBleTransport {
|
|
|
1394
1484
|
};
|
|
1395
1485
|
return {
|
|
1396
1486
|
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1487
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1397
1488
|
generation,
|
|
1398
1489
|
prepareCall: () => {
|
|
1399
1490
|
var _a;
|
|
@@ -1401,10 +1492,7 @@ class ElectronBleTransport {
|
|
|
1401
1492
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1402
1493
|
this.resetProtocolV2Frames(uuid);
|
|
1403
1494
|
},
|
|
1404
|
-
writeFrame: (frame) =>
|
|
1405
|
-
assertCurrentGeneration();
|
|
1406
|
-
return this.writeWithChunking(uuid, transport.bytesToHex(frame));
|
|
1407
|
-
},
|
|
1495
|
+
writeFrame: (frame, context) => this.writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration),
|
|
1408
1496
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1409
1497
|
assertCurrentGeneration();
|
|
1410
1498
|
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
@@ -1424,6 +1512,7 @@ class ElectronBleTransport {
|
|
|
1424
1512
|
};
|
|
1425
1513
|
}
|
|
1426
1514
|
processProtocolV1Notification(deviceId, hexData) {
|
|
1515
|
+
var _a;
|
|
1427
1516
|
try {
|
|
1428
1517
|
if (typeof hexData !== 'string') {
|
|
1429
1518
|
return { isComplete: false, error: 'Invalid hexData type' };
|
|
@@ -1442,6 +1531,10 @@ class ElectronBleTransport {
|
|
|
1442
1531
|
bufferState.buffer = [...data.subarray(3)];
|
|
1443
1532
|
}
|
|
1444
1533
|
else {
|
|
1534
|
+
if (bufferState.buffer.length === 0) {
|
|
1535
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Orphan continuation chunk discarded');
|
|
1536
|
+
return { isComplete: false };
|
|
1537
|
+
}
|
|
1445
1538
|
bufferState.buffer = bufferState.buffer.concat([...data]);
|
|
1446
1539
|
}
|
|
1447
1540
|
if (bufferState.buffer.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferState.bufferLength) {
|