@onekeyfe/hd-transport-web-device 1.2.0-alpha.2 → 1.2.0-alpha.21
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 +102 -8
- package/__tests__/webusb-protocol-v2-timeout.test.ts +63 -0
- package/dist/electron-ble-transport.d.ts +4 -4
- package/dist/electron-ble-transport.d.ts.map +1 -1
- package/dist/index.d.ts +96 -4
- package/dist/index.js +162 -177
- package/dist/transportLog.d.ts +7 -0
- package/dist/transportLog.d.ts.map +1 -0
- package/dist/webusb.d.ts +2 -0
- package/dist/webusb.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/electron-ble-transport.ts +111 -138
- package/src/transportLog.ts +11 -0
- package/src/webusb.ts +76 -78
package/dist/webusb.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export default class WebUsbTransport {
|
|
|
13
13
|
private deviceProtocolHints;
|
|
14
14
|
private protocolV2Assemblers;
|
|
15
15
|
private protocolV2Sessions;
|
|
16
|
+
private protocolV2Sequences;
|
|
16
17
|
private protocolV2ReadTimeouts;
|
|
17
18
|
private deviceEndpoints;
|
|
18
19
|
private mockSerialPaths;
|
|
@@ -50,6 +51,7 @@ export default class WebUsbTransport {
|
|
|
50
51
|
private getTransferInData;
|
|
51
52
|
private toArrayBuffer;
|
|
52
53
|
private transferOutWithRetry;
|
|
54
|
+
private transferOutOnce;
|
|
53
55
|
private transferInWithRetry;
|
|
54
56
|
private resetConnectionAfterProbe;
|
|
55
57
|
private withProtocolReadTimeout;
|
package/dist/webusb.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":";AACA,OAAO,SAWN,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"webusb.d.ts","sourceRoot":"","sources":["../src/webusb.ts"],"names":[],"mappings":";AACA,OAAO,SAWN,MAAM,wBAAwB,CAAC;AAYhC,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAqBhC,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B;AAaD,MAAM,CAAC,OAAO,OAAO,eAAe;IAClC,QAAQ,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGlE,UAAU,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAGpE,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAGnE,OAAO,CAAC,oBAAoB,CAAoD;IAGhF,OAAO,CAAC,kBAAkB,CAA6C;IAGvE,OAAO,CAAC,mBAAmB,CAAoD;IAG/E,OAAO,CAAC,sBAAsB,CAA8C;IAG5E,OAAO,CAAC,eAAe,CAA2C;IAMlE,OAAO,CAAC,eAAe,CAA6C;IAEpE,OAAO,CAAC,iBAAiB,CAAK;IAE9B,IAAI,SAAqB;IAEzB,OAAO,UAAS;IAEhB,UAAU,UAAS;IAEnB,GAAG,CAAC,EAAE,GAAG,CAAC;IAEV,GAAG,CAAC,EAAE,GAAG,CAAC;IAMV,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAM;IAEnC,eAAe,SAAoB;IAEnC,UAAU,SAAe;IAEzB,WAAW,SAAgB;IAK3B,IAAI,CAAC,MAAM,EAAE,GAAG;IAgBhB,SAAS,CAAC,UAAU,EAAE,GAAG;IASzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAW7B,kBAAkB;IAmBlB,SAAS;IAQf,OAAO,CAAC,aAAa;IAmBf,mBAAmB;IAgCnB,OAAO,CAAC,KAAK,EAAE,YAAY;IA0BjC,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;YAOtB,cAAc;IAgDtB,UAAU,CAAC,IAAI,EAAE,MAAM;IAwBvB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;IAkB1C,OAAO,CAAC,iBAAiB;IAiCnB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;YAmCpC,eAAe;YAmBf,iBAAiB;IAezB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIvE,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,wBAAwB;YAalB,yBAAyB;IAiCvC,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;YASP,oBAAoB;YA2BpB,eAAe;YAaf,mBAAmB;YA2CnB,yBAAyB;YAyBzB,uBAAuB;YAmCvB,eAAe;YAaf,eAAe;IAgBvB,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA8BlB,cAAc;YAkCd,cAAc;YA6Dd,sBAAsB;IA4C9B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;IAgD5C,OAAO,CAAC,IAAI,EAAE,MAAM;IAmB1B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-web-device",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.21",
|
|
4
4
|
"author": "OneKey",
|
|
5
5
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,13 +20,13 @@
|
|
|
20
20
|
"lint:fix": "eslint . --fix"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.21",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.21"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@onekeyfe/hd-transport-electron": "1.2.0-alpha.
|
|
27
|
+
"@onekeyfe/hd-transport-electron": "1.2.0-alpha.21",
|
|
28
28
|
"@types/w3c-web-usb": "^1.0.6",
|
|
29
29
|
"@types/web-bluetooth": "^0.0.17"
|
|
30
30
|
},
|
|
31
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "efe594367fb3b196a5126baee7e2aba3e94986cd"
|
|
32
32
|
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import transport, {
|
|
2
|
-
LogBlockCommand,
|
|
3
2
|
PROTOCOL_V1_MESSAGE_HEADER_SIZE,
|
|
4
3
|
PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
5
4
|
ProtocolV2FrameAssembler,
|
|
6
|
-
|
|
5
|
+
ProtocolV2LinkManager,
|
|
7
6
|
bytesToHex,
|
|
8
7
|
hexToBytes,
|
|
9
8
|
probeProtocolV2 as probeProtocolV2Helper,
|
|
@@ -17,22 +16,13 @@ import {
|
|
|
17
16
|
wait,
|
|
18
17
|
} from '@onekeyfe/hd-shared';
|
|
19
18
|
|
|
19
|
+
import { createTransportCallLog, shouldSuppressHighVolumeCallLog } from './transportLog';
|
|
20
|
+
|
|
20
21
|
import type { Deferred } from '@onekeyfe/hd-shared';
|
|
21
22
|
import type { DesktopAPI } from '@onekeyfe/hd-transport-electron';
|
|
22
23
|
import type { OneKeyDeviceInfo, ProtocolType, TransportCallOptions } from '@onekeyfe/hd-transport';
|
|
23
24
|
import type EventEmitter from 'events';
|
|
24
25
|
|
|
25
|
-
const FILE_WRITE_LOG_BLOCK_PATTERN = /(?:^|[^a-z])(?:raw)?(?:filesystem|emmc)?filewrite$/i;
|
|
26
|
-
|
|
27
|
-
function shouldSuppressHighVolumeCallLog(name: string) {
|
|
28
|
-
const normalized = name.replace(/[_\s-]/g, '');
|
|
29
|
-
return FILE_WRITE_LOG_BLOCK_PATTERN.test(normalized);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function isLogBlockCommand(name: string) {
|
|
33
|
-
return (LogBlockCommand as Set<string> | undefined)?.has?.(name) ?? false;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
26
|
const { parseConfigure, ProtocolV1, check } = transport;
|
|
37
27
|
|
|
38
28
|
declare global {
|
|
@@ -72,8 +62,6 @@ const toBleDescriptor = (
|
|
|
72
62
|
|
|
73
63
|
const BLE_PACKET_SIZE = 192;
|
|
74
64
|
const BLE_WRITE_DELAY_MS = 5;
|
|
75
|
-
const BLE_WRITE_MAX_RETRIES = 3;
|
|
76
|
-
const BLE_WRITE_RETRY_DELAY_MS = 300;
|
|
77
65
|
const BLE_RESPONSE_TIMEOUT_MS = 30_000;
|
|
78
66
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
79
67
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 5000;
|
|
@@ -113,9 +101,26 @@ export default class ElectronBleTransport {
|
|
|
113
101
|
|
|
114
102
|
private v2FramePromises: Map<string, Deferred<Uint8Array>> = new Map();
|
|
115
103
|
|
|
116
|
-
private
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
private protocolV2Links = new ProtocolV2LinkManager<string>({
|
|
105
|
+
getSchemas: () => {
|
|
106
|
+
if (!this._messages || !this._messagesV2) {
|
|
107
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
protocolV1: this._messages,
|
|
111
|
+
protocolV2: this._messagesV2,
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
classifyError: () => 'link-fatal',
|
|
115
|
+
onLinkInvalidated: async (uuid, reason) => {
|
|
116
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
117
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
118
|
+
this.Log?.debug('[Electron BLE] Protocol V2 link invalidated:', uuid, reason);
|
|
119
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
120
|
+
await this.release(uuid);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
});
|
|
119
124
|
|
|
120
125
|
private notificationCleanups: Map<string, () => void> = new Map();
|
|
121
126
|
|
|
@@ -157,6 +162,9 @@ export default class ElectronBleTransport {
|
|
|
157
162
|
}
|
|
158
163
|
|
|
159
164
|
private cleanupDeviceState(deviceId: string): void {
|
|
165
|
+
this.protocolV2Links
|
|
166
|
+
.invalidateLink(deviceId, 'Electron BLE device state cleaned')
|
|
167
|
+
.catch(error => this.Log?.debug('[Electron BLE] link cleanup failed:', error));
|
|
160
168
|
this.connectedDevices.delete(deviceId);
|
|
161
169
|
this.deviceProtocol.delete(deviceId);
|
|
162
170
|
// Keep deviceProtocolHints — it's inferred from device name (e.g. "Pro 2" → V2)
|
|
@@ -164,9 +172,6 @@ export default class ElectronBleTransport {
|
|
|
164
172
|
this.v1Buffers.delete(deviceId);
|
|
165
173
|
this.v2Assemblers.delete(deviceId);
|
|
166
174
|
this.resetProtocolV2Frames(deviceId);
|
|
167
|
-
if (this.activeProtocolV2Call?.uuid === deviceId) {
|
|
168
|
-
this.activeProtocolV2Call = null;
|
|
169
|
-
}
|
|
170
175
|
this.notificationTokens.delete(deviceId);
|
|
171
176
|
|
|
172
177
|
const notifyCleanup = this.notificationCleanups.get(deviceId);
|
|
@@ -203,7 +208,9 @@ export default class ElectronBleTransport {
|
|
|
203
208
|
|
|
204
209
|
configureProtocolV2(signedData: any) {
|
|
205
210
|
this._messagesV2 = parseConfigure(signedData);
|
|
206
|
-
this.
|
|
211
|
+
this.protocolV2Links
|
|
212
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
213
|
+
.catch(error => this.Log?.debug('[Electron BLE] schema link cleanup failed:', error));
|
|
207
214
|
}
|
|
208
215
|
|
|
209
216
|
async listen() {
|
|
@@ -238,12 +245,15 @@ export default class ElectronBleTransport {
|
|
|
238
245
|
throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
|
|
239
246
|
}
|
|
240
247
|
|
|
248
|
+
if (this.connectedDevices.has(uuid)) {
|
|
249
|
+
await this.release(uuid);
|
|
250
|
+
}
|
|
251
|
+
|
|
241
252
|
if (forceCleanRunPromise && this.runPromise) {
|
|
242
253
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
243
254
|
this.runPromise.reject(error);
|
|
244
255
|
this.rejectAllProtocolV2Frames(error);
|
|
245
256
|
this.runPromise = null;
|
|
246
|
-
this.activeProtocolV2Call = null;
|
|
247
257
|
}
|
|
248
258
|
|
|
249
259
|
try {
|
|
@@ -320,6 +330,7 @@ export default class ElectronBleTransport {
|
|
|
320
330
|
|
|
321
331
|
async release(id: string) {
|
|
322
332
|
try {
|
|
333
|
+
await this.protocolV2Links.invalidateLink(id, 'Electron BLE transport released');
|
|
323
334
|
if (this.connectedDevices.has(id)) {
|
|
324
335
|
if (window.desktopApi?.nobleBle) {
|
|
325
336
|
await window.desktopApi.nobleBle.unsubscribe(id);
|
|
@@ -368,23 +379,22 @@ export default class ElectronBleTransport {
|
|
|
368
379
|
}
|
|
369
380
|
|
|
370
381
|
if (expectedProtocol === 'V2') {
|
|
371
|
-
//
|
|
372
|
-
//
|
|
382
|
+
// Skip probing when the caller explicitly confirms V2, such as reconnect after a
|
|
383
|
+
// firmware reboot where expectedProtocol carries the previously probed result.
|
|
373
384
|
this.deviceProtocol.set(uuid, 'V2');
|
|
374
385
|
this.Log?.debug(`[Electron BLE] detectProtocol: uuid=${uuid} -> V2 (expected)`);
|
|
375
386
|
return 'V2';
|
|
376
387
|
}
|
|
377
388
|
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
// 不能作为最终结论。
|
|
389
|
+
// Protocol must be actively probed after connection. Name, PID, and descriptors only
|
|
390
|
+
// influence probe order; a V2 hint probes V2 first and falls back to V1.
|
|
381
391
|
const probeOrder: ProtocolType[] =
|
|
382
392
|
protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
383
393
|
|
|
384
394
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
385
395
|
const protocol = probeOrder[i];
|
|
386
396
|
if (i > 0) {
|
|
387
|
-
//
|
|
397
|
+
// Reset subscriptions and buffers after a failed probe before trying another protocol.
|
|
388
398
|
await this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
389
399
|
}
|
|
390
400
|
const detected =
|
|
@@ -417,12 +427,13 @@ export default class ElectronBleTransport {
|
|
|
417
427
|
}
|
|
418
428
|
|
|
419
429
|
private async resetProbeStateAfterProtocolProbe(uuid: string, protocol: ProtocolType) {
|
|
430
|
+
await this.protocolV2Links.invalidateLink(
|
|
431
|
+
uuid,
|
|
432
|
+
`Reset notify state after Protocol ${protocol} probe`
|
|
433
|
+
);
|
|
420
434
|
this.v1Buffers.set(uuid, { buffer: [], bufferLength: 0 });
|
|
421
435
|
this.v2Assemblers.get(uuid)?.reset();
|
|
422
436
|
this.resetProtocolV2Frames(uuid);
|
|
423
|
-
if (this.activeProtocolV2Call?.uuid === uuid) {
|
|
424
|
-
this.activeProtocolV2Call = null;
|
|
425
|
-
}
|
|
426
437
|
if (this.runPromise) {
|
|
427
438
|
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
428
439
|
this.runPromise.reject(error);
|
|
@@ -496,7 +507,7 @@ export default class ElectronBleTransport {
|
|
|
496
507
|
|
|
497
508
|
if (totalBytes <= BLE_PACKET_SIZE) {
|
|
498
509
|
await wait(BLE_WRITE_DELAY_MS);
|
|
499
|
-
await this.
|
|
510
|
+
await this.writeOnce(uuid, hexData);
|
|
500
511
|
return;
|
|
501
512
|
}
|
|
502
513
|
|
|
@@ -505,7 +516,7 @@ export default class ElectronBleTransport {
|
|
|
505
516
|
const chunkHex = hexData.substring(offset, offset + chunkHexLen);
|
|
506
517
|
offset += chunkHexLen;
|
|
507
518
|
|
|
508
|
-
await this.
|
|
519
|
+
await this.writeOnce(uuid, chunkHex);
|
|
509
520
|
|
|
510
521
|
if (offset < hexData.length) {
|
|
511
522
|
await wait(BLE_WRITE_DELAY_MS);
|
|
@@ -513,41 +524,23 @@ export default class ElectronBleTransport {
|
|
|
513
524
|
}
|
|
514
525
|
}
|
|
515
526
|
|
|
516
|
-
private async
|
|
517
|
-
let lastError: any;
|
|
527
|
+
private async writeOnce(uuid: string, hexData: string): Promise<void> {
|
|
518
528
|
const nobleBle = window.desktopApi?.nobleBle;
|
|
519
529
|
if (!nobleBle) {
|
|
520
530
|
throw new Error('Noble BLE API not available');
|
|
521
531
|
}
|
|
522
532
|
|
|
523
|
-
|
|
524
|
-
try {
|
|
525
|
-
await nobleBle.write(uuid, hexData);
|
|
526
|
-
return;
|
|
527
|
-
} catch (error) {
|
|
528
|
-
lastError = error;
|
|
529
|
-
this.Log?.error(
|
|
530
|
-
`[Electron BLE] write failed (attempt ${attempt}/${BLE_WRITE_MAX_RETRIES}):`,
|
|
531
|
-
error
|
|
532
|
-
);
|
|
533
|
-
if (attempt < BLE_WRITE_MAX_RETRIES) {
|
|
534
|
-
await wait(BLE_WRITE_RETRY_DELAY_MS);
|
|
535
|
-
}
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
throw ERRORS.TypedError(
|
|
539
|
-
HardwareErrorCode.BleWriteCharacteristicError,
|
|
540
|
-
`BLE write failed after ${BLE_WRITE_MAX_RETRIES} attempts: ${lastError?.message ?? lastError}`
|
|
541
|
-
);
|
|
533
|
+
await nobleBle.write(uuid, hexData);
|
|
542
534
|
}
|
|
543
535
|
|
|
544
536
|
private handleNotification(deviceId: string, hexData: string): void {
|
|
545
537
|
if (hexData === 'PAIRING_REJECTED') {
|
|
546
538
|
this.Log?.debug('[Electron BLE] Pairing rejection detected for device:', deviceId);
|
|
547
|
-
|
|
548
|
-
|
|
539
|
+
const error = ERRORS.TypedError(HardwareErrorCode.BleDeviceBondedCanceled);
|
|
540
|
+
if (this.deviceProtocol.get(deviceId) === 'V2') {
|
|
541
|
+
this.rejectProtocolV2Frames(deviceId, error);
|
|
542
|
+
} else if (this.runPromise) {
|
|
549
543
|
this.runPromise.reject(error);
|
|
550
|
-
this.rejectAllProtocolV2Frames(error);
|
|
551
544
|
}
|
|
552
545
|
return;
|
|
553
546
|
}
|
|
@@ -566,12 +559,6 @@ export default class ElectronBleTransport {
|
|
|
566
559
|
|
|
567
560
|
private handleProtocolV2Notification(deviceId: string, hexData: string): void {
|
|
568
561
|
try {
|
|
569
|
-
if (!this.runPromise || this.activeProtocolV2Call?.uuid !== deviceId) {
|
|
570
|
-
this.v2Assemblers.get(deviceId)?.reset();
|
|
571
|
-
this.resetProtocolV2Frames(deviceId);
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
562
|
const bytes = hexToBytes(hexData);
|
|
576
563
|
if (bytes.length === 0) return;
|
|
577
564
|
|
|
@@ -583,11 +570,8 @@ export default class ElectronBleTransport {
|
|
|
583
570
|
}
|
|
584
571
|
} catch (error) {
|
|
585
572
|
this.Log?.error('[Electron BLE] Protocol V2 notification error:', error);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
this.runPromise.reject(notifyError);
|
|
589
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
590
|
-
}
|
|
573
|
+
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
574
|
+
this.rejectProtocolV2Frames(deviceId, notifyError);
|
|
591
575
|
}
|
|
592
576
|
}
|
|
593
577
|
|
|
@@ -623,8 +607,13 @@ export default class ElectronBleTransport {
|
|
|
623
607
|
this.v2FramePromises.delete(uuid);
|
|
624
608
|
}
|
|
625
609
|
|
|
626
|
-
private
|
|
627
|
-
|
|
610
|
+
private rejectProtocolV2Frames(uuid: string, error: Error) {
|
|
611
|
+
this.v2FrameQueues.delete(uuid);
|
|
612
|
+
const framePromise = this.v2FramePromises.get(uuid);
|
|
613
|
+
if (framePromise) {
|
|
614
|
+
this.v2FramePromises.delete(uuid);
|
|
615
|
+
framePromise.reject(error);
|
|
616
|
+
}
|
|
628
617
|
}
|
|
629
618
|
|
|
630
619
|
private async readProtocolV2Frame(uuid: string) {
|
|
@@ -681,12 +670,8 @@ export default class ElectronBleTransport {
|
|
|
681
670
|
`Device protocol has not been detected for ${uuid}`
|
|
682
671
|
);
|
|
683
672
|
}
|
|
684
|
-
if (shouldSuppressHighVolumeCallLog(name)) {
|
|
685
|
-
|
|
686
|
-
} else if (isLogBlockCommand(name)) {
|
|
687
|
-
this.Log?.debug('[Electron BLE] call', 'name:', name, 'protocol:', protocol);
|
|
688
|
-
} else {
|
|
689
|
-
this.Log?.debug('[Electron BLE] call', 'name:', name, 'data:', data, 'protocol:', protocol);
|
|
673
|
+
if (!shouldSuppressHighVolumeCallLog(name)) {
|
|
674
|
+
this.Log?.debug('transport call', createTransportCallLog(name, protocol));
|
|
690
675
|
}
|
|
691
676
|
|
|
692
677
|
if (protocol === 'V2') {
|
|
@@ -776,79 +761,67 @@ export default class ElectronBleTransport {
|
|
|
776
761
|
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
777
762
|
}
|
|
778
763
|
|
|
779
|
-
const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'Ping';
|
|
780
|
-
if (this.runPromise) {
|
|
781
|
-
if (!forceRun) {
|
|
782
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
|
|
783
|
-
}
|
|
784
|
-
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
785
|
-
this.runPromise.reject(error);
|
|
786
|
-
this.rejectAllProtocolV2Frames(error);
|
|
787
|
-
this.runPromise = null;
|
|
788
|
-
this.activeProtocolV2Call = null;
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
const runPromise = createDeferred<Uint8Array | string>();
|
|
792
|
-
runPromise.promise.catch(() => undefined);
|
|
793
|
-
this.runPromise = runPromise;
|
|
794
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
795
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
796
|
-
this.v2Assemblers.get(uuid)?.reset();
|
|
797
|
-
this.resetProtocolV2Frames(uuid);
|
|
798
|
-
let completed = false;
|
|
799
764
|
const callOptions = {
|
|
800
765
|
...options,
|
|
801
766
|
timeoutMs: options?.timeoutMs ?? BLE_RESPONSE_TIMEOUT_MS,
|
|
802
767
|
};
|
|
803
768
|
|
|
804
769
|
try {
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
readFrame: async () => {
|
|
813
|
-
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
814
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
815
|
-
throw new Error('Response is not Uint8Array');
|
|
816
|
-
}
|
|
817
|
-
return rxFrame;
|
|
818
|
-
},
|
|
819
|
-
logger: this.Log,
|
|
820
|
-
logPrefix: 'ProtocolV2 BLE',
|
|
821
|
-
createTimeoutError: (_messageName: string, timeout: number) =>
|
|
822
|
-
ERRORS.TypedError(
|
|
823
|
-
HardwareErrorCode.BleTimeoutError,
|
|
824
|
-
`BLE response timeout after ${timeout}ms for ${name}`
|
|
825
|
-
),
|
|
826
|
-
});
|
|
827
|
-
|
|
828
|
-
const result = await session.call(name, data, callOptions);
|
|
829
|
-
completed = true;
|
|
830
|
-
return result;
|
|
770
|
+
return await this.protocolV2Links.call(
|
|
771
|
+
uuid,
|
|
772
|
+
() => this.createProtocolV2Adapter(uuid),
|
|
773
|
+
name,
|
|
774
|
+
data,
|
|
775
|
+
callOptions
|
|
776
|
+
);
|
|
831
777
|
} catch (e) {
|
|
832
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
833
|
-
this.v2Assemblers.get(uuid)?.reset();
|
|
834
|
-
this.resetProtocolV2Frames(uuid);
|
|
835
|
-
}
|
|
836
778
|
this.Log?.error('[Electron BLE] Protocol V2 call error:', e);
|
|
837
779
|
throw e;
|
|
838
|
-
} finally {
|
|
839
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
840
|
-
if (!completed) {
|
|
841
|
-
this.v2Assemblers.get(uuid)?.reset();
|
|
842
|
-
}
|
|
843
|
-
this.resetProtocolV2Frames(uuid);
|
|
844
|
-
this.activeProtocolV2Call = null;
|
|
845
|
-
}
|
|
846
|
-
if (this.runPromise === runPromise) {
|
|
847
|
-
this.runPromise = null;
|
|
848
|
-
}
|
|
849
780
|
}
|
|
850
781
|
}
|
|
851
782
|
|
|
783
|
+
private createProtocolV2Adapter(uuid: string) {
|
|
784
|
+
const generation = this.notificationTokens.get(uuid) ?? 0;
|
|
785
|
+
const assertCurrentGeneration = () => {
|
|
786
|
+
if (this.notificationTokens.get(uuid) !== generation) {
|
|
787
|
+
throw new Error(`Protocol V2 notification generation changed for ${uuid}`);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
return {
|
|
792
|
+
router: PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
793
|
+
generation,
|
|
794
|
+
prepareCall: () => {
|
|
795
|
+
assertCurrentGeneration();
|
|
796
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
797
|
+
this.resetProtocolV2Frames(uuid);
|
|
798
|
+
},
|
|
799
|
+
writeFrame: (frame: Uint8Array) => {
|
|
800
|
+
assertCurrentGeneration();
|
|
801
|
+
return this.writeWithChunking(uuid, bytesToHex(frame));
|
|
802
|
+
},
|
|
803
|
+
readFrame: async () => {
|
|
804
|
+
assertCurrentGeneration();
|
|
805
|
+
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
806
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
807
|
+
throw new Error('Response is not Uint8Array');
|
|
808
|
+
}
|
|
809
|
+
return rxFrame;
|
|
810
|
+
},
|
|
811
|
+
reset: (reason: string) => {
|
|
812
|
+
this.v2Assemblers.get(uuid)?.reset();
|
|
813
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
814
|
+
},
|
|
815
|
+
logger: this.Log,
|
|
816
|
+
logPrefix: 'ProtocolV2 BLE',
|
|
817
|
+
createTimeoutError: (messageName: string, timeout: number) =>
|
|
818
|
+
ERRORS.TypedError(
|
|
819
|
+
HardwareErrorCode.BleTimeoutError,
|
|
820
|
+
`BLE response timeout after ${timeout}ms for ${messageName}`
|
|
821
|
+
),
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
852
825
|
private processProtocolV1Notification(deviceId: string, hexData: string): PacketProcessResult {
|
|
853
826
|
try {
|
|
854
827
|
if (typeof hexData !== 'string') {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ProtocolType } from '@onekeyfe/hd-transport';
|
|
2
|
+
|
|
3
|
+
const HIGH_VOLUME_CALLS = new Set(['FileWrite', 'FilesystemFileWrite', 'EmmcFileWrite']);
|
|
4
|
+
|
|
5
|
+
export function shouldSuppressHighVolumeCallLog(name: string) {
|
|
6
|
+
return HIGH_VOLUME_CALLS.has(name);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function createTransportCallLog(name: string, protocol: ProtocolType) {
|
|
10
|
+
return { name, protocol };
|
|
11
|
+
}
|