@onekeyfe/hd-transport-react-native 1.1.34-alpha.2 → 1.1.34-alpha.3
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 +13 -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 +62 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +799 -150
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/subscribeBleOn.d.ts.map +1 -1
- package/dist/transportLog.d.ts +13 -0
- package/dist/transportLog.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 +42 -0
- package/src/__tests__/constants.test.ts +18 -0
- package/src/__tests__/protocolV2Link.test.ts +243 -0
- package/src/bleStrategy.ts +35 -0
- package/src/constants.ts +33 -1
- package/src/index.ts +836 -91
- package/src/logger.ts +19 -0
- package/src/subscribeBleOn.ts +0 -2
- package/src/transportLog.ts +18 -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,116 @@ 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 normalizeBleUuid = (uuid) => (uuid !== null && uuid !== void 0 ? uuid : '').replace(/-/g, '').toLowerCase();
|
|
98
|
+
const getBleUuidKey = (uuid) => {
|
|
99
|
+
const normalized = normalizeBleUuid(uuid);
|
|
100
|
+
return normalized.length >= 8 ? normalized.substring(4, 8) : normalized;
|
|
101
|
+
};
|
|
102
|
+
const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
|
|
103
|
+
const Pro2ServiceUUID = 'fffd';
|
|
104
|
+
const OneKeyServices = {
|
|
105
|
+
classic: {
|
|
106
|
+
[ClassicServiceUUID]: {
|
|
107
|
+
serviceUuid: ClassicServiceUUID,
|
|
108
|
+
writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
|
|
109
|
+
notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
|
|
110
|
+
},
|
|
111
|
+
[Pro2ServiceUUID]: {
|
|
112
|
+
serviceUuid: Pro2ServiceUUID,
|
|
113
|
+
writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
|
|
114
|
+
notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
const bluetoothServices = [];
|
|
119
|
+
for (const deviceType of Object.keys(OneKeyServices)) {
|
|
120
|
+
const services = OneKeyServices[deviceType];
|
|
121
|
+
bluetoothServices.push(...Object.keys(services));
|
|
122
|
+
}
|
|
123
|
+
const getBluetoothServiceUuids = () => bluetoothServices;
|
|
124
|
+
const getInfosForServiceUuid = (serviceUuid, deviceType) => {
|
|
125
|
+
var _a;
|
|
126
|
+
const services = OneKeyServices[deviceType];
|
|
127
|
+
if (!services) {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const normalizedServiceUuid = normalizeBleUuid(serviceUuid);
|
|
131
|
+
const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid ||
|
|
132
|
+
getBleUuidKey(item.serviceUuid) === getBleUuidKey(serviceUuid));
|
|
133
|
+
if (!service) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
return service;
|
|
137
|
+
};
|
|
138
|
+
const isSameBleUuid = (left, right) => {
|
|
139
|
+
const normalizedLeft = normalizeBleUuid(left);
|
|
140
|
+
const normalizedRight = normalizeBleUuid(right);
|
|
141
|
+
return (normalizedLeft === normalizedRight ||
|
|
142
|
+
(getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
function hasWritableCapability(characteristic) {
|
|
146
|
+
return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
|
|
147
|
+
}
|
|
148
|
+
function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PACKET_LENGTH, androidPacketLength = ANDROID_PACKET_LENGTH, mtu, }) {
|
|
149
|
+
if (platform === 'ios') {
|
|
150
|
+
return iosPacketLength;
|
|
151
|
+
}
|
|
152
|
+
if (platform === 'android') {
|
|
153
|
+
const payloadLength = Math.max((mtu !== null && mtu !== void 0 ? mtu : ANDROID_DEFAULT_MTU) - 3, 1);
|
|
154
|
+
return Math.min(androidPacketLength, payloadLength);
|
|
155
|
+
}
|
|
156
|
+
return androidPacketLength;
|
|
157
|
+
}
|
|
158
|
+
|
|
86
159
|
const timer = process.env.NODE_ENV === 'development'
|
|
87
160
|
? {
|
|
88
161
|
timeout: (fn, ms) => {
|
|
@@ -108,7 +181,6 @@ const timer = process.env.NODE_ENV === 'development'
|
|
|
108
181
|
const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
|
|
109
182
|
let done = false;
|
|
110
183
|
const subscription = bleManager.onStateChange(state => {
|
|
111
|
-
console.log('ble state -> ', state);
|
|
112
184
|
if (state === 'PoweredOn') {
|
|
113
185
|
if (done)
|
|
114
186
|
return;
|
|
@@ -126,58 +198,27 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
|
|
|
126
198
|
}, ms);
|
|
127
199
|
});
|
|
128
200
|
|
|
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
201
|
const isHeaderChunk = (chunk) => {
|
|
160
202
|
if (chunk.length < 9)
|
|
161
203
|
return false;
|
|
162
204
|
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.
|
|
205
|
+
if (String.fromCharCode(MagicQuestionMark) === String.fromCharCode(transport.PROTOCOL_V1_REPORT_ID) &&
|
|
206
|
+
String.fromCharCode(sharp1) === String.fromCharCode(transport.PROTOCOL_V1_HEADER_BYTE) &&
|
|
207
|
+
String.fromCharCode(sharp2) === String.fromCharCode(transport.PROTOCOL_V1_HEADER_BYTE)) {
|
|
166
208
|
return true;
|
|
167
209
|
}
|
|
168
210
|
return false;
|
|
169
211
|
};
|
|
170
212
|
|
|
171
|
-
const Log$1 =
|
|
213
|
+
const Log$1 = bleLogger;
|
|
172
214
|
class BleTransport {
|
|
173
215
|
constructor(device, writeCharacteristic, notifyCharacteristic) {
|
|
174
216
|
this.name = 'ReactNativeBleTransport';
|
|
175
|
-
this.mtuSize =
|
|
217
|
+
this.mtuSize = 23;
|
|
176
218
|
this.id = device.id;
|
|
177
219
|
this.device = device;
|
|
178
220
|
this.writeCharacteristic = writeCharacteristic;
|
|
179
221
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
180
|
-
console.log(`BleTransport(${String(this.id)}) new instance`);
|
|
181
222
|
}
|
|
182
223
|
writeWithRetry(data, retryCount = BleTransport.MAX_RETRIES) {
|
|
183
224
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -187,7 +228,7 @@ class BleTransport {
|
|
|
187
228
|
catch (error) {
|
|
188
229
|
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`);
|
|
189
230
|
if (retryCount > 0) {
|
|
190
|
-
yield
|
|
231
|
+
yield hdShared.wait(BleTransport.RETRY_DELAY);
|
|
191
232
|
if (error.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
192
233
|
error.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
193
234
|
try {
|
|
@@ -211,8 +252,20 @@ class BleTransport {
|
|
|
211
252
|
BleTransport.MAX_RETRIES = 5;
|
|
212
253
|
BleTransport.RETRY_DELAY = 2000;
|
|
213
254
|
|
|
214
|
-
|
|
215
|
-
|
|
255
|
+
function createTransportCallLog(name, protocol, data) {
|
|
256
|
+
if (name === 'ResourceUpdate' || name === 'ResourceAck') {
|
|
257
|
+
return {
|
|
258
|
+
name,
|
|
259
|
+
protocol,
|
|
260
|
+
file_name: data.file_name,
|
|
261
|
+
hash: data.hash,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return { name, protocol };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
268
|
+
const Log = bleLogger;
|
|
216
269
|
const transportCache = {};
|
|
217
270
|
const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
|
|
218
271
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
@@ -222,11 +275,6 @@ const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
|
|
|
222
275
|
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
223
276
|
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
224
277
|
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
225
|
-
const getBleIdentityName = (device) => {
|
|
226
|
-
var _a, _b;
|
|
227
|
-
const localName = device === null || device === void 0 ? void 0 : device.localName;
|
|
228
|
-
return (_b = (_a = device === null || device === void 0 ? void 0 : device.name) !== null && _a !== void 0 ? _a : localName) !== null && _b !== void 0 ? _b : null;
|
|
229
|
-
};
|
|
230
278
|
const delay = (ms) => new Promise(resolve => {
|
|
231
279
|
setTimeout(resolve, ms);
|
|
232
280
|
});
|
|
@@ -248,20 +296,83 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
248
296
|
return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
|
|
249
297
|
};
|
|
250
298
|
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
251
|
-
|
|
252
|
-
|
|
299
|
+
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
300
|
+
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
301
|
+
const DEVICE_SCAN_TIMEOUT_MS = 8000;
|
|
302
|
+
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
303
|
+
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
304
|
+
const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
|
|
305
|
+
iosPacketLength: IOS_PACKET_LENGTH,
|
|
306
|
+
androidPacketLength: ANDROID_PACKET_LENGTH,
|
|
307
|
+
};
|
|
308
|
+
let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
309
|
+
const normalizePositiveInteger = (value, fallback) => {
|
|
310
|
+
const normalized = Number(value);
|
|
311
|
+
if (!Number.isFinite(normalized) || normalized <= 0)
|
|
312
|
+
return fallback;
|
|
313
|
+
return Math.floor(normalized);
|
|
314
|
+
};
|
|
315
|
+
function configureProtocolV2BleTuning(tuning = {}) {
|
|
316
|
+
protocolV2BleTuning = {
|
|
317
|
+
iosPacketLength: normalizePositiveInteger(tuning.iosPacketLength, protocolV2BleTuning.iosPacketLength),
|
|
318
|
+
androidPacketLength: normalizePositiveInteger(tuning.androidPacketLength, protocolV2BleTuning.androidPacketLength),
|
|
319
|
+
};
|
|
320
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning configured', protocolV2BleTuning);
|
|
321
|
+
}
|
|
322
|
+
function resetProtocolV2BleTuning() {
|
|
323
|
+
protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
324
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning reset', protocolV2BleTuning);
|
|
325
|
+
}
|
|
326
|
+
function getProtocolV2BleTuning() {
|
|
327
|
+
return Object.assign({}, protocolV2BleTuning);
|
|
328
|
+
}
|
|
329
|
+
function inferProtocolHintFromDeviceName(name) {
|
|
330
|
+
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
331
|
+
}
|
|
332
|
+
function getDeviceDisplayName(device) {
|
|
333
|
+
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
334
|
+
}
|
|
335
|
+
function isGenericBleService(uuid) {
|
|
336
|
+
return ['1800', '1801', '180a'].includes(getBleUuidKey(uuid));
|
|
337
|
+
}
|
|
338
|
+
function hasKnownOneKeyService(device) {
|
|
339
|
+
var _a;
|
|
340
|
+
return ((_a = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _a !== void 0 ? _a : []).some(serviceUuid => getInfosForServiceUuid(serviceUuid, 'classic'));
|
|
341
|
+
}
|
|
342
|
+
const ANDROID_REQUEST_MTU = 256;
|
|
343
|
+
const connectOptions = {
|
|
344
|
+
requestMTU: ANDROID_REQUEST_MTU,
|
|
253
345
|
timeout: 3000,
|
|
254
346
|
refreshGatt: 'OnConnected',
|
|
255
347
|
};
|
|
256
348
|
const tryToGetConfiguration = (device) => {
|
|
257
349
|
if (!device || !device.serviceUUIDs)
|
|
258
350
|
return null;
|
|
259
|
-
const
|
|
351
|
+
const serviceUUID = device.serviceUUIDs.find(uuid => getInfosForServiceUuid(uuid, 'classic'));
|
|
352
|
+
if (!serviceUUID)
|
|
353
|
+
return null;
|
|
260
354
|
const infos = getInfosForServiceUuid(serviceUUID, 'classic');
|
|
261
355
|
if (!infos)
|
|
262
356
|
return null;
|
|
263
357
|
return infos;
|
|
264
358
|
};
|
|
359
|
+
const requestAndroidMtu = (device) => __awaiter(void 0, void 0, void 0, function* () {
|
|
360
|
+
if (reactNative.Platform.OS !== 'android')
|
|
361
|
+
return device;
|
|
362
|
+
try {
|
|
363
|
+
const mtuDevice = yield device.requestMTU(ANDROID_REQUEST_MTU);
|
|
364
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU configured', {
|
|
365
|
+
deviceId: device.id,
|
|
366
|
+
requested: ANDROID_REQUEST_MTU,
|
|
367
|
+
actual: mtuDevice.mtu,
|
|
368
|
+
});
|
|
369
|
+
return mtuDevice;
|
|
370
|
+
}
|
|
371
|
+
catch (error) {
|
|
372
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU request failed:', error);
|
|
373
|
+
return device;
|
|
374
|
+
}
|
|
375
|
+
});
|
|
265
376
|
function remapError(error) {
|
|
266
377
|
var _a;
|
|
267
378
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -286,12 +397,41 @@ class ReactNativeBleTransport {
|
|
|
286
397
|
this.name = 'ReactNativeBleTransport';
|
|
287
398
|
this.configured = false;
|
|
288
399
|
this.stopped = false;
|
|
289
|
-
this.scanTimeout =
|
|
400
|
+
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
290
401
|
this.runPromise = null;
|
|
291
402
|
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
292
|
-
this.
|
|
403
|
+
this.deviceProtocol = new Map();
|
|
404
|
+
this.deviceProtocolHints = new Map();
|
|
405
|
+
this.protocolV2Assemblers = new Map();
|
|
406
|
+
this.protocolV2FrameQueues = new Map();
|
|
407
|
+
this.protocolV2FramePromises = new Map();
|
|
408
|
+
this.protocolV2Links = new transport.ProtocolV2LinkManager({
|
|
409
|
+
getSchemas: () => {
|
|
410
|
+
if (!this._messages || !this._messagesV2) {
|
|
411
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
412
|
+
}
|
|
413
|
+
return {
|
|
414
|
+
protocolV1: this._messages,
|
|
415
|
+
protocolV2: this._messagesV2,
|
|
416
|
+
};
|
|
417
|
+
},
|
|
418
|
+
classifyError: () => 'link-fatal',
|
|
419
|
+
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
420
|
+
var _b;
|
|
421
|
+
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
422
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
423
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
424
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
425
|
+
yield this.release(uuid, true);
|
|
426
|
+
}
|
|
427
|
+
}),
|
|
428
|
+
});
|
|
429
|
+
this.monitorTokens = new Map();
|
|
430
|
+
this.nextMonitorToken = 1;
|
|
431
|
+
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
293
432
|
}
|
|
294
|
-
init(
|
|
433
|
+
init(logger, emitter) {
|
|
434
|
+
setBleLogger(logger);
|
|
295
435
|
this.emitter = emitter;
|
|
296
436
|
}
|
|
297
437
|
configure(signedData) {
|
|
@@ -299,6 +439,12 @@ class ReactNativeBleTransport {
|
|
|
299
439
|
this.configured = true;
|
|
300
440
|
this._messages = messages;
|
|
301
441
|
}
|
|
442
|
+
configureProtocolV2(signedData) {
|
|
443
|
+
this._messagesV2 = parseConfigure(signedData);
|
|
444
|
+
this.protocolV2Links
|
|
445
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
446
|
+
.catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
|
|
447
|
+
}
|
|
302
448
|
listen() {
|
|
303
449
|
}
|
|
304
450
|
getPlxManager() {
|
|
@@ -308,6 +454,7 @@ class ReactNativeBleTransport {
|
|
|
308
454
|
return Promise.resolve(this.blePlxManager);
|
|
309
455
|
}
|
|
310
456
|
resolveCharacteristics(device) {
|
|
457
|
+
var _a, _b, _c, _d;
|
|
311
458
|
return __awaiter(this, void 0, void 0, function* () {
|
|
312
459
|
yield device.discoverAllServicesAndCharacteristics();
|
|
313
460
|
let infos = tryToGetConfiguration(device);
|
|
@@ -324,7 +471,19 @@ class ReactNativeBleTransport {
|
|
|
324
471
|
}
|
|
325
472
|
}
|
|
326
473
|
}
|
|
474
|
+
let fallbackServiceUuid;
|
|
327
475
|
if (!infos) {
|
|
476
|
+
const services = yield device.services();
|
|
477
|
+
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));
|
|
478
|
+
const knownService = services.find(service => getInfosForServiceUuid(service.uuid, 'classic'));
|
|
479
|
+
const fallbackService = (_a = knownService !== null && knownService !== void 0 ? knownService : services.find(service => !isGenericBleService(service.uuid))) !== null && _a !== void 0 ? _a : services[0];
|
|
480
|
+
if (fallbackService) {
|
|
481
|
+
fallbackServiceUuid = fallbackService.uuid;
|
|
482
|
+
characteristics = yield device.characteristicsForService(fallbackService.uuid);
|
|
483
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (!infos && !fallbackServiceUuid) {
|
|
328
487
|
try {
|
|
329
488
|
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
330
489
|
yield device.cancelConnection();
|
|
@@ -334,7 +493,12 @@ class ReactNativeBleTransport {
|
|
|
334
493
|
}
|
|
335
494
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
336
495
|
}
|
|
337
|
-
const
|
|
496
|
+
const serviceUuid = (_b = infos === null || infos === void 0 ? void 0 : infos.serviceUuid) !== null && _b !== void 0 ? _b : fallbackServiceUuid;
|
|
497
|
+
const writeUuid = (_c = infos === null || infos === void 0 ? void 0 : infos.writeUuid) !== null && _c !== void 0 ? _c : '00000002-0000-1000-8000-00805f9b34fb';
|
|
498
|
+
const notifyUuid = (_d = infos === null || infos === void 0 ? void 0 : infos.notifyUuid) !== null && _d !== void 0 ? _d : '00000003-0000-1000-8000-00805f9b34fb';
|
|
499
|
+
if (!serviceUuid) {
|
|
500
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
501
|
+
}
|
|
338
502
|
if (!characteristics) {
|
|
339
503
|
characteristics = yield device.characteristicsForService(serviceUuid);
|
|
340
504
|
}
|
|
@@ -344,10 +508,10 @@ class ReactNativeBleTransport {
|
|
|
344
508
|
let writeCharacteristic;
|
|
345
509
|
let notifyCharacteristic;
|
|
346
510
|
for (const c of characteristics) {
|
|
347
|
-
if (c.uuid
|
|
511
|
+
if (isSameBleUuid(c.uuid, writeUuid)) {
|
|
348
512
|
writeCharacteristic = c;
|
|
349
513
|
}
|
|
350
|
-
else if (c.uuid
|
|
514
|
+
else if (isSameBleUuid(c.uuid, notifyUuid)) {
|
|
351
515
|
notifyCharacteristic = c;
|
|
352
516
|
}
|
|
353
517
|
}
|
|
@@ -357,7 +521,7 @@ class ReactNativeBleTransport {
|
|
|
357
521
|
if (!notifyCharacteristic) {
|
|
358
522
|
throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
359
523
|
}
|
|
360
|
-
if (!writeCharacteristic
|
|
524
|
+
if (!hasWritableCapability(writeCharacteristic)) {
|
|
361
525
|
throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
362
526
|
}
|
|
363
527
|
if (!notifyCharacteristic.isNotifiable) {
|
|
@@ -378,6 +542,10 @@ class ReactNativeBleTransport {
|
|
|
378
542
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
379
543
|
return;
|
|
380
544
|
}
|
|
545
|
+
if (transportCache[uuid] !== transport) {
|
|
546
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale transport: ', device === null || device === void 0 ? void 0 : device.id);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
381
549
|
try {
|
|
382
550
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
383
551
|
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
|
|
@@ -386,14 +554,16 @@ class ReactNativeBleTransport {
|
|
|
386
554
|
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
387
555
|
});
|
|
388
556
|
if (this.runPromise) {
|
|
389
|
-
|
|
557
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
558
|
+
this.runPromise.reject(error);
|
|
559
|
+
this.rejectAllProtocolV2Frames(error);
|
|
390
560
|
}
|
|
391
561
|
}
|
|
392
562
|
catch (e) {
|
|
393
563
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
|
|
394
564
|
}
|
|
395
565
|
finally {
|
|
396
|
-
this.release(uuid);
|
|
566
|
+
this.release(uuid, true);
|
|
397
567
|
}
|
|
398
568
|
});
|
|
399
569
|
}
|
|
@@ -415,7 +585,6 @@ class ReactNativeBleTransport {
|
|
|
415
585
|
catch (e) {
|
|
416
586
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
417
587
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
418
|
-
connectOptions = {};
|
|
419
588
|
device = yield device.connect();
|
|
420
589
|
}
|
|
421
590
|
else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
@@ -427,7 +596,13 @@ class ReactNativeBleTransport {
|
|
|
427
596
|
transport.device = device;
|
|
428
597
|
transport.writeCharacteristic = writeCharacteristic;
|
|
429
598
|
transport.notifyCharacteristic = notifyCharacteristic;
|
|
430
|
-
|
|
599
|
+
const monitorToken = this.nextMonitorToken;
|
|
600
|
+
this.nextMonitorToken += 1;
|
|
601
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
602
|
+
transport.monitorToken = monitorToken;
|
|
603
|
+
transport.notifyTransactionId = notifyTransactionId;
|
|
604
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
605
|
+
transport.notifySubscription = this._monitorCharacteristic(notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
431
606
|
this.attachDisconnectSubscription(transport, device, uuid);
|
|
432
607
|
}
|
|
433
608
|
finally {
|
|
@@ -462,11 +637,11 @@ class ReactNativeBleTransport {
|
|
|
462
637
|
}
|
|
463
638
|
}
|
|
464
639
|
blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
|
|
640
|
+
allowDuplicates: true,
|
|
465
641
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
466
642
|
}, (error, device) => {
|
|
467
|
-
var _a;
|
|
643
|
+
var _a, _b, _c;
|
|
468
644
|
if (error) {
|
|
469
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan manager: ', blePlxManager);
|
|
470
645
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
471
646
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
472
647
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
@@ -485,12 +660,20 @@ class ReactNativeBleTransport {
|
|
|
485
660
|
}
|
|
486
661
|
return;
|
|
487
662
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
663
|
+
const displayName = getDeviceDisplayName(device);
|
|
664
|
+
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) ||
|
|
665
|
+
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) ||
|
|
666
|
+
hasKnownOneKeyService(device);
|
|
667
|
+
if (isOneKey) {
|
|
492
668
|
addDevice(device);
|
|
493
|
-
|
|
669
|
+
}
|
|
670
|
+
else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
|
|
671
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Pro2-like BLE device was not accepted:', {
|
|
672
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
673
|
+
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
674
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
675
|
+
serviceUUIDs: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
676
|
+
});
|
|
494
677
|
}
|
|
495
678
|
});
|
|
496
679
|
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
@@ -499,14 +682,25 @@ class ReactNativeBleTransport {
|
|
|
499
682
|
const hasCachedServiceUuid = Boolean(serviceUUIDs === null || serviceUUIDs === void 0 ? void 0 : serviceUUIDs.length);
|
|
500
683
|
const keepDevice = reactNative.Platform.OS === 'ios' || hasCachedServiceUuid;
|
|
501
684
|
if (keepDevice) {
|
|
502
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
|
|
503
685
|
addDevice(device);
|
|
504
686
|
}
|
|
505
687
|
}
|
|
506
688
|
});
|
|
507
689
|
const addDevice = (device) => {
|
|
690
|
+
var _a;
|
|
508
691
|
if (deviceList.every(d => d.id !== device.id)) {
|
|
509
|
-
|
|
692
|
+
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
693
|
+
const protocolHint = inferProtocolHintFromDeviceName(displayName);
|
|
694
|
+
if (protocolHint) {
|
|
695
|
+
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
696
|
+
}
|
|
697
|
+
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
698
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
699
|
+
deviceId: device.id,
|
|
700
|
+
name: displayName,
|
|
701
|
+
serviceUUIDs: device.serviceUUIDs,
|
|
702
|
+
protocolHint,
|
|
703
|
+
});
|
|
510
704
|
}
|
|
511
705
|
};
|
|
512
706
|
timer.timeout(() => {
|
|
@@ -517,19 +711,31 @@ class ReactNativeBleTransport {
|
|
|
517
711
|
});
|
|
518
712
|
}
|
|
519
713
|
acquire(input) {
|
|
520
|
-
var _a;
|
|
714
|
+
var _a, _b;
|
|
521
715
|
return __awaiter(this, void 0, void 0, function* () {
|
|
522
|
-
const { uuid, forceCleanRunPromise } = input;
|
|
716
|
+
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
523
717
|
if (!uuid) {
|
|
524
718
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
525
719
|
}
|
|
526
|
-
|
|
527
|
-
if (
|
|
528
|
-
|
|
529
|
-
yield
|
|
720
|
+
const cachedTransport = transportCache[uuid];
|
|
721
|
+
if (cachedTransport) {
|
|
722
|
+
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
723
|
+
const isCachedDeviceConnected = yield cachedTransport.device.isConnected().catch(() => false);
|
|
724
|
+
if (isCachedDeviceConnected &&
|
|
725
|
+
cachedProtocol &&
|
|
726
|
+
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
727
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
728
|
+
return { uuid, protocolType: cachedProtocol };
|
|
729
|
+
}
|
|
730
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
731
|
+
yield this.release(uuid, true);
|
|
530
732
|
}
|
|
733
|
+
let device = null;
|
|
531
734
|
if (forceCleanRunPromise && this.runPromise) {
|
|
532
|
-
|
|
735
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
736
|
+
this.runPromise.reject(error);
|
|
737
|
+
this.rejectAllProtocolV2Frames(error);
|
|
738
|
+
this.runPromise = null;
|
|
533
739
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
534
740
|
}
|
|
535
741
|
const blePlxManager = yield this.getPlxManager();
|
|
@@ -545,6 +751,9 @@ class ReactNativeBleTransport {
|
|
|
545
751
|
if (bondState.bonding) {
|
|
546
752
|
yield onDeviceBondState(uuid);
|
|
547
753
|
}
|
|
754
|
+
else if (!bondState.bonded) {
|
|
755
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
|
|
756
|
+
}
|
|
548
757
|
}
|
|
549
758
|
if (!device) {
|
|
550
759
|
const devices = yield blePlxManager.devices([uuid]);
|
|
@@ -565,7 +774,6 @@ class ReactNativeBleTransport {
|
|
|
565
774
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
566
775
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
567
776
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
568
|
-
connectOptions = {};
|
|
569
777
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
570
778
|
device = yield blePlxManager.connectToDevice(uuid);
|
|
571
779
|
}
|
|
@@ -584,23 +792,22 @@ class ReactNativeBleTransport {
|
|
|
584
792
|
if (!(yield device.isConnected())) {
|
|
585
793
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
586
794
|
try {
|
|
587
|
-
yield device.connect(connectOptions);
|
|
795
|
+
device = yield device.connect(connectOptions);
|
|
588
796
|
}
|
|
589
797
|
catch (e) {
|
|
590
798
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
591
799
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
592
800
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
593
|
-
connectOptions = {};
|
|
594
801
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
595
802
|
try {
|
|
596
|
-
yield device.connect();
|
|
803
|
+
device = yield device.connect();
|
|
597
804
|
}
|
|
598
805
|
catch (e) {
|
|
599
806
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
|
|
600
807
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
601
808
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
602
809
|
yield device.cancelConnection();
|
|
603
|
-
yield device.connect();
|
|
810
|
+
device = yield device.connect();
|
|
604
811
|
}
|
|
605
812
|
}
|
|
606
813
|
}
|
|
@@ -609,58 +816,124 @@ class ReactNativeBleTransport {
|
|
|
609
816
|
}
|
|
610
817
|
}
|
|
611
818
|
}
|
|
819
|
+
device = yield requestAndroidMtu(device);
|
|
612
820
|
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(device);
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
(
|
|
821
|
+
const protocolHint = expectedProtocol
|
|
822
|
+
? undefined
|
|
823
|
+
: (_a = this.deviceProtocolHints.get(uuid)) !== null && _a !== void 0 ? _a : inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
|
|
824
|
+
yield this.release(uuid, true);
|
|
825
|
+
if (protocolHint) {
|
|
826
|
+
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
827
|
+
}
|
|
828
|
+
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
829
|
+
if (reactNative.Platform.OS === 'android') {
|
|
830
|
+
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
|
|
831
|
+
}
|
|
832
|
+
const monitorToken = this.nextMonitorToken;
|
|
833
|
+
this.nextMonitorToken += 1;
|
|
834
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
835
|
+
transport$1.monitorToken = monitorToken;
|
|
836
|
+
transport$1.notifyTransactionId = notifyTransactionId;
|
|
837
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
838
|
+
transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
839
|
+
transportCache[uuid] = transport$1;
|
|
840
|
+
this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
|
|
841
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
842
|
+
yield new Promise(resolve => {
|
|
843
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
844
|
+
});
|
|
845
|
+
}
|
|
846
|
+
else if (reactNative.Platform.OS === 'android') {
|
|
847
|
+
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
848
|
+
}
|
|
849
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
850
|
+
(_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
|
|
618
851
|
name: device.name,
|
|
619
852
|
id: device.id,
|
|
620
853
|
connectId: device.id,
|
|
621
854
|
});
|
|
622
|
-
this.attachDisconnectSubscription(transport, device, uuid);
|
|
623
|
-
return { uuid };
|
|
855
|
+
this.attachDisconnectSubscription(transport$1, device, uuid);
|
|
856
|
+
return { uuid, protocolType };
|
|
624
857
|
});
|
|
625
858
|
}
|
|
626
|
-
_monitorCharacteristic(characteristic, uuid) {
|
|
859
|
+
_monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
|
|
627
860
|
let bufferLength = 0;
|
|
628
861
|
let buffer$1 = [];
|
|
629
862
|
const subscription = characteristic.monitor((error, c) => {
|
|
630
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
863
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
864
|
+
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
631
865
|
if (error) {
|
|
632
866
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
633
867
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
634
868
|
Log === null || Log === void 0 ? void 0 : Log.debug('notify error ignored during FirmwareUpload write recovery: ', uuid);
|
|
635
869
|
return;
|
|
636
870
|
}
|
|
637
|
-
if (
|
|
638
|
-
|
|
871
|
+
if (!isCurrentMonitor) {
|
|
872
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
876
|
+
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
639
877
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
640
|
-
|
|
878
|
+
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
641
879
|
}
|
|
642
|
-
if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
643
|
-
|
|
880
|
+
else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
881
|
+
errorCode = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
644
882
|
}
|
|
645
|
-
if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
883
|
+
else if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
646
884
|
((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('Cannot find client characteristic config descriptor')) ||
|
|
647
885
|
((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
|
|
648
886
|
((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
|
|
649
887
|
((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
|
|
650
|
-
|
|
888
|
+
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
889
|
+
}
|
|
890
|
+
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
if (this.runPromise) {
|
|
894
|
+
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
895
|
+
if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
|
|
896
|
+
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
897
|
+
}
|
|
898
|
+
if ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Encryption is insufficient')) {
|
|
899
|
+
ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
900
|
+
}
|
|
901
|
+
if (((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('Cannot write client characteristic config descriptor')) ||
|
|
902
|
+
((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Cannot find client characteristic config descriptor')) ||
|
|
903
|
+
((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
|
|
904
|
+
((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
|
|
905
|
+
((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
|
|
906
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
907
|
+
this.runPromise.reject(notifyError);
|
|
908
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
651
909
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
652
910
|
return;
|
|
653
911
|
}
|
|
654
|
-
|
|
912
|
+
const notifyError = hdShared.ERRORS.TypedError(ERROR);
|
|
913
|
+
this.runPromise.reject(notifyError);
|
|
914
|
+
this.rejectAllProtocolV2Frames(notifyError);
|
|
655
915
|
Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
656
916
|
}
|
|
657
917
|
return;
|
|
658
918
|
}
|
|
919
|
+
if (!isCurrentMonitor) {
|
|
920
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored for stale transport: ', uuid, notifyTransactionId);
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
659
923
|
if (!c) {
|
|
660
924
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleMonitorError);
|
|
661
925
|
}
|
|
662
926
|
try {
|
|
663
927
|
const data = buffer.Buffer.from(c.value, 'base64');
|
|
928
|
+
const protocol = this.deviceProtocol.get(uuid);
|
|
929
|
+
if (!protocol) {
|
|
930
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
|
|
931
|
+
return;
|
|
932
|
+
}
|
|
933
|
+
if (protocol === 'V2') {
|
|
934
|
+
this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
664
937
|
if (isHeaderChunk(data)) {
|
|
665
938
|
bufferLength = data.readInt32BE(5);
|
|
666
939
|
buffer$1 = [...data.subarray(3)];
|
|
@@ -668,33 +941,74 @@ class ReactNativeBleTransport {
|
|
|
668
941
|
else {
|
|
669
942
|
buffer$1 = buffer$1.concat([...data]);
|
|
670
943
|
}
|
|
671
|
-
if (buffer$1.length - transport.
|
|
944
|
+
if (buffer$1.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferLength) {
|
|
672
945
|
const value = buffer.Buffer.from(buffer$1);
|
|
673
946
|
bufferLength = 0;
|
|
674
947
|
buffer$1 = [];
|
|
675
|
-
(
|
|
948
|
+
(_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
|
|
676
949
|
}
|
|
677
950
|
}
|
|
678
951
|
catch (error) {
|
|
679
952
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
680
|
-
|
|
953
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
954
|
+
if (this.deviceProtocol.get(uuid) === 'V2') {
|
|
955
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
956
|
+
}
|
|
957
|
+
else {
|
|
958
|
+
(_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
|
|
959
|
+
}
|
|
681
960
|
}
|
|
682
|
-
},
|
|
961
|
+
}, notifyTransactionId);
|
|
683
962
|
return subscription;
|
|
684
963
|
}
|
|
685
|
-
release(uuid) {
|
|
686
|
-
var _a, _b, _c;
|
|
964
|
+
release(uuid, onclose = false) {
|
|
965
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
687
966
|
return __awaiter(this, void 0, void 0, function* () {
|
|
688
967
|
const transport = transportCache[uuid];
|
|
968
|
+
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
969
|
+
if (this.runPromise) {
|
|
970
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
971
|
+
this.runPromise.reject(error);
|
|
972
|
+
this.runPromise = null;
|
|
973
|
+
this.rejectAllProtocolV2Frames(error);
|
|
974
|
+
}
|
|
975
|
+
else {
|
|
976
|
+
this.resetProtocolV2Frames(uuid);
|
|
977
|
+
}
|
|
978
|
+
if (reactNative.Platform.OS === 'android' && !onclose && transport) {
|
|
979
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
980
|
+
this.resetProtocolV2Frames(uuid);
|
|
981
|
+
return Promise.resolve(true);
|
|
982
|
+
}
|
|
689
983
|
if (transport) {
|
|
984
|
+
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
985
|
+
this.monitorTokens.delete(uuid);
|
|
986
|
+
}
|
|
690
987
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
|
|
691
|
-
(
|
|
988
|
+
(_b = transport.disconnectSubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
692
989
|
transport.disconnectSubscription = undefined;
|
|
693
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (
|
|
694
|
-
(
|
|
990
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_c = transport.notifyCharacteristic) === null || _c === void 0 ? void 0 : _c.uuid);
|
|
991
|
+
(_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
|
|
695
992
|
transport.notifySubscription = undefined;
|
|
993
|
+
if (transport.notifyTransactionId) {
|
|
994
|
+
try {
|
|
995
|
+
yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
|
|
996
|
+
}
|
|
997
|
+
catch (e) {
|
|
998
|
+
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);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
696
1001
|
delete transportCache[uuid];
|
|
697
|
-
|
|
1002
|
+
}
|
|
1003
|
+
this.deviceProtocol.delete(uuid);
|
|
1004
|
+
(_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
|
|
1005
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1006
|
+
this.resetProtocolV2Frames(uuid);
|
|
1007
|
+
try {
|
|
1008
|
+
yield ((_g = this.blePlxManager) === null || _g === void 0 ? void 0 : _g.cancelTransaction(uuid));
|
|
1009
|
+
}
|
|
1010
|
+
catch (e) {
|
|
1011
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
698
1012
|
}
|
|
699
1013
|
return Promise.resolve(true);
|
|
700
1014
|
});
|
|
@@ -704,7 +1018,7 @@ class ReactNativeBleTransport {
|
|
|
704
1018
|
yield this.call(session, name, data);
|
|
705
1019
|
});
|
|
706
1020
|
}
|
|
707
|
-
call(uuid, name, data) {
|
|
1021
|
+
call(uuid, name, data, options) {
|
|
708
1022
|
return __awaiter(this, void 0, void 0, function* () {
|
|
709
1023
|
if (this.stopped) {
|
|
710
1024
|
return Promise.reject(hdShared.ERRORS.TypedError('Transport stopped.'));
|
|
@@ -712,30 +1026,33 @@ class ReactNativeBleTransport {
|
|
|
712
1026
|
if (this._messages == null) {
|
|
713
1027
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
714
1028
|
}
|
|
1029
|
+
const protocol = this.getProtocolType(uuid);
|
|
1030
|
+
if (!protocol) {
|
|
1031
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1032
|
+
}
|
|
1033
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport call', createTransportCallLog(name, protocol, data));
|
|
1034
|
+
if (protocol === 'V2') {
|
|
1035
|
+
return this.callProtocolV2(uuid, name, data, options);
|
|
1036
|
+
}
|
|
715
1037
|
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
716
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native call this.runPromise', this.runPromise);
|
|
717
1038
|
if (this.runPromise && !forceRun) {
|
|
718
1039
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
719
1040
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
1041
|
+
return this.callProtocolV1(uuid, name, data, options);
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
callProtocolV1(uuid, name, data, options) {
|
|
1045
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1046
|
+
if (!this._messages) {
|
|
1047
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
723
1048
|
}
|
|
724
|
-
|
|
1049
|
+
const transport = this.getCachedTransport(uuid);
|
|
1050
|
+
const runPromise = hdShared.createDeferred();
|
|
1051
|
+
runPromise.promise.catch(() => undefined);
|
|
1052
|
+
this.runPromise = runPromise;
|
|
725
1053
|
const messages = this._messages;
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
file_name: data === null || data === void 0 ? void 0 : data.file_name,
|
|
729
|
-
hash: data === null || data === void 0 ? void 0 : data.hash,
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
else if (transport.LogBlockCommand.has(name)) {
|
|
733
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name);
|
|
734
|
-
}
|
|
735
|
-
else {
|
|
736
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data);
|
|
737
|
-
}
|
|
738
|
-
const buffers = buildBuffers(messages, name, data);
|
|
1054
|
+
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1055
|
+
let timeout;
|
|
739
1056
|
function writeChunkedData(buffers, writeFunction, onError) {
|
|
740
1057
|
return __awaiter(this, void 0, void 0, function* () {
|
|
741
1058
|
const packetCapacity = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_PACKET_LENGTH;
|
|
@@ -790,13 +1107,13 @@ class ReactNativeBleTransport {
|
|
|
790
1107
|
});
|
|
791
1108
|
}
|
|
792
1109
|
if (name === 'EmmcFileWrite') {
|
|
793
|
-
yield writeChunkedData(buffers, data => transport
|
|
1110
|
+
yield writeChunkedData(buffers, data => transport.writeWithRetry(data), e => {
|
|
794
1111
|
this.runPromise = null;
|
|
795
1112
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
796
1113
|
});
|
|
797
1114
|
}
|
|
798
1115
|
else if (name === 'FirmwareUpload') {
|
|
799
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
1116
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Firmware upload transport configured', {
|
|
800
1117
|
packetCapacity: FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY,
|
|
801
1118
|
burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
|
|
802
1119
|
pauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
|
|
@@ -807,7 +1124,7 @@ class ReactNativeBleTransport {
|
|
|
807
1124
|
let attempt = 0;
|
|
808
1125
|
while (true) {
|
|
809
1126
|
try {
|
|
810
|
-
yield transport
|
|
1127
|
+
yield transport.writeCharacteristic.writeWithoutResponse(data);
|
|
811
1128
|
return;
|
|
812
1129
|
}
|
|
813
1130
|
catch (error) {
|
|
@@ -832,7 +1149,7 @@ class ReactNativeBleTransport {
|
|
|
832
1149
|
attempt += 1;
|
|
833
1150
|
if (shouldReconnect) {
|
|
834
1151
|
try {
|
|
835
|
-
yield this.reconnectFirmwareUploadTransport(uuid, transport
|
|
1152
|
+
yield this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
836
1153
|
}
|
|
837
1154
|
catch (e) {
|
|
838
1155
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
@@ -852,7 +1169,7 @@ class ReactNativeBleTransport {
|
|
|
852
1169
|
for (const o of buffers) {
|
|
853
1170
|
const outData = o.toString('base64');
|
|
854
1171
|
try {
|
|
855
|
-
yield transport
|
|
1172
|
+
yield transport.writeCharacteristic.writeWithoutResponse(outData);
|
|
856
1173
|
}
|
|
857
1174
|
catch (e) {
|
|
858
1175
|
Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
|
|
@@ -870,20 +1187,39 @@ class ReactNativeBleTransport {
|
|
|
870
1187
|
}
|
|
871
1188
|
}
|
|
872
1189
|
try {
|
|
873
|
-
const response = yield
|
|
1190
|
+
const response = yield Promise.race([
|
|
1191
|
+
runPromise.promise,
|
|
1192
|
+
new Promise((_, reject) => {
|
|
1193
|
+
if (options === null || options === void 0 ? void 0 : options.timeoutMs) {
|
|
1194
|
+
timeout = setTimeout(() => {
|
|
1195
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${options.timeoutMs}ms for ${name}`);
|
|
1196
|
+
runPromise.reject(error);
|
|
1197
|
+
reject(error);
|
|
1198
|
+
}, options.timeoutMs);
|
|
1199
|
+
}
|
|
1200
|
+
}),
|
|
1201
|
+
]);
|
|
874
1202
|
if (typeof response !== 'string') {
|
|
875
1203
|
throw new Error('Returning data is not string.');
|
|
876
1204
|
}
|
|
877
|
-
|
|
878
|
-
const jsonData = receiveOne(messages, response);
|
|
1205
|
+
const jsonData = ProtocolV1.decodeMessage(messages, response);
|
|
879
1206
|
return check.call(jsonData);
|
|
880
1207
|
}
|
|
881
1208
|
catch (e) {
|
|
882
|
-
|
|
1209
|
+
if (name === 'Initialize' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
|
|
1210
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe call failed:', e);
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1214
|
+
}
|
|
883
1215
|
throw e;
|
|
884
1216
|
}
|
|
885
1217
|
finally {
|
|
886
|
-
|
|
1218
|
+
if (timeout)
|
|
1219
|
+
clearTimeout(timeout);
|
|
1220
|
+
if (this.runPromise === runPromise) {
|
|
1221
|
+
this.runPromise = null;
|
|
1222
|
+
}
|
|
887
1223
|
}
|
|
888
1224
|
});
|
|
889
1225
|
}
|
|
@@ -893,7 +1229,7 @@ class ReactNativeBleTransport {
|
|
|
893
1229
|
disconnect(session) {
|
|
894
1230
|
var _a, _b, _c, _d, _e;
|
|
895
1231
|
return __awaiter(this, void 0, void 0, function* () {
|
|
896
|
-
|
|
1232
|
+
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
897
1233
|
const transport = transportCache[session];
|
|
898
1234
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
899
1235
|
try {
|
|
@@ -940,6 +1276,10 @@ class ReactNativeBleTransport {
|
|
|
940
1276
|
if (transportCache[session]) {
|
|
941
1277
|
delete transportCache[session];
|
|
942
1278
|
}
|
|
1279
|
+
this.deviceProtocol.delete(session);
|
|
1280
|
+
this.deviceProtocolHints.delete(session);
|
|
1281
|
+
this.protocolV2Assemblers.delete(session);
|
|
1282
|
+
this.resetProtocolV2Frames(session);
|
|
943
1283
|
try {
|
|
944
1284
|
(_d = this.emitter) === null || _d === void 0 ? void 0 : _d.emit('device-disconnect', {
|
|
945
1285
|
name: (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name,
|
|
@@ -958,6 +1298,315 @@ class ReactNativeBleTransport {
|
|
|
958
1298
|
if (this.runPromise) ;
|
|
959
1299
|
this.runPromise = null;
|
|
960
1300
|
}
|
|
1301
|
+
getCachedTransport(uuid) {
|
|
1302
|
+
const transport = transportCache[uuid];
|
|
1303
|
+
if (!transport) {
|
|
1304
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
1305
|
+
}
|
|
1306
|
+
return transport;
|
|
1307
|
+
}
|
|
1308
|
+
createProtocolMismatchError(expected) {
|
|
1309
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1310
|
+
}
|
|
1311
|
+
createProtocolDetectionError() {
|
|
1312
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
|
|
1313
|
+
}
|
|
1314
|
+
clearProbeProtocol(uuid, protocol) {
|
|
1315
|
+
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1316
|
+
this.deviceProtocol.delete(uuid);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
detectProtocol(uuid, expectedProtocol, protocolHint) {
|
|
1320
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1321
|
+
if (expectedProtocol === 'V1') {
|
|
1322
|
+
if (yield this.probeProtocolV1(uuid)) {
|
|
1323
|
+
this.deviceProtocol.set(uuid, 'V1');
|
|
1324
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1325
|
+
deviceId: uuid,
|
|
1326
|
+
protocol: 'V1',
|
|
1327
|
+
source: 'expected',
|
|
1328
|
+
});
|
|
1329
|
+
return 'V1';
|
|
1330
|
+
}
|
|
1331
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1332
|
+
}
|
|
1333
|
+
if (expectedProtocol === 'V2') {
|
|
1334
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1335
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1336
|
+
deviceId: uuid,
|
|
1337
|
+
protocol: 'V2',
|
|
1338
|
+
source: 'expected',
|
|
1339
|
+
});
|
|
1340
|
+
return 'V2';
|
|
1341
|
+
}
|
|
1342
|
+
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1343
|
+
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1344
|
+
const protocol = probeOrder[i];
|
|
1345
|
+
if (i > 0) {
|
|
1346
|
+
yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
1347
|
+
}
|
|
1348
|
+
const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
|
|
1349
|
+
if (detected) {
|
|
1350
|
+
this.deviceProtocol.set(uuid, protocol);
|
|
1351
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1352
|
+
deviceId: uuid,
|
|
1353
|
+
protocol,
|
|
1354
|
+
source: 'probe',
|
|
1355
|
+
});
|
|
1356
|
+
return protocol;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
this.deviceProtocol.delete(uuid);
|
|
1360
|
+
throw this.createProtocolDetectionError();
|
|
1361
|
+
});
|
|
1362
|
+
}
|
|
1363
|
+
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1364
|
+
var _a, _b, _c;
|
|
1365
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1366
|
+
const transport = transportCache[uuid];
|
|
1367
|
+
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1368
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1369
|
+
this.resetProtocolV2Frames(uuid);
|
|
1370
|
+
if (this.runPromise) {
|
|
1371
|
+
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1372
|
+
this.runPromise.reject(error);
|
|
1373
|
+
this.runPromise = null;
|
|
1374
|
+
}
|
|
1375
|
+
if (!transport)
|
|
1376
|
+
return;
|
|
1377
|
+
const previousNotifyTransactionId = transport.notifyTransactionId;
|
|
1378
|
+
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
1379
|
+
this.monitorTokens.delete(uuid);
|
|
1380
|
+
}
|
|
1381
|
+
(_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1382
|
+
transport.notifySubscription = undefined;
|
|
1383
|
+
if (previousNotifyTransactionId) {
|
|
1384
|
+
try {
|
|
1385
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(previousNotifyTransactionId));
|
|
1386
|
+
}
|
|
1387
|
+
catch (error) {
|
|
1388
|
+
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);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
const monitorToken = this.nextMonitorToken;
|
|
1392
|
+
this.nextMonitorToken += 1;
|
|
1393
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
1394
|
+
transport.monitorToken = monitorToken;
|
|
1395
|
+
transport.notifyTransactionId = notifyTransactionId;
|
|
1396
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
1397
|
+
transport.notifySubscription = this._monitorCharacteristic(transport.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
1398
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
1399
|
+
yield new Promise(resolve => {
|
|
1400
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
probeProtocolV1(uuid) {
|
|
1406
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1407
|
+
if (!this._messages) {
|
|
1408
|
+
return false;
|
|
1409
|
+
}
|
|
1410
|
+
try {
|
|
1411
|
+
this.deviceProtocol.set(uuid, 'V1');
|
|
1412
|
+
yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1413
|
+
return true;
|
|
1414
|
+
}
|
|
1415
|
+
catch (error) {
|
|
1416
|
+
this.clearProbeProtocol(uuid, 'V1');
|
|
1417
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe failed:', error);
|
|
1418
|
+
return false;
|
|
1419
|
+
}
|
|
1420
|
+
});
|
|
1421
|
+
}
|
|
1422
|
+
probeProtocolV2(uuid) {
|
|
1423
|
+
var _a;
|
|
1424
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1425
|
+
if (!this._messages || !this._messagesV2) {
|
|
1426
|
+
return false;
|
|
1427
|
+
}
|
|
1428
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1429
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1430
|
+
const detected = yield transport.probeProtocolV2({
|
|
1431
|
+
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
1432
|
+
timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
|
|
1433
|
+
logger: Log,
|
|
1434
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1435
|
+
onProbeFailed: () => {
|
|
1436
|
+
var _a;
|
|
1437
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1438
|
+
this.resetProtocolV2Frames(uuid);
|
|
1439
|
+
},
|
|
1440
|
+
});
|
|
1441
|
+
if (!detected) {
|
|
1442
|
+
this.clearProbeProtocol(uuid, 'V2');
|
|
1443
|
+
}
|
|
1444
|
+
return detected;
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
handleProtocolV2Notification(uuid, monitorToken, data) {
|
|
1448
|
+
try {
|
|
1449
|
+
if (this.monitorTokens.get(uuid) !== monitorToken)
|
|
1450
|
+
return;
|
|
1451
|
+
if (data.length === 0)
|
|
1452
|
+
return;
|
|
1453
|
+
const assembler = this.protocolV2Assemblers.get(uuid);
|
|
1454
|
+
if (!assembler)
|
|
1455
|
+
return;
|
|
1456
|
+
for (const frameData of assembler.drain(data)) {
|
|
1457
|
+
this.resolveProtocolV2Frame(uuid, frameData);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
catch (error) {
|
|
1461
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
|
|
1462
|
+
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1463
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1464
|
+
this.protocolV2Links
|
|
1465
|
+
.invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
|
|
1466
|
+
.catch(invalidateError => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notify cleanup failed:', invalidateError));
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
getProtocolV2FrameQueue(uuid) {
|
|
1470
|
+
let queue = this.protocolV2FrameQueues.get(uuid);
|
|
1471
|
+
if (!queue) {
|
|
1472
|
+
queue = [];
|
|
1473
|
+
this.protocolV2FrameQueues.set(uuid, queue);
|
|
1474
|
+
}
|
|
1475
|
+
return queue;
|
|
1476
|
+
}
|
|
1477
|
+
resolveProtocolV2Frame(uuid, frame) {
|
|
1478
|
+
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1479
|
+
if (framePromise) {
|
|
1480
|
+
framePromise.resolve(frame);
|
|
1481
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1485
|
+
}
|
|
1486
|
+
rejectAllProtocolV2Frames(error) {
|
|
1487
|
+
this.protocolV2FrameQueues.clear();
|
|
1488
|
+
for (const framePromise of this.protocolV2FramePromises.values()) {
|
|
1489
|
+
framePromise.reject(error);
|
|
1490
|
+
}
|
|
1491
|
+
this.protocolV2FramePromises.clear();
|
|
1492
|
+
}
|
|
1493
|
+
resetProtocolV2Frames(uuid) {
|
|
1494
|
+
this.protocolV2FrameQueues.delete(uuid);
|
|
1495
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1496
|
+
}
|
|
1497
|
+
rejectProtocolV2Frames(uuid, error) {
|
|
1498
|
+
this.protocolV2FrameQueues.delete(uuid);
|
|
1499
|
+
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1500
|
+
if (framePromise) {
|
|
1501
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1502
|
+
framePromise.reject(error);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
readProtocolV2Frame(uuid) {
|
|
1506
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1507
|
+
const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
|
|
1508
|
+
if (queuedFrame) {
|
|
1509
|
+
return queuedFrame;
|
|
1510
|
+
}
|
|
1511
|
+
const framePromise = hdShared.createDeferred();
|
|
1512
|
+
this.protocolV2FramePromises.set(uuid, framePromise);
|
|
1513
|
+
try {
|
|
1514
|
+
return yield framePromise.promise;
|
|
1515
|
+
}
|
|
1516
|
+
finally {
|
|
1517
|
+
if (this.protocolV2FramePromises.get(uuid) === framePromise) {
|
|
1518
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
writeProtocolV2Frame(transport, frame) {
|
|
1524
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1525
|
+
const tuning = getProtocolV2BleTuning();
|
|
1526
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1527
|
+
platform: reactNative.Platform.OS,
|
|
1528
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
1529
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
1530
|
+
mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
|
|
1531
|
+
});
|
|
1532
|
+
for (let offset = 0; offset < frame.length; offset += packetCapacity) {
|
|
1533
|
+
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1534
|
+
const base64 = buffer.Buffer.from(chunk).toString('base64');
|
|
1535
|
+
yield transport.writeCharacteristic.writeWithoutResponse(base64);
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
callProtocolV2(uuid, name, data, options) {
|
|
1540
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1541
|
+
if (!this._messages || !this._messagesV2) {
|
|
1542
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1543
|
+
}
|
|
1544
|
+
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: options === null || options === void 0 ? void 0 : options.timeoutMs });
|
|
1545
|
+
const highVolumeWrite = transport.LogBlockCommand.has(name);
|
|
1546
|
+
if (highVolumeWrite) {
|
|
1547
|
+
const tuning = getProtocolV2BleTuning();
|
|
1548
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
|
|
1549
|
+
name,
|
|
1550
|
+
writeMode: 'withoutResponse',
|
|
1551
|
+
packetCapacity: reactNative.Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
try {
|
|
1555
|
+
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1556
|
+
}
|
|
1557
|
+
catch (e) {
|
|
1558
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1559
|
+
throw e;
|
|
1560
|
+
}
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
createProtocolV2Adapter(uuid) {
|
|
1564
|
+
var _a;
|
|
1565
|
+
const generation = (_a = this.monitorTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1566
|
+
const assertCurrentGeneration = () => {
|
|
1567
|
+
if (this.monitorTokens.get(uuid) !== generation) {
|
|
1568
|
+
throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1571
|
+
return {
|
|
1572
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1573
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1574
|
+
generation,
|
|
1575
|
+
prepareCall: () => {
|
|
1576
|
+
var _a;
|
|
1577
|
+
assertCurrentGeneration();
|
|
1578
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1579
|
+
this.resetProtocolV2Frames(uuid);
|
|
1580
|
+
},
|
|
1581
|
+
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
1582
|
+
assertCurrentGeneration();
|
|
1583
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
1584
|
+
yield this.writeProtocolV2Frame(currentTransport, frame);
|
|
1585
|
+
}),
|
|
1586
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1587
|
+
assertCurrentGeneration();
|
|
1588
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1589
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1590
|
+
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1591
|
+
}
|
|
1592
|
+
return rxFrame;
|
|
1593
|
+
}),
|
|
1594
|
+
reset: (reason) => {
|
|
1595
|
+
var _a;
|
|
1596
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1597
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1598
|
+
},
|
|
1599
|
+
logger: Log,
|
|
1600
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1601
|
+
createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
getProtocolType(path) {
|
|
1605
|
+
return this.deviceProtocol.get(path);
|
|
1606
|
+
}
|
|
961
1607
|
}
|
|
962
1608
|
|
|
963
|
-
|
|
1609
|
+
exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
|
|
1610
|
+
exports["default"] = ReactNativeBleTransport;
|
|
1611
|
+
exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
|
|
1612
|
+
exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;
|