@onekeyfe/hd-transport-react-native 1.2.0-alpha.6 → 1.2.0-alpha.63
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/BleTransport.d.ts +1 -3
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts +0 -2
- package/dist/bleStrategy.d.ts.map +1 -1
- package/dist/constants.d.ts +0 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +79 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +588 -388
- package/dist/subscribeBleOn.d.ts.map +1 -1
- package/dist/transportLog.d.ts +2 -0
- package/dist/transportLog.d.ts.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/jest.config.js +10 -0
- package/package.json +7 -6
- package/src/BleTransport.ts +2 -43
- package/src/__tests__/BleTransport.test.ts +41 -0
- package/src/__tests__/bleStrategy.test.ts +1 -6
- package/src/__tests__/connectTimeout.test.ts +192 -0
- package/src/__tests__/constants.test.ts +20 -0
- package/src/__tests__/protocolV2Link.test.ts +527 -0
- package/src/__tests__/staleCallTimeout.test.ts +211 -0
- package/src/__tests__/writePacketTimeout.test.ts +306 -0
- package/src/bleStrategy.ts +0 -25
- package/src/constants.ts +7 -13
- package/src/index.ts +774 -407
- package/src/subscribeBleOn.ts +0 -2
- package/src/transportLog.ts +1 -0
- package/src/types.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -117,42 +117,23 @@ const getInfosForServiceUuid = (serviceUuid, deviceType) => {
|
|
|
117
117
|
return null;
|
|
118
118
|
}
|
|
119
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
|
|
120
|
+
const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid ||
|
|
121
|
+
hdShared.matchesKnownBleUuid(serviceUuid, hdShared.createKnownBleUuidAliases(item.serviceUuid)));
|
|
121
122
|
if (!service) {
|
|
122
123
|
return null;
|
|
123
124
|
}
|
|
124
125
|
return service;
|
|
125
126
|
};
|
|
126
127
|
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
128
|
const isSameBleUuid = (left, right) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
(getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
|
|
129
|
+
if (!left || !right)
|
|
130
|
+
return false;
|
|
131
|
+
return hdShared.matchesKnownBleUuid(left, hdShared.createKnownBleUuidAliases(right));
|
|
136
132
|
};
|
|
137
133
|
|
|
138
134
|
function hasWritableCapability(characteristic) {
|
|
139
135
|
return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
|
|
140
136
|
}
|
|
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
137
|
function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PACKET_LENGTH, androidPacketLength = ANDROID_PACKET_LENGTH, mtu, }) {
|
|
157
138
|
if (platform === 'ios') {
|
|
158
139
|
return iosPacketLength;
|
|
@@ -189,7 +170,6 @@ const timer = process.env.NODE_ENV === 'development'
|
|
|
189
170
|
const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
|
|
190
171
|
let done = false;
|
|
191
172
|
const subscription = bleManager.onStateChange(state => {
|
|
192
|
-
console.log('ble state -> ', state);
|
|
193
173
|
if (state === 'PoweredOn') {
|
|
194
174
|
if (done)
|
|
195
175
|
return;
|
|
@@ -219,7 +199,6 @@ const isHeaderChunk = (chunk) => {
|
|
|
219
199
|
return false;
|
|
220
200
|
};
|
|
221
201
|
|
|
222
|
-
const Log$1 = bleLogger;
|
|
223
202
|
class BleTransport {
|
|
224
203
|
constructor(device, writeCharacteristic, notifyCharacteristic) {
|
|
225
204
|
this.name = 'ReactNativeBleTransport';
|
|
@@ -229,37 +208,12 @@ class BleTransport {
|
|
|
229
208
|
this.writeCharacteristic = writeCharacteristic;
|
|
230
209
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
231
210
|
}
|
|
232
|
-
writeWithRetry(data
|
|
211
|
+
writeWithRetry(data) {
|
|
233
212
|
return __awaiter(this, void 0, void 0, function* () {
|
|
234
|
-
|
|
235
|
-
yield this.writeCharacteristic.writeWithoutResponse(data);
|
|
236
|
-
}
|
|
237
|
-
catch (error) {
|
|
238
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`);
|
|
239
|
-
if (retryCount > 0) {
|
|
240
|
-
yield hdShared.wait(BleTransport.RETRY_DELAY);
|
|
241
|
-
if (error.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
242
|
-
error.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
243
|
-
try {
|
|
244
|
-
yield this.device.connect();
|
|
245
|
-
yield this.device.discoverAllServicesAndCharacteristics();
|
|
246
|
-
}
|
|
247
|
-
catch (e) {
|
|
248
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Connect or discoverAllServicesAndCharacteristics error: ${e}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`writeCharacteristic error: ${error}`);
|
|
253
|
-
}
|
|
254
|
-
return this.writeWithRetry(data, retryCount - 1);
|
|
255
|
-
}
|
|
256
|
-
throw error;
|
|
257
|
-
}
|
|
213
|
+
yield this.writeCharacteristic.writeWithoutResponse(data);
|
|
258
214
|
});
|
|
259
215
|
}
|
|
260
216
|
}
|
|
261
|
-
BleTransport.MAX_RETRIES = 5;
|
|
262
|
-
BleTransport.RETRY_DELAY = 2000;
|
|
263
217
|
|
|
264
218
|
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
265
219
|
const Log = bleLogger;
|
|
@@ -268,7 +222,6 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 :
|
|
|
268
222
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
269
223
|
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
|
|
270
224
|
const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
|
|
271
|
-
const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
|
|
272
225
|
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
273
226
|
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
274
227
|
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
@@ -279,10 +232,6 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
279
232
|
if (!error || typeof error !== 'object')
|
|
280
233
|
return null;
|
|
281
234
|
const bleWriteError = error;
|
|
282
|
-
if (bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
283
|
-
bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
284
|
-
return 'reconnectable';
|
|
285
|
-
}
|
|
286
235
|
if (bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
|
|
287
236
|
bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS) {
|
|
288
237
|
return 'congested';
|
|
@@ -293,22 +242,20 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
293
242
|
return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
|
|
294
243
|
};
|
|
295
244
|
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
296
|
-
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
297
245
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
298
246
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
299
|
-
const
|
|
247
|
+
const BLE_WRITE_PACKET_TIMEOUT_MS = 10000;
|
|
248
|
+
const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
249
|
+
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
250
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
251
|
+
error.message.startsWith(WEDGED_WRITE_MESSAGE);
|
|
252
|
+
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
253
|
+
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
300
254
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
301
255
|
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
256
|
const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
|
|
306
257
|
iosPacketLength: IOS_PACKET_LENGTH,
|
|
307
258
|
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
259
|
};
|
|
313
260
|
let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
314
261
|
const normalizePositiveInteger = (value, fallback) => {
|
|
@@ -318,20 +265,15 @@ const normalizePositiveInteger = (value, fallback) => {
|
|
|
318
265
|
return Math.floor(normalized);
|
|
319
266
|
};
|
|
320
267
|
function configureProtocolV2BleTuning(tuning = {}) {
|
|
321
|
-
var _a;
|
|
322
268
|
protocolV2BleTuning = {
|
|
323
269
|
iosPacketLength: normalizePositiveInteger(tuning.iosPacketLength, protocolV2BleTuning.iosPacketLength),
|
|
324
270
|
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
271
|
};
|
|
330
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
272
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning configured', protocolV2BleTuning);
|
|
331
273
|
}
|
|
332
274
|
function resetProtocolV2BleTuning() {
|
|
333
275
|
protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
334
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
276
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning reset', protocolV2BleTuning);
|
|
335
277
|
}
|
|
336
278
|
function getProtocolV2BleTuning() {
|
|
337
279
|
return Object.assign({}, protocolV2BleTuning);
|
|
@@ -342,19 +284,22 @@ function inferProtocolHintFromDeviceName(name) {
|
|
|
342
284
|
function getDeviceDisplayName(device) {
|
|
343
285
|
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
344
286
|
}
|
|
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
287
|
const ANDROID_REQUEST_MTU = 256;
|
|
288
|
+
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
353
289
|
const connectOptions = {
|
|
354
290
|
requestMTU: ANDROID_REQUEST_MTU,
|
|
355
|
-
timeout:
|
|
291
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
356
292
|
refreshGatt: 'OnConnected',
|
|
357
293
|
};
|
|
294
|
+
const fallbackConnectOptions = {
|
|
295
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
296
|
+
};
|
|
297
|
+
const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
298
|
+
const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
299
|
+
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
300
|
+
const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
|
|
301
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
302
|
+
error.message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
358
303
|
const tryToGetConfiguration = (device) => {
|
|
359
304
|
if (!device || !device.serviceUUIDs)
|
|
360
305
|
return null;
|
|
@@ -371,9 +316,10 @@ const requestAndroidMtu = (device) => __awaiter(void 0, void 0, void 0, function
|
|
|
371
316
|
return device;
|
|
372
317
|
try {
|
|
373
318
|
const mtuDevice = yield device.requestMTU(ANDROID_REQUEST_MTU);
|
|
374
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
319
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU configured', {
|
|
320
|
+
deviceId: device.id,
|
|
375
321
|
requested: ANDROID_REQUEST_MTU,
|
|
376
|
-
|
|
322
|
+
actual: mtuDevice.mtu,
|
|
377
323
|
});
|
|
378
324
|
return mtuDevice;
|
|
379
325
|
}
|
|
@@ -408,15 +354,39 @@ class ReactNativeBleTransport {
|
|
|
408
354
|
this.stopped = false;
|
|
409
355
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
410
356
|
this.runPromise = null;
|
|
357
|
+
this.runPromiseDeviceId = null;
|
|
411
358
|
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
412
359
|
this.deviceProtocol = new Map();
|
|
360
|
+
this.probingProtocols = new Map();
|
|
361
|
+
this.writeTimeoutCounts = new Map();
|
|
362
|
+
this.connectTimeoutCounts = new Map();
|
|
413
363
|
this.deviceProtocolHints = new Map();
|
|
414
364
|
this.protocolV2Assemblers = new Map();
|
|
415
365
|
this.protocolV2FrameQueues = new Map();
|
|
416
366
|
this.protocolV2FramePromises = new Map();
|
|
417
|
-
this.
|
|
418
|
-
|
|
367
|
+
this.protocolV2Links = new transport.ProtocolV2LinkManager({
|
|
368
|
+
getSchemas: () => {
|
|
369
|
+
if (!this._messages || !this._messagesV2) {
|
|
370
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
protocolV1: this._messages,
|
|
374
|
+
protocolV2: this._messagesV2,
|
|
375
|
+
};
|
|
376
|
+
},
|
|
377
|
+
classifyError: () => 'link-fatal',
|
|
378
|
+
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
379
|
+
var _b;
|
|
380
|
+
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
381
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
382
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
383
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
384
|
+
yield this.releaseNative(uuid, true);
|
|
385
|
+
}
|
|
386
|
+
}),
|
|
387
|
+
});
|
|
419
388
|
this.monitorTokens = new Map();
|
|
389
|
+
this.disconnectEventTokens = new Map();
|
|
420
390
|
this.nextMonitorToken = 1;
|
|
421
391
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
422
392
|
}
|
|
@@ -430,8 +400,18 @@ class ReactNativeBleTransport {
|
|
|
430
400
|
this._messages = messages;
|
|
431
401
|
}
|
|
432
402
|
configureProtocolV2(signedData) {
|
|
403
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
404
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
433
408
|
this._messagesV2 = parseConfigure(signedData);
|
|
434
|
-
|
|
409
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
410
|
+
if (isReconfiguration) {
|
|
411
|
+
this.protocolV2Links
|
|
412
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
413
|
+
.catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
|
|
414
|
+
}
|
|
435
415
|
}
|
|
436
416
|
listen() {
|
|
437
417
|
}
|
|
@@ -442,7 +422,6 @@ class ReactNativeBleTransport {
|
|
|
442
422
|
return Promise.resolve(this.blePlxManager);
|
|
443
423
|
}
|
|
444
424
|
resolveCharacteristics(device) {
|
|
445
|
-
var _a, _b, _c, _d;
|
|
446
425
|
return __awaiter(this, void 0, void 0, function* () {
|
|
447
426
|
yield device.discoverAllServicesAndCharacteristics();
|
|
448
427
|
let infos = tryToGetConfiguration(device);
|
|
@@ -459,19 +438,11 @@ class ReactNativeBleTransport {
|
|
|
459
438
|
}
|
|
460
439
|
}
|
|
461
440
|
}
|
|
462
|
-
let fallbackServiceUuid;
|
|
463
441
|
if (!infos) {
|
|
464
442
|
const services = yield device.services();
|
|
465
443
|
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
444
|
}
|
|
474
|
-
if (!infos
|
|
445
|
+
if (!infos) {
|
|
475
446
|
try {
|
|
476
447
|
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
477
448
|
yield device.cancelConnection();
|
|
@@ -481,9 +452,7 @@ class ReactNativeBleTransport {
|
|
|
481
452
|
}
|
|
482
453
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
483
454
|
}
|
|
484
|
-
const serviceUuid
|
|
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';
|
|
455
|
+
const { serviceUuid, writeUuid, notifyUuid } = infos;
|
|
487
456
|
if (!serviceUuid) {
|
|
488
457
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
489
458
|
}
|
|
@@ -524,8 +493,8 @@ class ReactNativeBleTransport {
|
|
|
524
493
|
attachDisconnectSubscription(transport, device, uuid) {
|
|
525
494
|
var _a;
|
|
526
495
|
(_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
496
|
+
const { monitorToken } = transport;
|
|
527
497
|
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
528
|
-
var _a;
|
|
529
498
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
530
499
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
531
500
|
return;
|
|
@@ -534,17 +503,16 @@ class ReactNativeBleTransport {
|
|
|
534
503
|
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
504
|
return;
|
|
536
505
|
}
|
|
506
|
+
if (this.monitorTokens.get(uuid) !== monitorToken) {
|
|
507
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale generation: ', device === null || device === void 0 ? void 0 : device.id);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
537
510
|
try {
|
|
538
511
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
539
|
-
(
|
|
540
|
-
|
|
541
|
-
id: device === null || device === void 0 ? void 0 : device.id,
|
|
542
|
-
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
543
|
-
});
|
|
544
|
-
if (this.runPromise) {
|
|
512
|
+
this.emitDeviceDisconnect(uuid, device === null || device === void 0 ? void 0 : device.name, monitorToken);
|
|
513
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
545
514
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
546
515
|
this.runPromise.reject(error);
|
|
547
|
-
this.rejectAllProtocolV2Frames(error);
|
|
548
516
|
}
|
|
549
517
|
}
|
|
550
518
|
catch (e) {
|
|
@@ -555,6 +523,22 @@ class ReactNativeBleTransport {
|
|
|
555
523
|
}
|
|
556
524
|
});
|
|
557
525
|
}
|
|
526
|
+
emitDeviceDisconnect(uuid, name, token) {
|
|
527
|
+
var _a;
|
|
528
|
+
if (token === undefined || this.disconnectEventTokens.get(uuid) === token) {
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
if (this.monitorTokens.get(uuid) !== token) {
|
|
532
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect event ignored for stale generation: ', uuid);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
this.disconnectEventTokens.set(uuid, token);
|
|
536
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
537
|
+
name,
|
|
538
|
+
id: uuid,
|
|
539
|
+
connectId: uuid,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
558
542
|
reconnectFirmwareUploadTransport(uuid, transport) {
|
|
559
543
|
var _a, _b;
|
|
560
544
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -568,12 +552,12 @@ class ReactNativeBleTransport {
|
|
|
568
552
|
const isConnected = yield device.isConnected().catch(() => false);
|
|
569
553
|
if (!isConnected) {
|
|
570
554
|
try {
|
|
571
|
-
device = yield device.connect(connectOptions);
|
|
555
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect(connectOptions));
|
|
572
556
|
}
|
|
573
557
|
catch (e) {
|
|
574
558
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
575
559
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
576
|
-
device = yield device.connect();
|
|
560
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect());
|
|
577
561
|
}
|
|
578
562
|
else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
579
563
|
throw e;
|
|
@@ -624,13 +608,12 @@ class ReactNativeBleTransport {
|
|
|
624
608
|
return;
|
|
625
609
|
}
|
|
626
610
|
}
|
|
627
|
-
blePlxManager.startDeviceScan(
|
|
611
|
+
blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
|
|
628
612
|
allowDuplicates: true,
|
|
629
613
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
630
614
|
}, (error, device) => {
|
|
631
|
-
var _a
|
|
615
|
+
var _a;
|
|
632
616
|
if (error) {
|
|
633
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan manager: ', blePlxManager);
|
|
634
617
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
635
618
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
636
619
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
@@ -650,25 +633,14 @@ class ReactNativeBleTransport {
|
|
|
650
633
|
return;
|
|
651
634
|
}
|
|
652
635
|
const displayName = getDeviceDisplayName(device);
|
|
653
|
-
const isOneKey = hdShared.
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
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
|
-
}
|
|
636
|
+
const isOneKey = hdShared.isOnekeyBluetoothDevice({
|
|
637
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
638
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
639
|
+
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
640
|
+
serviceUuids: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
641
|
+
});
|
|
666
642
|
if (isOneKey) {
|
|
667
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('search device start ======================');
|
|
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(',')}`);
|
|
670
643
|
addDevice(device);
|
|
671
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('search device end ======================\n');
|
|
672
644
|
}
|
|
673
645
|
else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
|
|
674
646
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Pro2-like BLE device was not accepted:', {
|
|
@@ -679,10 +651,20 @@ class ReactNativeBleTransport {
|
|
|
679
651
|
});
|
|
680
652
|
}
|
|
681
653
|
});
|
|
682
|
-
getConnectedDeviceIds(getBluetoothServiceUuids()).then(devices => {
|
|
654
|
+
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
683
655
|
for (const device of devices) {
|
|
684
|
-
|
|
685
|
-
|
|
656
|
+
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
657
|
+
? device.localName
|
|
658
|
+
: null;
|
|
659
|
+
if (hdShared.isOnekeyBluetoothDevice({
|
|
660
|
+
id: device.id,
|
|
661
|
+
name: device.name,
|
|
662
|
+
localName,
|
|
663
|
+
serviceUuids: device.serviceUUIDs,
|
|
664
|
+
})) {
|
|
665
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
|
|
666
|
+
addDevice(device);
|
|
667
|
+
}
|
|
686
668
|
}
|
|
687
669
|
});
|
|
688
670
|
const addDevice = (device) => {
|
|
@@ -694,6 +676,12 @@ class ReactNativeBleTransport {
|
|
|
694
676
|
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
695
677
|
}
|
|
696
678
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
679
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
680
|
+
deviceId: device.id,
|
|
681
|
+
name: displayName,
|
|
682
|
+
serviceUUIDs: device.serviceUUIDs,
|
|
683
|
+
protocolHint,
|
|
684
|
+
});
|
|
697
685
|
}
|
|
698
686
|
};
|
|
699
687
|
timer.timeout(() => {
|
|
@@ -703,6 +691,33 @@ class ReactNativeBleTransport {
|
|
|
703
691
|
}));
|
|
704
692
|
});
|
|
705
693
|
}
|
|
694
|
+
installTransportForAcquire(uuid, device, characteristics) {
|
|
695
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
696
|
+
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristics(device));
|
|
697
|
+
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
698
|
+
if (reactNative.Platform.OS === 'android') {
|
|
699
|
+
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
|
|
700
|
+
}
|
|
701
|
+
const monitorToken = this.nextMonitorToken;
|
|
702
|
+
this.nextMonitorToken += 1;
|
|
703
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
704
|
+
transport$1.monitorToken = monitorToken;
|
|
705
|
+
transport$1.notifyTransactionId = notifyTransactionId;
|
|
706
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
707
|
+
transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
708
|
+
transportCache[uuid] = transport$1;
|
|
709
|
+
this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
710
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
711
|
+
yield new Promise(resolve => {
|
|
712
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
else if (reactNative.Platform.OS === 'android') {
|
|
716
|
+
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
717
|
+
}
|
|
718
|
+
return transport$1;
|
|
719
|
+
});
|
|
720
|
+
}
|
|
706
721
|
acquire(input) {
|
|
707
722
|
var _a, _b;
|
|
708
723
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -727,9 +742,8 @@ class ReactNativeBleTransport {
|
|
|
727
742
|
if (forceCleanRunPromise && this.runPromise) {
|
|
728
743
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
729
744
|
this.runPromise.reject(error);
|
|
730
|
-
this.rejectAllProtocolV2Frames(error);
|
|
731
745
|
this.runPromise = null;
|
|
732
|
-
this.
|
|
746
|
+
this.runPromiseDeviceId = null;
|
|
733
747
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
734
748
|
}
|
|
735
749
|
const blePlxManager = yield this.getPlxManager();
|
|
@@ -762,14 +776,17 @@ class ReactNativeBleTransport {
|
|
|
762
776
|
if (!device) {
|
|
763
777
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
|
|
764
778
|
try {
|
|
765
|
-
device = yield blePlxManager.connectToDevice(uuid, connectOptions);
|
|
779
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, connectOptions));
|
|
766
780
|
}
|
|
767
781
|
catch (e) {
|
|
768
782
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
783
|
+
if (isConnectTimeoutError(e)) {
|
|
784
|
+
throw e;
|
|
785
|
+
}
|
|
769
786
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
770
787
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
771
788
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
772
|
-
device = yield blePlxManager.connectToDevice(uuid);
|
|
789
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
773
790
|
}
|
|
774
791
|
else if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
775
792
|
Log === null || Log === void 0 ? void 0 : Log.debug('device already connected');
|
|
@@ -785,23 +802,27 @@ class ReactNativeBleTransport {
|
|
|
785
802
|
}
|
|
786
803
|
if (!(yield device.isConnected())) {
|
|
787
804
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
805
|
+
const disconnectedDevice = device;
|
|
788
806
|
try {
|
|
789
|
-
device = yield
|
|
807
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(connectOptions));
|
|
790
808
|
}
|
|
791
809
|
catch (e) {
|
|
792
810
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
811
|
+
if (isConnectTimeoutError(e)) {
|
|
812
|
+
throw e;
|
|
813
|
+
}
|
|
793
814
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
794
815
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
795
816
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
796
817
|
try {
|
|
797
|
-
device = yield
|
|
818
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
798
819
|
}
|
|
799
820
|
catch (e) {
|
|
800
821
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
|
|
801
822
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
802
823
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
803
|
-
yield
|
|
804
|
-
device = yield
|
|
824
|
+
yield disconnectedDevice.cancelConnection();
|
|
825
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
805
826
|
}
|
|
806
827
|
}
|
|
807
828
|
}
|
|
@@ -811,50 +832,41 @@ class ReactNativeBleTransport {
|
|
|
811
832
|
}
|
|
812
833
|
}
|
|
813
834
|
device = yield requestAndroidMtu(device);
|
|
814
|
-
const
|
|
835
|
+
const acquiredDevice = device;
|
|
836
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(acquiredDevice);
|
|
815
837
|
const protocolHint = expectedProtocol
|
|
816
838
|
? undefined
|
|
817
|
-
: (_a = this.deviceProtocolHints.get(uuid)) !== null &&
|
|
839
|
+
: (_b = (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
|
|
818
840
|
yield this.release(uuid, true);
|
|
819
841
|
if (protocolHint) {
|
|
820
842
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
821
843
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
yield new Promise(resolve => {
|
|
837
|
-
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
838
|
-
});
|
|
844
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice, {
|
|
845
|
+
writeCharacteristic,
|
|
846
|
+
notifyCharacteristic,
|
|
847
|
+
});
|
|
848
|
+
try {
|
|
849
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
850
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
851
|
+
}));
|
|
852
|
+
const currentTransport = transportCache[uuid];
|
|
853
|
+
if (!currentTransport) {
|
|
854
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
855
|
+
}
|
|
856
|
+
this.attachDisconnectSubscription(currentTransport, acquiredDevice, uuid);
|
|
857
|
+
return { uuid, protocolType };
|
|
839
858
|
}
|
|
840
|
-
|
|
841
|
-
yield
|
|
859
|
+
catch (error) {
|
|
860
|
+
yield this.release(uuid, true);
|
|
861
|
+
throw error;
|
|
842
862
|
}
|
|
843
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
844
|
-
(_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
|
|
845
|
-
name: device.name,
|
|
846
|
-
id: device.id,
|
|
847
|
-
connectId: device.id,
|
|
848
|
-
});
|
|
849
|
-
this.attachDisconnectSubscription(transport$1, device, uuid);
|
|
850
|
-
return { uuid, protocolType };
|
|
851
863
|
});
|
|
852
864
|
}
|
|
853
865
|
_monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
|
|
854
866
|
let bufferLength = 0;
|
|
855
867
|
let buffer$1 = [];
|
|
856
868
|
const subscription = characteristic.monitor((error, c) => {
|
|
857
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
869
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
858
870
|
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
859
871
|
if (error) {
|
|
860
872
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
@@ -866,28 +878,44 @@ class ReactNativeBleTransport {
|
|
|
866
878
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
867
879
|
return;
|
|
868
880
|
}
|
|
869
|
-
if (this.
|
|
870
|
-
let
|
|
881
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
882
|
+
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
871
883
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
872
|
-
|
|
884
|
+
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
873
885
|
}
|
|
874
|
-
if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
875
|
-
|
|
886
|
+
else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
887
|
+
errorCode = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
876
888
|
}
|
|
877
|
-
if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
889
|
+
else if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
878
890
|
((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('Cannot find client characteristic config descriptor')) ||
|
|
879
891
|
((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
|
|
880
892
|
((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
|
|
881
893
|
((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
|
|
894
|
+
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
895
|
+
}
|
|
896
|
+
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
897
|
+
return;
|
|
898
|
+
}
|
|
899
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
900
|
+
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
901
|
+
if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
|
|
902
|
+
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
903
|
+
}
|
|
904
|
+
if ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Encryption is insufficient')) {
|
|
905
|
+
ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
906
|
+
}
|
|
907
|
+
if (((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('Cannot write client characteristic config descriptor')) ||
|
|
908
|
+
((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Cannot find client characteristic config descriptor')) ||
|
|
909
|
+
((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
|
|
910
|
+
((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
|
|
911
|
+
((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
|
|
882
912
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
883
913
|
this.runPromise.reject(notifyError);
|
|
884
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
885
914
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
886
915
|
return;
|
|
887
916
|
}
|
|
888
917
|
const notifyError = hdShared.ERRORS.TypedError(ERROR);
|
|
889
918
|
this.runPromise.reject(notifyError);
|
|
890
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
891
919
|
Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
892
920
|
}
|
|
893
921
|
return;
|
|
@@ -901,13 +929,13 @@ class ReactNativeBleTransport {
|
|
|
901
929
|
}
|
|
902
930
|
try {
|
|
903
931
|
const data = buffer.Buffer.from(c.value, 'base64');
|
|
904
|
-
const protocol = this.
|
|
932
|
+
const protocol = this.getActiveProtocol(uuid);
|
|
905
933
|
if (!protocol) {
|
|
906
934
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
|
|
907
935
|
return;
|
|
908
936
|
}
|
|
909
937
|
if (protocol === 'V2') {
|
|
910
|
-
this.handleProtocolV2Notification(uuid, new Uint8Array(data));
|
|
938
|
+
this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
|
|
911
939
|
return;
|
|
912
940
|
}
|
|
913
941
|
if (isHeaderChunk(data)) {
|
|
@@ -921,28 +949,40 @@ class ReactNativeBleTransport {
|
|
|
921
949
|
const value = buffer.Buffer.from(buffer$1);
|
|
922
950
|
bufferLength = 0;
|
|
923
951
|
buffer$1 = [];
|
|
924
|
-
(
|
|
952
|
+
if (this.runPromiseDeviceId === uuid) {
|
|
953
|
+
(_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
|
|
954
|
+
}
|
|
925
955
|
}
|
|
926
956
|
}
|
|
927
957
|
catch (error) {
|
|
928
958
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
929
959
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
930
|
-
(
|
|
931
|
-
|
|
960
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
961
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
962
|
+
}
|
|
963
|
+
else if (this.runPromiseDeviceId === uuid) {
|
|
964
|
+
(_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
|
|
965
|
+
}
|
|
932
966
|
}
|
|
933
967
|
}, notifyTransactionId);
|
|
934
968
|
return subscription;
|
|
935
969
|
}
|
|
936
970
|
release(uuid, onclose = false) {
|
|
937
|
-
|
|
971
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
972
|
+
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
973
|
+
return this.releaseNative(uuid, onclose);
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
releaseNative(uuid, onclose = false) {
|
|
977
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
938
978
|
return __awaiter(this, void 0, void 0, function* () {
|
|
939
979
|
const transport = transportCache[uuid];
|
|
940
|
-
if (this.runPromise) {
|
|
980
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
941
981
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
942
982
|
this.runPromise.reject(error);
|
|
943
983
|
this.runPromise = null;
|
|
944
|
-
this.
|
|
945
|
-
this.
|
|
984
|
+
this.runPromiseDeviceId = null;
|
|
985
|
+
this.rejectProtocolV2Frames(uuid, error);
|
|
946
986
|
}
|
|
947
987
|
else {
|
|
948
988
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -950,9 +990,6 @@ class ReactNativeBleTransport {
|
|
|
950
990
|
if (reactNative.Platform.OS === 'android' && !onclose && transport) {
|
|
951
991
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
952
992
|
this.resetProtocolV2Frames(uuid);
|
|
953
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
954
|
-
this.activeProtocolV2Call = null;
|
|
955
|
-
}
|
|
956
993
|
return Promise.resolve(true);
|
|
957
994
|
}
|
|
958
995
|
if (transport) {
|
|
@@ -960,14 +997,14 @@ class ReactNativeBleTransport {
|
|
|
960
997
|
this.monitorTokens.delete(uuid);
|
|
961
998
|
}
|
|
962
999
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
|
|
963
|
-
(
|
|
1000
|
+
(_b = transport.disconnectSubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
964
1001
|
transport.disconnectSubscription = undefined;
|
|
965
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (
|
|
966
|
-
(
|
|
1002
|
+
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);
|
|
1003
|
+
(_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
|
|
967
1004
|
transport.notifySubscription = undefined;
|
|
968
1005
|
if (transport.notifyTransactionId) {
|
|
969
1006
|
try {
|
|
970
|
-
yield ((
|
|
1007
|
+
yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
|
|
971
1008
|
}
|
|
972
1009
|
catch (e) {
|
|
973
1010
|
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);
|
|
@@ -976,12 +1013,12 @@ class ReactNativeBleTransport {
|
|
|
976
1013
|
delete transportCache[uuid];
|
|
977
1014
|
}
|
|
978
1015
|
this.deviceProtocol.delete(uuid);
|
|
979
|
-
this.
|
|
980
|
-
(
|
|
1016
|
+
this.probingProtocols.delete(uuid);
|
|
1017
|
+
(_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
|
|
981
1018
|
this.protocolV2Assemblers.delete(uuid);
|
|
982
1019
|
this.resetProtocolV2Frames(uuid);
|
|
983
1020
|
try {
|
|
984
|
-
yield ((
|
|
1021
|
+
yield ((_g = this.blePlxManager) === null || _g === void 0 ? void 0 : _g.cancelTransaction(uuid));
|
|
985
1022
|
}
|
|
986
1023
|
catch (e) {
|
|
987
1024
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1002,30 +1039,18 @@ class ReactNativeBleTransport {
|
|
|
1002
1039
|
if (this._messages == null) {
|
|
1003
1040
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1004
1041
|
}
|
|
1005
|
-
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1006
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native call this.runPromise', this.runPromise);
|
|
1007
|
-
if (this.runPromise && !forceRun) {
|
|
1008
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1009
|
-
}
|
|
1010
1042
|
const protocol = this.getProtocolType(uuid);
|
|
1011
1043
|
if (!protocol) {
|
|
1012
1044
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1013
1045
|
}
|
|
1014
|
-
|
|
1015
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', {
|
|
1016
|
-
file_name: data === null || data === void 0 ? void 0 : data.file_name,
|
|
1017
|
-
hash: data === null || data === void 0 ? void 0 : data.hash,
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
else if (transport.LogBlockCommand.has(name)) {
|
|
1021
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' protocol: ', protocol);
|
|
1022
|
-
}
|
|
1023
|
-
else {
|
|
1024
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
1025
|
-
}
|
|
1046
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport call', transport.createTransportCallLog(name, protocol, data));
|
|
1026
1047
|
if (protocol === 'V2') {
|
|
1027
1048
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1028
1049
|
}
|
|
1050
|
+
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1051
|
+
if (this.runPromise && !forceRun) {
|
|
1052
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1053
|
+
}
|
|
1029
1054
|
return this.callProtocolV1(uuid, name, data, options);
|
|
1030
1055
|
});
|
|
1031
1056
|
}
|
|
@@ -1037,7 +1062,19 @@ class ReactNativeBleTransport {
|
|
|
1037
1062
|
const transport = this.getCachedTransport(uuid);
|
|
1038
1063
|
const runPromise = hdShared.createDeferred();
|
|
1039
1064
|
runPromise.promise.catch(() => undefined);
|
|
1065
|
+
const supersededRunPromise = this.runPromise;
|
|
1066
|
+
if (supersededRunPromise) {
|
|
1067
|
+
supersededRunPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
|
|
1068
|
+
}
|
|
1040
1069
|
this.runPromise = runPromise;
|
|
1070
|
+
this.runPromiseDeviceId = uuid;
|
|
1071
|
+
const releaseOwnershipIfCurrent = () => {
|
|
1072
|
+
if (this.runPromise === runPromise) {
|
|
1073
|
+
this.runPromise = null;
|
|
1074
|
+
this.runPromiseDeviceId = null;
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
const isCurrentOwner = () => this.runPromise === runPromise;
|
|
1041
1078
|
const messages = this._messages;
|
|
1042
1079
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1043
1080
|
let timeout;
|
|
@@ -1058,6 +1095,9 @@ class ReactNativeBleTransport {
|
|
|
1058
1095
|
}
|
|
1059
1096
|
catch (e) {
|
|
1060
1097
|
onError(e);
|
|
1098
|
+
if (isWedgedWriteError(e)) {
|
|
1099
|
+
throw e;
|
|
1100
|
+
}
|
|
1061
1101
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1062
1102
|
}
|
|
1063
1103
|
}
|
|
@@ -1085,6 +1125,9 @@ class ReactNativeBleTransport {
|
|
|
1085
1125
|
}
|
|
1086
1126
|
catch (e) {
|
|
1087
1127
|
onError(e);
|
|
1128
|
+
if (isWedgedWriteError(e)) {
|
|
1129
|
+
throw e;
|
|
1130
|
+
}
|
|
1088
1131
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1089
1132
|
}
|
|
1090
1133
|
}
|
|
@@ -1095,13 +1138,13 @@ class ReactNativeBleTransport {
|
|
|
1095
1138
|
});
|
|
1096
1139
|
}
|
|
1097
1140
|
if (name === 'EmmcFileWrite') {
|
|
1098
|
-
yield writeChunkedData(buffers, data => transport.writeWithRetry(
|
|
1099
|
-
|
|
1141
|
+
yield writeChunkedData(buffers, data => this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner), e => {
|
|
1142
|
+
releaseOwnershipIfCurrent();
|
|
1100
1143
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1101
1144
|
});
|
|
1102
1145
|
}
|
|
1103
1146
|
else if (name === 'FirmwareUpload') {
|
|
1104
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
1147
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Firmware upload transport configured', {
|
|
1105
1148
|
packetCapacity: FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY,
|
|
1106
1149
|
burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
|
|
1107
1150
|
pauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
|
|
@@ -1112,7 +1155,7 @@ class ReactNativeBleTransport {
|
|
|
1112
1155
|
let attempt = 0;
|
|
1113
1156
|
while (true) {
|
|
1114
1157
|
try {
|
|
1115
|
-
yield transport.writeCharacteristic.writeWithoutResponse(
|
|
1158
|
+
yield this.writeBlePacket(uuid, data, payload => transport.writeCharacteristic.writeWithoutResponse(payload), isCurrentOwner);
|
|
1116
1159
|
return;
|
|
1117
1160
|
}
|
|
1118
1161
|
catch (error) {
|
|
@@ -1120,36 +1163,18 @@ class ReactNativeBleTransport {
|
|
|
1120
1163
|
if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1121
1164
|
throw error;
|
|
1122
1165
|
}
|
|
1123
|
-
const
|
|
1124
|
-
const delayMs = shouldReconnect
|
|
1125
|
-
? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
|
|
1126
|
-
: resolveFirmwareUploadRetryDelay(attempt);
|
|
1166
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1127
1167
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
|
|
1128
1168
|
attempt: attempt + 1,
|
|
1129
1169
|
delayMs,
|
|
1130
|
-
reconnect: shouldReconnect,
|
|
1131
1170
|
error,
|
|
1132
1171
|
});
|
|
1133
|
-
if (shouldReconnect) {
|
|
1134
|
-
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
1135
|
-
}
|
|
1136
1172
|
yield delay(delayMs);
|
|
1137
1173
|
attempt += 1;
|
|
1138
|
-
if (shouldReconnect) {
|
|
1139
|
-
try {
|
|
1140
|
-
yield this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
1141
|
-
}
|
|
1142
|
-
catch (e) {
|
|
1143
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
1144
|
-
if (attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1145
|
-
throw e;
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
1174
|
}
|
|
1150
1175
|
}
|
|
1151
1176
|
}), e => {
|
|
1152
|
-
|
|
1177
|
+
releaseOwnershipIfCurrent();
|
|
1153
1178
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1154
1179
|
});
|
|
1155
1180
|
}
|
|
@@ -1157,11 +1182,14 @@ class ReactNativeBleTransport {
|
|
|
1157
1182
|
for (const o of buffers) {
|
|
1158
1183
|
const outData = o.toString('base64');
|
|
1159
1184
|
try {
|
|
1160
|
-
yield transport.writeCharacteristic.writeWithoutResponse(
|
|
1185
|
+
yield this.writeBlePacket(uuid, outData, payload => transport.writeCharacteristic.writeWithoutResponse(payload), isCurrentOwner);
|
|
1161
1186
|
}
|
|
1162
1187
|
catch (e) {
|
|
1163
1188
|
Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
|
|
1164
|
-
|
|
1189
|
+
releaseOwnershipIfCurrent();
|
|
1190
|
+
if (isWedgedWriteError(e)) {
|
|
1191
|
+
throw e;
|
|
1192
|
+
}
|
|
1165
1193
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected) {
|
|
1166
1194
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded);
|
|
1167
1195
|
}
|
|
@@ -1190,17 +1218,23 @@ class ReactNativeBleTransport {
|
|
|
1190
1218
|
if (typeof response !== 'string') {
|
|
1191
1219
|
throw new Error('Returning data is not string.');
|
|
1192
1220
|
}
|
|
1193
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('receive data: ', response);
|
|
1194
1221
|
const jsonData = ProtocolV1.decodeMessage(messages, response);
|
|
1195
1222
|
return check.call(jsonData);
|
|
1196
1223
|
}
|
|
1197
1224
|
catch (e) {
|
|
1198
|
-
if (name === '
|
|
1199
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1225
|
+
if (name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
|
|
1226
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
|
|
1200
1227
|
}
|
|
1201
1228
|
else {
|
|
1202
1229
|
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1203
1230
|
}
|
|
1231
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1232
|
+
const isStaleCall = this.runPromise !== runPromise;
|
|
1233
|
+
if (!isProbeTimeout &&
|
|
1234
|
+
!isStaleCall &&
|
|
1235
|
+
(e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1236
|
+
yield this.disconnect(uuid);
|
|
1237
|
+
}
|
|
1204
1238
|
throw e;
|
|
1205
1239
|
}
|
|
1206
1240
|
finally {
|
|
@@ -1208,6 +1242,7 @@ class ReactNativeBleTransport {
|
|
|
1208
1242
|
clearTimeout(timeout);
|
|
1209
1243
|
if (this.runPromise === runPromise) {
|
|
1210
1244
|
this.runPromise = null;
|
|
1245
|
+
this.runPromiseDeviceId = null;
|
|
1211
1246
|
}
|
|
1212
1247
|
}
|
|
1213
1248
|
});
|
|
@@ -1216,10 +1251,11 @@ class ReactNativeBleTransport {
|
|
|
1216
1251
|
this.stopped = true;
|
|
1217
1252
|
}
|
|
1218
1253
|
disconnect(session) {
|
|
1219
|
-
var _a, _b, _c, _d, _e
|
|
1254
|
+
var _a, _b, _c, _d, _e;
|
|
1220
1255
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1221
|
-
|
|
1256
|
+
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1222
1257
|
const transport = transportCache[session];
|
|
1258
|
+
const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
|
|
1223
1259
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
1224
1260
|
try {
|
|
1225
1261
|
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing disconnect subscription');
|
|
@@ -1232,7 +1268,7 @@ class ReactNativeBleTransport {
|
|
|
1232
1268
|
}
|
|
1233
1269
|
if (transport === null || transport === void 0 ? void 0 : transport.notifySubscription) {
|
|
1234
1270
|
try {
|
|
1235
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (
|
|
1271
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (_b = transport.notifyCharacteristic) === null || _b === void 0 ? void 0 : _b.uuid);
|
|
1236
1272
|
transport.notifySubscription.remove();
|
|
1237
1273
|
transport.notifySubscription = undefined;
|
|
1238
1274
|
}
|
|
@@ -1242,7 +1278,7 @@ class ReactNativeBleTransport {
|
|
|
1242
1278
|
}
|
|
1243
1279
|
if (session) {
|
|
1244
1280
|
try {
|
|
1245
|
-
yield ((
|
|
1281
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(session));
|
|
1246
1282
|
}
|
|
1247
1283
|
catch (e) {
|
|
1248
1284
|
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1257,7 +1293,7 @@ class ReactNativeBleTransport {
|
|
|
1257
1293
|
}
|
|
1258
1294
|
}
|
|
1259
1295
|
try {
|
|
1260
|
-
yield ((
|
|
1296
|
+
yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelDeviceConnection(session));
|
|
1261
1297
|
}
|
|
1262
1298
|
catch (e) {
|
|
1263
1299
|
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1266,22 +1302,19 @@ class ReactNativeBleTransport {
|
|
|
1266
1302
|
delete transportCache[session];
|
|
1267
1303
|
}
|
|
1268
1304
|
this.deviceProtocol.delete(session);
|
|
1305
|
+
this.probingProtocols.delete(session);
|
|
1269
1306
|
this.deviceProtocolHints.delete(session);
|
|
1270
1307
|
this.protocolV2Assemblers.delete(session);
|
|
1271
1308
|
this.resetProtocolV2Frames(session);
|
|
1272
|
-
if (((_d = this.activeProtocolV2Call) === null || _d === void 0 ? void 0 : _d.uuid) === session) {
|
|
1273
|
-
this.activeProtocolV2Call = null;
|
|
1274
|
-
}
|
|
1275
1309
|
try {
|
|
1276
|
-
(_e =
|
|
1277
|
-
name: (_f = transport === null || transport === void 0 ? void 0 : transport.device) === null || _f === void 0 ? void 0 : _f.name,
|
|
1278
|
-
id: session,
|
|
1279
|
-
connectId: session,
|
|
1280
|
-
});
|
|
1310
|
+
this.emitDeviceDisconnect(session, (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name, monitorToken);
|
|
1281
1311
|
}
|
|
1282
1312
|
catch (e) {
|
|
1283
1313
|
Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
|
|
1284
1314
|
}
|
|
1315
|
+
if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
|
|
1316
|
+
this.monitorTokens.delete(session);
|
|
1317
|
+
}
|
|
1285
1318
|
yield new Promise(resolve => setTimeout(() => resolve(), 100));
|
|
1286
1319
|
});
|
|
1287
1320
|
}
|
|
@@ -1289,6 +1322,61 @@ class ReactNativeBleTransport {
|
|
|
1289
1322
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1290
1323
|
if (this.runPromise) ;
|
|
1291
1324
|
this.runPromise = null;
|
|
1325
|
+
this.runPromiseDeviceId = null;
|
|
1326
|
+
}
|
|
1327
|
+
connectWithTimeout(uuid, connect) {
|
|
1328
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1329
|
+
let timer;
|
|
1330
|
+
let timedOut = false;
|
|
1331
|
+
const pending = connect();
|
|
1332
|
+
pending.catch(() => undefined);
|
|
1333
|
+
try {
|
|
1334
|
+
const result = yield Promise.race([
|
|
1335
|
+
pending,
|
|
1336
|
+
new Promise((_, reject) => {
|
|
1337
|
+
timer = setTimeout(() => {
|
|
1338
|
+
timedOut = true;
|
|
1339
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `BLE connect timeout after ${BLE_CONNECT_TIMEOUT_MS}ms for ${uuid}`));
|
|
1340
|
+
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1341
|
+
}),
|
|
1342
|
+
]);
|
|
1343
|
+
this.connectTimeoutCounts.delete(uuid);
|
|
1344
|
+
return result;
|
|
1345
|
+
}
|
|
1346
|
+
catch (error) {
|
|
1347
|
+
if (timedOut) {
|
|
1348
|
+
this.abandonStalledConnect(uuid);
|
|
1349
|
+
}
|
|
1350
|
+
throw error;
|
|
1351
|
+
}
|
|
1352
|
+
finally {
|
|
1353
|
+
if (timer)
|
|
1354
|
+
clearTimeout(timer);
|
|
1355
|
+
}
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
abandonStalledConnect(uuid) {
|
|
1359
|
+
var _a, _b;
|
|
1360
|
+
const timeouts = ((_a = this.connectTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1361
|
+
this.connectTimeoutCounts.set(uuid, timeouts);
|
|
1362
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE connect timed out:', uuid, {
|
|
1363
|
+
consecutiveConnectTimeouts: timeouts,
|
|
1364
|
+
});
|
|
1365
|
+
(_b = this.blePlxManager) === null || _b === void 0 ? void 0 : _b.cancelDeviceConnection(uuid).catch(() => {
|
|
1366
|
+
});
|
|
1367
|
+
const stalled = transportCache[uuid];
|
|
1368
|
+
if (stalled) {
|
|
1369
|
+
delete transportCache[uuid];
|
|
1370
|
+
}
|
|
1371
|
+
this.deviceProtocol.delete(uuid);
|
|
1372
|
+
this.probingProtocols.delete(uuid);
|
|
1373
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1374
|
+
this.resetProtocolV2Frames(uuid);
|
|
1375
|
+
if (timeouts >= BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1376
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE connects wedged repeatedly, resetting BLE manager');
|
|
1377
|
+
this.resetPlxManager();
|
|
1378
|
+
this.connectTimeoutCounts.delete(uuid);
|
|
1379
|
+
}
|
|
1292
1380
|
}
|
|
1293
1381
|
getCachedTransport(uuid) {
|
|
1294
1382
|
const transport = transportCache[uuid];
|
|
@@ -1297,58 +1385,159 @@ class ReactNativeBleTransport {
|
|
|
1297
1385
|
}
|
|
1298
1386
|
return transport;
|
|
1299
1387
|
}
|
|
1388
|
+
writeBlePacket(uuid, data, write, isCurrentOwner) {
|
|
1389
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1390
|
+
let timer;
|
|
1391
|
+
let timedOut = false;
|
|
1392
|
+
try {
|
|
1393
|
+
yield Promise.race([
|
|
1394
|
+
write(data),
|
|
1395
|
+
new Promise((_, reject) => {
|
|
1396
|
+
timer = setTimeout(() => {
|
|
1397
|
+
timedOut = true;
|
|
1398
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write timeout after ${BLE_WRITE_PACKET_TIMEOUT_MS}ms`));
|
|
1399
|
+
}, BLE_WRITE_PACKET_TIMEOUT_MS);
|
|
1400
|
+
}),
|
|
1401
|
+
]);
|
|
1402
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1403
|
+
}
|
|
1404
|
+
catch (error) {
|
|
1405
|
+
if (timedOut) {
|
|
1406
|
+
if (isCurrentOwner && !isCurrentOwner()) {
|
|
1407
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] stale BLE write timed out, link kept:', uuid);
|
|
1408
|
+
}
|
|
1409
|
+
else {
|
|
1410
|
+
this.tearDownWedgedLink(uuid);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
throw error;
|
|
1414
|
+
}
|
|
1415
|
+
finally {
|
|
1416
|
+
if (timer)
|
|
1417
|
+
clearTimeout(timer);
|
|
1418
|
+
}
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
tearDownWedgedLink(uuid) {
|
|
1422
|
+
var _a;
|
|
1423
|
+
const timeouts = ((_a = this.writeTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1424
|
+
this.writeTimeoutCounts.set(uuid, timeouts);
|
|
1425
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE write timed out, tearing down link:', uuid, {
|
|
1426
|
+
consecutiveWriteTimeouts: timeouts,
|
|
1427
|
+
});
|
|
1428
|
+
const wedged = transportCache[uuid];
|
|
1429
|
+
this.disconnect(uuid).catch(error => {
|
|
1430
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] wedged link teardown failed (ignored):', error);
|
|
1431
|
+
});
|
|
1432
|
+
if (wedged && transportCache[uuid] === wedged) {
|
|
1433
|
+
delete transportCache[uuid];
|
|
1434
|
+
}
|
|
1435
|
+
this.deviceProtocol.delete(uuid);
|
|
1436
|
+
this.probingProtocols.delete(uuid);
|
|
1437
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1438
|
+
this.resetProtocolV2Frames(uuid);
|
|
1439
|
+
if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1440
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE writes wedged repeatedly, resetting BLE manager');
|
|
1441
|
+
this.resetPlxManager();
|
|
1442
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
resetPlxManager() {
|
|
1446
|
+
const manager = this.blePlxManager;
|
|
1447
|
+
this.blePlxManager = undefined;
|
|
1448
|
+
Object.keys(transportCache).forEach(key => {
|
|
1449
|
+
delete transportCache[key];
|
|
1450
|
+
});
|
|
1451
|
+
this.deviceProtocol.clear();
|
|
1452
|
+
this.probingProtocols.clear();
|
|
1453
|
+
this.monitorTokens.clear();
|
|
1454
|
+
this.protocolV2Assemblers.clear();
|
|
1455
|
+
try {
|
|
1456
|
+
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
1457
|
+
}
|
|
1458
|
+
catch (error) {
|
|
1459
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1300
1462
|
createProtocolMismatchError(expected) {
|
|
1301
1463
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1302
1464
|
}
|
|
1303
1465
|
createProtocolDetectionError() {
|
|
1304
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1466
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
1305
1467
|
}
|
|
1306
1468
|
clearProbeProtocol(uuid, protocol) {
|
|
1469
|
+
if (this.probingProtocols.get(uuid) === protocol) {
|
|
1470
|
+
this.probingProtocols.delete(uuid);
|
|
1471
|
+
}
|
|
1307
1472
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1308
1473
|
this.deviceProtocol.delete(uuid);
|
|
1309
1474
|
}
|
|
1310
1475
|
}
|
|
1311
|
-
|
|
1476
|
+
getActiveProtocol(uuid) {
|
|
1477
|
+
var _a;
|
|
1478
|
+
return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
|
|
1479
|
+
}
|
|
1480
|
+
detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
|
|
1312
1481
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1313
1482
|
if (expectedProtocol === 'V1') {
|
|
1314
1483
|
if (yield this.probeProtocolV1(uuid)) {
|
|
1315
1484
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1316
|
-
Log === null || Log === void 0 ? void 0 : Log.debug(
|
|
1485
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1486
|
+
deviceId: uuid,
|
|
1487
|
+
protocol: 'V1',
|
|
1488
|
+
source: 'expected',
|
|
1489
|
+
});
|
|
1317
1490
|
return 'V1';
|
|
1318
1491
|
}
|
|
1319
1492
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1320
1493
|
}
|
|
1321
1494
|
if (expectedProtocol === 'V2') {
|
|
1322
|
-
this.
|
|
1323
|
-
|
|
1324
|
-
|
|
1495
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1496
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1497
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1498
|
+
deviceId: uuid,
|
|
1499
|
+
protocol: 'V2',
|
|
1500
|
+
source: 'expected',
|
|
1501
|
+
});
|
|
1502
|
+
return 'V2';
|
|
1503
|
+
}
|
|
1504
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1325
1505
|
}
|
|
1326
1506
|
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1327
1507
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1328
1508
|
const protocol = probeOrder[i];
|
|
1329
1509
|
if (i > 0) {
|
|
1330
1510
|
yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
1511
|
+
if (!transportCache[uuid]) {
|
|
1512
|
+
if (!rebuildTransport) {
|
|
1513
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
1514
|
+
}
|
|
1515
|
+
yield rebuildTransport();
|
|
1516
|
+
}
|
|
1331
1517
|
}
|
|
1332
1518
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
|
|
1333
1519
|
if (detected) {
|
|
1334
1520
|
this.deviceProtocol.set(uuid, protocol);
|
|
1335
|
-
Log === null || Log === void 0 ? void 0 : Log.debug(
|
|
1521
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1522
|
+
deviceId: uuid,
|
|
1523
|
+
protocol,
|
|
1524
|
+
source: 'probe',
|
|
1525
|
+
});
|
|
1336
1526
|
return protocol;
|
|
1337
1527
|
}
|
|
1338
1528
|
}
|
|
1339
1529
|
this.deviceProtocol.delete(uuid);
|
|
1530
|
+
this.probingProtocols.delete(uuid);
|
|
1340
1531
|
throw this.createProtocolDetectionError();
|
|
1341
1532
|
});
|
|
1342
1533
|
}
|
|
1343
1534
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1344
|
-
var _a, _b, _c
|
|
1535
|
+
var _a, _b, _c;
|
|
1345
1536
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1346
1537
|
const transport = transportCache[uuid];
|
|
1538
|
+
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1347
1539
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1348
1540
|
this.resetProtocolV2Frames(uuid);
|
|
1349
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
1350
|
-
this.activeProtocolV2Call = null;
|
|
1351
|
-
}
|
|
1352
1541
|
if (this.runPromise) {
|
|
1353
1542
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1354
1543
|
this.runPromise.reject(error);
|
|
@@ -1360,11 +1549,11 @@ class ReactNativeBleTransport {
|
|
|
1360
1549
|
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
1361
1550
|
this.monitorTokens.delete(uuid);
|
|
1362
1551
|
}
|
|
1363
|
-
(
|
|
1552
|
+
(_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1364
1553
|
transport.notifySubscription = undefined;
|
|
1365
1554
|
if (previousNotifyTransactionId) {
|
|
1366
1555
|
try {
|
|
1367
|
-
yield ((
|
|
1556
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(previousNotifyTransactionId));
|
|
1368
1557
|
}
|
|
1369
1558
|
catch (error) {
|
|
1370
1559
|
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);
|
|
@@ -1390,13 +1579,17 @@ class ReactNativeBleTransport {
|
|
|
1390
1579
|
return false;
|
|
1391
1580
|
}
|
|
1392
1581
|
try {
|
|
1393
|
-
this.
|
|
1394
|
-
yield this.callProtocolV1(uuid, '
|
|
1582
|
+
this.probingProtocols.set(uuid, 'V1');
|
|
1583
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1584
|
+
this.probingProtocols.delete(uuid);
|
|
1395
1585
|
return true;
|
|
1396
1586
|
}
|
|
1397
1587
|
catch (error) {
|
|
1398
1588
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1399
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1589
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1590
|
+
if (isWedgedWriteError(error)) {
|
|
1591
|
+
throw error;
|
|
1592
|
+
}
|
|
1400
1593
|
return false;
|
|
1401
1594
|
}
|
|
1402
1595
|
});
|
|
@@ -1407,7 +1600,7 @@ class ReactNativeBleTransport {
|
|
|
1407
1600
|
if (!this._messages || !this._messagesV2) {
|
|
1408
1601
|
return false;
|
|
1409
1602
|
}
|
|
1410
|
-
this.
|
|
1603
|
+
this.probingProtocols.set(uuid, 'V2');
|
|
1411
1604
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1412
1605
|
const detected = yield transport.probeProtocolV2({
|
|
1413
1606
|
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
@@ -1423,17 +1616,16 @@ class ReactNativeBleTransport {
|
|
|
1423
1616
|
if (!detected) {
|
|
1424
1617
|
this.clearProbeProtocol(uuid, 'V2');
|
|
1425
1618
|
}
|
|
1619
|
+
else {
|
|
1620
|
+
this.probingProtocols.delete(uuid);
|
|
1621
|
+
}
|
|
1426
1622
|
return detected;
|
|
1427
1623
|
});
|
|
1428
1624
|
}
|
|
1429
|
-
handleProtocolV2Notification(uuid, data) {
|
|
1430
|
-
var _a, _b, _c;
|
|
1625
|
+
handleProtocolV2Notification(uuid, monitorToken, data) {
|
|
1431
1626
|
try {
|
|
1432
|
-
if (
|
|
1433
|
-
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1434
|
-
this.resetProtocolV2Frames(uuid);
|
|
1627
|
+
if (this.monitorTokens.get(uuid) !== monitorToken)
|
|
1435
1628
|
return;
|
|
1436
|
-
}
|
|
1437
1629
|
if (data.length === 0)
|
|
1438
1630
|
return;
|
|
1439
1631
|
const assembler = this.protocolV2Assemblers.get(uuid);
|
|
@@ -1446,8 +1638,10 @@ class ReactNativeBleTransport {
|
|
|
1446
1638
|
catch (error) {
|
|
1447
1639
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
|
|
1448
1640
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1449
|
-
|
|
1450
|
-
this.
|
|
1641
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1642
|
+
this.protocolV2Links
|
|
1643
|
+
.invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
|
|
1644
|
+
.catch(invalidateError => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notify cleanup failed:', invalidateError));
|
|
1451
1645
|
}
|
|
1452
1646
|
}
|
|
1453
1647
|
getProtocolV2FrameQueue(uuid) {
|
|
@@ -1467,20 +1661,16 @@ class ReactNativeBleTransport {
|
|
|
1467
1661
|
}
|
|
1468
1662
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1469
1663
|
}
|
|
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
1664
|
resetProtocolV2Frames(uuid) {
|
|
1478
|
-
this.
|
|
1479
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1665
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1480
1666
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1667
|
+
rejectProtocolV2Frames(uuid, error) {
|
|
1668
|
+
this.protocolV2FrameQueues.delete(uuid);
|
|
1669
|
+
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1670
|
+
if (framePromise) {
|
|
1671
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1672
|
+
framePromise.reject(error);
|
|
1673
|
+
}
|
|
1484
1674
|
}
|
|
1485
1675
|
readProtocolV2Frame(uuid) {
|
|
1486
1676
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1500,133 +1690,143 @@ class ReactNativeBleTransport {
|
|
|
1500
1690
|
}
|
|
1501
1691
|
});
|
|
1502
1692
|
}
|
|
1503
|
-
|
|
1693
|
+
writeProtocolV2Packet(uuid, transport, base64, context, assertCurrentGeneration) {
|
|
1694
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1695
|
+
let attempt = 0;
|
|
1696
|
+
for (;;) {
|
|
1697
|
+
assertCurrentGeneration();
|
|
1698
|
+
if (context.signal.aborted) {
|
|
1699
|
+
throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
|
|
1700
|
+
}
|
|
1701
|
+
try {
|
|
1702
|
+
yield this.writeBlePacket(uuid, base64, payload => transport.writeCharacteristic.writeWithoutResponse(payload), () => {
|
|
1703
|
+
try {
|
|
1704
|
+
assertCurrentGeneration();
|
|
1705
|
+
return !context.signal.aborted;
|
|
1706
|
+
}
|
|
1707
|
+
catch (_a) {
|
|
1708
|
+
return false;
|
|
1709
|
+
}
|
|
1710
|
+
});
|
|
1711
|
+
assertCurrentGeneration();
|
|
1712
|
+
return;
|
|
1713
|
+
}
|
|
1714
|
+
catch (error) {
|
|
1715
|
+
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
1716
|
+
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1717
|
+
throw error;
|
|
1718
|
+
}
|
|
1719
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1720
|
+
attempt += 1;
|
|
1721
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 congested write retry:', {
|
|
1722
|
+
name: context.messageName,
|
|
1723
|
+
attempt,
|
|
1724
|
+
delayMs,
|
|
1725
|
+
});
|
|
1726
|
+
yield delay(delayMs);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
});
|
|
1730
|
+
}
|
|
1731
|
+
writeProtocolV2Frame(uuid, transport$1, frame, context, assertCurrentGeneration) {
|
|
1504
1732
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1505
1733
|
const tuning = getProtocolV2BleTuning();
|
|
1506
1734
|
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1507
1735
|
platform: reactNative.Platform.OS,
|
|
1508
1736
|
iosPacketLength: tuning.iosPacketLength,
|
|
1509
1737
|
androidPacketLength: tuning.androidPacketLength,
|
|
1510
|
-
mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
|
|
1738
|
+
mtu: reactNative.Platform.OS === 'android' ? transport$1.mtuSize : undefined,
|
|
1739
|
+
});
|
|
1740
|
+
yield transport.writeProtocolV2BleFrame({
|
|
1741
|
+
frame,
|
|
1742
|
+
packetCapacity,
|
|
1743
|
+
assertActive: assertCurrentGeneration,
|
|
1744
|
+
signal: context.signal,
|
|
1745
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1746
|
+
burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
|
|
1747
|
+
burstPauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
|
|
1748
|
+
flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
|
|
1749
|
+
wait: delay,
|
|
1750
|
+
writePacket: packet => this.writeProtocolV2Packet(uuid, transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
|
|
1511
1751
|
});
|
|
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
|
-
for (let offset = 0; offset < frame.length; offset += packetCapacity) {
|
|
1517
|
-
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1518
|
-
const base64 = buffer.Buffer.from(chunk).toString('base64');
|
|
1519
|
-
if (writeMode === 'withResponse') {
|
|
1520
|
-
yield transport.writeCharacteristic.writeWithResponse(base64);
|
|
1521
|
-
}
|
|
1522
|
-
else {
|
|
1523
|
-
yield transport.writeCharacteristic.writeWithoutResponse(base64);
|
|
1524
|
-
}
|
|
1525
|
-
packetsWritten += 1;
|
|
1526
|
-
if (shouldThrottle &&
|
|
1527
|
-
packetsWritten % tuning.highVolumeWriteBurstSize === 0 &&
|
|
1528
|
-
offset + packetCapacity < frame.length) {
|
|
1529
|
-
yield delay(tuning.highVolumeWritePauseMs);
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
if (shouldThrottle) {
|
|
1533
|
-
yield delay(tuning.highVolumeWriteFlushDelayMs);
|
|
1534
|
-
}
|
|
1535
1752
|
});
|
|
1536
1753
|
}
|
|
1537
1754
|
callProtocolV2(uuid, name, data, options) {
|
|
1538
|
-
var _a, _b, _c, _d;
|
|
1539
1755
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1540
1756
|
if (!this._messages || !this._messagesV2) {
|
|
1541
1757
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1542
1758
|
}
|
|
1543
|
-
const
|
|
1544
|
-
if (this.runPromise) {
|
|
1545
|
-
if (!forceRun) {
|
|
1546
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1547
|
-
}
|
|
1548
|
-
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1549
|
-
this.runPromise.reject(error);
|
|
1550
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1551
|
-
this.runPromise = null;
|
|
1552
|
-
this.activeProtocolV2Call = null;
|
|
1553
|
-
}
|
|
1554
|
-
const transport$1 = this.getCachedTransport(uuid);
|
|
1555
|
-
const runPromise = hdShared.createDeferred();
|
|
1556
|
-
runPromise.promise.catch(() => undefined);
|
|
1557
|
-
this.runPromise = runPromise;
|
|
1558
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1559
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1560
|
-
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1561
|
-
this.resetProtocolV2Frames(uuid);
|
|
1562
|
-
let completed = false;
|
|
1563
|
-
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 });
|
|
1759
|
+
const callOptions = options;
|
|
1564
1760
|
const highVolumeWrite = transport.LogBlockCommand.has(name);
|
|
1565
1761
|
if (highVolumeWrite) {
|
|
1566
1762
|
const tuning = getProtocolV2BleTuning();
|
|
1567
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write
|
|
1763
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
|
|
1764
|
+
name,
|
|
1765
|
+
writeMode: 'withoutResponse',
|
|
1568
1766
|
packetCapacity: reactNative.Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
|
|
1569
|
-
burstSize: tuning.highVolumeWriteBurstSize,
|
|
1570
|
-
pauseMs: tuning.highVolumeWritePauseMs,
|
|
1571
|
-
flushDelayMs: tuning.highVolumeWriteFlushDelayMs,
|
|
1572
|
-
writeWithResponse: tuning.highVolumeWriteWithResponse,
|
|
1573
1767
|
});
|
|
1574
1768
|
}
|
|
1575
1769
|
try {
|
|
1576
|
-
|
|
1577
|
-
schemas: {
|
|
1578
|
-
protocolV1: this._messages,
|
|
1579
|
-
protocolV2: this._messagesV2,
|
|
1580
|
-
},
|
|
1581
|
-
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1582
|
-
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
1583
|
-
yield this.writeProtocolV2Frame(transport$1, frame, {
|
|
1584
|
-
highVolume: highVolumeWrite,
|
|
1585
|
-
});
|
|
1586
|
-
}),
|
|
1587
|
-
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
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
|
-
logger: Log,
|
|
1595
|
-
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1596
|
-
createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
|
|
1597
|
-
});
|
|
1598
|
-
const result = yield session.call(name, data, callOptions);
|
|
1599
|
-
completed = true;
|
|
1600
|
-
return result;
|
|
1770
|
+
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1601
1771
|
}
|
|
1602
1772
|
catch (e) {
|
|
1603
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1604
|
-
(_c = this.protocolV2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1605
|
-
this.resetProtocolV2Frames(uuid);
|
|
1606
|
-
}
|
|
1607
1773
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1608
1774
|
throw e;
|
|
1609
1775
|
}
|
|
1610
|
-
finally {
|
|
1611
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1612
|
-
if (!completed) {
|
|
1613
|
-
(_d = this.protocolV2Assemblers.get(uuid)) === null || _d === void 0 ? void 0 : _d.reset();
|
|
1614
|
-
}
|
|
1615
|
-
this.resetProtocolV2Frames(uuid);
|
|
1616
|
-
this.activeProtocolV2Call = null;
|
|
1617
|
-
}
|
|
1618
|
-
if (this.runPromise === runPromise) {
|
|
1619
|
-
this.runPromise = null;
|
|
1620
|
-
}
|
|
1621
|
-
}
|
|
1622
1776
|
});
|
|
1623
1777
|
}
|
|
1778
|
+
createProtocolV2Adapter(uuid) {
|
|
1779
|
+
var _a;
|
|
1780
|
+
const generation = (_a = this.monitorTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1781
|
+
const assertCurrentGeneration = () => {
|
|
1782
|
+
if (this.monitorTokens.get(uuid) !== generation) {
|
|
1783
|
+
throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
return {
|
|
1787
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1788
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
1789
|
+
generation,
|
|
1790
|
+
prepareCall: () => {
|
|
1791
|
+
var _a;
|
|
1792
|
+
assertCurrentGeneration();
|
|
1793
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1794
|
+
this.resetProtocolV2Frames(uuid);
|
|
1795
|
+
},
|
|
1796
|
+
writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
|
|
1797
|
+
assertCurrentGeneration();
|
|
1798
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
1799
|
+
yield this.writeProtocolV2Frame(uuid, currentTransport, frame, context, assertCurrentGeneration);
|
|
1800
|
+
}),
|
|
1801
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1802
|
+
assertCurrentGeneration();
|
|
1803
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1804
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
1805
|
+
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1806
|
+
}
|
|
1807
|
+
return rxFrame;
|
|
1808
|
+
}),
|
|
1809
|
+
reset: (reason) => {
|
|
1810
|
+
var _a;
|
|
1811
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1812
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1813
|
+
},
|
|
1814
|
+
logger: Log,
|
|
1815
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1816
|
+
createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
|
|
1817
|
+
};
|
|
1818
|
+
}
|
|
1624
1819
|
getProtocolType(path) {
|
|
1625
|
-
return this.
|
|
1820
|
+
return this.getActiveProtocol(path);
|
|
1626
1821
|
}
|
|
1627
1822
|
}
|
|
1628
1823
|
|
|
1824
|
+
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
1825
|
+
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
1826
|
+
exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
|
|
1827
|
+
exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
1629
1828
|
exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
|
|
1630
1829
|
exports["default"] = ReactNativeBleTransport;
|
|
1830
|
+
exports.getFirmwareUploadWriteRetryType = getFirmwareUploadWriteRetryType;
|
|
1631
1831
|
exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
|
|
1632
1832
|
exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;
|