@onekeyfe/hd-transport-web-device 1.2.0-alpha.7 → 1.2.0-alpha.71
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 +450 -12
- 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 +14 -5
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +107 -14
- package/dist/index.js +387 -325
- 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 +279 -175
- 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,16 +748,39 @@ 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();
|
|
783
760
|
this.v2FramePromises = new Map();
|
|
784
|
-
this.
|
|
785
|
-
|
|
761
|
+
this.protocolV2Links = new transport.ProtocolV2LinkManager({
|
|
762
|
+
getSchemas: () => {
|
|
763
|
+
if (!this._messages || !this._messagesV2) {
|
|
764
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
765
|
+
}
|
|
766
|
+
return {
|
|
767
|
+
protocolV1: this._messages,
|
|
768
|
+
protocolV2: this._messagesV2,
|
|
769
|
+
};
|
|
770
|
+
},
|
|
771
|
+
classifyError: () => 'link-fatal',
|
|
772
|
+
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
773
|
+
var _a, _b;
|
|
774
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
775
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
776
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
777
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
778
|
+
yield this.releaseNative(uuid);
|
|
779
|
+
}
|
|
780
|
+
}),
|
|
781
|
+
});
|
|
786
782
|
this.notificationCleanups = new Map();
|
|
783
|
+
this.mtuCleanups = new Map();
|
|
787
784
|
this.disconnectCleanups = new Map();
|
|
788
785
|
this.notificationTokens = new Map();
|
|
789
786
|
this.nextNotificationToken = 1;
|
|
@@ -818,21 +815,32 @@ class ElectronBleTransport {
|
|
|
818
815
|
throw error;
|
|
819
816
|
}
|
|
820
817
|
cleanupDeviceState(deviceId) {
|
|
821
|
-
|
|
818
|
+
this.protocolV2Links
|
|
819
|
+
.invalidateLink(deviceId, 'Electron BLE device state cleaned')
|
|
820
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] link cleanup failed:', error); });
|
|
822
821
|
this.connectedDevices.delete(deviceId);
|
|
823
822
|
this.deviceProtocol.delete(deviceId);
|
|
823
|
+
this.deviceMtus.delete(deviceId);
|
|
824
|
+
this.devicePacketCapacities.delete(deviceId);
|
|
824
825
|
this.v1Buffers.delete(deviceId);
|
|
825
826
|
this.v2Assemblers.delete(deviceId);
|
|
826
827
|
this.resetProtocolV2Frames(deviceId);
|
|
827
|
-
if (((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === deviceId) {
|
|
828
|
-
this.activeProtocolV2Call = null;
|
|
829
|
-
}
|
|
830
828
|
this.notificationTokens.delete(deviceId);
|
|
829
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
830
|
+
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceDisconnected));
|
|
831
|
+
this.runPromise = null;
|
|
832
|
+
this.runPromiseDeviceId = null;
|
|
833
|
+
}
|
|
831
834
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
832
835
|
if (notifyCleanup) {
|
|
833
836
|
notifyCleanup();
|
|
834
837
|
this.notificationCleanups.delete(deviceId);
|
|
835
838
|
}
|
|
839
|
+
const mtuCleanup = this.mtuCleanups.get(deviceId);
|
|
840
|
+
if (mtuCleanup) {
|
|
841
|
+
mtuCleanup();
|
|
842
|
+
this.mtuCleanups.delete(deviceId);
|
|
843
|
+
}
|
|
836
844
|
const disconnectCleanup = this.disconnectCleanups.get(deviceId);
|
|
837
845
|
if (disconnectCleanup) {
|
|
838
846
|
disconnectCleanup();
|
|
@@ -853,9 +861,18 @@ class ElectronBleTransport {
|
|
|
853
861
|
this.configured = true;
|
|
854
862
|
}
|
|
855
863
|
configureProtocolV2(signedData) {
|
|
856
|
-
|
|
864
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
865
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
857
869
|
this._messagesV2 = parseConfigure(signedData);
|
|
858
|
-
|
|
870
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
871
|
+
if (isReconfiguration) {
|
|
872
|
+
this.protocolV2Links
|
|
873
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
874
|
+
.catch(error => { var _a; return (_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] schema link cleanup failed:', error); });
|
|
875
|
+
}
|
|
859
876
|
}
|
|
860
877
|
listen() {
|
|
861
878
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -887,18 +904,20 @@ class ElectronBleTransport {
|
|
|
887
904
|
});
|
|
888
905
|
}
|
|
889
906
|
acquire(input) {
|
|
890
|
-
var _a, _b, _c, _d, _e, _f;
|
|
907
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
891
908
|
return __awaiter(this, void 0, void 0, function* () {
|
|
892
909
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
893
910
|
if (!uuid) {
|
|
894
911
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
895
912
|
}
|
|
913
|
+
if (this.connectedDevices.has(uuid)) {
|
|
914
|
+
yield this.release(uuid);
|
|
915
|
+
}
|
|
896
916
|
if (forceCleanRunPromise && this.runPromise) {
|
|
897
917
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
898
918
|
this.runPromise.reject(error);
|
|
899
|
-
this.rejectAllProtocolV2Frames(error);
|
|
900
919
|
this.runPromise = null;
|
|
901
|
-
this.
|
|
920
|
+
this.runPromiseDeviceId = null;
|
|
902
921
|
}
|
|
903
922
|
try {
|
|
904
923
|
if (!((_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle)) {
|
|
@@ -910,7 +929,7 @@ class ElectronBleTransport {
|
|
|
910
929
|
}
|
|
911
930
|
const protocolHint = expectedProtocol
|
|
912
931
|
? undefined
|
|
913
|
-
: (_b = this.deviceProtocolHints.get(uuid)) !== null &&
|
|
932
|
+
: (_c = (_b = input.protocolHint) !== null && _b !== void 0 ? _b : this.deviceProtocolHints.get(uuid)) !== null && _c !== void 0 ? _c : inferProtocolHintFromDeviceName(device.name);
|
|
914
933
|
if (protocolHint) {
|
|
915
934
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
916
935
|
}
|
|
@@ -921,16 +940,31 @@ class ElectronBleTransport {
|
|
|
921
940
|
catch (error) {
|
|
922
941
|
this.handleBluetoothError(error);
|
|
923
942
|
}
|
|
943
|
+
const mtuCleanup = this.createMtuSubscription(uuid);
|
|
944
|
+
if (mtuCleanup) {
|
|
945
|
+
this.mtuCleanups.set(uuid, mtuCleanup);
|
|
946
|
+
}
|
|
924
947
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
925
|
-
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
|
|
948
|
+
this.v2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
926
949
|
yield window.desktopApi.nobleBle.subscribe(uuid);
|
|
950
|
+
yield this.refreshBlePacketCapacity(uuid);
|
|
927
951
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
928
952
|
this.notificationCleanups.set(uuid, cleanup);
|
|
953
|
+
const connectionToken = this.notificationTokens.get(uuid);
|
|
954
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
955
|
+
if (protocolType === 'V2') {
|
|
956
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug('[Electron BLE] Protocol V2 write configured', {
|
|
957
|
+
writeMode: 'withoutResponse',
|
|
958
|
+
negotiatedMtu: this.deviceMtus.get(uuid),
|
|
959
|
+
packetCapacity: (_e = this.devicePacketCapacities.get(uuid)) !== null && _e !== void 0 ? _e : BLE_PACKET_SIZE_FALLBACK,
|
|
960
|
+
});
|
|
961
|
+
}
|
|
929
962
|
const disconnectCleanup = window.desktopApi.nobleBle.onDeviceDisconnected((disconnectedDevice) => {
|
|
930
963
|
var _a;
|
|
931
|
-
if (disconnectedDevice.id === uuid
|
|
964
|
+
if (disconnectedDevice.id === uuid &&
|
|
965
|
+
this.notificationTokens.get(uuid) === connectionToken) {
|
|
932
966
|
this.cleanupDeviceState(uuid);
|
|
933
|
-
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(
|
|
967
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
934
968
|
name: disconnectedDevice.name,
|
|
935
969
|
id: disconnectedDevice.id,
|
|
936
970
|
connectId: disconnectedDevice.id,
|
|
@@ -938,24 +972,18 @@ class ElectronBleTransport {
|
|
|
938
972
|
}
|
|
939
973
|
});
|
|
940
974
|
this.disconnectCleanups.set(uuid, disconnectCleanup);
|
|
941
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
942
|
-
(_c = this.emitter) === null || _c === void 0 ? void 0 : _c.emit('device-connect', {
|
|
943
|
-
name: device.name,
|
|
944
|
-
id: device.id,
|
|
945
|
-
connectId: device.id,
|
|
946
|
-
});
|
|
947
975
|
return Object.assign(Object.assign({}, toBleDescriptor({ id: device.id, name: device.name }, protocolType)), { uuid });
|
|
948
976
|
}
|
|
949
977
|
catch (error) {
|
|
950
|
-
(
|
|
978
|
+
(_f = this.Log) === null || _f === void 0 ? void 0 : _f.error('[Electron BLE] acquire failed:', error);
|
|
951
979
|
try {
|
|
952
|
-
if (((
|
|
980
|
+
if (((_g = window.desktopApi) === null || _g === void 0 ? void 0 : _g.nobleBle) && this.connectedDevices.has(uuid)) {
|
|
953
981
|
yield window.desktopApi.nobleBle.unsubscribe(uuid);
|
|
954
982
|
yield window.desktopApi.nobleBle.disconnect(uuid);
|
|
955
983
|
}
|
|
956
984
|
}
|
|
957
985
|
catch (cleanupError) {
|
|
958
|
-
(
|
|
986
|
+
(_h = this.Log) === null || _h === void 0 ? void 0 : _h.debug('[Electron BLE] acquire cleanup failed:', cleanupError);
|
|
959
987
|
}
|
|
960
988
|
this.cleanupDeviceState(uuid);
|
|
961
989
|
throw error;
|
|
@@ -963,6 +991,19 @@ class ElectronBleTransport {
|
|
|
963
991
|
});
|
|
964
992
|
}
|
|
965
993
|
release(id) {
|
|
994
|
+
var _a;
|
|
995
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
996
|
+
try {
|
|
997
|
+
yield this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
998
|
+
yield this.releaseNative(id);
|
|
999
|
+
}
|
|
1000
|
+
catch (error) {
|
|
1001
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] release failed:', error);
|
|
1002
|
+
this.cleanupDeviceState(id);
|
|
1003
|
+
}
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
releaseNative(id) {
|
|
966
1007
|
var _a, _b;
|
|
967
1008
|
return __awaiter(this, void 0, void 0, function* () {
|
|
968
1009
|
try {
|
|
@@ -984,7 +1025,7 @@ class ElectronBleTransport {
|
|
|
984
1025
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
985
1026
|
}
|
|
986
1027
|
createProtocolDetectionError() {
|
|
987
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1028
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
988
1029
|
}
|
|
989
1030
|
clearProbeProtocol(uuid, protocol) {
|
|
990
1031
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
@@ -1003,9 +1044,12 @@ class ElectronBleTransport {
|
|
|
1003
1044
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1004
1045
|
}
|
|
1005
1046
|
if (expectedProtocol === 'V2') {
|
|
1006
|
-
this.
|
|
1007
|
-
|
|
1008
|
-
|
|
1047
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1048
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1049
|
+
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
|
|
1050
|
+
return 'V2';
|
|
1051
|
+
}
|
|
1052
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1009
1053
|
}
|
|
1010
1054
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1011
1055
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
@@ -1039,18 +1083,17 @@ class ElectronBleTransport {
|
|
|
1039
1083
|
});
|
|
1040
1084
|
}
|
|
1041
1085
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1042
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1086
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
1043
1087
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1088
|
+
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1044
1089
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1045
1090
|
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1046
1091
|
this.resetProtocolV2Frames(uuid);
|
|
1047
|
-
if (
|
|
1048
|
-
this.activeProtocolV2Call = null;
|
|
1049
|
-
}
|
|
1050
|
-
if (this.runPromise) {
|
|
1092
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
1051
1093
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1052
1094
|
this.runPromise.reject(error);
|
|
1053
1095
|
this.runPromise = null;
|
|
1096
|
+
this.runPromiseDeviceId = null;
|
|
1054
1097
|
}
|
|
1055
1098
|
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1056
1099
|
if (notifyCleanup) {
|
|
@@ -1059,16 +1102,26 @@ class ElectronBleTransport {
|
|
|
1059
1102
|
}
|
|
1060
1103
|
this.notificationTokens.delete(uuid);
|
|
1061
1104
|
try {
|
|
1062
|
-
yield ((
|
|
1105
|
+
yield ((_c = (_b = window.desktopApi) === null || _b === void 0 ? void 0 : _b.nobleBle) === null || _c === void 0 ? void 0 : _c.unsubscribe(uuid));
|
|
1063
1106
|
}
|
|
1064
1107
|
catch (error) {
|
|
1065
|
-
(
|
|
1108
|
+
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.debug(`[Electron BLE] unsubscribe after Protocol ${protocol} probe failed:`, error);
|
|
1066
1109
|
}
|
|
1067
1110
|
try {
|
|
1068
|
-
yield ((
|
|
1111
|
+
yield ((_f = (_e = window.desktopApi) === null || _e === void 0 ? void 0 : _e.nobleBle) === null || _f === void 0 ? void 0 : _f.disconnect(uuid));
|
|
1069
1112
|
}
|
|
1070
1113
|
catch (error) {
|
|
1071
|
-
(
|
|
1114
|
+
(_g = this.Log) === null || _g === void 0 ? void 0 : _g.debug(`[Electron BLE] disconnect after Protocol ${protocol} probe failed:`, error);
|
|
1115
|
+
}
|
|
1116
|
+
this.connectedDevices.delete(uuid);
|
|
1117
|
+
try {
|
|
1118
|
+
yield ((_j = (_h = window.desktopApi) === null || _h === void 0 ? void 0 : _h.nobleBle) === null || _j === void 0 ? void 0 : _j.connect(uuid));
|
|
1119
|
+
this.connectedDevices.add(uuid);
|
|
1120
|
+
yield ((_l = (_k = window.desktopApi) === null || _k === void 0 ? void 0 : _k.nobleBle) === null || _l === void 0 ? void 0 : _l.subscribe(uuid));
|
|
1121
|
+
yield this.refreshBlePacketCapacity(uuid);
|
|
1122
|
+
}
|
|
1123
|
+
catch (error) {
|
|
1124
|
+
(_m = this.Log) === null || _m === void 0 ? void 0 : _m.debug(`[Electron BLE] reconnect after Protocol ${protocol} probe failed:`, error);
|
|
1072
1125
|
throw error;
|
|
1073
1126
|
}
|
|
1074
1127
|
const cleanup = this.createNotificationSubscription(uuid);
|
|
@@ -1083,12 +1136,12 @@ class ElectronBleTransport {
|
|
|
1083
1136
|
}
|
|
1084
1137
|
try {
|
|
1085
1138
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1086
|
-
yield this.callProtocolV1(uuid, '
|
|
1139
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1087
1140
|
return true;
|
|
1088
1141
|
}
|
|
1089
1142
|
catch (error) {
|
|
1090
1143
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1091
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1
|
|
1144
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Protocol V1 GetFeatures probe failed:', error);
|
|
1092
1145
|
return false;
|
|
1093
1146
|
}
|
|
1094
1147
|
});
|
|
@@ -1118,25 +1171,6 @@ class ElectronBleTransport {
|
|
|
1118
1171
|
return detected;
|
|
1119
1172
|
});
|
|
1120
1173
|
}
|
|
1121
|
-
writeWithChunking(uuid, hexData) {
|
|
1122
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1123
|
-
const totalBytes = hexData.length / 2;
|
|
1124
|
-
if (totalBytes <= BLE_PACKET_SIZE) {
|
|
1125
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1126
|
-
yield this.writeOnce(uuid, hexData);
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
for (let offset = 0; offset < hexData.length;) {
|
|
1130
|
-
const chunkHexLen = Math.min(BLE_PACKET_SIZE * 2, hexData.length - offset);
|
|
1131
|
-
const chunkHex = hexData.substring(offset, offset + chunkHexLen);
|
|
1132
|
-
offset += chunkHexLen;
|
|
1133
|
-
yield this.writeOnce(uuid, chunkHex);
|
|
1134
|
-
if (offset < hexData.length) {
|
|
1135
|
-
yield hdShared.wait(BLE_WRITE_DELAY_MS);
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
1174
|
writeOnce(uuid, hexData) {
|
|
1141
1175
|
var _a;
|
|
1142
1176
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1147,14 +1181,60 @@ class ElectronBleTransport {
|
|
|
1147
1181
|
yield nobleBle.write(uuid, hexData);
|
|
1148
1182
|
});
|
|
1149
1183
|
}
|
|
1184
|
+
refreshBlePacketCapacity(uuid) {
|
|
1185
|
+
var _a, _b;
|
|
1186
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1187
|
+
const device = yield ((_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.getDevice(uuid));
|
|
1188
|
+
this.updateBlePacketCapacity(uuid, device === null || device === void 0 ? void 0 : device.mtu);
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
updateBlePacketCapacity(uuid, mtu) {
|
|
1192
|
+
const packetCapacity = resolveBlePacketCapacity(mtu, BLE_PACKET_SIZE_MAXIMUM, BLE_PACKET_SIZE_FALLBACK);
|
|
1193
|
+
if (typeof mtu === 'number') {
|
|
1194
|
+
this.deviceMtus.set(uuid, mtu);
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
this.deviceMtus.delete(uuid);
|
|
1198
|
+
}
|
|
1199
|
+
this.devicePacketCapacities.set(uuid, packetCapacity);
|
|
1200
|
+
}
|
|
1201
|
+
createMtuSubscription(uuid) {
|
|
1202
|
+
var _a, _b;
|
|
1203
|
+
const onMtuChanged = (_b = (_a = window.desktopApi) === null || _a === void 0 ? void 0 : _a.nobleBle) === null || _b === void 0 ? void 0 : _b.onMtuChanged;
|
|
1204
|
+
if (!onMtuChanged)
|
|
1205
|
+
return undefined;
|
|
1206
|
+
return onMtuChanged(device => {
|
|
1207
|
+
if (device.id === uuid) {
|
|
1208
|
+
this.updateBlePacketCapacity(uuid, device.mtu);
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration) {
|
|
1213
|
+
var _a;
|
|
1214
|
+
const packetCapacity = (_a = this.devicePacketCapacities.get(uuid)) !== null && _a !== void 0 ? _a : BLE_PACKET_SIZE_FALLBACK;
|
|
1215
|
+
const shouldPace = !context.highVolume;
|
|
1216
|
+
return transport.writeProtocolV2BleFrame({
|
|
1217
|
+
frame,
|
|
1218
|
+
packetCapacity,
|
|
1219
|
+
assertActive: assertCurrentGeneration,
|
|
1220
|
+
signal: context.signal,
|
|
1221
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1222
|
+
initialDelayMs: shouldPace && frame.length <= packetCapacity ? BLE_WRITE_DELAY_MS : 0,
|
|
1223
|
+
burstSize: shouldPace ? 1 : undefined,
|
|
1224
|
+
burstPauseMs: shouldPace ? BLE_WRITE_DELAY_MS : 0,
|
|
1225
|
+
writePacket: packet => this.writeOnce(uuid, transport.bytesToHex(packet)),
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1150
1228
|
handleNotification(deviceId, hexData) {
|
|
1151
1229
|
var _a, _b;
|
|
1152
1230
|
if (hexData === 'PAIRING_REJECTED') {
|
|
1153
1231
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] Pairing rejection detected for device:', deviceId);
|
|
1154
|
-
|
|
1155
|
-
|
|
1232
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled);
|
|
1233
|
+
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
1234
|
+
this.rejectProtocolV2Frames(deviceId, error);
|
|
1235
|
+
}
|
|
1236
|
+
else if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1156
1237
|
this.runPromise.reject(error);
|
|
1157
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1158
1238
|
}
|
|
1159
1239
|
return;
|
|
1160
1240
|
}
|
|
@@ -1170,13 +1250,8 @@ class ElectronBleTransport {
|
|
|
1170
1250
|
this.handleProtocolV1Notification(deviceId, hexData);
|
|
1171
1251
|
}
|
|
1172
1252
|
handleProtocolV2Notification(deviceId, hexData) {
|
|
1173
|
-
var _a
|
|
1253
|
+
var _a;
|
|
1174
1254
|
try {
|
|
1175
|
-
if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== deviceId) {
|
|
1176
|
-
(_b = this.v2Assemblers.get(deviceId)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1177
|
-
this.resetProtocolV2Frames(deviceId);
|
|
1178
|
-
return;
|
|
1179
|
-
}
|
|
1180
1255
|
const bytes = transport.hexToBytes(hexData);
|
|
1181
1256
|
if (bytes.length === 0)
|
|
1182
1257
|
return;
|
|
@@ -1188,12 +1263,9 @@ class ElectronBleTransport {
|
|
|
1188
1263
|
}
|
|
1189
1264
|
}
|
|
1190
1265
|
catch (error) {
|
|
1191
|
-
(
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
this.runPromise.reject(notifyError);
|
|
1195
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
1196
|
-
}
|
|
1266
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 notification error:', error);
|
|
1267
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1268
|
+
this.rejectProtocolV2Frames(deviceId, notifyError);
|
|
1197
1269
|
}
|
|
1198
1270
|
}
|
|
1199
1271
|
getProtocolV2FrameQueue(uuid) {
|
|
@@ -1213,20 +1285,16 @@ class ElectronBleTransport {
|
|
|
1213
1285
|
}
|
|
1214
1286
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1215
1287
|
}
|
|
1216
|
-
rejectAllProtocolV2Frames(error) {
|
|
1217
|
-
this.v2FrameQueues.clear();
|
|
1218
|
-
for (const framePromise of this.v2FramePromises.values()) {
|
|
1219
|
-
framePromise.reject(error);
|
|
1220
|
-
}
|
|
1221
|
-
this.v2FramePromises.clear();
|
|
1222
|
-
}
|
|
1223
1288
|
resetProtocolV2Frames(uuid) {
|
|
1224
|
-
this.
|
|
1225
|
-
this.v2FramePromises.delete(uuid);
|
|
1289
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1226
1290
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1291
|
+
rejectProtocolV2Frames(uuid, error) {
|
|
1292
|
+
this.v2FrameQueues.delete(uuid);
|
|
1293
|
+
const framePromise = this.v2FramePromises.get(uuid);
|
|
1294
|
+
if (framePromise) {
|
|
1295
|
+
this.v2FramePromises.delete(uuid);
|
|
1296
|
+
framePromise.reject(error);
|
|
1297
|
+
}
|
|
1230
1298
|
}
|
|
1231
1299
|
readProtocolV2Frame(uuid) {
|
|
1232
1300
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1251,17 +1319,20 @@ class ElectronBleTransport {
|
|
|
1251
1319
|
const result = this.processProtocolV1Notification(deviceId, hexData);
|
|
1252
1320
|
if (result.error) {
|
|
1253
1321
|
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V1 packet processing error:', result.error);
|
|
1254
|
-
if (this.runPromise) {
|
|
1322
|
+
if (this.runPromise && this.runPromiseDeviceId === deviceId) {
|
|
1255
1323
|
this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
|
|
1256
1324
|
}
|
|
1257
1325
|
return;
|
|
1258
1326
|
}
|
|
1259
|
-
if (result.isComplete &&
|
|
1327
|
+
if (result.isComplete &&
|
|
1328
|
+
result.completePacket &&
|
|
1329
|
+
this.runPromise &&
|
|
1330
|
+
this.runPromiseDeviceId === deviceId) {
|
|
1260
1331
|
this.runPromise.resolve(result.completePacket);
|
|
1261
1332
|
}
|
|
1262
1333
|
}
|
|
1263
1334
|
call(uuid, name, data, options) {
|
|
1264
|
-
var _a
|
|
1335
|
+
var _a;
|
|
1265
1336
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1266
1337
|
if (!this._messages) {
|
|
1267
1338
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
@@ -1273,12 +1344,8 @@ class ElectronBleTransport {
|
|
|
1273
1344
|
if (!protocol) {
|
|
1274
1345
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1275
1346
|
}
|
|
1276
|
-
if (shouldSuppressHighVolumeCallLog(name))
|
|
1277
|
-
|
|
1278
|
-
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('[Electron BLE] call', 'name:', name, 'protocol:', protocol);
|
|
1279
|
-
}
|
|
1280
|
-
else {
|
|
1281
|
-
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.debug('[Electron BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
|
|
1347
|
+
if (!transport.shouldSuppressHighVolumeCallLog(name)) {
|
|
1348
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.debug('transport call', transport.createTransportCallLog(name, protocol, data));
|
|
1282
1349
|
}
|
|
1283
1350
|
if (protocol === 'V2') {
|
|
1284
1351
|
return this.callProtocolV2(uuid, name, data, options);
|
|
@@ -1299,6 +1366,7 @@ class ElectronBleTransport {
|
|
|
1299
1366
|
const runPromise = hdShared.createDeferred();
|
|
1300
1367
|
runPromise.promise.catch(() => undefined);
|
|
1301
1368
|
this.runPromise = runPromise;
|
|
1369
|
+
this.runPromiseDeviceId = uuid;
|
|
1302
1370
|
const messages = this._messages;
|
|
1303
1371
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1304
1372
|
let timeout;
|
|
@@ -1337,6 +1405,17 @@ class ElectronBleTransport {
|
|
|
1337
1405
|
}
|
|
1338
1406
|
catch (e) {
|
|
1339
1407
|
(_b = this.Log) === null || _b === void 0 ? void 0 : _b.error('[Electron BLE] Protocol V1 call error:', e);
|
|
1408
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1409
|
+
if ((e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1410
|
+
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
1411
|
+
const notifyCleanup = this.notificationCleanups.get(uuid);
|
|
1412
|
+
notifyCleanup === null || notifyCleanup === void 0 ? void 0 : notifyCleanup();
|
|
1413
|
+
this.notificationCleanups.delete(uuid);
|
|
1414
|
+
this.notificationTokens.delete(uuid);
|
|
1415
|
+
if (!isProbeTimeout) {
|
|
1416
|
+
yield this.releaseNative(uuid);
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1340
1419
|
throw e;
|
|
1341
1420
|
}
|
|
1342
1421
|
finally {
|
|
@@ -1344,81 +1423,64 @@ class ElectronBleTransport {
|
|
|
1344
1423
|
clearTimeout(timeout);
|
|
1345
1424
|
if (this.runPromise === runPromise) {
|
|
1346
1425
|
this.runPromise = null;
|
|
1426
|
+
this.runPromiseDeviceId = null;
|
|
1347
1427
|
}
|
|
1348
1428
|
}
|
|
1349
1429
|
});
|
|
1350
1430
|
}
|
|
1351
1431
|
callProtocolV2(uuid, name, data, options) {
|
|
1352
|
-
var _a
|
|
1432
|
+
var _a;
|
|
1353
1433
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1354
1434
|
if (!this._messages || !this._messagesV2) {
|
|
1355
1435
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1356
1436
|
}
|
|
1357
|
-
const
|
|
1358
|
-
if (this.runPromise) {
|
|
1359
|
-
if (!forceRun) {
|
|
1360
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1361
|
-
}
|
|
1362
|
-
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1363
|
-
this.runPromise.reject(error);
|
|
1364
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1365
|
-
this.runPromise = null;
|
|
1366
|
-
this.activeProtocolV2Call = null;
|
|
1367
|
-
}
|
|
1368
|
-
const runPromise = hdShared.createDeferred();
|
|
1369
|
-
runPromise.promise.catch(() => undefined);
|
|
1370
|
-
this.runPromise = runPromise;
|
|
1371
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1372
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1373
|
-
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1374
|
-
this.resetProtocolV2Frames(uuid);
|
|
1375
|
-
let completed = false;
|
|
1376
|
-
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
|
|
1437
|
+
const callOptions = options;
|
|
1377
1438
|
try {
|
|
1378
|
-
|
|
1379
|
-
schemas: {
|
|
1380
|
-
protocolV1: this._messages,
|
|
1381
|
-
protocolV2: this._messagesV2,
|
|
1382
|
-
},
|
|
1383
|
-
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1384
|
-
writeFrame: (frame) => this.writeWithChunking(uuid, transport.bytesToHex(frame)),
|
|
1385
|
-
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1386
|
-
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1387
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
1388
|
-
throw new Error('Response is not Uint8Array');
|
|
1389
|
-
}
|
|
1390
|
-
return rxFrame;
|
|
1391
|
-
}),
|
|
1392
|
-
logger: this.Log,
|
|
1393
|
-
logPrefix: 'ProtocolV2 BLE',
|
|
1394
|
-
createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
|
|
1395
|
-
});
|
|
1396
|
-
const result = yield session.call(name, data, callOptions);
|
|
1397
|
-
completed = true;
|
|
1398
|
-
return result;
|
|
1439
|
+
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1399
1440
|
}
|
|
1400
1441
|
catch (e) {
|
|
1401
|
-
|
|
1402
|
-
(_c = this.v2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1403
|
-
this.resetProtocolV2Frames(uuid);
|
|
1404
|
-
}
|
|
1405
|
-
(_d = this.Log) === null || _d === void 0 ? void 0 : _d.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1442
|
+
(_a = this.Log) === null || _a === void 0 ? void 0 : _a.error('[Electron BLE] Protocol V2 call error:', e);
|
|
1406
1443
|
throw e;
|
|
1407
1444
|
}
|
|
1408
|
-
finally {
|
|
1409
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1410
|
-
if (!completed) {
|
|
1411
|
-
(_e = this.v2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
|
|
1412
|
-
}
|
|
1413
|
-
this.resetProtocolV2Frames(uuid);
|
|
1414
|
-
this.activeProtocolV2Call = null;
|
|
1415
|
-
}
|
|
1416
|
-
if (this.runPromise === runPromise) {
|
|
1417
|
-
this.runPromise = null;
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
1445
|
});
|
|
1421
1446
|
}
|
|
1447
|
+
createProtocolV2Adapter(uuid) {
|
|
1448
|
+
var _a;
|
|
1449
|
+
const generation = (_a = this.notificationTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1450
|
+
const assertCurrentGeneration = () => {
|
|
1451
|
+
if (this.notificationTokens.get(uuid) !== generation) {
|
|
1452
|
+
throw new Error(`Protocol V2 notification generation changed for ${uuid}`);
|
|
1453
|
+
}
|
|
1454
|
+
};
|
|
1455
|
+
return {
|
|
1456
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1457
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1458
|
+
generation,
|
|
1459
|
+
prepareCall: () => {
|
|
1460
|
+
var _a;
|
|
1461
|
+
assertCurrentGeneration();
|
|
1462
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1463
|
+
this.resetProtocolV2Frames(uuid);
|
|
1464
|
+
},
|
|
1465
|
+
writeFrame: (frame, context) => this.writeProtocolV2Frame(uuid, frame, context, assertCurrentGeneration),
|
|
1466
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1467
|
+
assertCurrentGeneration();
|
|
1468
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1469
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1470
|
+
throw new Error('Response is not Uint8Array');
|
|
1471
|
+
}
|
|
1472
|
+
return rxFrame;
|
|
1473
|
+
}),
|
|
1474
|
+
reset: (reason) => {
|
|
1475
|
+
var _a;
|
|
1476
|
+
(_a = this.v2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1477
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1478
|
+
},
|
|
1479
|
+
logger: this.Log,
|
|
1480
|
+
logPrefix: 'ProtocolV2 BLE',
|
|
1481
|
+
createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
|
|
1482
|
+
};
|
|
1483
|
+
}
|
|
1422
1484
|
processProtocolV1Notification(deviceId, hexData) {
|
|
1423
1485
|
try {
|
|
1424
1486
|
if (typeof hexData !== 'string') {
|