@onekeyfe/hd-transport-react-native 1.1.27-patch.1 → 1.2.0-alpha.0
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 +2 -0
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts +15 -0
- package/dist/bleStrategy.d.ts.map +1 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +58 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +814 -122
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/BleManager.ts +11 -14
- package/src/BleTransport.ts +9 -5
- package/src/__tests__/bleStrategy.test.ts +47 -0
- package/src/bleStrategy.ts +60 -0
- package/src/constants.ts +25 -1
- package/src/index.ts +888 -65
- package/src/logger.ts +19 -0
- package/src/types.ts +3 -0
- package/src/utils/validateNotify.ts +4 -4
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
3
5
|
var reactNative = require('react-native');
|
|
4
6
|
var buffer = require('buffer');
|
|
5
7
|
var reactNativeBlePlx = require('react-native-ble-plx');
|
|
6
8
|
var ByteBuffer = require('bytebuffer');
|
|
7
9
|
var transport = require('@onekeyfe/hd-transport');
|
|
8
10
|
var hdShared = require('@onekeyfe/hd-shared');
|
|
9
|
-
var hdCore = require('@onekeyfe/hd-core');
|
|
10
11
|
var BleUtils = require('@onekeyfe/react-native-ble-utils');
|
|
11
12
|
|
|
12
13
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
@@ -45,44 +46,124 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
45
46
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
46
47
|
};
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
let activeLogger;
|
|
50
|
+
const setBleLogger = (logger) => {
|
|
51
|
+
activeLogger = logger;
|
|
52
|
+
};
|
|
53
|
+
const bleLogger = {
|
|
54
|
+
debug: (...args) => { var _a; return (_a = activeLogger === null || activeLogger === void 0 ? void 0 : activeLogger.debug) === null || _a === void 0 ? void 0 : _a.call(activeLogger, ...args); },
|
|
55
|
+
error: (...args) => { var _a; return (_a = activeLogger === null || activeLogger === void 0 ? void 0 : activeLogger.error) === null || _a === void 0 ? void 0 : _a.call(activeLogger, ...args); },
|
|
56
|
+
warn: (...args) => { var _a; return (_a = activeLogger === null || activeLogger === void 0 ? void 0 : activeLogger.warn) === null || _a === void 0 ? void 0 : _a.call(activeLogger, ...args); },
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const Logger = bleLogger;
|
|
49
60
|
const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
|
|
50
61
|
const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
|
|
51
62
|
const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
|
|
52
|
-
|
|
53
|
-
const cleanup = (cleanupListener) => {
|
|
63
|
+
const cleanup = () => {
|
|
54
64
|
if (timeout) {
|
|
55
65
|
clearTimeout(timeout);
|
|
56
66
|
}
|
|
57
67
|
if (cleanupListener)
|
|
58
68
|
cleanupListener();
|
|
59
69
|
};
|
|
70
|
+
const timeout = setTimeout(() => {
|
|
71
|
+
cleanup();
|
|
72
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
|
|
73
|
+
}, 60 * 1000);
|
|
60
74
|
const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
|
|
61
75
|
var _a;
|
|
62
76
|
if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
|
|
63
77
|
return;
|
|
64
78
|
}
|
|
65
79
|
const { bondState } = peripheral;
|
|
66
|
-
if (bondState.preState === 'BOND_NONE' && bondState.state === 'BOND_BONDING') {
|
|
67
|
-
timeout = setTimeout(() => {
|
|
68
|
-
cleanup(cleanupListener);
|
|
69
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
|
|
70
|
-
}, 60 * 1000);
|
|
71
|
-
}
|
|
72
80
|
const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
|
|
73
81
|
const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
|
|
74
82
|
Logger.debug('onDeviceBondState bondState:', bondState);
|
|
75
83
|
if (hasBonded) {
|
|
76
|
-
cleanup(
|
|
84
|
+
cleanup();
|
|
77
85
|
resolve(peripheral);
|
|
78
86
|
}
|
|
79
87
|
else if (hasCanceled) {
|
|
80
|
-
cleanup(
|
|
88
|
+
cleanup();
|
|
81
89
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
|
|
82
90
|
}
|
|
83
91
|
});
|
|
84
92
|
});
|
|
85
93
|
|
|
94
|
+
const IOS_PACKET_LENGTH = 128;
|
|
95
|
+
const ANDROID_PACKET_LENGTH = 192;
|
|
96
|
+
const ANDROID_DEFAULT_MTU = 23;
|
|
97
|
+
const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
|
|
98
|
+
const OneKeyServices = {
|
|
99
|
+
classic: {
|
|
100
|
+
[ClassicServiceUUID]: {
|
|
101
|
+
serviceUuid: ClassicServiceUUID,
|
|
102
|
+
writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
|
|
103
|
+
notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
const bluetoothServices = [];
|
|
108
|
+
for (const deviceType of Object.keys(OneKeyServices)) {
|
|
109
|
+
const services = OneKeyServices[deviceType];
|
|
110
|
+
bluetoothServices.push(...Object.keys(services));
|
|
111
|
+
}
|
|
112
|
+
const getBluetoothServiceUuids = () => bluetoothServices;
|
|
113
|
+
const getInfosForServiceUuid = (serviceUuid, deviceType) => {
|
|
114
|
+
var _a;
|
|
115
|
+
const services = OneKeyServices[deviceType];
|
|
116
|
+
if (!services) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const normalizedServiceUuid = normalizeBleUuid(serviceUuid);
|
|
120
|
+
const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid);
|
|
121
|
+
if (!service) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return service;
|
|
125
|
+
};
|
|
126
|
+
const normalizeBleUuid = (uuid) => (uuid !== null && uuid !== void 0 ? uuid : '').replace(/-/g, '').toLowerCase();
|
|
127
|
+
const getBleUuidKey = (uuid) => {
|
|
128
|
+
const normalized = normalizeBleUuid(uuid);
|
|
129
|
+
return normalized.length >= 8 ? normalized.substring(4, 8) : normalized;
|
|
130
|
+
};
|
|
131
|
+
const isSameBleUuid = (left, right) => {
|
|
132
|
+
const normalizedLeft = normalizeBleUuid(left);
|
|
133
|
+
const normalizedRight = normalizeBleUuid(right);
|
|
134
|
+
return (normalizedLeft === normalizedRight ||
|
|
135
|
+
(getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
function hasWritableCapability(characteristic) {
|
|
139
|
+
return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
|
|
140
|
+
}
|
|
141
|
+
function resolveBleWriteMode(characteristic, preferredMode = 'withoutResponse') {
|
|
142
|
+
if (preferredMode === 'withoutResponse' && characteristic.isWritableWithoutResponse) {
|
|
143
|
+
return 'withoutResponse';
|
|
144
|
+
}
|
|
145
|
+
if (preferredMode === 'withResponse' && characteristic.isWritableWithResponse) {
|
|
146
|
+
return 'withResponse';
|
|
147
|
+
}
|
|
148
|
+
if (characteristic.isWritableWithoutResponse) {
|
|
149
|
+
return 'withoutResponse';
|
|
150
|
+
}
|
|
151
|
+
if (characteristic.isWritableWithResponse) {
|
|
152
|
+
return 'withResponse';
|
|
153
|
+
}
|
|
154
|
+
return preferredMode;
|
|
155
|
+
}
|
|
156
|
+
function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PACKET_LENGTH, androidPacketLength = ANDROID_PACKET_LENGTH, mtu, }) {
|
|
157
|
+
if (platform === 'ios') {
|
|
158
|
+
return iosPacketLength;
|
|
159
|
+
}
|
|
160
|
+
if (platform === 'android') {
|
|
161
|
+
const payloadLength = Math.max((mtu !== null && mtu !== void 0 ? mtu : ANDROID_DEFAULT_MTU) - 3, 1);
|
|
162
|
+
return Math.min(androidPacketLength, payloadLength);
|
|
163
|
+
}
|
|
164
|
+
return androidPacketLength;
|
|
165
|
+
}
|
|
166
|
+
|
|
86
167
|
const timer = process.env.NODE_ENV === 'development'
|
|
87
168
|
? {
|
|
88
169
|
timeout: (fn, ms) => {
|
|
@@ -126,58 +207,27 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
|
|
|
126
207
|
}, ms);
|
|
127
208
|
});
|
|
128
209
|
|
|
129
|
-
const IOS_PACKET_LENGTH = 128;
|
|
130
|
-
const ANDROID_PACKET_LENGTH = 192;
|
|
131
|
-
const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
|
|
132
|
-
const OneKeyServices = {
|
|
133
|
-
classic: {
|
|
134
|
-
[ClassicServiceUUID]: {
|
|
135
|
-
serviceUuid: ClassicServiceUUID,
|
|
136
|
-
writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
|
|
137
|
-
notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
const bluetoothServices = [];
|
|
142
|
-
for (const deviceType of Object.keys(OneKeyServices)) {
|
|
143
|
-
const services = OneKeyServices[deviceType];
|
|
144
|
-
bluetoothServices.push(...Object.keys(services));
|
|
145
|
-
}
|
|
146
|
-
const getBluetoothServiceUuids = () => bluetoothServices;
|
|
147
|
-
const getInfosForServiceUuid = (serviceUuid, deviceType) => {
|
|
148
|
-
const services = OneKeyServices[deviceType];
|
|
149
|
-
if (!services) {
|
|
150
|
-
return null;
|
|
151
|
-
}
|
|
152
|
-
const service = services[serviceUuid];
|
|
153
|
-
if (!service) {
|
|
154
|
-
return null;
|
|
155
|
-
}
|
|
156
|
-
return service;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
210
|
const isHeaderChunk = (chunk) => {
|
|
160
211
|
if (chunk.length < 9)
|
|
161
212
|
return false;
|
|
162
213
|
const [MagicQuestionMark, sharp1, sharp2] = chunk;
|
|
163
|
-
if (String.fromCharCode(MagicQuestionMark) === String.fromCharCode(transport.
|
|
164
|
-
String.fromCharCode(sharp1) === String.fromCharCode(transport.
|
|
165
|
-
String.fromCharCode(sharp2) === String.fromCharCode(transport.
|
|
214
|
+
if (String.fromCharCode(MagicQuestionMark) === String.fromCharCode(transport.PROTOCOL_V1_REPORT_ID) &&
|
|
215
|
+
String.fromCharCode(sharp1) === String.fromCharCode(transport.PROTOCOL_V1_HEADER_BYTE) &&
|
|
216
|
+
String.fromCharCode(sharp2) === String.fromCharCode(transport.PROTOCOL_V1_HEADER_BYTE)) {
|
|
166
217
|
return true;
|
|
167
218
|
}
|
|
168
219
|
return false;
|
|
169
220
|
};
|
|
170
221
|
|
|
171
|
-
const Log$1 =
|
|
222
|
+
const Log$1 = bleLogger;
|
|
172
223
|
class BleTransport {
|
|
173
224
|
constructor(device, writeCharacteristic, notifyCharacteristic) {
|
|
174
225
|
this.name = 'ReactNativeBleTransport';
|
|
175
|
-
this.mtuSize =
|
|
226
|
+
this.mtuSize = 23;
|
|
176
227
|
this.id = device.id;
|
|
177
228
|
this.device = device;
|
|
178
229
|
this.writeCharacteristic = writeCharacteristic;
|
|
179
230
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
180
|
-
console.log(`BleTransport(${String(this.id)}) new instance`);
|
|
181
231
|
}
|
|
182
232
|
writeWithRetry(data, retryCount = BleTransport.MAX_RETRIES) {
|
|
183
233
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -187,7 +237,7 @@ class BleTransport {
|
|
|
187
237
|
catch (error) {
|
|
188
238
|
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`);
|
|
189
239
|
if (retryCount > 0) {
|
|
190
|
-
yield
|
|
240
|
+
yield hdShared.wait(BleTransport.RETRY_DELAY);
|
|
191
241
|
if (error.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
192
242
|
error.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
193
243
|
try {
|
|
@@ -211,8 +261,8 @@ class BleTransport {
|
|
|
211
261
|
BleTransport.MAX_RETRIES = 5;
|
|
212
262
|
BleTransport.RETRY_DELAY = 2000;
|
|
213
263
|
|
|
214
|
-
const { check,
|
|
215
|
-
const Log =
|
|
264
|
+
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
265
|
+
const Log = bleLogger;
|
|
216
266
|
const transportCache = {};
|
|
217
267
|
const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
|
|
218
268
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
@@ -243,20 +293,95 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
243
293
|
return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
|
|
244
294
|
};
|
|
245
295
|
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
246
|
-
|
|
247
|
-
|
|
296
|
+
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
297
|
+
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
298
|
+
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
299
|
+
const DEVICE_SCAN_TIMEOUT_MS = 8000;
|
|
300
|
+
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
301
|
+
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
302
|
+
const HIGH_VOLUME_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 6;
|
|
303
|
+
const HIGH_VOLUME_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 6 : 2;
|
|
304
|
+
const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 20 : 8;
|
|
305
|
+
const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
|
|
306
|
+
iosPacketLength: IOS_PACKET_LENGTH,
|
|
307
|
+
androidPacketLength: ANDROID_PACKET_LENGTH,
|
|
308
|
+
highVolumeWriteBurstSize: HIGH_VOLUME_WRITE_BURST_SIZE,
|
|
309
|
+
highVolumeWritePauseMs: HIGH_VOLUME_WRITE_PAUSE_MS,
|
|
310
|
+
highVolumeWriteFlushDelayMs: HIGH_VOLUME_WRITE_FLUSH_DELAY_MS,
|
|
311
|
+
highVolumeWriteWithResponse: false,
|
|
312
|
+
};
|
|
313
|
+
let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
314
|
+
const normalizePositiveInteger = (value, fallback) => {
|
|
315
|
+
const normalized = Number(value);
|
|
316
|
+
if (!Number.isFinite(normalized) || normalized <= 0)
|
|
317
|
+
return fallback;
|
|
318
|
+
return Math.floor(normalized);
|
|
319
|
+
};
|
|
320
|
+
function configureProtocolV2BleTuning(tuning = {}) {
|
|
321
|
+
var _a;
|
|
322
|
+
protocolV2BleTuning = {
|
|
323
|
+
iosPacketLength: normalizePositiveInteger(tuning.iosPacketLength, protocolV2BleTuning.iosPacketLength),
|
|
324
|
+
androidPacketLength: normalizePositiveInteger(tuning.androidPacketLength, protocolV2BleTuning.androidPacketLength),
|
|
325
|
+
highVolumeWriteBurstSize: normalizePositiveInteger(tuning.highVolumeWriteBurstSize, protocolV2BleTuning.highVolumeWriteBurstSize),
|
|
326
|
+
highVolumeWritePauseMs: normalizePositiveInteger(tuning.highVolumeWritePauseMs, protocolV2BleTuning.highVolumeWritePauseMs),
|
|
327
|
+
highVolumeWriteFlushDelayMs: normalizePositiveInteger(tuning.highVolumeWriteFlushDelayMs, protocolV2BleTuning.highVolumeWriteFlushDelayMs),
|
|
328
|
+
highVolumeWriteWithResponse: (_a = tuning.highVolumeWriteWithResponse) !== null && _a !== void 0 ? _a : protocolV2BleTuning.highVolumeWriteWithResponse,
|
|
329
|
+
};
|
|
330
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning configured:', protocolV2BleTuning);
|
|
331
|
+
}
|
|
332
|
+
function resetProtocolV2BleTuning() {
|
|
333
|
+
protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
334
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning reset:', protocolV2BleTuning);
|
|
335
|
+
}
|
|
336
|
+
function getProtocolV2BleTuning() {
|
|
337
|
+
return Object.assign({}, protocolV2BleTuning);
|
|
338
|
+
}
|
|
339
|
+
function inferProtocolHintFromDeviceName(name) {
|
|
340
|
+
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
341
|
+
}
|
|
342
|
+
function getDeviceDisplayName(device) {
|
|
343
|
+
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
344
|
+
}
|
|
345
|
+
function isGenericBleService(uuid) {
|
|
346
|
+
return ['1800', '1801', '180a'].includes(getBleUuidKey(uuid));
|
|
347
|
+
}
|
|
348
|
+
function hasKnownOneKeyService(device) {
|
|
349
|
+
var _a;
|
|
350
|
+
return ((_a = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _a !== void 0 ? _a : []).some(serviceUuid => getInfosForServiceUuid(serviceUuid, 'classic'));
|
|
351
|
+
}
|
|
352
|
+
const ANDROID_REQUEST_MTU = 256;
|
|
353
|
+
const connectOptions = {
|
|
354
|
+
requestMTU: ANDROID_REQUEST_MTU,
|
|
248
355
|
timeout: 3000,
|
|
249
356
|
refreshGatt: 'OnConnected',
|
|
250
357
|
};
|
|
251
358
|
const tryToGetConfiguration = (device) => {
|
|
252
359
|
if (!device || !device.serviceUUIDs)
|
|
253
360
|
return null;
|
|
254
|
-
const
|
|
361
|
+
const serviceUUID = device.serviceUUIDs.find(uuid => getInfosForServiceUuid(uuid, 'classic'));
|
|
362
|
+
if (!serviceUUID)
|
|
363
|
+
return null;
|
|
255
364
|
const infos = getInfosForServiceUuid(serviceUUID, 'classic');
|
|
256
365
|
if (!infos)
|
|
257
366
|
return null;
|
|
258
367
|
return infos;
|
|
259
368
|
};
|
|
369
|
+
const requestAndroidMtu = (device) => __awaiter(void 0, void 0, void 0, function* () {
|
|
370
|
+
if (reactNative.Platform.OS !== 'android')
|
|
371
|
+
return device;
|
|
372
|
+
try {
|
|
373
|
+
const mtuDevice = yield device.requestMTU(ANDROID_REQUEST_MTU);
|
|
374
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU requested:', {
|
|
375
|
+
requested: ANDROID_REQUEST_MTU,
|
|
376
|
+
mtu: mtuDevice.mtu,
|
|
377
|
+
});
|
|
378
|
+
return mtuDevice;
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU request failed:', error);
|
|
382
|
+
return device;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
260
385
|
function remapError(error) {
|
|
261
386
|
var _a;
|
|
262
387
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -281,12 +406,22 @@ class ReactNativeBleTransport {
|
|
|
281
406
|
this.name = 'ReactNativeBleTransport';
|
|
282
407
|
this.configured = false;
|
|
283
408
|
this.stopped = false;
|
|
284
|
-
this.scanTimeout =
|
|
409
|
+
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
285
410
|
this.runPromise = null;
|
|
286
411
|
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
287
|
-
this.
|
|
412
|
+
this.deviceProtocol = new Map();
|
|
413
|
+
this.deviceProtocolHints = new Map();
|
|
414
|
+
this.protocolV2Assemblers = new Map();
|
|
415
|
+
this.protocolV2FrameQueues = new Map();
|
|
416
|
+
this.protocolV2FramePromises = new Map();
|
|
417
|
+
this.activeProtocolV2Call = null;
|
|
418
|
+
this.nextProtocolV2CallToken = 1;
|
|
419
|
+
this.monitorTokens = new Map();
|
|
420
|
+
this.nextMonitorToken = 1;
|
|
421
|
+
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
288
422
|
}
|
|
289
|
-
init(
|
|
423
|
+
init(logger, emitter) {
|
|
424
|
+
setBleLogger(logger);
|
|
290
425
|
this.emitter = emitter;
|
|
291
426
|
}
|
|
292
427
|
configure(signedData) {
|
|
@@ -294,6 +429,10 @@ class ReactNativeBleTransport {
|
|
|
294
429
|
this.configured = true;
|
|
295
430
|
this._messages = messages;
|
|
296
431
|
}
|
|
432
|
+
configureProtocolV2(signedData) {
|
|
433
|
+
this._messagesV2 = parseConfigure(signedData);
|
|
434
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
|
|
435
|
+
}
|
|
297
436
|
listen() {
|
|
298
437
|
}
|
|
299
438
|
getPlxManager() {
|
|
@@ -303,6 +442,7 @@ class ReactNativeBleTransport {
|
|
|
303
442
|
return Promise.resolve(this.blePlxManager);
|
|
304
443
|
}
|
|
305
444
|
resolveCharacteristics(device) {
|
|
445
|
+
var _a, _b, _c, _d;
|
|
306
446
|
return __awaiter(this, void 0, void 0, function* () {
|
|
307
447
|
yield device.discoverAllServicesAndCharacteristics();
|
|
308
448
|
let infos = tryToGetConfiguration(device);
|
|
@@ -319,7 +459,19 @@ class ReactNativeBleTransport {
|
|
|
319
459
|
}
|
|
320
460
|
}
|
|
321
461
|
}
|
|
462
|
+
let fallbackServiceUuid;
|
|
322
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) {
|
|
323
475
|
try {
|
|
324
476
|
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
325
477
|
yield device.cancelConnection();
|
|
@@ -329,7 +481,12 @@ class ReactNativeBleTransport {
|
|
|
329
481
|
}
|
|
330
482
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
331
483
|
}
|
|
332
|
-
const
|
|
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
|
+
}
|
|
333
490
|
if (!characteristics) {
|
|
334
491
|
characteristics = yield device.characteristicsForService(serviceUuid);
|
|
335
492
|
}
|
|
@@ -339,10 +496,10 @@ class ReactNativeBleTransport {
|
|
|
339
496
|
let writeCharacteristic;
|
|
340
497
|
let notifyCharacteristic;
|
|
341
498
|
for (const c of characteristics) {
|
|
342
|
-
if (c.uuid
|
|
499
|
+
if (isSameBleUuid(c.uuid, writeUuid)) {
|
|
343
500
|
writeCharacteristic = c;
|
|
344
501
|
}
|
|
345
|
-
else if (c.uuid
|
|
502
|
+
else if (isSameBleUuid(c.uuid, notifyUuid)) {
|
|
346
503
|
notifyCharacteristic = c;
|
|
347
504
|
}
|
|
348
505
|
}
|
|
@@ -352,7 +509,7 @@ class ReactNativeBleTransport {
|
|
|
352
509
|
if (!notifyCharacteristic) {
|
|
353
510
|
throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
354
511
|
}
|
|
355
|
-
if (!writeCharacteristic
|
|
512
|
+
if (!hasWritableCapability(writeCharacteristic)) {
|
|
356
513
|
throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
357
514
|
}
|
|
358
515
|
if (!notifyCharacteristic.isNotifiable) {
|
|
@@ -373,6 +530,10 @@ class ReactNativeBleTransport {
|
|
|
373
530
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
374
531
|
return;
|
|
375
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
|
+
}
|
|
376
537
|
try {
|
|
377
538
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
378
539
|
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
|
|
@@ -381,14 +542,16 @@ class ReactNativeBleTransport {
|
|
|
381
542
|
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
382
543
|
});
|
|
383
544
|
if (this.runPromise) {
|
|
384
|
-
|
|
545
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
546
|
+
this.runPromise.reject(error);
|
|
547
|
+
this.rejectAllProtocolV2Frames(error);
|
|
385
548
|
}
|
|
386
549
|
}
|
|
387
550
|
catch (e) {
|
|
388
551
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
|
|
389
552
|
}
|
|
390
553
|
finally {
|
|
391
|
-
this.release(uuid);
|
|
554
|
+
this.release(uuid, true);
|
|
392
555
|
}
|
|
393
556
|
});
|
|
394
557
|
}
|
|
@@ -410,7 +573,6 @@ class ReactNativeBleTransport {
|
|
|
410
573
|
catch (e) {
|
|
411
574
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
412
575
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
413
|
-
connectOptions = {};
|
|
414
576
|
device = yield device.connect();
|
|
415
577
|
}
|
|
416
578
|
else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
@@ -422,7 +584,13 @@ class ReactNativeBleTransport {
|
|
|
422
584
|
transport.device = device;
|
|
423
585
|
transport.writeCharacteristic = writeCharacteristic;
|
|
424
586
|
transport.notifyCharacteristic = notifyCharacteristic;
|
|
425
|
-
|
|
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);
|
|
426
594
|
this.attachDisconnectSubscription(transport, device, uuid);
|
|
427
595
|
}
|
|
428
596
|
finally {
|
|
@@ -457,9 +625,10 @@ class ReactNativeBleTransport {
|
|
|
457
625
|
}
|
|
458
626
|
}
|
|
459
627
|
blePlxManager.startDeviceScan(null, {
|
|
628
|
+
allowDuplicates: true,
|
|
460
629
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
461
630
|
}, (error, device) => {
|
|
462
|
-
var _a, _b;
|
|
631
|
+
var _a, _b, _c;
|
|
463
632
|
if (error) {
|
|
464
633
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan manager: ', blePlxManager);
|
|
465
634
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
@@ -480,13 +649,35 @@ class ReactNativeBleTransport {
|
|
|
480
649
|
}
|
|
481
650
|
return;
|
|
482
651
|
}
|
|
483
|
-
|
|
652
|
+
const displayName = getDeviceDisplayName(device);
|
|
653
|
+
const isOneKey = hdShared.isOnekeyDevice((_b = device === null || device === void 0 ? void 0 : device.name) !== null && _b !== void 0 ? _b : null, device === null || device === void 0 ? void 0 : device.id) ||
|
|
654
|
+
hdShared.isOnekeyDevice((_c = device === null || device === void 0 ? void 0 : device.localName) !== null && _c !== void 0 ? _c : null, device === null || device === void 0 ? void 0 : device.id) ||
|
|
655
|
+
hasKnownOneKeyService(device);
|
|
656
|
+
const shouldTraceCandidate = !!displayName && /onekey|bixinkey|pro\s*2|pro\b|touch|^k\d|^t\d/i.test(displayName);
|
|
657
|
+
if (shouldTraceCandidate) {
|
|
658
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan candidate', {
|
|
659
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
660
|
+
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
661
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
662
|
+
serviceUUIDs: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
663
|
+
accepted: isOneKey,
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
if (isOneKey) {
|
|
484
667
|
Log === null || Log === void 0 ? void 0 : Log.debug('search device start ======================');
|
|
485
|
-
const { name, localName, id } = device !== null && device !== void 0 ? device : {};
|
|
486
|
-
Log === null || Log === void 0 ? void 0 : Log.debug(`device name: ${name !== null && name !== void 0 ? name : ''}\nlocalName: ${localName !== null && localName !== void 0 ? localName : ''}\nid: ${id !== null && id !== void 0 ? id : ''}`);
|
|
668
|
+
const { name, localName, id, serviceUUIDs } = device !== null && device !== void 0 ? device : {};
|
|
669
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`device name: ${name !== null && name !== void 0 ? name : ''}\nlocalName: ${localName !== null && localName !== void 0 ? localName : ''}\nid: ${id !== null && id !== void 0 ? id : ''}\nserviceUUIDs: ${(serviceUUIDs !== null && serviceUUIDs !== void 0 ? serviceUUIDs : []).join(',')}`);
|
|
487
670
|
addDevice(device);
|
|
488
671
|
Log === null || Log === void 0 ? void 0 : Log.debug('search device end ======================\n');
|
|
489
672
|
}
|
|
673
|
+
else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
|
|
674
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Pro2-like BLE device was not accepted:', {
|
|
675
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
676
|
+
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
677
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
678
|
+
serviceUUIDs: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
679
|
+
});
|
|
680
|
+
}
|
|
490
681
|
});
|
|
491
682
|
getConnectedDeviceIds(getBluetoothServiceUuids()).then(devices => {
|
|
492
683
|
for (const device of devices) {
|
|
@@ -495,8 +686,14 @@ class ReactNativeBleTransport {
|
|
|
495
686
|
}
|
|
496
687
|
});
|
|
497
688
|
const addDevice = (device) => {
|
|
689
|
+
var _a;
|
|
498
690
|
if (deviceList.every(d => d.id !== device.id)) {
|
|
499
|
-
|
|
691
|
+
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
692
|
+
const protocolHint = inferProtocolHintFromDeviceName(displayName);
|
|
693
|
+
if (protocolHint) {
|
|
694
|
+
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
695
|
+
}
|
|
696
|
+
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
500
697
|
}
|
|
501
698
|
};
|
|
502
699
|
timer.timeout(() => {
|
|
@@ -507,19 +704,32 @@ class ReactNativeBleTransport {
|
|
|
507
704
|
});
|
|
508
705
|
}
|
|
509
706
|
acquire(input) {
|
|
510
|
-
var _a;
|
|
707
|
+
var _a, _b;
|
|
511
708
|
return __awaiter(this, void 0, void 0, function* () {
|
|
512
|
-
const { uuid, forceCleanRunPromise } = input;
|
|
709
|
+
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
513
710
|
if (!uuid) {
|
|
514
711
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
515
712
|
}
|
|
516
|
-
|
|
517
|
-
if (
|
|
518
|
-
|
|
519
|
-
yield
|
|
713
|
+
const cachedTransport = transportCache[uuid];
|
|
714
|
+
if (cachedTransport) {
|
|
715
|
+
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
716
|
+
const isCachedDeviceConnected = yield cachedTransport.device.isConnected().catch(() => false);
|
|
717
|
+
if (isCachedDeviceConnected &&
|
|
718
|
+
cachedProtocol &&
|
|
719
|
+
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
720
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
721
|
+
return { uuid, protocolType: cachedProtocol };
|
|
722
|
+
}
|
|
723
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
724
|
+
yield this.release(uuid, true);
|
|
520
725
|
}
|
|
726
|
+
let device = null;
|
|
521
727
|
if (forceCleanRunPromise && this.runPromise) {
|
|
522
|
-
|
|
728
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
729
|
+
this.runPromise.reject(error);
|
|
730
|
+
this.rejectAllProtocolV2Frames(error);
|
|
731
|
+
this.runPromise = null;
|
|
732
|
+
this.activeProtocolV2Call = null;
|
|
523
733
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
524
734
|
}
|
|
525
735
|
const blePlxManager = yield this.getPlxManager();
|
|
@@ -535,6 +745,9 @@ class ReactNativeBleTransport {
|
|
|
535
745
|
if (bondState.bonding) {
|
|
536
746
|
yield onDeviceBondState(uuid);
|
|
537
747
|
}
|
|
748
|
+
else if (!bondState.bonded) {
|
|
749
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
|
|
750
|
+
}
|
|
538
751
|
}
|
|
539
752
|
if (!device) {
|
|
540
753
|
const devices = yield blePlxManager.devices([uuid]);
|
|
@@ -555,7 +768,6 @@ class ReactNativeBleTransport {
|
|
|
555
768
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
556
769
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
557
770
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
558
|
-
connectOptions = {};
|
|
559
771
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
560
772
|
device = yield blePlxManager.connectToDevice(uuid);
|
|
561
773
|
}
|
|
@@ -574,23 +786,22 @@ class ReactNativeBleTransport {
|
|
|
574
786
|
if (!(yield device.isConnected())) {
|
|
575
787
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
576
788
|
try {
|
|
577
|
-
yield device.connect(connectOptions);
|
|
789
|
+
device = yield device.connect(connectOptions);
|
|
578
790
|
}
|
|
579
791
|
catch (e) {
|
|
580
792
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
581
793
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
582
794
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
583
|
-
connectOptions = {};
|
|
584
795
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
585
796
|
try {
|
|
586
|
-
yield device.connect();
|
|
797
|
+
device = yield device.connect();
|
|
587
798
|
}
|
|
588
799
|
catch (e) {
|
|
589
800
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
|
|
590
801
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
591
802
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
592
803
|
yield device.cancelConnection();
|
|
593
|
-
yield device.connect();
|
|
804
|
+
device = yield device.connect();
|
|
594
805
|
}
|
|
595
806
|
}
|
|
596
807
|
}
|
|
@@ -599,31 +810,62 @@ class ReactNativeBleTransport {
|
|
|
599
810
|
}
|
|
600
811
|
}
|
|
601
812
|
}
|
|
813
|
+
device = yield requestAndroidMtu(device);
|
|
602
814
|
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(device);
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
(
|
|
815
|
+
const protocolHint = expectedProtocol
|
|
816
|
+
? undefined
|
|
817
|
+
: (_a = this.deviceProtocolHints.get(uuid)) !== null && _a !== void 0 ? _a : inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
|
|
818
|
+
yield this.release(uuid, true);
|
|
819
|
+
if (protocolHint) {
|
|
820
|
+
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
821
|
+
}
|
|
822
|
+
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
823
|
+
if (reactNative.Platform.OS === 'android') {
|
|
824
|
+
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
|
|
825
|
+
}
|
|
826
|
+
const monitorToken = this.nextMonitorToken;
|
|
827
|
+
this.nextMonitorToken += 1;
|
|
828
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
829
|
+
transport$1.monitorToken = monitorToken;
|
|
830
|
+
transport$1.notifyTransactionId = notifyTransactionId;
|
|
831
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
832
|
+
transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
833
|
+
transportCache[uuid] = transport$1;
|
|
834
|
+
this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
|
|
835
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
836
|
+
yield new Promise(resolve => {
|
|
837
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
838
|
+
});
|
|
839
|
+
}
|
|
840
|
+
else if (reactNative.Platform.OS === 'android') {
|
|
841
|
+
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
842
|
+
}
|
|
843
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
844
|
+
(_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
|
|
608
845
|
name: device.name,
|
|
609
846
|
id: device.id,
|
|
610
847
|
connectId: device.id,
|
|
611
848
|
});
|
|
612
|
-
this.attachDisconnectSubscription(transport, device, uuid);
|
|
613
|
-
return { uuid };
|
|
849
|
+
this.attachDisconnectSubscription(transport$1, device, uuid);
|
|
850
|
+
return { uuid, protocolType };
|
|
614
851
|
});
|
|
615
852
|
}
|
|
616
|
-
_monitorCharacteristic(characteristic, uuid) {
|
|
853
|
+
_monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
|
|
617
854
|
let bufferLength = 0;
|
|
618
855
|
let buffer$1 = [];
|
|
619
856
|
const subscription = characteristic.monitor((error, c) => {
|
|
620
857
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
858
|
+
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
621
859
|
if (error) {
|
|
622
860
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
623
861
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
624
862
|
Log === null || Log === void 0 ? void 0 : Log.debug('notify error ignored during FirmwareUpload write recovery: ', uuid);
|
|
625
863
|
return;
|
|
626
864
|
}
|
|
865
|
+
if (!isCurrentMonitor) {
|
|
866
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
627
869
|
if (this.runPromise) {
|
|
628
870
|
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
629
871
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
@@ -637,20 +879,37 @@ class ReactNativeBleTransport {
|
|
|
637
879
|
((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
|
|
638
880
|
((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
|
|
639
881
|
((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
|
|
640
|
-
|
|
882
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
883
|
+
this.runPromise.reject(notifyError);
|
|
884
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
641
885
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
642
886
|
return;
|
|
643
887
|
}
|
|
644
|
-
|
|
888
|
+
const notifyError = hdShared.ERRORS.TypedError(ERROR);
|
|
889
|
+
this.runPromise.reject(notifyError);
|
|
890
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
645
891
|
Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
646
892
|
}
|
|
647
893
|
return;
|
|
648
894
|
}
|
|
895
|
+
if (!isCurrentMonitor) {
|
|
896
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored for stale transport: ', uuid, notifyTransactionId);
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
649
899
|
if (!c) {
|
|
650
900
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleMonitorError);
|
|
651
901
|
}
|
|
652
902
|
try {
|
|
653
903
|
const data = buffer.Buffer.from(c.value, 'base64');
|
|
904
|
+
const protocol = this.deviceProtocol.get(uuid);
|
|
905
|
+
if (!protocol) {
|
|
906
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
|
|
907
|
+
return;
|
|
908
|
+
}
|
|
909
|
+
if (protocol === 'V2') {
|
|
910
|
+
this.handleProtocolV2Notification(uuid, new Uint8Array(data));
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
654
913
|
if (isHeaderChunk(data)) {
|
|
655
914
|
bufferLength = data.readInt32BE(5);
|
|
656
915
|
buffer$1 = [...data.subarray(3)];
|
|
@@ -658,7 +917,7 @@ class ReactNativeBleTransport {
|
|
|
658
917
|
else {
|
|
659
918
|
buffer$1 = buffer$1.concat([...data]);
|
|
660
919
|
}
|
|
661
|
-
if (buffer$1.length - transport.
|
|
920
|
+
if (buffer$1.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferLength) {
|
|
662
921
|
const value = buffer.Buffer.from(buffer$1);
|
|
663
922
|
bufferLength = 0;
|
|
664
923
|
buffer$1 = [];
|
|
@@ -667,24 +926,65 @@ class ReactNativeBleTransport {
|
|
|
667
926
|
}
|
|
668
927
|
catch (error) {
|
|
669
928
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
670
|
-
|
|
929
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
930
|
+
(_j = this.runPromise) === null || _j === void 0 ? void 0 : _j.reject(notifyError);
|
|
931
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
671
932
|
}
|
|
672
|
-
},
|
|
933
|
+
}, notifyTransactionId);
|
|
673
934
|
return subscription;
|
|
674
935
|
}
|
|
675
|
-
release(uuid) {
|
|
676
|
-
var _a, _b, _c;
|
|
936
|
+
release(uuid, onclose = false) {
|
|
937
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
677
938
|
return __awaiter(this, void 0, void 0, function* () {
|
|
678
939
|
const transport = transportCache[uuid];
|
|
940
|
+
if (this.runPromise) {
|
|
941
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
942
|
+
this.runPromise.reject(error);
|
|
943
|
+
this.runPromise = null;
|
|
944
|
+
this.rejectAllProtocolV2Frames(error);
|
|
945
|
+
this.activeProtocolV2Call = null;
|
|
946
|
+
}
|
|
947
|
+
else {
|
|
948
|
+
this.resetProtocolV2Frames(uuid);
|
|
949
|
+
}
|
|
950
|
+
if (reactNative.Platform.OS === 'android' && !onclose && transport) {
|
|
951
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
952
|
+
this.resetProtocolV2Frames(uuid);
|
|
953
|
+
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
954
|
+
this.activeProtocolV2Call = null;
|
|
955
|
+
}
|
|
956
|
+
return Promise.resolve(true);
|
|
957
|
+
}
|
|
679
958
|
if (transport) {
|
|
959
|
+
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
960
|
+
this.monitorTokens.delete(uuid);
|
|
961
|
+
}
|
|
680
962
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
|
|
681
|
-
(
|
|
963
|
+
(_c = transport.disconnectSubscription) === null || _c === void 0 ? void 0 : _c.remove();
|
|
682
964
|
transport.disconnectSubscription = undefined;
|
|
683
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (
|
|
684
|
-
(
|
|
965
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_d = transport.notifyCharacteristic) === null || _d === void 0 ? void 0 : _d.uuid);
|
|
966
|
+
(_e = transport.notifySubscription) === null || _e === void 0 ? void 0 : _e.remove();
|
|
685
967
|
transport.notifySubscription = undefined;
|
|
968
|
+
if (transport.notifyTransactionId) {
|
|
969
|
+
try {
|
|
970
|
+
yield ((_f = this.blePlxManager) === null || _f === void 0 ? void 0 : _f.cancelTransaction(transport.notifyTransactionId));
|
|
971
|
+
}
|
|
972
|
+
catch (e) {
|
|
973
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel notify transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
686
976
|
delete transportCache[uuid];
|
|
687
|
-
|
|
977
|
+
}
|
|
978
|
+
this.deviceProtocol.delete(uuid);
|
|
979
|
+
this.deviceProtocolHints.delete(uuid);
|
|
980
|
+
(_g = this.protocolV2Assemblers.get(uuid)) === null || _g === void 0 ? void 0 : _g.reset();
|
|
981
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
982
|
+
this.resetProtocolV2Frames(uuid);
|
|
983
|
+
try {
|
|
984
|
+
yield ((_h = this.blePlxManager) === null || _h === void 0 ? void 0 : _h.cancelTransaction(uuid));
|
|
985
|
+
}
|
|
986
|
+
catch (e) {
|
|
987
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
688
988
|
}
|
|
689
989
|
return Promise.resolve(true);
|
|
690
990
|
});
|
|
@@ -694,7 +994,7 @@ class ReactNativeBleTransport {
|
|
|
694
994
|
yield this.call(session, name, data);
|
|
695
995
|
});
|
|
696
996
|
}
|
|
697
|
-
call(uuid, name, data) {
|
|
997
|
+
call(uuid, name, data, options) {
|
|
698
998
|
return __awaiter(this, void 0, void 0, function* () {
|
|
699
999
|
if (this.stopped) {
|
|
700
1000
|
return Promise.reject(hdShared.ERRORS.TypedError('Transport stopped.'));
|
|
@@ -707,12 +1007,10 @@ class ReactNativeBleTransport {
|
|
|
707
1007
|
if (this.runPromise && !forceRun) {
|
|
708
1008
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
709
1009
|
}
|
|
710
|
-
const
|
|
711
|
-
if (!
|
|
712
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.
|
|
1010
|
+
const protocol = this.getProtocolType(uuid);
|
|
1011
|
+
if (!protocol) {
|
|
1012
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
713
1013
|
}
|
|
714
|
-
this.runPromise = hdShared.createDeferred();
|
|
715
|
-
const messages = this._messages;
|
|
716
1014
|
if (name === 'ResourceUpdate' || name === 'ResourceAck') {
|
|
717
1015
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', {
|
|
718
1016
|
file_name: data === null || data === void 0 ? void 0 : data.file_name,
|
|
@@ -720,12 +1018,29 @@ class ReactNativeBleTransport {
|
|
|
720
1018
|
});
|
|
721
1019
|
}
|
|
722
1020
|
else if (transport.LogBlockCommand.has(name)) {
|
|
723
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name);
|
|
1021
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' protocol: ', protocol);
|
|
724
1022
|
}
|
|
725
1023
|
else {
|
|
726
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data);
|
|
1024
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
1025
|
+
}
|
|
1026
|
+
if (protocol === 'V2') {
|
|
1027
|
+
return this.callProtocolV2(uuid, name, data, options);
|
|
1028
|
+
}
|
|
1029
|
+
return this.callProtocolV1(uuid, name, data, options);
|
|
1030
|
+
});
|
|
1031
|
+
}
|
|
1032
|
+
callProtocolV1(uuid, name, data, options) {
|
|
1033
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1034
|
+
if (!this._messages) {
|
|
1035
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
727
1036
|
}
|
|
728
|
-
const
|
|
1037
|
+
const transport = this.getCachedTransport(uuid);
|
|
1038
|
+
const runPromise = hdShared.createDeferred();
|
|
1039
|
+
runPromise.promise.catch(() => undefined);
|
|
1040
|
+
this.runPromise = runPromise;
|
|
1041
|
+
const messages = this._messages;
|
|
1042
|
+
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1043
|
+
let timeout;
|
|
729
1044
|
function writeChunkedData(buffers, writeFunction, onError) {
|
|
730
1045
|
return __awaiter(this, void 0, void 0, function* () {
|
|
731
1046
|
const packetCapacity = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_PACKET_LENGTH;
|
|
@@ -780,7 +1095,7 @@ class ReactNativeBleTransport {
|
|
|
780
1095
|
});
|
|
781
1096
|
}
|
|
782
1097
|
if (name === 'EmmcFileWrite') {
|
|
783
|
-
yield writeChunkedData(buffers, data => transport
|
|
1098
|
+
yield writeChunkedData(buffers, data => transport.writeWithRetry(data), e => {
|
|
784
1099
|
this.runPromise = null;
|
|
785
1100
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
786
1101
|
});
|
|
@@ -797,7 +1112,7 @@ class ReactNativeBleTransport {
|
|
|
797
1112
|
let attempt = 0;
|
|
798
1113
|
while (true) {
|
|
799
1114
|
try {
|
|
800
|
-
yield transport
|
|
1115
|
+
yield transport.writeCharacteristic.writeWithoutResponse(data);
|
|
801
1116
|
return;
|
|
802
1117
|
}
|
|
803
1118
|
catch (error) {
|
|
@@ -822,7 +1137,7 @@ class ReactNativeBleTransport {
|
|
|
822
1137
|
attempt += 1;
|
|
823
1138
|
if (shouldReconnect) {
|
|
824
1139
|
try {
|
|
825
|
-
yield this.reconnectFirmwareUploadTransport(uuid, transport
|
|
1140
|
+
yield this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
826
1141
|
}
|
|
827
1142
|
catch (e) {
|
|
828
1143
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
@@ -842,7 +1157,7 @@ class ReactNativeBleTransport {
|
|
|
842
1157
|
for (const o of buffers) {
|
|
843
1158
|
const outData = o.toString('base64');
|
|
844
1159
|
try {
|
|
845
|
-
yield transport
|
|
1160
|
+
yield transport.writeCharacteristic.writeWithoutResponse(outData);
|
|
846
1161
|
}
|
|
847
1162
|
catch (e) {
|
|
848
1163
|
Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
|
|
@@ -860,20 +1175,40 @@ class ReactNativeBleTransport {
|
|
|
860
1175
|
}
|
|
861
1176
|
}
|
|
862
1177
|
try {
|
|
863
|
-
const response = yield
|
|
1178
|
+
const response = yield Promise.race([
|
|
1179
|
+
runPromise.promise,
|
|
1180
|
+
new Promise((_, reject) => {
|
|
1181
|
+
if (options === null || options === void 0 ? void 0 : options.timeoutMs) {
|
|
1182
|
+
timeout = setTimeout(() => {
|
|
1183
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${options.timeoutMs}ms for ${name}`);
|
|
1184
|
+
runPromise.reject(error);
|
|
1185
|
+
reject(error);
|
|
1186
|
+
}, options.timeoutMs);
|
|
1187
|
+
}
|
|
1188
|
+
}),
|
|
1189
|
+
]);
|
|
864
1190
|
if (typeof response !== 'string') {
|
|
865
1191
|
throw new Error('Returning data is not string.');
|
|
866
1192
|
}
|
|
867
1193
|
Log === null || Log === void 0 ? void 0 : Log.debug('receive data: ', response);
|
|
868
|
-
const jsonData =
|
|
1194
|
+
const jsonData = ProtocolV1.decodeMessage(messages, response);
|
|
869
1195
|
return check.call(jsonData);
|
|
870
1196
|
}
|
|
871
1197
|
catch (e) {
|
|
872
|
-
|
|
1198
|
+
if (name === 'Initialize' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
|
|
1199
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe call failed:', e);
|
|
1200
|
+
}
|
|
1201
|
+
else {
|
|
1202
|
+
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1203
|
+
}
|
|
873
1204
|
throw e;
|
|
874
1205
|
}
|
|
875
1206
|
finally {
|
|
876
|
-
|
|
1207
|
+
if (timeout)
|
|
1208
|
+
clearTimeout(timeout);
|
|
1209
|
+
if (this.runPromise === runPromise) {
|
|
1210
|
+
this.runPromise = null;
|
|
1211
|
+
}
|
|
877
1212
|
}
|
|
878
1213
|
});
|
|
879
1214
|
}
|
|
@@ -881,7 +1216,7 @@ class ReactNativeBleTransport {
|
|
|
881
1216
|
this.stopped = true;
|
|
882
1217
|
}
|
|
883
1218
|
disconnect(session) {
|
|
884
|
-
var _a, _b, _c, _d, _e;
|
|
1219
|
+
var _a, _b, _c, _d, _e, _f;
|
|
885
1220
|
return __awaiter(this, void 0, void 0, function* () {
|
|
886
1221
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport resetSession: ', session);
|
|
887
1222
|
const transport = transportCache[session];
|
|
@@ -930,9 +1265,16 @@ class ReactNativeBleTransport {
|
|
|
930
1265
|
if (transportCache[session]) {
|
|
931
1266
|
delete transportCache[session];
|
|
932
1267
|
}
|
|
1268
|
+
this.deviceProtocol.delete(session);
|
|
1269
|
+
this.deviceProtocolHints.delete(session);
|
|
1270
|
+
this.protocolV2Assemblers.delete(session);
|
|
1271
|
+
this.resetProtocolV2Frames(session);
|
|
1272
|
+
if (((_d = this.activeProtocolV2Call) === null || _d === void 0 ? void 0 : _d.uuid) === session) {
|
|
1273
|
+
this.activeProtocolV2Call = null;
|
|
1274
|
+
}
|
|
933
1275
|
try {
|
|
934
|
-
(
|
|
935
|
-
name: (
|
|
1276
|
+
(_e = this.emitter) === null || _e === void 0 ? void 0 : _e.emit('device-disconnect', {
|
|
1277
|
+
name: (_f = transport === null || transport === void 0 ? void 0 : transport.device) === null || _f === void 0 ? void 0 : _f.name,
|
|
936
1278
|
id: session,
|
|
937
1279
|
connectId: session,
|
|
938
1280
|
});
|
|
@@ -948,6 +1290,356 @@ class ReactNativeBleTransport {
|
|
|
948
1290
|
if (this.runPromise) ;
|
|
949
1291
|
this.runPromise = null;
|
|
950
1292
|
}
|
|
1293
|
+
getCachedTransport(uuid) {
|
|
1294
|
+
const transport = transportCache[uuid];
|
|
1295
|
+
if (!transport) {
|
|
1296
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
1297
|
+
}
|
|
1298
|
+
return transport;
|
|
1299
|
+
}
|
|
1300
|
+
createProtocolMismatchError(expected) {
|
|
1301
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1302
|
+
}
|
|
1303
|
+
createProtocolDetectionError() {
|
|
1304
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
|
|
1305
|
+
}
|
|
1306
|
+
clearProbeProtocol(uuid, protocol) {
|
|
1307
|
+
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1308
|
+
this.deviceProtocol.delete(uuid);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
detectProtocol(uuid, expectedProtocol, protocolHint) {
|
|
1312
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1313
|
+
if (expectedProtocol === 'V1') {
|
|
1314
|
+
if (yield this.probeProtocolV1(uuid)) {
|
|
1315
|
+
this.deviceProtocol.set(uuid, 'V1');
|
|
1316
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V1 (expected)`);
|
|
1317
|
+
return 'V1';
|
|
1318
|
+
}
|
|
1319
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1320
|
+
}
|
|
1321
|
+
if (expectedProtocol === 'V2') {
|
|
1322
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1323
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (expected)`);
|
|
1324
|
+
return 'V2';
|
|
1325
|
+
}
|
|
1326
|
+
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1327
|
+
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1328
|
+
const protocol = probeOrder[i];
|
|
1329
|
+
if (i > 0) {
|
|
1330
|
+
yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
1331
|
+
}
|
|
1332
|
+
const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
|
|
1333
|
+
if (detected) {
|
|
1334
|
+
this.deviceProtocol.set(uuid, protocol);
|
|
1335
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> ${protocol}`);
|
|
1336
|
+
return protocol;
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
this.deviceProtocol.delete(uuid);
|
|
1340
|
+
throw this.createProtocolDetectionError();
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1344
|
+
var _a, _b, _c, _d;
|
|
1345
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1346
|
+
const transport = transportCache[uuid];
|
|
1347
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1348
|
+
this.resetProtocolV2Frames(uuid);
|
|
1349
|
+
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
1350
|
+
this.activeProtocolV2Call = null;
|
|
1351
|
+
}
|
|
1352
|
+
if (this.runPromise) {
|
|
1353
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1354
|
+
this.runPromise.reject(error);
|
|
1355
|
+
this.runPromise = null;
|
|
1356
|
+
}
|
|
1357
|
+
if (!transport)
|
|
1358
|
+
return;
|
|
1359
|
+
const previousNotifyTransactionId = transport.notifyTransactionId;
|
|
1360
|
+
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
1361
|
+
this.monitorTokens.delete(uuid);
|
|
1362
|
+
}
|
|
1363
|
+
(_c = transport.notifySubscription) === null || _c === void 0 ? void 0 : _c.remove();
|
|
1364
|
+
transport.notifySubscription = undefined;
|
|
1365
|
+
if (previousNotifyTransactionId) {
|
|
1366
|
+
try {
|
|
1367
|
+
yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelTransaction(previousNotifyTransactionId));
|
|
1368
|
+
}
|
|
1369
|
+
catch (error) {
|
|
1370
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] cancel notify after Protocol ${protocol} probe failed:`, (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
const monitorToken = this.nextMonitorToken;
|
|
1374
|
+
this.nextMonitorToken += 1;
|
|
1375
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
1376
|
+
transport.monitorToken = monitorToken;
|
|
1377
|
+
transport.notifyTransactionId = notifyTransactionId;
|
|
1378
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
1379
|
+
transport.notifySubscription = this._monitorCharacteristic(transport.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
1380
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
1381
|
+
yield new Promise(resolve => {
|
|
1382
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
1383
|
+
});
|
|
1384
|
+
}
|
|
1385
|
+
});
|
|
1386
|
+
}
|
|
1387
|
+
probeProtocolV1(uuid) {
|
|
1388
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1389
|
+
if (!this._messages) {
|
|
1390
|
+
return false;
|
|
1391
|
+
}
|
|
1392
|
+
try {
|
|
1393
|
+
this.deviceProtocol.set(uuid, 'V1');
|
|
1394
|
+
yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
catch (error) {
|
|
1398
|
+
this.clearProbeProtocol(uuid, 'V1');
|
|
1399
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe failed:', error);
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
});
|
|
1403
|
+
}
|
|
1404
|
+
probeProtocolV2(uuid) {
|
|
1405
|
+
var _a;
|
|
1406
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1407
|
+
if (!this._messages || !this._messagesV2) {
|
|
1408
|
+
return false;
|
|
1409
|
+
}
|
|
1410
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1411
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1412
|
+
const detected = yield transport.probeProtocolV2({
|
|
1413
|
+
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
1414
|
+
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
|
|
1415
|
+
logger: Log,
|
|
1416
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1417
|
+
onProbeFailed: () => {
|
|
1418
|
+
var _a;
|
|
1419
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1420
|
+
this.resetProtocolV2Frames(uuid);
|
|
1421
|
+
},
|
|
1422
|
+
});
|
|
1423
|
+
if (!detected) {
|
|
1424
|
+
this.clearProbeProtocol(uuid, 'V2');
|
|
1425
|
+
}
|
|
1426
|
+
return detected;
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
handleProtocolV2Notification(uuid, data) {
|
|
1430
|
+
var _a, _b, _c;
|
|
1431
|
+
try {
|
|
1432
|
+
if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== uuid) {
|
|
1433
|
+
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1434
|
+
this.resetProtocolV2Frames(uuid);
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
if (data.length === 0)
|
|
1438
|
+
return;
|
|
1439
|
+
const assembler = this.protocolV2Assemblers.get(uuid);
|
|
1440
|
+
if (!assembler)
|
|
1441
|
+
return;
|
|
1442
|
+
for (const frameData of assembler.drain(data)) {
|
|
1443
|
+
this.resolveProtocolV2Frame(uuid, frameData);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
catch (error) {
|
|
1447
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
|
|
1448
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1449
|
+
(_c = this.runPromise) === null || _c === void 0 ? void 0 : _c.reject(notifyError);
|
|
1450
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
getProtocolV2FrameQueue(uuid) {
|
|
1454
|
+
let queue = this.protocolV2FrameQueues.get(uuid);
|
|
1455
|
+
if (!queue) {
|
|
1456
|
+
queue = [];
|
|
1457
|
+
this.protocolV2FrameQueues.set(uuid, queue);
|
|
1458
|
+
}
|
|
1459
|
+
return queue;
|
|
1460
|
+
}
|
|
1461
|
+
resolveProtocolV2Frame(uuid, frame) {
|
|
1462
|
+
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1463
|
+
if (framePromise) {
|
|
1464
|
+
framePromise.resolve(frame);
|
|
1465
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1469
|
+
}
|
|
1470
|
+
rejectAllProtocolV2Frames(error) {
|
|
1471
|
+
this.protocolV2FrameQueues.clear();
|
|
1472
|
+
for (const framePromise of this.protocolV2FramePromises.values()) {
|
|
1473
|
+
framePromise.reject(error);
|
|
1474
|
+
}
|
|
1475
|
+
this.protocolV2FramePromises.clear();
|
|
1476
|
+
}
|
|
1477
|
+
resetProtocolV2Frames(uuid) {
|
|
1478
|
+
this.protocolV2FrameQueues.delete(uuid);
|
|
1479
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1480
|
+
}
|
|
1481
|
+
isActiveProtocolV2Call(uuid, token) {
|
|
1482
|
+
var _a;
|
|
1483
|
+
return ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === uuid && this.activeProtocolV2Call.token === token;
|
|
1484
|
+
}
|
|
1485
|
+
readProtocolV2Frame(uuid) {
|
|
1486
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1487
|
+
const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
|
|
1488
|
+
if (queuedFrame) {
|
|
1489
|
+
return queuedFrame;
|
|
1490
|
+
}
|
|
1491
|
+
const framePromise = hdShared.createDeferred();
|
|
1492
|
+
this.protocolV2FramePromises.set(uuid, framePromise);
|
|
1493
|
+
try {
|
|
1494
|
+
return yield framePromise.promise;
|
|
1495
|
+
}
|
|
1496
|
+
finally {
|
|
1497
|
+
if (this.protocolV2FramePromises.get(uuid) === framePromise) {
|
|
1498
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
writeProtocolV2Frame(transport, frame, options) {
|
|
1504
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1505
|
+
const tuning = getProtocolV2BleTuning();
|
|
1506
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1507
|
+
platform: reactNative.Platform.OS,
|
|
1508
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
1509
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
1510
|
+
mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
|
|
1511
|
+
});
|
|
1512
|
+
const writeWithResponse = !!(options === null || options === void 0 ? void 0 : options.writeWithResponse) || (!!(options === null || options === void 0 ? void 0 : options.highVolume) && tuning.highVolumeWriteWithResponse);
|
|
1513
|
+
const writeMode = resolveBleWriteMode(transport.writeCharacteristic, writeWithResponse ? 'withResponse' : 'withoutResponse');
|
|
1514
|
+
const shouldThrottle = !!(options === null || options === void 0 ? void 0 : options.highVolume) && writeMode === 'withoutResponse';
|
|
1515
|
+
let packetsWritten = 0;
|
|
1516
|
+
try {
|
|
1517
|
+
for (let offset = 0; offset < frame.length; offset += packetCapacity) {
|
|
1518
|
+
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1519
|
+
const base64 = buffer.Buffer.from(chunk).toString('base64');
|
|
1520
|
+
if (writeMode === 'withResponse') {
|
|
1521
|
+
yield transport.writeCharacteristic.writeWithResponse(base64);
|
|
1522
|
+
}
|
|
1523
|
+
else {
|
|
1524
|
+
yield transport.writeCharacteristic.writeWithoutResponse(base64);
|
|
1525
|
+
}
|
|
1526
|
+
packetsWritten += 1;
|
|
1527
|
+
if (shouldThrottle &&
|
|
1528
|
+
packetsWritten % tuning.highVolumeWriteBurstSize === 0 &&
|
|
1529
|
+
offset + packetCapacity < frame.length) {
|
|
1530
|
+
yield delay(tuning.highVolumeWritePauseMs);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
if (shouldThrottle) {
|
|
1534
|
+
yield delay(tuning.highVolumeWriteFlushDelayMs);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
catch (error) {
|
|
1538
|
+
if ((options === null || options === void 0 ? void 0 : options.highVolume) && !writeWithResponse && packetsWritten === 0) {
|
|
1539
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume writeWithoutResponse failed before data was sent, fallback to writeWithResponse:', error);
|
|
1540
|
+
yield this.writeProtocolV2Frame(transport, frame, {
|
|
1541
|
+
highVolume: true,
|
|
1542
|
+
writeWithResponse: true,
|
|
1543
|
+
});
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
throw error;
|
|
1547
|
+
}
|
|
1548
|
+
});
|
|
1549
|
+
}
|
|
1550
|
+
callProtocolV2(uuid, name, data, options) {
|
|
1551
|
+
var _a, _b, _c, _d;
|
|
1552
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1553
|
+
if (!this._messages || !this._messagesV2) {
|
|
1554
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1555
|
+
}
|
|
1556
|
+
const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'GetProtoVersion';
|
|
1557
|
+
if (this.runPromise) {
|
|
1558
|
+
if (!forceRun) {
|
|
1559
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1560
|
+
}
|
|
1561
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1562
|
+
this.runPromise.reject(error);
|
|
1563
|
+
this.rejectAllProtocolV2Frames(error);
|
|
1564
|
+
this.runPromise = null;
|
|
1565
|
+
this.activeProtocolV2Call = null;
|
|
1566
|
+
}
|
|
1567
|
+
const transport$1 = this.getCachedTransport(uuid);
|
|
1568
|
+
const runPromise = hdShared.createDeferred();
|
|
1569
|
+
runPromise.promise.catch(() => undefined);
|
|
1570
|
+
this.runPromise = runPromise;
|
|
1571
|
+
const callToken = this.nextProtocolV2CallToken++;
|
|
1572
|
+
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1573
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1574
|
+
this.resetProtocolV2Frames(uuid);
|
|
1575
|
+
let completed = false;
|
|
1576
|
+
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
|
|
1577
|
+
const highVolumeWrite = transport.LogBlockCommand.has(name);
|
|
1578
|
+
if (highVolumeWrite) {
|
|
1579
|
+
const tuning = getProtocolV2BleTuning();
|
|
1580
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write uses throttled writeWithoutResponse:', name, {
|
|
1581
|
+
packetCapacity: reactNative.Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
|
|
1582
|
+
burstSize: tuning.highVolumeWriteBurstSize,
|
|
1583
|
+
pauseMs: tuning.highVolumeWritePauseMs,
|
|
1584
|
+
flushDelayMs: tuning.highVolumeWriteFlushDelayMs,
|
|
1585
|
+
writeWithResponse: tuning.highVolumeWriteWithResponse,
|
|
1586
|
+
});
|
|
1587
|
+
}
|
|
1588
|
+
try {
|
|
1589
|
+
const session = new transport.ProtocolV2Session({
|
|
1590
|
+
schemas: {
|
|
1591
|
+
protocolV1: this._messages,
|
|
1592
|
+
protocolV2: this._messagesV2,
|
|
1593
|
+
},
|
|
1594
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1595
|
+
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
1596
|
+
yield this.writeProtocolV2Frame(transport$1, frame, {
|
|
1597
|
+
highVolume: highVolumeWrite,
|
|
1598
|
+
});
|
|
1599
|
+
}),
|
|
1600
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1601
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1602
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1603
|
+
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1604
|
+
}
|
|
1605
|
+
return rxFrame;
|
|
1606
|
+
}),
|
|
1607
|
+
logger: Log,
|
|
1608
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1609
|
+
createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
|
|
1610
|
+
});
|
|
1611
|
+
const result = yield session.call(name, data, callOptions);
|
|
1612
|
+
completed = true;
|
|
1613
|
+
return result;
|
|
1614
|
+
}
|
|
1615
|
+
catch (e) {
|
|
1616
|
+
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1617
|
+
(_c = this.protocolV2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1618
|
+
this.resetProtocolV2Frames(uuid);
|
|
1619
|
+
}
|
|
1620
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1621
|
+
throw e;
|
|
1622
|
+
}
|
|
1623
|
+
finally {
|
|
1624
|
+
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1625
|
+
if (!completed) {
|
|
1626
|
+
(_d = this.protocolV2Assemblers.get(uuid)) === null || _d === void 0 ? void 0 : _d.reset();
|
|
1627
|
+
}
|
|
1628
|
+
this.resetProtocolV2Frames(uuid);
|
|
1629
|
+
this.activeProtocolV2Call = null;
|
|
1630
|
+
}
|
|
1631
|
+
if (this.runPromise === runPromise) {
|
|
1632
|
+
this.runPromise = null;
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
});
|
|
1636
|
+
}
|
|
1637
|
+
getProtocolType(path) {
|
|
1638
|
+
return this.deviceProtocol.get(path);
|
|
1639
|
+
}
|
|
951
1640
|
}
|
|
952
1641
|
|
|
953
|
-
|
|
1642
|
+
exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
|
|
1643
|
+
exports["default"] = ReactNativeBleTransport;
|
|
1644
|
+
exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
|
|
1645
|
+
exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;
|