@onekeyfe/hd-transport-react-native 1.1.27-alpha.40 → 1.1.27-alpha.5
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 +0 -2
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/constants.d.ts +0 -4
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +6 -56
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +124 -828
- package/dist/types.d.ts +0 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/BleManager.ts +14 -14
- package/src/BleTransport.ts +5 -9
- package/src/constants.ts +1 -25
- package/src/index.ts +69 -899
- package/src/types.ts +0 -3
- package/src/utils/validateNotify.ts +4 -4
- package/dist/bleStrategy.d.ts +0 -15
- package/dist/bleStrategy.d.ts.map +0 -1
- package/dist/logger.d.ts +0 -14
- package/dist/logger.d.ts.map +0 -1
- package/src/__tests__/bleStrategy.test.ts +0 -47
- package/src/bleStrategy.ts +0 -62
- package/src/logger.ts +0 -19
package/src/index.ts
CHANGED
|
@@ -9,150 +9,38 @@ import {
|
|
|
9
9
|
} from 'react-native-ble-plx';
|
|
10
10
|
import ByteBuffer from 'bytebuffer';
|
|
11
11
|
import transport, {
|
|
12
|
+
COMMON_HEADER_SIZE,
|
|
12
13
|
LogBlockCommand,
|
|
13
14
|
type OneKeyDeviceInfoBase,
|
|
14
|
-
PROTOCOL_V1_MESSAGE_HEADER_SIZE,
|
|
15
|
-
PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
16
|
-
type ProtocolType,
|
|
17
|
-
ProtocolV2FrameAssembler,
|
|
18
|
-
ProtocolV2Session,
|
|
19
|
-
type TransportCallOptions,
|
|
20
|
-
probeProtocolV2 as probeProtocolV2Helper,
|
|
21
15
|
} from '@onekeyfe/hd-transport';
|
|
22
16
|
import { ERRORS, HardwareErrorCode, createDeferred, isOnekeyDevice } from '@onekeyfe/hd-shared';
|
|
17
|
+
import { LoggerNames, getLogger } from '@onekeyfe/hd-core';
|
|
23
18
|
|
|
24
19
|
import { getConnectedDeviceIds, onDeviceBondState, pairDevice } from './BleManager';
|
|
25
|
-
import {
|
|
26
|
-
hasWritableCapability,
|
|
27
|
-
resolveBleWriteMode,
|
|
28
|
-
resolveProtocolV2PacketCapacity,
|
|
29
|
-
} from './bleStrategy';
|
|
30
20
|
import { subscribeBleOn } from './subscribeBleOn';
|
|
31
21
|
import {
|
|
32
22
|
ANDROID_PACKET_LENGTH,
|
|
33
23
|
IOS_PACKET_LENGTH,
|
|
34
|
-
getBleUuidKey,
|
|
35
24
|
getBluetoothServiceUuids,
|
|
36
25
|
getInfosForServiceUuid,
|
|
37
|
-
isSameBleUuid,
|
|
38
26
|
} from './constants';
|
|
39
27
|
import { isHeaderChunk } from './utils/validateNotify';
|
|
40
28
|
import BleTransport from './BleTransport';
|
|
41
29
|
import timer from './utils/timer';
|
|
42
|
-
import { bleLogger, setBleLogger } from './logger';
|
|
43
30
|
|
|
44
31
|
import type { Deferred } from '@onekeyfe/hd-shared';
|
|
45
32
|
import type { Characteristic, Device, Subscription } from 'react-native-ble-plx';
|
|
46
33
|
import type EventEmitter from 'events';
|
|
47
34
|
import type { BleAcquireInput, TransportOptions } from './types';
|
|
48
35
|
|
|
49
|
-
const { check,
|
|
36
|
+
const { check, buildBuffers, receiveOne, parseConfigure } = transport;
|
|
50
37
|
|
|
51
|
-
const Log =
|
|
38
|
+
const Log = getLogger(LoggerNames.HdBleTransport);
|
|
52
39
|
|
|
53
40
|
const transportCache: Record<string, BleTransport> = {};
|
|
54
|
-
const BLE_RESPONSE_TIMEOUT_MS = 30_000;
|
|
55
|
-
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
56
|
-
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10_000;
|
|
57
|
-
const DEVICE_SCAN_TIMEOUT_MS = 8000;
|
|
58
|
-
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
59
|
-
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
60
|
-
const HIGH_VOLUME_WRITE_BURST_SIZE = Platform.OS === 'ios' ? 4 : 6;
|
|
61
|
-
const HIGH_VOLUME_WRITE_PAUSE_MS = Platform.OS === 'ios' ? 6 : 2;
|
|
62
|
-
const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = Platform.OS === 'ios' ? 20 : 8;
|
|
63
|
-
|
|
64
|
-
const delay = (ms: number) =>
|
|
65
|
-
new Promise<void>(resolve => {
|
|
66
|
-
setTimeout(resolve, ms);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
export type ProtocolV2BleTuning = {
|
|
70
|
-
iosPacketLength?: number;
|
|
71
|
-
androidPacketLength?: number;
|
|
72
|
-
highVolumeWriteBurstSize?: number;
|
|
73
|
-
highVolumeWritePauseMs?: number;
|
|
74
|
-
highVolumeWriteFlushDelayMs?: number;
|
|
75
|
-
highVolumeWriteWithResponse?: boolean;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
type ResolvedProtocolV2BleTuning = Required<ProtocolV2BleTuning>;
|
|
79
|
-
|
|
80
|
-
const DEFAULT_PROTOCOL_V2_BLE_TUNING: ResolvedProtocolV2BleTuning = {
|
|
81
|
-
iosPacketLength: IOS_PACKET_LENGTH,
|
|
82
|
-
androidPacketLength: ANDROID_PACKET_LENGTH,
|
|
83
|
-
highVolumeWriteBurstSize: HIGH_VOLUME_WRITE_BURST_SIZE,
|
|
84
|
-
highVolumeWritePauseMs: HIGH_VOLUME_WRITE_PAUSE_MS,
|
|
85
|
-
highVolumeWriteFlushDelayMs: HIGH_VOLUME_WRITE_FLUSH_DELAY_MS,
|
|
86
|
-
highVolumeWriteWithResponse: false,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
let protocolV2BleTuning: ResolvedProtocolV2BleTuning = { ...DEFAULT_PROTOCOL_V2_BLE_TUNING };
|
|
90
|
-
|
|
91
|
-
const normalizePositiveInteger = (value: unknown, fallback: number) => {
|
|
92
|
-
const normalized = Number(value);
|
|
93
|
-
if (!Number.isFinite(normalized) || normalized <= 0) return fallback;
|
|
94
|
-
return Math.floor(normalized);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export function configureProtocolV2BleTuning(tuning: ProtocolV2BleTuning = {}) {
|
|
98
|
-
protocolV2BleTuning = {
|
|
99
|
-
iosPacketLength: normalizePositiveInteger(
|
|
100
|
-
tuning.iosPacketLength,
|
|
101
|
-
protocolV2BleTuning.iosPacketLength
|
|
102
|
-
),
|
|
103
|
-
androidPacketLength: normalizePositiveInteger(
|
|
104
|
-
tuning.androidPacketLength,
|
|
105
|
-
protocolV2BleTuning.androidPacketLength
|
|
106
|
-
),
|
|
107
|
-
highVolumeWriteBurstSize: normalizePositiveInteger(
|
|
108
|
-
tuning.highVolumeWriteBurstSize,
|
|
109
|
-
protocolV2BleTuning.highVolumeWriteBurstSize
|
|
110
|
-
),
|
|
111
|
-
highVolumeWritePauseMs: normalizePositiveInteger(
|
|
112
|
-
tuning.highVolumeWritePauseMs,
|
|
113
|
-
protocolV2BleTuning.highVolumeWritePauseMs
|
|
114
|
-
),
|
|
115
|
-
highVolumeWriteFlushDelayMs: normalizePositiveInteger(
|
|
116
|
-
tuning.highVolumeWriteFlushDelayMs,
|
|
117
|
-
protocolV2BleTuning.highVolumeWriteFlushDelayMs
|
|
118
|
-
),
|
|
119
|
-
highVolumeWriteWithResponse:
|
|
120
|
-
tuning.highVolumeWriteWithResponse ?? protocolV2BleTuning.highVolumeWriteWithResponse,
|
|
121
|
-
};
|
|
122
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning configured:', protocolV2BleTuning);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export function resetProtocolV2BleTuning() {
|
|
126
|
-
protocolV2BleTuning = { ...DEFAULT_PROTOCOL_V2_BLE_TUNING };
|
|
127
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning reset:', protocolV2BleTuning);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function getProtocolV2BleTuning() {
|
|
131
|
-
return { ...protocolV2BleTuning };
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function inferProtocolHintFromDeviceName(name?: string | null): ProtocolType | undefined {
|
|
135
|
-
return /\bpro\s*2\b/i.test(name ?? '') ? 'V2' : undefined;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function getDeviceDisplayName(device?: Device | null) {
|
|
139
|
-
return device?.name || device?.localName || null;
|
|
140
|
-
}
|
|
141
41
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function hasKnownOneKeyService(device?: Device | null) {
|
|
147
|
-
return (device?.serviceUUIDs ?? []).some(serviceUuid =>
|
|
148
|
-
getInfosForServiceUuid(serviceUuid, 'classic')
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const ANDROID_REQUEST_MTU = 256;
|
|
153
|
-
|
|
154
|
-
const connectOptions: Record<string, unknown> = {
|
|
155
|
-
requestMTU: ANDROID_REQUEST_MTU,
|
|
42
|
+
let connectOptions: Record<string, unknown> = {
|
|
43
|
+
requestMTU: 256,
|
|
156
44
|
timeout: 3000,
|
|
157
45
|
refreshGatt: 'OnConnected',
|
|
158
46
|
};
|
|
@@ -161,29 +49,12 @@ export type IOneKeyDevice = OneKeyDeviceInfoBase & Device;
|
|
|
161
49
|
|
|
162
50
|
const tryToGetConfiguration = (device: Device) => {
|
|
163
51
|
if (!device || !device.serviceUUIDs) return null;
|
|
164
|
-
const serviceUUID = device.serviceUUIDs
|
|
165
|
-
if (!serviceUUID) return null;
|
|
52
|
+
const [serviceUUID] = device.serviceUUIDs;
|
|
166
53
|
const infos = getInfosForServiceUuid(serviceUUID, 'classic');
|
|
167
54
|
if (!infos) return null;
|
|
168
55
|
return infos;
|
|
169
56
|
};
|
|
170
57
|
|
|
171
|
-
const requestAndroidMtu = async (device: Device) => {
|
|
172
|
-
if (Platform.OS !== 'android') return device;
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
const mtuDevice = await device.requestMTU(ANDROID_REQUEST_MTU);
|
|
176
|
-
Log?.debug('[ReactNativeBleTransport] Android MTU requested:', {
|
|
177
|
-
requested: ANDROID_REQUEST_MTU,
|
|
178
|
-
mtu: mtuDevice.mtu,
|
|
179
|
-
});
|
|
180
|
-
return mtuDevice;
|
|
181
|
-
} catch (error) {
|
|
182
|
-
Log?.debug('[ReactNativeBleTransport] Android MTU request failed:', error);
|
|
183
|
-
return device;
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
|
|
187
58
|
type IOBleErrorRemap = Error | BleError | null | undefined;
|
|
188
59
|
|
|
189
60
|
function remapError(error: IOBleErrorRemap) {
|
|
@@ -221,45 +92,23 @@ export default class ReactNativeBleTransport {
|
|
|
221
92
|
|
|
222
93
|
_messages: ReturnType<typeof transport.parseConfigure> | undefined;
|
|
223
94
|
|
|
224
|
-
_messagesV2: ReturnType<typeof transport.parseConfigure> | undefined;
|
|
225
|
-
|
|
226
95
|
name = 'ReactNativeBleTransport';
|
|
227
96
|
|
|
228
97
|
configured = false;
|
|
229
98
|
|
|
230
99
|
stopped = false;
|
|
231
100
|
|
|
232
|
-
scanTimeout =
|
|
101
|
+
scanTimeout = 3000;
|
|
233
102
|
|
|
234
103
|
runPromise: Deferred<any> | null = null;
|
|
235
104
|
|
|
236
105
|
emitter?: EventEmitter;
|
|
237
106
|
|
|
238
|
-
/** Per-device protocol type detected by active wire-level probe after connect. */
|
|
239
|
-
private deviceProtocol: Map<string, ProtocolType> = new Map();
|
|
240
|
-
|
|
241
|
-
private deviceProtocolHints: Map<string, ProtocolType> = new Map();
|
|
242
|
-
|
|
243
|
-
private protocolV2Assemblers: Map<string, ProtocolV2FrameAssembler> = new Map();
|
|
244
|
-
|
|
245
|
-
private protocolV2FrameQueues: Map<string, Uint8Array[]> = new Map();
|
|
246
|
-
|
|
247
|
-
private protocolV2FramePromises: Map<string, Deferred<Uint8Array>> = new Map();
|
|
248
|
-
|
|
249
|
-
private activeProtocolV2Call: { uuid: string; token: number } | null = null;
|
|
250
|
-
|
|
251
|
-
private nextProtocolV2CallToken = 1;
|
|
252
|
-
|
|
253
|
-
private monitorTokens: Map<string, number> = new Map();
|
|
254
|
-
|
|
255
|
-
private nextMonitorToken = 1;
|
|
256
|
-
|
|
257
107
|
constructor(options: TransportOptions) {
|
|
258
|
-
this.scanTimeout = options.scanTimeout ??
|
|
108
|
+
this.scanTimeout = options.scanTimeout ?? 3000;
|
|
259
109
|
}
|
|
260
110
|
|
|
261
|
-
init(
|
|
262
|
-
setBleLogger(logger);
|
|
111
|
+
init(_logger: any, emitter: EventEmitter) {
|
|
263
112
|
this.emitter = emitter;
|
|
264
113
|
}
|
|
265
114
|
|
|
@@ -269,11 +118,6 @@ export default class ReactNativeBleTransport {
|
|
|
269
118
|
this._messages = messages;
|
|
270
119
|
}
|
|
271
120
|
|
|
272
|
-
configureProtocolV2(signedData: any) {
|
|
273
|
-
this._messagesV2 = parseConfigure(signedData);
|
|
274
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
|
|
275
|
-
}
|
|
276
|
-
|
|
277
121
|
listen() {
|
|
278
122
|
// empty
|
|
279
123
|
}
|
|
@@ -323,7 +167,6 @@ export default class ReactNativeBleTransport {
|
|
|
323
167
|
blePlxManager.startDeviceScan(
|
|
324
168
|
null,
|
|
325
169
|
{
|
|
326
|
-
allowDuplicates: true,
|
|
327
170
|
scanMode: ScanMode.LowLatency,
|
|
328
171
|
},
|
|
329
172
|
(error, device) => {
|
|
@@ -351,41 +194,14 @@ export default class ReactNativeBleTransport {
|
|
|
351
194
|
return;
|
|
352
195
|
}
|
|
353
196
|
|
|
354
|
-
|
|
355
|
-
const isOneKey =
|
|
356
|
-
isOnekeyDevice(device?.name ?? null, device?.id) ||
|
|
357
|
-
isOnekeyDevice(device?.localName ?? null, device?.id) ||
|
|
358
|
-
hasKnownOneKeyService(device);
|
|
359
|
-
const shouldTraceCandidate =
|
|
360
|
-
!!displayName && /onekey|bixinkey|pro\s*2|pro\b|touch|^k\d|^t\d/i.test(displayName);
|
|
361
|
-
|
|
362
|
-
if (shouldTraceCandidate) {
|
|
363
|
-
Log?.debug('[ReactNativeBleTransport] scan candidate', {
|
|
364
|
-
name: device?.name,
|
|
365
|
-
localName: device?.localName,
|
|
366
|
-
id: device?.id,
|
|
367
|
-
serviceUUIDs: device?.serviceUUIDs,
|
|
368
|
-
accepted: isOneKey,
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
if (isOneKey) {
|
|
197
|
+
if (isOnekeyDevice(device?.name ?? null, device?.id)) {
|
|
373
198
|
Log?.debug('search device start ======================');
|
|
374
|
-
const { name, localName, id
|
|
199
|
+
const { name, localName, id } = device ?? {};
|
|
375
200
|
Log?.debug(
|
|
376
|
-
`device name: ${name ?? ''}\nlocalName: ${localName ?? ''}\nid: ${
|
|
377
|
-
id ?? ''
|
|
378
|
-
}\nserviceUUIDs: ${(serviceUUIDs ?? []).join(',')}`
|
|
201
|
+
`device name: ${name ?? ''}\nlocalName: ${localName ?? ''}\nid: ${id ?? ''}`
|
|
379
202
|
);
|
|
380
203
|
addDevice(device as unknown as Device);
|
|
381
204
|
Log?.debug('search device end ======================\n');
|
|
382
|
-
} else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
|
|
383
|
-
Log?.debug('[ReactNativeBleTransport] Pro2-like BLE device was not accepted:', {
|
|
384
|
-
name: device?.name,
|
|
385
|
-
localName: device?.localName,
|
|
386
|
-
id: device?.id,
|
|
387
|
-
serviceUUIDs: device?.serviceUUIDs,
|
|
388
|
-
});
|
|
389
205
|
}
|
|
390
206
|
}
|
|
391
207
|
);
|
|
@@ -399,16 +215,7 @@ export default class ReactNativeBleTransport {
|
|
|
399
215
|
|
|
400
216
|
const addDevice = (device: Device) => {
|
|
401
217
|
if (deviceList.every(d => d.id !== device.id)) {
|
|
402
|
-
|
|
403
|
-
const protocolHint = inferProtocolHintFromDeviceName(displayName);
|
|
404
|
-
if (protocolHint) {
|
|
405
|
-
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
406
|
-
}
|
|
407
|
-
deviceList.push({
|
|
408
|
-
...device,
|
|
409
|
-
name: displayName,
|
|
410
|
-
commType: 'ble',
|
|
411
|
-
} as IOneKeyDevice);
|
|
218
|
+
deviceList.push({ ...device, commType: 'ble' } as IOneKeyDevice);
|
|
412
219
|
}
|
|
413
220
|
};
|
|
414
221
|
|
|
@@ -420,45 +227,25 @@ export default class ReactNativeBleTransport {
|
|
|
420
227
|
}
|
|
421
228
|
|
|
422
229
|
async acquire(input: BleAcquireInput) {
|
|
423
|
-
const { uuid, forceCleanRunPromise
|
|
230
|
+
const { uuid, forceCleanRunPromise } = input;
|
|
424
231
|
|
|
425
232
|
if (!uuid) {
|
|
426
233
|
throw ERRORS.TypedError(HardwareErrorCode.BleRequiredUUID);
|
|
427
234
|
}
|
|
428
235
|
|
|
429
|
-
|
|
430
|
-
if (cachedTransport) {
|
|
431
|
-
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
432
|
-
const isCachedDeviceConnected = await cachedTransport.device.isConnected().catch(() => false);
|
|
433
|
-
if (
|
|
434
|
-
isCachedDeviceConnected &&
|
|
435
|
-
cachedProtocol &&
|
|
436
|
-
(!expectedProtocol || cachedProtocol === expectedProtocol)
|
|
437
|
-
) {
|
|
438
|
-
Log?.debug(
|
|
439
|
-
'[ReactNativeBleTransport] reuse cached BLE transport:',
|
|
440
|
-
uuid,
|
|
441
|
-
cachedProtocol
|
|
442
|
-
);
|
|
443
|
-
return { uuid, protocolType: cachedProtocol };
|
|
444
|
-
}
|
|
236
|
+
let device: Device | null = null;
|
|
445
237
|
|
|
238
|
+
if (transportCache[uuid]) {
|
|
446
239
|
/**
|
|
447
|
-
* If the transport is not
|
|
448
|
-
*
|
|
240
|
+
* If the transport is not released due to an exception operation
|
|
241
|
+
* it will be handled again here
|
|
449
242
|
*/
|
|
450
|
-
Log?.debug('transport not
|
|
451
|
-
await this.release(uuid
|
|
243
|
+
Log?.debug('transport not be released, will release: ', uuid);
|
|
244
|
+
await this.release(uuid);
|
|
452
245
|
}
|
|
453
246
|
|
|
454
|
-
let device: Device | null = null;
|
|
455
|
-
|
|
456
247
|
if (forceCleanRunPromise && this.runPromise) {
|
|
457
|
-
|
|
458
|
-
this.runPromise.reject(error);
|
|
459
|
-
this.rejectAllProtocolV2Frames(error);
|
|
460
|
-
this.runPromise = null;
|
|
461
|
-
this.activeProtocolV2Call = null;
|
|
248
|
+
this.runPromise.reject(ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise));
|
|
462
249
|
Log?.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
463
250
|
}
|
|
464
251
|
|
|
@@ -470,12 +257,11 @@ export default class ReactNativeBleTransport {
|
|
|
470
257
|
throw error;
|
|
471
258
|
}
|
|
472
259
|
|
|
260
|
+
// check device is bonded
|
|
473
261
|
if (Platform.OS === 'android') {
|
|
474
262
|
const bondState = await pairDevice(uuid);
|
|
475
263
|
if (bondState.bonding) {
|
|
476
264
|
await onDeviceBondState(uuid);
|
|
477
|
-
} else if (!bondState.bonded) {
|
|
478
|
-
throw ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
|
|
479
265
|
}
|
|
480
266
|
}
|
|
481
267
|
|
|
@@ -501,6 +287,7 @@ export default class ReactNativeBleTransport {
|
|
|
501
287
|
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
502
288
|
e.errorCode === BleErrorCode.OperationCancelled
|
|
503
289
|
) {
|
|
290
|
+
connectOptions = {};
|
|
504
291
|
Log?.debug('first try to reconnect without params');
|
|
505
292
|
device = await blePlxManager.connectToDevice(uuid);
|
|
506
293
|
} else if (e.errorCode === BleErrorCode.DeviceAlreadyConnected) {
|
|
@@ -520,16 +307,17 @@ export default class ReactNativeBleTransport {
|
|
|
520
307
|
Log?.debug('not connected, try to connect to device: ', uuid);
|
|
521
308
|
|
|
522
309
|
try {
|
|
523
|
-
|
|
310
|
+
await device.connect(connectOptions);
|
|
524
311
|
} catch (e) {
|
|
525
312
|
Log?.debug('not connected, try to connect to device has error: ', e);
|
|
526
313
|
if (
|
|
527
314
|
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
528
315
|
e.errorCode === BleErrorCode.OperationCancelled
|
|
529
316
|
) {
|
|
317
|
+
connectOptions = {};
|
|
530
318
|
Log?.debug('second try to reconnect without params');
|
|
531
319
|
try {
|
|
532
|
-
|
|
320
|
+
await device.connect();
|
|
533
321
|
} catch (e) {
|
|
534
322
|
Log?.debug('last try to reconnect error: ', e);
|
|
535
323
|
// last try to reconnect device if this issue exists
|
|
@@ -537,7 +325,7 @@ export default class ReactNativeBleTransport {
|
|
|
537
325
|
if (e.errorCode === BleErrorCode.OperationCancelled) {
|
|
538
326
|
Log?.debug('last try to reconnect');
|
|
539
327
|
await device.cancelConnection();
|
|
540
|
-
|
|
328
|
+
await device.connect();
|
|
541
329
|
}
|
|
542
330
|
}
|
|
543
331
|
} else {
|
|
@@ -546,12 +334,9 @@ export default class ReactNativeBleTransport {
|
|
|
546
334
|
}
|
|
547
335
|
}
|
|
548
336
|
|
|
549
|
-
device = await requestAndroidMtu(device);
|
|
550
|
-
|
|
551
337
|
await device.discoverAllServicesAndCharacteristics();
|
|
552
338
|
let infos = tryToGetConfiguration(device);
|
|
553
339
|
let characteristics;
|
|
554
|
-
let fallbackServiceUuid: string | undefined;
|
|
555
340
|
|
|
556
341
|
if (!infos) {
|
|
557
342
|
for (const serviceUuid of getBluetoothServiceUuids()) {
|
|
@@ -566,45 +351,17 @@ export default class ReactNativeBleTransport {
|
|
|
566
351
|
}
|
|
567
352
|
|
|
568
353
|
if (!infos) {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
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);
|
|
354
|
+
try {
|
|
355
|
+
Log?.debug('cancel connection when service not found');
|
|
356
|
+
await device.cancelConnection();
|
|
357
|
+
} catch (e) {
|
|
358
|
+
Log?.debug('cancel connection error when service not found: ', e.message || e.reason);
|
|
597
359
|
}
|
|
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
360
|
throw ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound);
|
|
606
361
|
}
|
|
607
362
|
|
|
363
|
+
const { serviceUuid, writeUuid, notifyUuid } = infos;
|
|
364
|
+
|
|
608
365
|
if (!characteristics) {
|
|
609
366
|
characteristics = await device.characteristicsForService(serviceUuid);
|
|
610
367
|
}
|
|
@@ -616,9 +373,9 @@ export default class ReactNativeBleTransport {
|
|
|
616
373
|
let writeCharacteristic;
|
|
617
374
|
let notifyCharacteristic;
|
|
618
375
|
for (const c of characteristics) {
|
|
619
|
-
if (
|
|
376
|
+
if (c.uuid === writeUuid) {
|
|
620
377
|
writeCharacteristic = c;
|
|
621
|
-
} else if (
|
|
378
|
+
} else if (c.uuid === notifyUuid) {
|
|
622
379
|
notifyCharacteristic = c;
|
|
623
380
|
}
|
|
624
381
|
}
|
|
@@ -631,7 +388,7 @@ export default class ReactNativeBleTransport {
|
|
|
631
388
|
throw ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
632
389
|
}
|
|
633
390
|
|
|
634
|
-
if (!
|
|
391
|
+
if (!writeCharacteristic.isWritableWithResponse) {
|
|
635
392
|
throw ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
636
393
|
}
|
|
637
394
|
|
|
@@ -641,47 +398,16 @@ export default class ReactNativeBleTransport {
|
|
|
641
398
|
);
|
|
642
399
|
}
|
|
643
400
|
|
|
644
|
-
const protocolHint = expectedProtocol
|
|
645
|
-
? undefined
|
|
646
|
-
: this.deviceProtocolHints.get(uuid) ??
|
|
647
|
-
inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
|
|
648
|
-
|
|
649
401
|
// release transport before new transport instance
|
|
650
|
-
await this.release(uuid
|
|
651
|
-
if (protocolHint) {
|
|
652
|
-
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
653
|
-
}
|
|
402
|
+
await this.release(uuid);
|
|
654
403
|
|
|
655
404
|
const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
656
|
-
if (Platform.OS === 'android') {
|
|
657
|
-
transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport.mtuSize;
|
|
658
|
-
}
|
|
659
|
-
const monitorToken = this.nextMonitorToken;
|
|
660
|
-
this.nextMonitorToken += 1;
|
|
661
|
-
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
662
|
-
transport.monitorToken = monitorToken;
|
|
663
|
-
transport.notifyTransactionId = notifyTransactionId;
|
|
664
|
-
this.monitorTokens.set(uuid, monitorToken);
|
|
665
405
|
transport.notifySubscription = this._monitorCharacteristic(
|
|
666
406
|
transport.notifyCharacteristic,
|
|
667
|
-
uuid
|
|
668
|
-
monitorToken,
|
|
669
|
-
notifyTransactionId
|
|
407
|
+
uuid
|
|
670
408
|
);
|
|
671
409
|
transportCache[uuid] = transport;
|
|
672
410
|
|
|
673
|
-
this.protocolV2Assemblers.set(uuid, new ProtocolV2FrameAssembler());
|
|
674
|
-
|
|
675
|
-
if (Platform.OS === 'ios') {
|
|
676
|
-
await new Promise<void>(resolve => {
|
|
677
|
-
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
678
|
-
});
|
|
679
|
-
} else if (Platform.OS === 'android') {
|
|
680
|
-
await delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const protocolType = await this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
684
|
-
|
|
685
411
|
this.emitter?.emit('device-connect', {
|
|
686
412
|
name: device.name,
|
|
687
413
|
id: device.id,
|
|
@@ -689,11 +415,6 @@ export default class ReactNativeBleTransport {
|
|
|
689
415
|
});
|
|
690
416
|
|
|
691
417
|
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
692
|
-
if (transportCache[uuid] !== transport) {
|
|
693
|
-
Log?.debug('device disconnect ignored for stale transport: ', device?.id);
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
418
|
try {
|
|
698
419
|
Log?.debug('device disconnect: ', device?.id);
|
|
699
420
|
this.emitter?.emit('device-disconnect', {
|
|
@@ -702,40 +423,28 @@ export default class ReactNativeBleTransport {
|
|
|
702
423
|
connectId: device?.id,
|
|
703
424
|
});
|
|
704
425
|
if (this.runPromise) {
|
|
705
|
-
|
|
706
|
-
this.runPromise.reject(error);
|
|
707
|
-
this.rejectAllProtocolV2Frames(error);
|
|
426
|
+
this.runPromise.reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError));
|
|
708
427
|
}
|
|
709
428
|
} catch (e) {
|
|
710
429
|
Log?.debug('device disconnect error: ', e);
|
|
711
430
|
} finally {
|
|
712
|
-
this.release(uuid
|
|
431
|
+
this.release(uuid);
|
|
713
432
|
}
|
|
714
433
|
});
|
|
715
434
|
|
|
716
|
-
return { uuid
|
|
435
|
+
return { uuid };
|
|
717
436
|
}
|
|
718
437
|
|
|
719
|
-
_monitorCharacteristic(
|
|
720
|
-
characteristic: Characteristic,
|
|
721
|
-
uuid: string,
|
|
722
|
-
monitorToken: number,
|
|
723
|
-
notifyTransactionId: string
|
|
724
|
-
): Subscription {
|
|
438
|
+
_monitorCharacteristic(characteristic: Characteristic, uuid: string): Subscription {
|
|
725
439
|
let bufferLength = 0;
|
|
726
440
|
let buffer: any[] = [];
|
|
727
441
|
const subscription = characteristic.monitor((error, c) => {
|
|
728
|
-
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
729
442
|
if (error) {
|
|
730
443
|
Log?.debug(
|
|
731
444
|
`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${
|
|
732
445
|
error as unknown as string
|
|
733
446
|
}`
|
|
734
447
|
);
|
|
735
|
-
if (!isCurrentMonitor) {
|
|
736
|
-
Log?.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
737
|
-
return;
|
|
738
|
-
}
|
|
739
448
|
if (this.runPromise) {
|
|
740
449
|
let ERROR:
|
|
741
450
|
| typeof HardwareErrorCode.BleDeviceBondError
|
|
@@ -755,45 +464,27 @@ export default class ReactNativeBleTransport {
|
|
|
755
464
|
error.reason?.includes('Writing is not permitted') || // pro firmware 2.3.4 upgrade
|
|
756
465
|
error.reason?.includes('notify change failed for device')
|
|
757
466
|
) {
|
|
758
|
-
|
|
759
|
-
HardwareErrorCode.BleCharacteristicNotifyChangeFailure
|
|
467
|
+
this.runPromise.reject(
|
|
468
|
+
ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotifyChangeFailure)
|
|
760
469
|
);
|
|
761
|
-
this.runPromise.reject(notifyError);
|
|
762
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
763
470
|
Log?.debug(
|
|
764
471
|
`${HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`
|
|
765
472
|
);
|
|
766
473
|
return;
|
|
767
474
|
}
|
|
768
|
-
|
|
769
|
-
this.runPromise.reject(notifyError);
|
|
770
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
475
|
+
this.runPromise.reject(ERRORS.TypedError(ERROR));
|
|
771
476
|
Log?.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
772
477
|
}
|
|
773
478
|
|
|
774
479
|
return;
|
|
775
480
|
}
|
|
776
481
|
|
|
777
|
-
if (!isCurrentMonitor) {
|
|
778
|
-
Log?.debug('monitor data ignored for stale transport: ', uuid, notifyTransactionId);
|
|
779
|
-
return;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
482
|
if (!c) {
|
|
783
483
|
throw ERRORS.TypedError(HardwareErrorCode.BleMonitorError);
|
|
784
484
|
}
|
|
785
485
|
|
|
786
486
|
try {
|
|
787
487
|
const data = Buffer.from(c.value as string, 'base64');
|
|
788
|
-
const protocol = this.deviceProtocol.get(uuid);
|
|
789
|
-
if (!protocol) {
|
|
790
|
-
Log?.debug('monitor data ignored before protocol detection: ', uuid);
|
|
791
|
-
return;
|
|
792
|
-
}
|
|
793
|
-
if (protocol === 'V2') {
|
|
794
|
-
this.handleProtocolV2Notification(uuid, new Uint8Array(data));
|
|
795
|
-
return;
|
|
796
|
-
}
|
|
797
488
|
// console.log('[hd-transport-react-native] Received a packet, ', 'buffer: ', data);
|
|
798
489
|
if (isHeaderChunk(data)) {
|
|
799
490
|
bufferLength = data.readInt32BE(5);
|
|
@@ -802,7 +493,7 @@ export default class ReactNativeBleTransport {
|
|
|
802
493
|
buffer = buffer.concat([...data]);
|
|
803
494
|
}
|
|
804
495
|
|
|
805
|
-
if (buffer.length -
|
|
496
|
+
if (buffer.length - COMMON_HEADER_SIZE >= bufferLength) {
|
|
806
497
|
const value = Buffer.from(buffer);
|
|
807
498
|
// console.log(
|
|
808
499
|
// '[hd-transport-react-native] Received a complete packet of data, resolve Promise, this.runPromise: ',
|
|
@@ -816,41 +507,17 @@ export default class ReactNativeBleTransport {
|
|
|
816
507
|
}
|
|
817
508
|
} catch (error) {
|
|
818
509
|
Log?.debug('monitor data error: ', error);
|
|
819
|
-
|
|
820
|
-
this.runPromise?.reject(notifyError);
|
|
821
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
510
|
+
this.runPromise?.reject(ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError));
|
|
822
511
|
}
|
|
823
|
-
},
|
|
512
|
+
}, uuid);
|
|
824
513
|
|
|
825
514
|
return subscription;
|
|
826
515
|
}
|
|
827
516
|
|
|
828
|
-
async release(uuid: string
|
|
517
|
+
async release(uuid: string) {
|
|
829
518
|
const transport = transportCache[uuid];
|
|
830
|
-
if (this.runPromise) {
|
|
831
|
-
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
832
|
-
this.runPromise.reject(error);
|
|
833
|
-
this.runPromise = null;
|
|
834
|
-
this.rejectAllProtocolV2Frames(error);
|
|
835
|
-
this.activeProtocolV2Call = null;
|
|
836
|
-
} else {
|
|
837
|
-
this.resetProtocolV2Frames(uuid);
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
if (Platform.OS === 'android' && !onclose && transport) {
|
|
841
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
842
|
-
this.resetProtocolV2Frames(uuid);
|
|
843
|
-
if (this.activeProtocolV2Call?.uuid === uuid) {
|
|
844
|
-
this.activeProtocolV2Call = null;
|
|
845
|
-
}
|
|
846
|
-
return Promise.resolve(true);
|
|
847
|
-
}
|
|
848
519
|
|
|
849
520
|
if (transport) {
|
|
850
|
-
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
851
|
-
this.monitorTokens.delete(uuid);
|
|
852
|
-
}
|
|
853
|
-
|
|
854
521
|
// Clean up disconnect subscription first to prevent callbacks on released transport
|
|
855
522
|
Log?.debug('release: removing disconnect subscription for device: ', uuid);
|
|
856
523
|
transport.disconnectSubscription?.remove();
|
|
@@ -864,27 +531,12 @@ export default class ReactNativeBleTransport {
|
|
|
864
531
|
transport.notifySubscription?.remove();
|
|
865
532
|
transport.notifySubscription = undefined;
|
|
866
533
|
|
|
867
|
-
if (transport.notifyTransactionId) {
|
|
868
|
-
try {
|
|
869
|
-
await this.blePlxManager?.cancelTransaction(transport.notifyTransactionId);
|
|
870
|
-
} catch (e) {
|
|
871
|
-
Log?.debug('release: cancel notify transaction error (ignored): ', e?.message || e);
|
|
872
|
-
}
|
|
873
|
-
}
|
|
874
|
-
|
|
875
534
|
delete transportCache[uuid];
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
this.deviceProtocol.delete(uuid);
|
|
879
|
-
this.deviceProtocolHints.delete(uuid);
|
|
880
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
881
|
-
this.protocolV2Assemblers.delete(uuid);
|
|
882
|
-
this.resetProtocolV2Frames(uuid);
|
|
883
535
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
536
|
+
// Temporary close the Android disconnect after each request
|
|
537
|
+
if (Platform.OS === 'android') {
|
|
538
|
+
// await this.blePlxManager?.cancelDeviceConnection(uuid);
|
|
539
|
+
}
|
|
888
540
|
}
|
|
889
541
|
|
|
890
542
|
return Promise.resolve(true);
|
|
@@ -894,12 +546,7 @@ export default class ReactNativeBleTransport {
|
|
|
894
546
|
await this.call(session, name, data);
|
|
895
547
|
}
|
|
896
548
|
|
|
897
|
-
async call(
|
|
898
|
-
uuid: string,
|
|
899
|
-
name: string,
|
|
900
|
-
data: Record<string, unknown>,
|
|
901
|
-
options?: TransportCallOptions
|
|
902
|
-
) {
|
|
549
|
+
async call(uuid: string, name: string, data: Record<string, unknown>) {
|
|
903
550
|
if (this.stopped) {
|
|
904
551
|
// eslint-disable-next-line prefer-promise-reject-errors
|
|
905
552
|
return Promise.reject(ERRORS.TypedError('Transport stopped.'));
|
|
@@ -915,13 +562,13 @@ export default class ReactNativeBleTransport {
|
|
|
915
562
|
throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
|
|
916
563
|
}
|
|
917
564
|
|
|
918
|
-
const
|
|
919
|
-
if (!
|
|
920
|
-
throw ERRORS.TypedError(
|
|
921
|
-
HardwareErrorCode.RuntimeError,
|
|
922
|
-
`Device protocol has not been detected for ${uuid}`
|
|
923
|
-
);
|
|
565
|
+
const transport = transportCache[uuid];
|
|
566
|
+
if (!transport) {
|
|
567
|
+
throw ERRORS.TypedError(HardwareErrorCode.TransportNotFound);
|
|
924
568
|
}
|
|
569
|
+
|
|
570
|
+
this.runPromise = createDeferred();
|
|
571
|
+
const messages = this._messages;
|
|
925
572
|
// Upload resources on low-end phones may OOM
|
|
926
573
|
if (name === 'ResourceUpdate' || name === 'ResourceAck') {
|
|
927
574
|
Log?.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', {
|
|
@@ -929,44 +576,12 @@ export default class ReactNativeBleTransport {
|
|
|
929
576
|
hash: data?.hash,
|
|
930
577
|
});
|
|
931
578
|
} else if (LogBlockCommand.has(name)) {
|
|
932
|
-
Log?.debug('transport-react-native', 'call-', ' name: ', name
|
|
579
|
+
Log?.debug('transport-react-native', 'call-', ' name: ', name);
|
|
933
580
|
} else {
|
|
934
|
-
Log?.debug(
|
|
935
|
-
'transport-react-native',
|
|
936
|
-
'call-',
|
|
937
|
-
' name: ',
|
|
938
|
-
name,
|
|
939
|
-
' data: ',
|
|
940
|
-
data,
|
|
941
|
-
' protocol: ',
|
|
942
|
-
protocol
|
|
943
|
-
);
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
if (protocol === 'V2') {
|
|
947
|
-
return this.callProtocolV2(uuid, name, data, options);
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
return this.callProtocolV1(uuid, name, data, options);
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
private async callProtocolV1(
|
|
954
|
-
uuid: string,
|
|
955
|
-
name: string,
|
|
956
|
-
data: Record<string, unknown>,
|
|
957
|
-
options?: TransportCallOptions
|
|
958
|
-
) {
|
|
959
|
-
if (!this._messages) {
|
|
960
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
581
|
+
Log?.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data);
|
|
961
582
|
}
|
|
962
583
|
|
|
963
|
-
const
|
|
964
|
-
const runPromise = createDeferred<string>();
|
|
965
|
-
runPromise.promise.catch(() => undefined);
|
|
966
|
-
this.runPromise = runPromise;
|
|
967
|
-
const messages = this._messages;
|
|
968
|
-
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
969
|
-
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
584
|
+
const buffers = buildBuffers(messages, name, data);
|
|
970
585
|
|
|
971
586
|
async function writeChunkedData(
|
|
972
587
|
buffers: ByteBuffer[],
|
|
@@ -1037,41 +652,20 @@ export default class ReactNativeBleTransport {
|
|
|
1037
652
|
}
|
|
1038
653
|
|
|
1039
654
|
try {
|
|
1040
|
-
const response = await
|
|
1041
|
-
runPromise.promise,
|
|
1042
|
-
new Promise<never>((_, reject) => {
|
|
1043
|
-
if (options?.timeoutMs) {
|
|
1044
|
-
timeout = setTimeout(() => {
|
|
1045
|
-
const error = ERRORS.TypedError(
|
|
1046
|
-
HardwareErrorCode.BleTimeoutError,
|
|
1047
|
-
`BLE response timeout after ${options.timeoutMs}ms for ${name}`
|
|
1048
|
-
);
|
|
1049
|
-
runPromise.reject(error);
|
|
1050
|
-
reject(error);
|
|
1051
|
-
}, options.timeoutMs);
|
|
1052
|
-
}
|
|
1053
|
-
}),
|
|
1054
|
-
]);
|
|
655
|
+
const response = await this.runPromise.promise;
|
|
1055
656
|
|
|
1056
657
|
if (typeof response !== 'string') {
|
|
1057
658
|
throw new Error('Returning data is not string.');
|
|
1058
659
|
}
|
|
1059
660
|
|
|
1060
661
|
Log?.debug('receive data: ', response);
|
|
1061
|
-
const jsonData =
|
|
662
|
+
const jsonData = receiveOne(messages, response);
|
|
1062
663
|
return check.call(jsonData);
|
|
1063
664
|
} catch (e) {
|
|
1064
|
-
|
|
1065
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe call failed:', e);
|
|
1066
|
-
} else {
|
|
1067
|
-
Log?.error('call error: ', e);
|
|
1068
|
-
}
|
|
665
|
+
Log?.error('call error: ', e);
|
|
1069
666
|
throw e;
|
|
1070
667
|
} finally {
|
|
1071
|
-
|
|
1072
|
-
if (this.runPromise === runPromise) {
|
|
1073
|
-
this.runPromise = null;
|
|
1074
|
-
}
|
|
668
|
+
this.runPromise = null;
|
|
1075
669
|
}
|
|
1076
670
|
}
|
|
1077
671
|
|
|
@@ -1138,13 +732,6 @@ export default class ReactNativeBleTransport {
|
|
|
1138
732
|
if (transportCache[session]) {
|
|
1139
733
|
delete transportCache[session];
|
|
1140
734
|
}
|
|
1141
|
-
this.deviceProtocol.delete(session);
|
|
1142
|
-
this.deviceProtocolHints.delete(session);
|
|
1143
|
-
this.protocolV2Assemblers.delete(session);
|
|
1144
|
-
this.resetProtocolV2Frames(session);
|
|
1145
|
-
if (this.activeProtocolV2Call?.uuid === session) {
|
|
1146
|
-
this.activeProtocolV2Call = null;
|
|
1147
|
-
}
|
|
1148
735
|
|
|
1149
736
|
// emit the disconnect event
|
|
1150
737
|
try {
|
|
@@ -1167,421 +754,4 @@ export default class ReactNativeBleTransport {
|
|
|
1167
754
|
}
|
|
1168
755
|
this.runPromise = null;
|
|
1169
756
|
}
|
|
1170
|
-
|
|
1171
|
-
private getCachedTransport(uuid: string) {
|
|
1172
|
-
const transport = transportCache[uuid];
|
|
1173
|
-
if (!transport) {
|
|
1174
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportNotFound);
|
|
1175
|
-
}
|
|
1176
|
-
return transport;
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
private createProtocolMismatchError(expected: ProtocolType) {
|
|
1180
|
-
return ERRORS.TypedError(
|
|
1181
|
-
HardwareErrorCode.RuntimeError,
|
|
1182
|
-
`Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`
|
|
1183
|
-
);
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
private createProtocolDetectionError() {
|
|
1187
|
-
return ERRORS.TypedError(
|
|
1188
|
-
HardwareErrorCode.BleTimeoutError,
|
|
1189
|
-
'Unable to detect BLE protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping'
|
|
1190
|
-
);
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
private clearProbeProtocol(uuid: string, protocol: ProtocolType) {
|
|
1194
|
-
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1195
|
-
this.deviceProtocol.delete(uuid);
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
|
-
private async detectProtocol(
|
|
1200
|
-
uuid: string,
|
|
1201
|
-
expectedProtocol?: ProtocolType,
|
|
1202
|
-
protocolHint?: ProtocolType
|
|
1203
|
-
): Promise<ProtocolType> {
|
|
1204
|
-
if (expectedProtocol === 'V1') {
|
|
1205
|
-
if (await this.probeProtocolV1(uuid)) {
|
|
1206
|
-
this.deviceProtocol.set(uuid, 'V1');
|
|
1207
|
-
Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V1 (expected)`);
|
|
1208
|
-
return 'V1';
|
|
1209
|
-
}
|
|
1210
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
if (expectedProtocol === 'V2') {
|
|
1214
|
-
this.deviceProtocol.set(uuid, 'V2');
|
|
1215
|
-
Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (expected)`);
|
|
1216
|
-
return 'V2';
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
if (protocolHint === 'V2') {
|
|
1220
|
-
this.deviceProtocol.set(uuid, 'V2');
|
|
1221
|
-
Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
|
|
1222
|
-
return 'V2';
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
1226
|
-
this.deviceProtocol.set(uuid, 'V2');
|
|
1227
|
-
Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (cached)`);
|
|
1228
|
-
return 'V2';
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
const protocolV1Detected = await this.probeProtocolV1(uuid);
|
|
1232
|
-
if (protocolV1Detected) {
|
|
1233
|
-
this.deviceProtocol.set(uuid, 'V1');
|
|
1234
|
-
Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V1`);
|
|
1235
|
-
return 'V1';
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
|
-
await this.resetProbeStateAfterProtocolProbe(uuid, 'V1');
|
|
1239
|
-
if (await this.probeProtocolV2(uuid)) {
|
|
1240
|
-
this.deviceProtocol.set(uuid, 'V2');
|
|
1241
|
-
Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2`);
|
|
1242
|
-
return 'V2';
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
this.deviceProtocol.delete(uuid);
|
|
1246
|
-
throw this.createProtocolDetectionError();
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
private async resetProbeStateAfterProtocolProbe(uuid: string, protocol: ProtocolType) {
|
|
1250
|
-
const transport = transportCache[uuid];
|
|
1251
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1252
|
-
this.resetProtocolV2Frames(uuid);
|
|
1253
|
-
if (this.activeProtocolV2Call?.uuid === uuid) {
|
|
1254
|
-
this.activeProtocolV2Call = null;
|
|
1255
|
-
}
|
|
1256
|
-
if (this.runPromise) {
|
|
1257
|
-
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
1258
|
-
this.runPromise.reject(error);
|
|
1259
|
-
this.runPromise = null;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
if (!transport) return;
|
|
1263
|
-
|
|
1264
|
-
const previousNotifyTransactionId = transport.notifyTransactionId;
|
|
1265
|
-
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
1266
|
-
this.monitorTokens.delete(uuid);
|
|
1267
|
-
}
|
|
1268
|
-
transport.notifySubscription?.remove();
|
|
1269
|
-
transport.notifySubscription = undefined;
|
|
1270
|
-
if (previousNotifyTransactionId) {
|
|
1271
|
-
try {
|
|
1272
|
-
await this.blePlxManager?.cancelTransaction(previousNotifyTransactionId);
|
|
1273
|
-
} catch (error) {
|
|
1274
|
-
Log?.debug(
|
|
1275
|
-
`[ReactNativeBleTransport] cancel notify after Protocol ${protocol} probe failed:`,
|
|
1276
|
-
error?.message || error
|
|
1277
|
-
);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
const monitorToken = this.nextMonitorToken;
|
|
1282
|
-
this.nextMonitorToken += 1;
|
|
1283
|
-
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
1284
|
-
transport.monitorToken = monitorToken;
|
|
1285
|
-
transport.notifyTransactionId = notifyTransactionId;
|
|
1286
|
-
this.monitorTokens.set(uuid, monitorToken);
|
|
1287
|
-
transport.notifySubscription = this._monitorCharacteristic(
|
|
1288
|
-
transport.notifyCharacteristic,
|
|
1289
|
-
uuid,
|
|
1290
|
-
monitorToken,
|
|
1291
|
-
notifyTransactionId
|
|
1292
|
-
);
|
|
1293
|
-
if (Platform.OS === 'ios') {
|
|
1294
|
-
await new Promise<void>(resolve => {
|
|
1295
|
-
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
1296
|
-
});
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
private async probeProtocolV1(uuid: string) {
|
|
1301
|
-
if (!this._messages) {
|
|
1302
|
-
return false;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
try {
|
|
1306
|
-
this.deviceProtocol.set(uuid, 'V1');
|
|
1307
|
-
await this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1308
|
-
return true;
|
|
1309
|
-
} catch (error) {
|
|
1310
|
-
this.clearProbeProtocol(uuid, 'V1');
|
|
1311
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe failed:', error);
|
|
1312
|
-
return false;
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
private async probeProtocolV2(uuid: string) {
|
|
1317
|
-
if (!this._messages || !this._messagesV2) {
|
|
1318
|
-
return false;
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
this.deviceProtocol.set(uuid, 'V2');
|
|
1322
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1323
|
-
const detected = await probeProtocolV2Helper({
|
|
1324
|
-
call: (name: string, data: Record<string, unknown>, options?: TransportCallOptions) =>
|
|
1325
|
-
this.callProtocolV2(uuid, name, data, options),
|
|
1326
|
-
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
|
|
1327
|
-
logger: Log,
|
|
1328
|
-
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1329
|
-
onProbeFailed: () => {
|
|
1330
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1331
|
-
this.resetProtocolV2Frames(uuid);
|
|
1332
|
-
},
|
|
1333
|
-
});
|
|
1334
|
-
if (!detected) {
|
|
1335
|
-
this.clearProbeProtocol(uuid, 'V2');
|
|
1336
|
-
}
|
|
1337
|
-
return detected;
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
private handleProtocolV2Notification(uuid: string, data: Uint8Array) {
|
|
1341
|
-
try {
|
|
1342
|
-
if (!this.runPromise || this.activeProtocolV2Call?.uuid !== uuid) {
|
|
1343
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1344
|
-
this.resetProtocolV2Frames(uuid);
|
|
1345
|
-
return;
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
if (data.length === 0) return;
|
|
1349
|
-
|
|
1350
|
-
const assembler = this.protocolV2Assemblers.get(uuid);
|
|
1351
|
-
if (!assembler) return;
|
|
1352
|
-
|
|
1353
|
-
let frameData = assembler.push(data);
|
|
1354
|
-
while (frameData) {
|
|
1355
|
-
this.resolveProtocolV2Frame(uuid, frameData);
|
|
1356
|
-
frameData = assembler.push(new Uint8Array(0));
|
|
1357
|
-
}
|
|
1358
|
-
} catch (error) {
|
|
1359
|
-
Log?.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
|
|
1360
|
-
const notifyError = ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError);
|
|
1361
|
-
this.runPromise?.reject(notifyError);
|
|
1362
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
private getProtocolV2FrameQueue(uuid: string) {
|
|
1367
|
-
let queue = this.protocolV2FrameQueues.get(uuid);
|
|
1368
|
-
if (!queue) {
|
|
1369
|
-
queue = [];
|
|
1370
|
-
this.protocolV2FrameQueues.set(uuid, queue);
|
|
1371
|
-
}
|
|
1372
|
-
return queue;
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
private resolveProtocolV2Frame(uuid: string, frame: Uint8Array) {
|
|
1376
|
-
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1377
|
-
if (framePromise) {
|
|
1378
|
-
framePromise.resolve(frame);
|
|
1379
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1380
|
-
return;
|
|
1381
|
-
}
|
|
1382
|
-
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
private rejectAllProtocolV2Frames(error: Error) {
|
|
1386
|
-
this.protocolV2FrameQueues.clear();
|
|
1387
|
-
for (const framePromise of this.protocolV2FramePromises.values()) {
|
|
1388
|
-
framePromise.reject(error);
|
|
1389
|
-
}
|
|
1390
|
-
this.protocolV2FramePromises.clear();
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
private resetProtocolV2Frames(uuid: string) {
|
|
1394
|
-
this.protocolV2FrameQueues.delete(uuid);
|
|
1395
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
private isActiveProtocolV2Call(uuid: string, token: number) {
|
|
1399
|
-
return this.activeProtocolV2Call?.uuid === uuid && this.activeProtocolV2Call.token === token;
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
private async readProtocolV2Frame(uuid: string) {
|
|
1403
|
-
const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
|
|
1404
|
-
if (queuedFrame) {
|
|
1405
|
-
return queuedFrame;
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
|
-
const framePromise = createDeferred<Uint8Array>();
|
|
1409
|
-
this.protocolV2FramePromises.set(uuid, framePromise);
|
|
1410
|
-
try {
|
|
1411
|
-
return await framePromise.promise;
|
|
1412
|
-
} finally {
|
|
1413
|
-
if (this.protocolV2FramePromises.get(uuid) === framePromise) {
|
|
1414
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1419
|
-
private async writeProtocolV2Frame(
|
|
1420
|
-
transport: BleTransport,
|
|
1421
|
-
frame: Uint8Array,
|
|
1422
|
-
options?: { highVolume?: boolean; writeWithResponse?: boolean }
|
|
1423
|
-
) {
|
|
1424
|
-
const tuning = getProtocolV2BleTuning();
|
|
1425
|
-
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1426
|
-
platform: Platform.OS,
|
|
1427
|
-
iosPacketLength: tuning.iosPacketLength,
|
|
1428
|
-
androidPacketLength: tuning.androidPacketLength,
|
|
1429
|
-
mtu: Platform.OS === 'android' ? transport.mtuSize : undefined,
|
|
1430
|
-
});
|
|
1431
|
-
const writeWithResponse =
|
|
1432
|
-
!!options?.writeWithResponse || (!!options?.highVolume && tuning.highVolumeWriteWithResponse);
|
|
1433
|
-
const writeMode = resolveBleWriteMode(
|
|
1434
|
-
transport.writeCharacteristic,
|
|
1435
|
-
writeWithResponse ? 'withResponse' : 'withoutResponse'
|
|
1436
|
-
);
|
|
1437
|
-
const shouldThrottle = !!options?.highVolume && writeMode === 'withoutResponse';
|
|
1438
|
-
let packetsWritten = 0;
|
|
1439
|
-
|
|
1440
|
-
try {
|
|
1441
|
-
for (let offset = 0; offset < frame.length; offset += packetCapacity) {
|
|
1442
|
-
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1443
|
-
const base64 = Buffer.from(chunk).toString('base64');
|
|
1444
|
-
if (writeMode === 'withResponse') {
|
|
1445
|
-
await transport.writeCharacteristic.writeWithResponse(base64);
|
|
1446
|
-
} else {
|
|
1447
|
-
await transport.writeCharacteristic.writeWithoutResponse(base64);
|
|
1448
|
-
}
|
|
1449
|
-
packetsWritten += 1;
|
|
1450
|
-
|
|
1451
|
-
if (
|
|
1452
|
-
shouldThrottle &&
|
|
1453
|
-
packetsWritten % tuning.highVolumeWriteBurstSize === 0 &&
|
|
1454
|
-
offset + packetCapacity < frame.length
|
|
1455
|
-
) {
|
|
1456
|
-
await delay(tuning.highVolumeWritePauseMs);
|
|
1457
|
-
}
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
if (shouldThrottle) {
|
|
1461
|
-
await delay(tuning.highVolumeWriteFlushDelayMs);
|
|
1462
|
-
}
|
|
1463
|
-
} catch (error) {
|
|
1464
|
-
if (options?.highVolume && !writeWithResponse && packetsWritten === 0) {
|
|
1465
|
-
Log?.debug(
|
|
1466
|
-
'[ReactNativeBleTransport] Protocol V2 high-volume writeWithoutResponse failed before data was sent, fallback to writeWithResponse:',
|
|
1467
|
-
error
|
|
1468
|
-
);
|
|
1469
|
-
await this.writeProtocolV2Frame(transport, frame, {
|
|
1470
|
-
highVolume: true,
|
|
1471
|
-
writeWithResponse: true,
|
|
1472
|
-
});
|
|
1473
|
-
return;
|
|
1474
|
-
}
|
|
1475
|
-
throw error;
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
private async callProtocolV2(
|
|
1480
|
-
uuid: string,
|
|
1481
|
-
name: string,
|
|
1482
|
-
data: Record<string, unknown>,
|
|
1483
|
-
options?: TransportCallOptions
|
|
1484
|
-
) {
|
|
1485
|
-
if (!this._messages || !this._messagesV2) {
|
|
1486
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'GetProtoVersion';
|
|
1490
|
-
if (this.runPromise) {
|
|
1491
|
-
if (!forceRun) {
|
|
1492
|
-
throw ERRORS.TypedError(HardwareErrorCode.TransportCallInProgress);
|
|
1493
|
-
}
|
|
1494
|
-
const error = ERRORS.TypedError(HardwareErrorCode.BleForceCleanRunPromise);
|
|
1495
|
-
this.runPromise.reject(error);
|
|
1496
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1497
|
-
this.runPromise = null;
|
|
1498
|
-
this.activeProtocolV2Call = null;
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
const transport = this.getCachedTransport(uuid);
|
|
1502
|
-
const runPromise = createDeferred<Uint8Array>();
|
|
1503
|
-
runPromise.promise.catch(() => undefined);
|
|
1504
|
-
this.runPromise = runPromise;
|
|
1505
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1506
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1507
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1508
|
-
this.resetProtocolV2Frames(uuid);
|
|
1509
|
-
let completed = false;
|
|
1510
|
-
const callOptions = {
|
|
1511
|
-
...options,
|
|
1512
|
-
timeoutMs: options?.timeoutMs ?? BLE_RESPONSE_TIMEOUT_MS,
|
|
1513
|
-
};
|
|
1514
|
-
const highVolumeWrite = LogBlockCommand.has(name);
|
|
1515
|
-
|
|
1516
|
-
if (highVolumeWrite) {
|
|
1517
|
-
const tuning = getProtocolV2BleTuning();
|
|
1518
|
-
Log?.debug(
|
|
1519
|
-
'[ReactNativeBleTransport] Protocol V2 high-volume write uses throttled writeWithoutResponse:',
|
|
1520
|
-
name,
|
|
1521
|
-
{
|
|
1522
|
-
packetCapacity:
|
|
1523
|
-
Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
|
|
1524
|
-
burstSize: tuning.highVolumeWriteBurstSize,
|
|
1525
|
-
pauseMs: tuning.highVolumeWritePauseMs,
|
|
1526
|
-
flushDelayMs: tuning.highVolumeWriteFlushDelayMs,
|
|
1527
|
-
writeWithResponse: tuning.highVolumeWriteWithResponse,
|
|
1528
|
-
}
|
|
1529
|
-
);
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
try {
|
|
1533
|
-
const session = new ProtocolV2Session({
|
|
1534
|
-
schemas: {
|
|
1535
|
-
protocolV1: this._messages,
|
|
1536
|
-
protocolV2: this._messagesV2,
|
|
1537
|
-
},
|
|
1538
|
-
router: PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1539
|
-
writeFrame: async (frame: Uint8Array) => {
|
|
1540
|
-
await this.writeProtocolV2Frame(transport, frame, {
|
|
1541
|
-
highVolume: highVolumeWrite,
|
|
1542
|
-
});
|
|
1543
|
-
},
|
|
1544
|
-
readFrame: async () => {
|
|
1545
|
-
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
1546
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
1547
|
-
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1548
|
-
}
|
|
1549
|
-
return rxFrame;
|
|
1550
|
-
},
|
|
1551
|
-
logger: Log,
|
|
1552
|
-
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1553
|
-
createTimeoutError: (_messageName: string, timeout: number) =>
|
|
1554
|
-
ERRORS.TypedError(
|
|
1555
|
-
HardwareErrorCode.BleTimeoutError,
|
|
1556
|
-
`BLE response timeout after ${timeout}ms for ${name}`
|
|
1557
|
-
),
|
|
1558
|
-
});
|
|
1559
|
-
|
|
1560
|
-
const result = await session.call(name, data, callOptions);
|
|
1561
|
-
completed = true;
|
|
1562
|
-
return result;
|
|
1563
|
-
} catch (e) {
|
|
1564
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1565
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1566
|
-
this.resetProtocolV2Frames(uuid);
|
|
1567
|
-
}
|
|
1568
|
-
Log?.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1569
|
-
throw e;
|
|
1570
|
-
} finally {
|
|
1571
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1572
|
-
if (!completed) {
|
|
1573
|
-
this.protocolV2Assemblers.get(uuid)?.reset();
|
|
1574
|
-
}
|
|
1575
|
-
this.resetProtocolV2Frames(uuid);
|
|
1576
|
-
this.activeProtocolV2Call = null;
|
|
1577
|
-
}
|
|
1578
|
-
if (this.runPromise === runPromise) {
|
|
1579
|
-
this.runPromise = null;
|
|
1580
|
-
}
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
getProtocolType(path: string): ProtocolType | undefined {
|
|
1585
|
-
return this.deviceProtocol.get(path);
|
|
1586
|
-
}
|
|
1587
757
|
}
|