@onekeyfe/hd-transport-react-native 1.1.27-alpha.42 → 1.1.27-alpha.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BleManager.d.ts.map +1 -1
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts.map +1 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +275 -111
- package/package.json +5 -5
- package/src/BleManager.ts +4 -7
- package/src/BleTransport.ts +2 -2
- package/src/bleStrategy.ts +1 -3
- package/src/index.ts +328 -129
package/dist/BleManager.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BleManager.d.ts","sourceRoot":"","sources":["../src/BleManager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BleManager.d.ts","sourceRoot":"","sources":["../src/BleManager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AASnE,eAAO,MAAM,qBAAqB,iBAAkB,MAAM,EAAE,0BACZ,CAAC;AAEjD,eAAO,MAAM,gBAAgB,6BAAwC,CAAC;AAEtE,eAAO,MAAM,UAAU,eAAgB,MAAM;;;EAAoC,CAAC;AAElF,eAAO,MAAM,iBAAiB,kBAAmB,MAAM,KAAG,QAAQ,UAAU,GAAG,SAAS,CA+BpF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,SAAM;IAEb,mBAAmB,EAAE,cAAc,CAAC;IAEpC,oBAAoB,EAAE,cAAc,CAAC;IAErC,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAElC,sBAAsB,CAAC,EAAE,YAAY,CAAC;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,MAAM,CAAC,WAAW,SAAK;IAEvB,MAAM,CAAC,WAAW,SAAQ;gBAGxB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;IAchC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;CA2BzF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bleStrategy.d.ts","sourceRoot":"","sources":["../src/bleStrategy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE9D,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"bleStrategy.d.ts","sourceRoot":"","sources":["../src/bleStrategy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE9D,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,WAEvE;AAED,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,kBAAkB,EAClC,aAAa,GAAE,YAAgC,GAC9C,YAAY,CAkBd;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,QAAQ,EACR,eAAmC,EACnC,mBAA2C,EAC3C,GAAG,GACJ,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,UAWA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
import * as transport from '@onekeyfe/hd-transport';
|
|
2
2
|
import transport__default, { ProtocolType, OneKeyDeviceInfoBase, TransportCallOptions } from '@onekeyfe/hd-transport';
|
|
3
|
-
import { Device,
|
|
3
|
+
import { Device, Characteristic, Subscription, BleManager } from 'react-native-ble-plx';
|
|
4
4
|
import { Deferred } from '@onekeyfe/hd-shared';
|
|
5
5
|
import EventEmitter from 'events';
|
|
6
6
|
|
|
7
|
+
declare class BleTransport {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
device: Device;
|
|
11
|
+
mtuSize: number;
|
|
12
|
+
writeCharacteristic: Characteristic;
|
|
13
|
+
notifyCharacteristic: Characteristic;
|
|
14
|
+
notifySubscription?: Subscription;
|
|
15
|
+
disconnectSubscription?: Subscription;
|
|
16
|
+
notifyTransactionId?: string;
|
|
17
|
+
monitorToken?: number;
|
|
18
|
+
static MAX_RETRIES: number;
|
|
19
|
+
static RETRY_DELAY: number;
|
|
20
|
+
constructor(device: Device, writeCharacteristic: Characteristic, notifyCharacteristic: Characteristic);
|
|
21
|
+
writeWithRetry(data: string, retryCount?: number): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
7
24
|
type TransportOptions = {
|
|
8
25
|
scanTimeout?: number;
|
|
9
26
|
};
|
|
@@ -13,6 +30,10 @@ type BleAcquireInput = {
|
|
|
13
30
|
expectedProtocol?: ProtocolType;
|
|
14
31
|
};
|
|
15
32
|
|
|
33
|
+
type ResolvedBleCharacteristics = {
|
|
34
|
+
writeCharacteristic: Characteristic;
|
|
35
|
+
notifyCharacteristic: Characteristic;
|
|
36
|
+
};
|
|
16
37
|
type ProtocolV2BleTuning = {
|
|
17
38
|
iosPacketLength?: number;
|
|
18
39
|
androidPacketLength?: number;
|
|
@@ -42,6 +63,7 @@ declare class ReactNativeBleTransport {
|
|
|
42
63
|
scanTimeout: number;
|
|
43
64
|
runPromise: Deferred<any> | null;
|
|
44
65
|
emitter?: EventEmitter;
|
|
66
|
+
firmwareUploadWriteRecoveryIds: Set<string>;
|
|
45
67
|
private deviceProtocol;
|
|
46
68
|
private deviceProtocolHints;
|
|
47
69
|
private protocolV2Assemblers;
|
|
@@ -57,6 +79,9 @@ declare class ReactNativeBleTransport {
|
|
|
57
79
|
configureProtocolV2(signedData: any): void;
|
|
58
80
|
listen(): void;
|
|
59
81
|
getPlxManager(): Promise<BleManager>;
|
|
82
|
+
resolveCharacteristics(device: Device): Promise<ResolvedBleCharacteristics>;
|
|
83
|
+
attachDisconnectSubscription(transport: BleTransport, device: Device, uuid: string): void;
|
|
84
|
+
reconnectFirmwareUploadTransport(uuid: string, transport: BleTransport): Promise<void>;
|
|
60
85
|
enumerate(): Promise<IOneKeyDevice[]>;
|
|
61
86
|
acquire(input: BleAcquireInput): Promise<{
|
|
62
87
|
uuid: string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAEhB,KAAK,oBAAoB,EAGzB,KAAK,YAAY,EAGjB,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -60,8 +60,6 @@ const Logger = bleLogger;
|
|
|
60
60
|
const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
|
|
61
61
|
const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
|
|
62
62
|
const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
|
|
63
|
-
let timeout;
|
|
64
|
-
let cleanupListener;
|
|
65
63
|
const cleanup = () => {
|
|
66
64
|
if (timeout) {
|
|
67
65
|
clearTimeout(timeout);
|
|
@@ -69,11 +67,11 @@ const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
|
|
|
69
67
|
if (cleanupListener)
|
|
70
68
|
cleanupListener();
|
|
71
69
|
};
|
|
72
|
-
timeout = setTimeout(() => {
|
|
70
|
+
const timeout = setTimeout(() => {
|
|
73
71
|
cleanup();
|
|
74
72
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
|
|
75
73
|
}, 60 * 1000);
|
|
76
|
-
cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
|
|
74
|
+
const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
|
|
77
75
|
var _a;
|
|
78
76
|
if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
|
|
79
77
|
return;
|
|
@@ -266,6 +264,35 @@ BleTransport.RETRY_DELAY = 2000;
|
|
|
266
264
|
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
267
265
|
const Log = bleLogger;
|
|
268
266
|
const transportCache = {};
|
|
267
|
+
const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
|
|
268
|
+
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
269
|
+
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
|
|
270
|
+
const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
|
|
271
|
+
const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
|
|
272
|
+
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
273
|
+
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
274
|
+
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
275
|
+
const delay = (ms) => new Promise(resolve => {
|
|
276
|
+
setTimeout(resolve, ms);
|
|
277
|
+
});
|
|
278
|
+
const getFirmwareUploadWriteRetryType = (error) => {
|
|
279
|
+
if (!error || typeof error !== 'object')
|
|
280
|
+
return null;
|
|
281
|
+
const bleWriteError = error;
|
|
282
|
+
if (bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
283
|
+
bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
284
|
+
return 'reconnectable';
|
|
285
|
+
}
|
|
286
|
+
if (bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
|
|
287
|
+
bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS) {
|
|
288
|
+
return 'congested';
|
|
289
|
+
}
|
|
290
|
+
const text = [bleWriteError.reason, bleWriteError.message, bleWriteError.name]
|
|
291
|
+
.filter(value => typeof value === 'string')
|
|
292
|
+
.join(' ');
|
|
293
|
+
return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
|
|
294
|
+
};
|
|
295
|
+
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
269
296
|
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
270
297
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
271
298
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
@@ -275,9 +302,6 @@ const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
|
275
302
|
const HIGH_VOLUME_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 6;
|
|
276
303
|
const HIGH_VOLUME_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 6 : 2;
|
|
277
304
|
const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 20 : 8;
|
|
278
|
-
const delay = (ms) => new Promise(resolve => {
|
|
279
|
-
setTimeout(resolve, ms);
|
|
280
|
-
});
|
|
281
305
|
const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
|
|
282
306
|
iosPacketLength: IOS_PACKET_LENGTH,
|
|
283
307
|
androidPacketLength: ANDROID_PACKET_LENGTH,
|
|
@@ -384,6 +408,7 @@ class ReactNativeBleTransport {
|
|
|
384
408
|
this.stopped = false;
|
|
385
409
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
386
410
|
this.runPromise = null;
|
|
411
|
+
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
387
412
|
this.deviceProtocol = new Map();
|
|
388
413
|
this.deviceProtocolHints = new Map();
|
|
389
414
|
this.protocolV2Assemblers = new Map();
|
|
@@ -416,6 +441,163 @@ class ReactNativeBleTransport {
|
|
|
416
441
|
this.blePlxManager = new reactNativeBlePlx.BleManager();
|
|
417
442
|
return Promise.resolve(this.blePlxManager);
|
|
418
443
|
}
|
|
444
|
+
resolveCharacteristics(device) {
|
|
445
|
+
var _a, _b, _c, _d;
|
|
446
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
447
|
+
yield device.discoverAllServicesAndCharacteristics();
|
|
448
|
+
let infos = tryToGetConfiguration(device);
|
|
449
|
+
let characteristics;
|
|
450
|
+
if (!infos) {
|
|
451
|
+
for (const serviceUuid of getBluetoothServiceUuids()) {
|
|
452
|
+
try {
|
|
453
|
+
characteristics = yield device.characteristicsForService(serviceUuid);
|
|
454
|
+
infos = getInfosForServiceUuid(serviceUuid, 'classic');
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
catch (e) {
|
|
458
|
+
Log === null || Log === void 0 ? void 0 : Log.error(e);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
let fallbackServiceUuid;
|
|
463
|
+
if (!infos) {
|
|
464
|
+
const services = yield device.services();
|
|
465
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Known OneKey service UUID not found, discovered services:', services === null || services === void 0 ? void 0 : services.map(service => service.uuid));
|
|
466
|
+
const knownService = services.find(service => getInfosForServiceUuid(service.uuid, 'classic'));
|
|
467
|
+
const fallbackService = (_a = knownService !== null && knownService !== void 0 ? knownService : services.find(service => !isGenericBleService(service.uuid))) !== null && _a !== void 0 ? _a : services[0];
|
|
468
|
+
if (fallbackService) {
|
|
469
|
+
fallbackServiceUuid = fallbackService.uuid;
|
|
470
|
+
characteristics = yield device.characteristicsForService(fallbackService.uuid);
|
|
471
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (!infos && !fallbackServiceUuid) {
|
|
475
|
+
try {
|
|
476
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
477
|
+
yield device.cancelConnection();
|
|
478
|
+
}
|
|
479
|
+
catch (e) {
|
|
480
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection error when service not found: ', e.message || e.reason);
|
|
481
|
+
}
|
|
482
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
483
|
+
}
|
|
484
|
+
const serviceUuid = (_b = infos === null || infos === void 0 ? void 0 : infos.serviceUuid) !== null && _b !== void 0 ? _b : fallbackServiceUuid;
|
|
485
|
+
const writeUuid = (_c = infos === null || infos === void 0 ? void 0 : infos.writeUuid) !== null && _c !== void 0 ? _c : '00000002-0000-1000-8000-00805f9b34fb';
|
|
486
|
+
const notifyUuid = (_d = infos === null || infos === void 0 ? void 0 : infos.notifyUuid) !== null && _d !== void 0 ? _d : '00000003-0000-1000-8000-00805f9b34fb';
|
|
487
|
+
if (!serviceUuid) {
|
|
488
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
489
|
+
}
|
|
490
|
+
if (!characteristics) {
|
|
491
|
+
characteristics = yield device.characteristicsForService(serviceUuid);
|
|
492
|
+
}
|
|
493
|
+
if (!characteristics) {
|
|
494
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound);
|
|
495
|
+
}
|
|
496
|
+
let writeCharacteristic;
|
|
497
|
+
let notifyCharacteristic;
|
|
498
|
+
for (const c of characteristics) {
|
|
499
|
+
if (isSameBleUuid(c.uuid, writeUuid)) {
|
|
500
|
+
writeCharacteristic = c;
|
|
501
|
+
}
|
|
502
|
+
else if (isSameBleUuid(c.uuid, notifyUuid)) {
|
|
503
|
+
notifyCharacteristic = c;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
if (!writeCharacteristic) {
|
|
507
|
+
throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: write characteristic not found');
|
|
508
|
+
}
|
|
509
|
+
if (!notifyCharacteristic) {
|
|
510
|
+
throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
511
|
+
}
|
|
512
|
+
if (!hasWritableCapability(writeCharacteristic)) {
|
|
513
|
+
throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
514
|
+
}
|
|
515
|
+
if (!notifyCharacteristic.isNotifiable) {
|
|
516
|
+
throw hdShared.ERRORS.TypedError('BLECharacteristicNotNotifiable: notify characteristic not notifiable');
|
|
517
|
+
}
|
|
518
|
+
return {
|
|
519
|
+
writeCharacteristic,
|
|
520
|
+
notifyCharacteristic,
|
|
521
|
+
};
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
attachDisconnectSubscription(transport, device, uuid) {
|
|
525
|
+
var _a;
|
|
526
|
+
(_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
527
|
+
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
528
|
+
var _a;
|
|
529
|
+
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
530
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
if (transportCache[uuid] !== transport) {
|
|
534
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale transport: ', device === null || device === void 0 ? void 0 : device.id);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
try {
|
|
538
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
539
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
|
|
540
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
541
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
542
|
+
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
543
|
+
});
|
|
544
|
+
if (this.runPromise) {
|
|
545
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
546
|
+
this.runPromise.reject(error);
|
|
547
|
+
this.rejectAllProtocolV2Frames(error);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
catch (e) {
|
|
551
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
|
|
552
|
+
}
|
|
553
|
+
finally {
|
|
554
|
+
this.release(uuid, true);
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
reconnectFirmwareUploadTransport(uuid, transport) {
|
|
559
|
+
var _a, _b;
|
|
560
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
561
|
+
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
562
|
+
try {
|
|
563
|
+
(_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
564
|
+
transport.disconnectSubscription = undefined;
|
|
565
|
+
(_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
566
|
+
transport.notifySubscription = undefined;
|
|
567
|
+
let { device } = transport;
|
|
568
|
+
const isConnected = yield device.isConnected().catch(() => false);
|
|
569
|
+
if (!isConnected) {
|
|
570
|
+
try {
|
|
571
|
+
device = yield device.connect(connectOptions);
|
|
572
|
+
}
|
|
573
|
+
catch (e) {
|
|
574
|
+
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
575
|
+
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
576
|
+
device = yield device.connect();
|
|
577
|
+
}
|
|
578
|
+
else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
579
|
+
throw e;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(device);
|
|
584
|
+
transport.device = device;
|
|
585
|
+
transport.writeCharacteristic = writeCharacteristic;
|
|
586
|
+
transport.notifyCharacteristic = notifyCharacteristic;
|
|
587
|
+
const monitorToken = this.nextMonitorToken;
|
|
588
|
+
this.nextMonitorToken += 1;
|
|
589
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
590
|
+
transport.monitorToken = monitorToken;
|
|
591
|
+
transport.notifyTransactionId = notifyTransactionId;
|
|
592
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
593
|
+
transport.notifySubscription = this._monitorCharacteristic(notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
594
|
+
this.attachDisconnectSubscription(transport, device, uuid);
|
|
595
|
+
}
|
|
596
|
+
finally {
|
|
597
|
+
this.firmwareUploadWriteRecoveryIds.delete(uuid);
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
419
601
|
enumerate() {
|
|
420
602
|
return __awaiter(this, void 0, void 0, function* () {
|
|
421
603
|
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -522,7 +704,7 @@ class ReactNativeBleTransport {
|
|
|
522
704
|
});
|
|
523
705
|
}
|
|
524
706
|
acquire(input) {
|
|
525
|
-
var _a, _b
|
|
707
|
+
var _a, _b;
|
|
526
708
|
return __awaiter(this, void 0, void 0, function* () {
|
|
527
709
|
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
528
710
|
if (!uuid) {
|
|
@@ -629,82 +811,10 @@ class ReactNativeBleTransport {
|
|
|
629
811
|
}
|
|
630
812
|
}
|
|
631
813
|
device = yield requestAndroidMtu(device);
|
|
632
|
-
yield
|
|
633
|
-
let infos = tryToGetConfiguration(device);
|
|
634
|
-
let characteristics;
|
|
635
|
-
let fallbackServiceUuid;
|
|
636
|
-
if (!infos) {
|
|
637
|
-
for (const serviceUuid of getBluetoothServiceUuids()) {
|
|
638
|
-
try {
|
|
639
|
-
characteristics = yield device.characteristicsForService(serviceUuid);
|
|
640
|
-
infos = getInfosForServiceUuid(serviceUuid, 'classic');
|
|
641
|
-
break;
|
|
642
|
-
}
|
|
643
|
-
catch (e) {
|
|
644
|
-
Log === null || Log === void 0 ? void 0 : Log.error(e);
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
if (!infos) {
|
|
649
|
-
const services = yield device.services();
|
|
650
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Known OneKey service UUID not found, discovered services:', services === null || services === void 0 ? void 0 : services.map(service => service.uuid));
|
|
651
|
-
const knownService = services.find(service => getInfosForServiceUuid(service.uuid, 'classic'));
|
|
652
|
-
const fallbackService = (_a = knownService !== null && knownService !== void 0 ? knownService : services.find(service => !isGenericBleService(service.uuid))) !== null && _a !== void 0 ? _a : services[0];
|
|
653
|
-
if (fallbackService) {
|
|
654
|
-
fallbackServiceUuid = fallbackService.uuid;
|
|
655
|
-
characteristics = yield device.characteristicsForService(fallbackService.uuid);
|
|
656
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
if (!infos) {
|
|
660
|
-
if (!fallbackServiceUuid) {
|
|
661
|
-
try {
|
|
662
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
663
|
-
yield device.cancelConnection();
|
|
664
|
-
}
|
|
665
|
-
catch (e) {
|
|
666
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection error when service not found: ', e.message || e.reason);
|
|
667
|
-
}
|
|
668
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
const serviceUuid = (_b = infos === null || infos === void 0 ? void 0 : infos.serviceUuid) !== null && _b !== void 0 ? _b : fallbackServiceUuid;
|
|
672
|
-
const writeUuid = (_c = infos === null || infos === void 0 ? void 0 : infos.writeUuid) !== null && _c !== void 0 ? _c : '00000002-0000-1000-8000-00805f9b34fb';
|
|
673
|
-
const notifyUuid = (_d = infos === null || infos === void 0 ? void 0 : infos.notifyUuid) !== null && _d !== void 0 ? _d : '00000003-0000-1000-8000-00805f9b34fb';
|
|
674
|
-
if (!serviceUuid) {
|
|
675
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
676
|
-
}
|
|
677
|
-
if (!characteristics) {
|
|
678
|
-
characteristics = yield device.characteristicsForService(serviceUuid);
|
|
679
|
-
}
|
|
680
|
-
if (!characteristics) {
|
|
681
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound);
|
|
682
|
-
}
|
|
683
|
-
let writeCharacteristic;
|
|
684
|
-
let notifyCharacteristic;
|
|
685
|
-
for (const c of characteristics) {
|
|
686
|
-
if (isSameBleUuid(c.uuid, writeUuid)) {
|
|
687
|
-
writeCharacteristic = c;
|
|
688
|
-
}
|
|
689
|
-
else if (isSameBleUuid(c.uuid, notifyUuid)) {
|
|
690
|
-
notifyCharacteristic = c;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
if (!writeCharacteristic) {
|
|
694
|
-
throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: write characteristic not found');
|
|
695
|
-
}
|
|
696
|
-
if (!notifyCharacteristic) {
|
|
697
|
-
throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
698
|
-
}
|
|
699
|
-
if (!hasWritableCapability(writeCharacteristic)) {
|
|
700
|
-
throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
701
|
-
}
|
|
702
|
-
if (!notifyCharacteristic.isNotifiable) {
|
|
703
|
-
throw hdShared.ERRORS.TypedError('BLECharacteristicNotNotifiable: notify characteristic not notifiable');
|
|
704
|
-
}
|
|
814
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(device);
|
|
705
815
|
const protocolHint = expectedProtocol
|
|
706
816
|
? undefined
|
|
707
|
-
: (
|
|
817
|
+
: (_a = this.deviceProtocolHints.get(uuid)) !== null && _a !== void 0 ? _a : inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
|
|
708
818
|
yield this.release(uuid, true);
|
|
709
819
|
if (protocolHint) {
|
|
710
820
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
@@ -731,37 +841,12 @@ class ReactNativeBleTransport {
|
|
|
731
841
|
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
732
842
|
}
|
|
733
843
|
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
734
|
-
(
|
|
844
|
+
(_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
|
|
735
845
|
name: device.name,
|
|
736
846
|
id: device.id,
|
|
737
847
|
connectId: device.id,
|
|
738
848
|
});
|
|
739
|
-
transport$1
|
|
740
|
-
var _a;
|
|
741
|
-
if (transportCache[uuid] !== transport$1) {
|
|
742
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale transport: ', device === null || device === void 0 ? void 0 : device.id);
|
|
743
|
-
return;
|
|
744
|
-
}
|
|
745
|
-
try {
|
|
746
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
747
|
-
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
|
|
748
|
-
name: device === null || device === void 0 ? void 0 : device.name,
|
|
749
|
-
id: device === null || device === void 0 ? void 0 : device.id,
|
|
750
|
-
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
751
|
-
});
|
|
752
|
-
if (this.runPromise) {
|
|
753
|
-
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
754
|
-
this.runPromise.reject(error);
|
|
755
|
-
this.rejectAllProtocolV2Frames(error);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
catch (e) {
|
|
759
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
|
|
760
|
-
}
|
|
761
|
-
finally {
|
|
762
|
-
this.release(uuid, true);
|
|
763
|
-
}
|
|
764
|
-
});
|
|
849
|
+
this.attachDisconnectSubscription(transport$1, device, uuid);
|
|
765
850
|
return { uuid, protocolType };
|
|
766
851
|
});
|
|
767
852
|
}
|
|
@@ -773,6 +858,10 @@ class ReactNativeBleTransport {
|
|
|
773
858
|
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
774
859
|
if (error) {
|
|
775
860
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
861
|
+
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
862
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('notify error ignored during FirmwareUpload write recovery: ', uuid);
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
776
865
|
if (!isCurrentMonitor) {
|
|
777
866
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
778
867
|
return;
|
|
@@ -975,6 +1064,36 @@ class ReactNativeBleTransport {
|
|
|
975
1064
|
}
|
|
976
1065
|
});
|
|
977
1066
|
}
|
|
1067
|
+
function writeFirmwareUploadChunkedData(buffers, writeFunction, onError) {
|
|
1068
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1069
|
+
let index = 0;
|
|
1070
|
+
let packetsWritten = 0;
|
|
1071
|
+
let chunk = ByteBuffer__default["default"].allocate(FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY);
|
|
1072
|
+
while (index < buffers.length) {
|
|
1073
|
+
const buffer = buffers[index].toBuffer();
|
|
1074
|
+
chunk.append(buffer);
|
|
1075
|
+
index += 1;
|
|
1076
|
+
if (chunk.offset === FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY || index >= buffers.length) {
|
|
1077
|
+
chunk.reset();
|
|
1078
|
+
try {
|
|
1079
|
+
yield writeFunction(chunk.toString('base64'));
|
|
1080
|
+
packetsWritten += 1;
|
|
1081
|
+
chunk = ByteBuffer__default["default"].allocate(FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY);
|
|
1082
|
+
if (packetsWritten % FIRMWARE_UPLOAD_WRITE_BURST_SIZE === 0 && index < buffers.length) {
|
|
1083
|
+
yield delay(FIRMWARE_UPLOAD_WRITE_PAUSE_MS);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
catch (e) {
|
|
1087
|
+
onError(e);
|
|
1088
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
if (packetsWritten > 0) {
|
|
1093
|
+
yield delay(FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS);
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
978
1097
|
if (name === 'EmmcFileWrite') {
|
|
979
1098
|
yield writeChunkedData(buffers, data => transport.writeWithRetry(data), e => {
|
|
980
1099
|
this.runPromise = null;
|
|
@@ -982,8 +1101,53 @@ class ReactNativeBleTransport {
|
|
|
982
1101
|
});
|
|
983
1102
|
}
|
|
984
1103
|
else if (name === 'FirmwareUpload') {
|
|
985
|
-
|
|
986
|
-
|
|
1104
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write uses throttled BLE packets:', {
|
|
1105
|
+
packetCapacity: FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY,
|
|
1106
|
+
burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
|
|
1107
|
+
pauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
|
|
1108
|
+
flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
|
|
1109
|
+
maxRetries: FIRMWARE_UPLOAD_WRITE_MAX_RETRIES,
|
|
1110
|
+
});
|
|
1111
|
+
yield writeFirmwareUploadChunkedData(buffers, (data) => __awaiter(this, void 0, void 0, function* () {
|
|
1112
|
+
let attempt = 0;
|
|
1113
|
+
while (true) {
|
|
1114
|
+
try {
|
|
1115
|
+
yield transport.writeCharacteristic.writeWithoutResponse(data);
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
catch (error) {
|
|
1119
|
+
const retryType = getFirmwareUploadWriteRetryType(error);
|
|
1120
|
+
if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1121
|
+
throw error;
|
|
1122
|
+
}
|
|
1123
|
+
const shouldReconnect = retryType === 'reconnectable';
|
|
1124
|
+
const delayMs = shouldReconnect
|
|
1125
|
+
? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
|
|
1126
|
+
: resolveFirmwareUploadRetryDelay(attempt);
|
|
1127
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
|
|
1128
|
+
attempt: attempt + 1,
|
|
1129
|
+
delayMs,
|
|
1130
|
+
reconnect: shouldReconnect,
|
|
1131
|
+
error,
|
|
1132
|
+
});
|
|
1133
|
+
if (shouldReconnect) {
|
|
1134
|
+
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
1135
|
+
}
|
|
1136
|
+
yield delay(delayMs);
|
|
1137
|
+
attempt += 1;
|
|
1138
|
+
if (shouldReconnect) {
|
|
1139
|
+
try {
|
|
1140
|
+
yield this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
1141
|
+
}
|
|
1142
|
+
catch (e) {
|
|
1143
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
1144
|
+
if (attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1145
|
+
throw e;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
987
1151
|
}), e => {
|
|
988
1152
|
this.runPromise = null;
|
|
989
1153
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.1.27-alpha.
|
|
3
|
+
"version": "1.1.27-alpha.45",
|
|
4
4
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -19,11 +19,11 @@
|
|
|
19
19
|
"lint:fix": "eslint . --fix"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@onekeyfe/hd-core": "1.1.27-alpha.
|
|
23
|
-
"@onekeyfe/hd-shared": "1.1.27-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.1.27-alpha.
|
|
22
|
+
"@onekeyfe/hd-core": "1.1.27-alpha.45",
|
|
23
|
+
"@onekeyfe/hd-shared": "1.1.27-alpha.45",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.1.27-alpha.45",
|
|
25
25
|
"@onekeyfe/react-native-ble-utils": "^0.1.4",
|
|
26
26
|
"react-native-ble-plx": "3.5.1"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "058b5f61f627da21171c74c93d2e4b87c1d8ade6"
|
|
29
29
|
}
|
package/src/BleManager.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import BleUtils from '@onekeyfe/react-native-ble-utils';
|
|
2
2
|
import { ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
3
|
|
|
4
|
-
import type { Peripheral } from '@onekeyfe/react-native-ble-utils';
|
|
5
|
-
|
|
6
4
|
import { bleLogger } from './logger';
|
|
7
5
|
|
|
6
|
+
import type { Peripheral } from '@onekeyfe/react-native-ble-utils';
|
|
7
|
+
|
|
8
8
|
const Logger = bleLogger;
|
|
9
9
|
|
|
10
10
|
/**
|
|
@@ -21,9 +21,6 @@ export const pairDevice = (macAddress: string) => BleUtils.pairDevice(macAddress
|
|
|
21
21
|
|
|
22
22
|
export const onDeviceBondState = (bleMacAddress: string): Promise<Peripheral | undefined> =>
|
|
23
23
|
new Promise((resolve, reject) => {
|
|
24
|
-
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
25
|
-
let cleanupListener: (() => void) | undefined;
|
|
26
|
-
|
|
27
24
|
const cleanup = () => {
|
|
28
25
|
if (timeout) {
|
|
29
26
|
clearTimeout(timeout);
|
|
@@ -31,12 +28,12 @@ export const onDeviceBondState = (bleMacAddress: string): Promise<Peripheral | u
|
|
|
31
28
|
if (cleanupListener) cleanupListener();
|
|
32
29
|
};
|
|
33
30
|
|
|
34
|
-
timeout = setTimeout(() => {
|
|
31
|
+
const timeout = setTimeout(() => {
|
|
35
32
|
cleanup();
|
|
36
33
|
reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
|
|
37
34
|
}, 60 * 1000);
|
|
38
35
|
|
|
39
|
-
cleanupListener = BleUtils.onDeviceBondState(peripheral => {
|
|
36
|
+
const cleanupListener = BleUtils.onDeviceBondState(peripheral => {
|
|
40
37
|
if (peripheral.id?.toLowerCase() !== bleMacAddress.toLowerCase()) {
|
|
41
38
|
return;
|
|
42
39
|
}
|
package/src/BleTransport.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BleErrorCode } from 'react-native-ble-plx';
|
|
2
2
|
import { wait } from '@onekeyfe/hd-shared';
|
|
3
3
|
|
|
4
|
-
import type { Characteristic, Device, Subscription } from 'react-native-ble-plx';
|
|
5
|
-
|
|
6
4
|
import { bleLogger } from './logger';
|
|
7
5
|
|
|
6
|
+
import type { Characteristic, Device, Subscription } from 'react-native-ble-plx';
|
|
7
|
+
|
|
8
8
|
const Log = bleLogger;
|
|
9
9
|
|
|
10
10
|
export default class BleTransport {
|
package/src/bleStrategy.ts
CHANGED
|
@@ -10,9 +10,7 @@ export type BleWriteCapability = {
|
|
|
10
10
|
export type BleWriteMode = 'withResponse' | 'withoutResponse';
|
|
11
11
|
|
|
12
12
|
export function hasWritableCapability(characteristic: BleWriteCapability) {
|
|
13
|
-
return !!(
|
|
14
|
-
characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse
|
|
15
|
-
);
|
|
13
|
+
return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
|
|
16
14
|
}
|
|
17
15
|
|
|
18
16
|
export function resolveBleWriteMode(
|
package/src/index.ts
CHANGED
|
@@ -51,6 +51,60 @@ const { check, ProtocolV1, parseConfigure } = transport;
|
|
|
51
51
|
const Log = bleLogger;
|
|
52
52
|
|
|
53
53
|
const transportCache: Record<string, BleTransport> = {};
|
|
54
|
+
const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = Platform.OS === 'ios' ? 4 : 5;
|
|
55
|
+
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = Platform.OS === 'ios' ? 8 : 10;
|
|
56
|
+
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = Platform.OS === 'ios' ? 24 : 30;
|
|
57
|
+
const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
|
|
58
|
+
const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
|
|
59
|
+
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
60
|
+
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY =
|
|
61
|
+
Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
62
|
+
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
63
|
+
|
|
64
|
+
type FirmwareUploadWriteRetryType = 'congested' | 'reconnectable';
|
|
65
|
+
type ResolvedBleCharacteristics = {
|
|
66
|
+
writeCharacteristic: Characteristic;
|
|
67
|
+
notifyCharacteristic: Characteristic;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const delay = (ms: number) =>
|
|
71
|
+
new Promise<void>(resolve => {
|
|
72
|
+
setTimeout(resolve, ms);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const getFirmwareUploadWriteRetryType = (error: unknown): FirmwareUploadWriteRetryType | null => {
|
|
76
|
+
if (!error || typeof error !== 'object') return null;
|
|
77
|
+
const bleWriteError = error as {
|
|
78
|
+
androidErrorCode?: unknown;
|
|
79
|
+
status?: unknown;
|
|
80
|
+
errorCode?: unknown;
|
|
81
|
+
reason?: unknown;
|
|
82
|
+
message?: unknown;
|
|
83
|
+
name?: unknown;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
if (
|
|
87
|
+
bleWriteError.errorCode === BleErrorCode.DeviceDisconnected ||
|
|
88
|
+
bleWriteError.errorCode === BleErrorCode.CharacteristicNotFound
|
|
89
|
+
) {
|
|
90
|
+
return 'reconnectable';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (
|
|
94
|
+
bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
|
|
95
|
+
bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS
|
|
96
|
+
) {
|
|
97
|
+
return 'congested';
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const text = [bleWriteError.reason, bleWriteError.message, bleWriteError.name]
|
|
101
|
+
.filter(value => typeof value === 'string')
|
|
102
|
+
.join(' ');
|
|
103
|
+
return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const resolveFirmwareUploadRetryDelay = (attempt: number, baseDelayMs = 200, maxDelayMs = 1200) =>
|
|
107
|
+
Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
|
|
54
108
|
const BLE_RESPONSE_TIMEOUT_MS = 30_000;
|
|
55
109
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
56
110
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10_000;
|
|
@@ -61,11 +115,6 @@ const HIGH_VOLUME_WRITE_BURST_SIZE = Platform.OS === 'ios' ? 4 : 6;
|
|
|
61
115
|
const HIGH_VOLUME_WRITE_PAUSE_MS = Platform.OS === 'ios' ? 6 : 2;
|
|
62
116
|
const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = Platform.OS === 'ios' ? 20 : 8;
|
|
63
117
|
|
|
64
|
-
const delay = (ms: number) =>
|
|
65
|
-
new Promise<void>(resolve => {
|
|
66
|
-
setTimeout(resolve, ms);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
118
|
export type ProtocolV2BleTuning = {
|
|
70
119
|
iosPacketLength?: number;
|
|
71
120
|
androidPacketLength?: number;
|
|
@@ -235,6 +284,8 @@ export default class ReactNativeBleTransport {
|
|
|
235
284
|
|
|
236
285
|
emitter?: EventEmitter;
|
|
237
286
|
|
|
287
|
+
firmwareUploadWriteRecoveryIds = new Set<string>();
|
|
288
|
+
|
|
238
289
|
/** Per-device protocol type detected by active wire-level probe after connect. */
|
|
239
290
|
private deviceProtocol: Map<string, ProtocolType> = new Map();
|
|
240
291
|
|
|
@@ -284,6 +335,187 @@ export default class ReactNativeBleTransport {
|
|
|
284
335
|
return Promise.resolve(this.blePlxManager);
|
|
285
336
|
}
|
|
286
337
|
|
|
338
|
+
async resolveCharacteristics(device: Device): Promise<ResolvedBleCharacteristics> {
|
|
339
|
+
await device.discoverAllServicesAndCharacteristics();
|
|
340
|
+
let infos = tryToGetConfiguration(device);
|
|
341
|
+
let characteristics: Characteristic[] | undefined;
|
|
342
|
+
|
|
343
|
+
if (!infos) {
|
|
344
|
+
for (const serviceUuid of getBluetoothServiceUuids()) {
|
|
345
|
+
try {
|
|
346
|
+
characteristics = await device.characteristicsForService(serviceUuid);
|
|
347
|
+
infos = getInfosForServiceUuid(serviceUuid, 'classic');
|
|
348
|
+
break;
|
|
349
|
+
} catch (e) {
|
|
350
|
+
Log?.error(e);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
let fallbackServiceUuid: string | undefined;
|
|
356
|
+
|
|
357
|
+
if (!infos) {
|
|
358
|
+
const services = await device.services();
|
|
359
|
+
Log?.debug(
|
|
360
|
+
'[ReactNativeBleTransport] Known OneKey service UUID not found, discovered services:',
|
|
361
|
+
services?.map(service => service.uuid)
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
const knownService = services.find(service =>
|
|
365
|
+
getInfosForServiceUuid(service.uuid, 'classic')
|
|
366
|
+
);
|
|
367
|
+
const fallbackService =
|
|
368
|
+
knownService ?? services.find(service => !isGenericBleService(service.uuid)) ?? services[0];
|
|
369
|
+
|
|
370
|
+
if (fallbackService) {
|
|
371
|
+
fallbackServiceUuid = fallbackService.uuid;
|
|
372
|
+
characteristics = await device.characteristicsForService(fallbackService.uuid);
|
|
373
|
+
Log?.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (!infos && !fallbackServiceUuid) {
|
|
378
|
+
try {
|
|
379
|
+
Log?.debug('cancel connection when service not found');
|
|
380
|
+
await device.cancelConnection();
|
|
381
|
+
} catch (e) {
|
|
382
|
+
Log?.debug('cancel connection error when service not found: ', e.message || e.reason);
|
|
383
|
+
}
|
|
384
|
+
throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const serviceUuid = infos?.serviceUuid ?? fallbackServiceUuid;
|
|
388
|
+
const writeUuid = infos?.writeUuid ?? '00000002-0000-1000-8000-00805f9b34fb';
|
|
389
|
+
const notifyUuid = infos?.notifyUuid ?? '00000003-0000-1000-8000-00805f9b34fb';
|
|
390
|
+
|
|
391
|
+
if (!serviceUuid) {
|
|
392
|
+
throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
if (!characteristics) {
|
|
396
|
+
characteristics = await device.characteristicsForService(serviceUuid);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (!characteristics) {
|
|
400
|
+
throw ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotFound);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
let writeCharacteristic;
|
|
404
|
+
let notifyCharacteristic;
|
|
405
|
+
for (const c of characteristics) {
|
|
406
|
+
if (isSameBleUuid(c.uuid, writeUuid)) {
|
|
407
|
+
writeCharacteristic = c;
|
|
408
|
+
} else if (isSameBleUuid(c.uuid, notifyUuid)) {
|
|
409
|
+
notifyCharacteristic = c;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (!writeCharacteristic) {
|
|
414
|
+
throw ERRORS.TypedError('BLECharacteristicNotFound: write characteristic not found');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (!notifyCharacteristic) {
|
|
418
|
+
throw ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (!hasWritableCapability(writeCharacteristic)) {
|
|
422
|
+
throw ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (!notifyCharacteristic.isNotifiable) {
|
|
426
|
+
throw ERRORS.TypedError(
|
|
427
|
+
'BLECharacteristicNotNotifiable: notify characteristic not notifiable'
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return {
|
|
432
|
+
writeCharacteristic,
|
|
433
|
+
notifyCharacteristic,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
attachDisconnectSubscription(transport: BleTransport, device: Device, uuid: string) {
|
|
438
|
+
transport.disconnectSubscription?.remove();
|
|
439
|
+
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
440
|
+
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
441
|
+
Log?.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (transportCache[uuid] !== transport) {
|
|
445
|
+
Log?.debug('device disconnect ignored for stale transport: ', device?.id);
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
try {
|
|
450
|
+
Log?.debug('device disconnect: ', device?.id);
|
|
451
|
+
this.emitter?.emit('device-disconnect', {
|
|
452
|
+
name: device?.name,
|
|
453
|
+
id: device?.id,
|
|
454
|
+
connectId: device?.id,
|
|
455
|
+
});
|
|
456
|
+
if (this.runPromise) {
|
|
457
|
+
const error = ERRORS.TypedError(HardwareErrorCode.BleConnectedError);
|
|
458
|
+
this.runPromise.reject(error);
|
|
459
|
+
this.rejectAllProtocolV2Frames(error);
|
|
460
|
+
}
|
|
461
|
+
} catch (e) {
|
|
462
|
+
Log?.debug('device disconnect error: ', e);
|
|
463
|
+
} finally {
|
|
464
|
+
this.release(uuid, true);
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
async reconnectFirmwareUploadTransport(uuid: string, transport: BleTransport) {
|
|
470
|
+
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
471
|
+
try {
|
|
472
|
+
transport.disconnectSubscription?.remove();
|
|
473
|
+
transport.disconnectSubscription = undefined;
|
|
474
|
+
transport.notifySubscription?.remove();
|
|
475
|
+
transport.notifySubscription = undefined;
|
|
476
|
+
|
|
477
|
+
let { device } = transport;
|
|
478
|
+
const isConnected = await device.isConnected().catch(() => false);
|
|
479
|
+
if (!isConnected) {
|
|
480
|
+
try {
|
|
481
|
+
device = await device.connect(connectOptions);
|
|
482
|
+
} catch (e) {
|
|
483
|
+
if (
|
|
484
|
+
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
485
|
+
e.errorCode === BleErrorCode.OperationCancelled
|
|
486
|
+
) {
|
|
487
|
+
device = await device.connect();
|
|
488
|
+
} else if (e.errorCode !== BleErrorCode.DeviceAlreadyConnected) {
|
|
489
|
+
throw e;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const { writeCharacteristic, notifyCharacteristic } = await this.resolveCharacteristics(
|
|
495
|
+
device
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
transport.device = device;
|
|
499
|
+
transport.writeCharacteristic = writeCharacteristic;
|
|
500
|
+
transport.notifyCharacteristic = notifyCharacteristic;
|
|
501
|
+
const monitorToken = this.nextMonitorToken;
|
|
502
|
+
this.nextMonitorToken += 1;
|
|
503
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
504
|
+
transport.monitorToken = monitorToken;
|
|
505
|
+
transport.notifyTransactionId = notifyTransactionId;
|
|
506
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
507
|
+
transport.notifySubscription = this._monitorCharacteristic(
|
|
508
|
+
notifyCharacteristic,
|
|
509
|
+
uuid,
|
|
510
|
+
monitorToken,
|
|
511
|
+
notifyTransactionId
|
|
512
|
+
);
|
|
513
|
+
this.attachDisconnectSubscription(transport, device, uuid);
|
|
514
|
+
} finally {
|
|
515
|
+
this.firmwareUploadWriteRecoveryIds.delete(uuid);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
287
519
|
/**
|
|
288
520
|
* 获取设备列表
|
|
289
521
|
* 在搜索超过超时时间或设备数量大于 5 台时,返回 OneKey 设备,
|
|
@@ -435,11 +667,7 @@ export default class ReactNativeBleTransport {
|
|
|
435
667
|
cachedProtocol &&
|
|
436
668
|
(!expectedProtocol || cachedProtocol === expectedProtocol)
|
|
437
669
|
) {
|
|
438
|
-
Log?.debug(
|
|
439
|
-
'[ReactNativeBleTransport] reuse cached BLE transport:',
|
|
440
|
-
uuid,
|
|
441
|
-
cachedProtocol
|
|
442
|
-
);
|
|
670
|
+
Log?.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
443
671
|
return { uuid, protocolType: cachedProtocol };
|
|
444
672
|
}
|
|
445
673
|
|
|
@@ -547,99 +775,7 @@ export default class ReactNativeBleTransport {
|
|
|
547
775
|
}
|
|
548
776
|
|
|
549
777
|
device = await requestAndroidMtu(device);
|
|
550
|
-
|
|
551
|
-
await device.discoverAllServicesAndCharacteristics();
|
|
552
|
-
let infos = tryToGetConfiguration(device);
|
|
553
|
-
let characteristics;
|
|
554
|
-
let fallbackServiceUuid: string | undefined;
|
|
555
|
-
|
|
556
|
-
if (!infos) {
|
|
557
|
-
for (const serviceUuid of getBluetoothServiceUuids()) {
|
|
558
|
-
try {
|
|
559
|
-
characteristics = await device.characteristicsForService(serviceUuid);
|
|
560
|
-
infos = getInfosForServiceUuid(serviceUuid, 'classic');
|
|
561
|
-
break;
|
|
562
|
-
} catch (e) {
|
|
563
|
-
Log?.error(e);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
if (!infos) {
|
|
569
|
-
const services = await device.services();
|
|
570
|
-
Log?.debug(
|
|
571
|
-
'[ReactNativeBleTransport] Known OneKey service UUID not found, discovered services:',
|
|
572
|
-
services?.map(service => service.uuid)
|
|
573
|
-
);
|
|
574
|
-
|
|
575
|
-
const knownService = services.find(service =>
|
|
576
|
-
getInfosForServiceUuid(service.uuid, 'classic')
|
|
577
|
-
);
|
|
578
|
-
const fallbackService =
|
|
579
|
-
knownService ?? services.find(service => !isGenericBleService(service.uuid)) ?? services[0];
|
|
580
|
-
|
|
581
|
-
if (fallbackService) {
|
|
582
|
-
fallbackServiceUuid = fallbackService.uuid;
|
|
583
|
-
characteristics = await device.characteristicsForService(fallbackService.uuid);
|
|
584
|
-
Log?.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
if (!infos) {
|
|
589
|
-
if (!fallbackServiceUuid) {
|
|
590
|
-
try {
|
|
591
|
-
Log?.debug('cancel connection when service not found');
|
|
592
|
-
await device.cancelConnection();
|
|
593
|
-
} catch (e) {
|
|
594
|
-
Log?.debug('cancel connection error when service not found: ', e.message || e.reason);
|
|
595
|
-
}
|
|
596
|
-
throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
const serviceUuid = infos?.serviceUuid ?? fallbackServiceUuid;
|
|
601
|
-
const writeUuid = infos?.writeUuid ?? '00000002-0000-1000-8000-00805f9b34fb';
|
|
602
|
-
const notifyUuid = infos?.notifyUuid ?? '00000003-0000-1000-8000-00805f9b34fb';
|
|
603
|
-
|
|
604
|
-
if (!serviceUuid) {
|
|
605
|
-
throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (!characteristics) {
|
|
609
|
-
characteristics = await device.characteristicsForService(serviceUuid);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
if (!characteristics) {
|
|
613
|
-
throw ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotFound);
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
let writeCharacteristic;
|
|
617
|
-
let notifyCharacteristic;
|
|
618
|
-
for (const c of characteristics) {
|
|
619
|
-
if (isSameBleUuid(c.uuid, writeUuid)) {
|
|
620
|
-
writeCharacteristic = c;
|
|
621
|
-
} else if (isSameBleUuid(c.uuid, notifyUuid)) {
|
|
622
|
-
notifyCharacteristic = c;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
if (!writeCharacteristic) {
|
|
627
|
-
throw ERRORS.TypedError('BLECharacteristicNotFound: write characteristic not found');
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
if (!notifyCharacteristic) {
|
|
631
|
-
throw ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
if (!hasWritableCapability(writeCharacteristic)) {
|
|
635
|
-
throw ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
if (!notifyCharacteristic.isNotifiable) {
|
|
639
|
-
throw ERRORS.TypedError(
|
|
640
|
-
'BLECharacteristicNotNotifiable: notify characteristic not notifiable'
|
|
641
|
-
);
|
|
642
|
-
}
|
|
778
|
+
const { writeCharacteristic, notifyCharacteristic } = await this.resolveCharacteristics(device);
|
|
643
779
|
|
|
644
780
|
const protocolHint = expectedProtocol
|
|
645
781
|
? undefined
|
|
@@ -688,30 +824,7 @@ export default class ReactNativeBleTransport {
|
|
|
688
824
|
connectId: device.id,
|
|
689
825
|
});
|
|
690
826
|
|
|
691
|
-
transport
|
|
692
|
-
if (transportCache[uuid] !== transport) {
|
|
693
|
-
Log?.debug('device disconnect ignored for stale transport: ', device?.id);
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
try {
|
|
698
|
-
Log?.debug('device disconnect: ', device?.id);
|
|
699
|
-
this.emitter?.emit('device-disconnect', {
|
|
700
|
-
name: device?.name,
|
|
701
|
-
id: device?.id,
|
|
702
|
-
connectId: device?.id,
|
|
703
|
-
});
|
|
704
|
-
if (this.runPromise) {
|
|
705
|
-
const error = ERRORS.TypedError(HardwareErrorCode.BleConnectedError);
|
|
706
|
-
this.runPromise.reject(error);
|
|
707
|
-
this.rejectAllProtocolV2Frames(error);
|
|
708
|
-
}
|
|
709
|
-
} catch (e) {
|
|
710
|
-
Log?.debug('device disconnect error: ', e);
|
|
711
|
-
} finally {
|
|
712
|
-
this.release(uuid, true);
|
|
713
|
-
}
|
|
714
|
-
});
|
|
827
|
+
this.attachDisconnectSubscription(transport, device, uuid);
|
|
715
828
|
|
|
716
829
|
return { uuid, protocolType };
|
|
717
830
|
}
|
|
@@ -732,6 +845,10 @@ export default class ReactNativeBleTransport {
|
|
|
732
845
|
error as unknown as string
|
|
733
846
|
}`
|
|
734
847
|
);
|
|
848
|
+
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
849
|
+
Log?.debug('notify error ignored during FirmwareUpload write recovery: ', uuid);
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
735
852
|
if (!isCurrentMonitor) {
|
|
736
853
|
Log?.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
737
854
|
return;
|
|
@@ -995,6 +1112,41 @@ export default class ReactNativeBleTransport {
|
|
|
995
1112
|
}
|
|
996
1113
|
}
|
|
997
1114
|
|
|
1115
|
+
async function writeFirmwareUploadChunkedData(
|
|
1116
|
+
buffers: ByteBuffer[],
|
|
1117
|
+
writeFunction: (data: string) => Promise<void>,
|
|
1118
|
+
onError: (e: any) => void
|
|
1119
|
+
) {
|
|
1120
|
+
let index = 0;
|
|
1121
|
+
let packetsWritten = 0;
|
|
1122
|
+
let chunk = ByteBuffer.allocate(FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY);
|
|
1123
|
+
|
|
1124
|
+
while (index < buffers.length) {
|
|
1125
|
+
const buffer = buffers[index].toBuffer();
|
|
1126
|
+
chunk.append(buffer);
|
|
1127
|
+
index += 1;
|
|
1128
|
+
|
|
1129
|
+
if (chunk.offset === FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY || index >= buffers.length) {
|
|
1130
|
+
chunk.reset();
|
|
1131
|
+
try {
|
|
1132
|
+
await writeFunction(chunk.toString('base64'));
|
|
1133
|
+
packetsWritten += 1;
|
|
1134
|
+
chunk = ByteBuffer.allocate(FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY);
|
|
1135
|
+
if (packetsWritten % FIRMWARE_UPLOAD_WRITE_BURST_SIZE === 0 && index < buffers.length) {
|
|
1136
|
+
await delay(FIRMWARE_UPLOAD_WRITE_PAUSE_MS);
|
|
1137
|
+
}
|
|
1138
|
+
} catch (e) {
|
|
1139
|
+
onError(e);
|
|
1140
|
+
throw ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
if (packetsWritten > 0) {
|
|
1146
|
+
await delay(FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
|
|
998
1150
|
if (name === 'EmmcFileWrite') {
|
|
999
1151
|
await writeChunkedData(
|
|
1000
1152
|
buffers,
|
|
@@ -1005,10 +1157,57 @@ export default class ReactNativeBleTransport {
|
|
|
1005
1157
|
}
|
|
1006
1158
|
);
|
|
1007
1159
|
} else if (name === 'FirmwareUpload') {
|
|
1008
|
-
|
|
1160
|
+
Log?.debug('[ReactNativeBleTransport] FirmwareUpload write uses throttled BLE packets:', {
|
|
1161
|
+
packetCapacity: FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY,
|
|
1162
|
+
burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
|
|
1163
|
+
pauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
|
|
1164
|
+
flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
|
|
1165
|
+
maxRetries: FIRMWARE_UPLOAD_WRITE_MAX_RETRIES,
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
await writeFirmwareUploadChunkedData(
|
|
1009
1169
|
buffers,
|
|
1010
1170
|
async data => {
|
|
1011
|
-
|
|
1171
|
+
let attempt = 0;
|
|
1172
|
+
// Retry only congestion. Other write errors should surface immediately.
|
|
1173
|
+
// GATT_CONGESTED is usually transient backpressure from the Android BLE queue.
|
|
1174
|
+
// eslint-disable-next-line no-constant-condition
|
|
1175
|
+
while (true) {
|
|
1176
|
+
try {
|
|
1177
|
+
await transport.writeCharacteristic.writeWithoutResponse(data);
|
|
1178
|
+
return;
|
|
1179
|
+
} catch (error) {
|
|
1180
|
+
const retryType = getFirmwareUploadWriteRetryType(error);
|
|
1181
|
+
if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1182
|
+
throw error;
|
|
1183
|
+
}
|
|
1184
|
+
const shouldReconnect = retryType === 'reconnectable';
|
|
1185
|
+
const delayMs = shouldReconnect
|
|
1186
|
+
? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
|
|
1187
|
+
: resolveFirmwareUploadRetryDelay(attempt);
|
|
1188
|
+
Log?.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
|
|
1189
|
+
attempt: attempt + 1,
|
|
1190
|
+
delayMs,
|
|
1191
|
+
reconnect: shouldReconnect,
|
|
1192
|
+
error,
|
|
1193
|
+
});
|
|
1194
|
+
if (shouldReconnect) {
|
|
1195
|
+
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
1196
|
+
}
|
|
1197
|
+
await delay(delayMs);
|
|
1198
|
+
attempt += 1;
|
|
1199
|
+
if (shouldReconnect) {
|
|
1200
|
+
try {
|
|
1201
|
+
await this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
1202
|
+
} catch (e) {
|
|
1203
|
+
Log?.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
1204
|
+
if (attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1205
|
+
throw e;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1012
1211
|
},
|
|
1013
1212
|
e => {
|
|
1014
1213
|
this.runPromise = null;
|