@onekeyfe/hd-transport-react-native 1.2.0-alpha.13 → 1.2.0-alpha.130
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 +2 -4
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts +7 -0
- package/dist/bleStrategy.d.ts.map +1 -1
- package/dist/constants.d.ts +2 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts +120 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +772 -254
- package/dist/transportLog.d.ts +1 -12
- package/dist/transportLog.d.ts.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/jest.config.js +10 -0
- package/package.json +6 -5
- package/src/BleTransport.ts +10 -42
- package/src/__tests__/BleTransport.test.ts +114 -0
- package/src/__tests__/bleStrategy.test.ts +93 -5
- package/src/__tests__/connectTimeout.test.ts +292 -0
- package/src/__tests__/constants.test.ts +20 -0
- package/src/__tests__/enumerate.test.ts +150 -0
- package/src/__tests__/protocolReprobe.test.ts +156 -0
- package/src/__tests__/protocolV1SchemaFixture.ts +39 -0
- package/src/__tests__/protocolV2Link.test.ts +775 -32
- package/src/__tests__/staleCallTimeout.test.ts +210 -0
- package/src/__tests__/writePacketTimeout.test.ts +305 -0
- package/src/bleStrategy.ts +26 -11
- package/src/constants.ts +9 -14
- package/src/index.ts +1015 -228
- package/src/transportLog.ts +1 -18
- package/src/types.ts +1 -0
package/dist/index.js
CHANGED
|
@@ -93,7 +93,8 @@ const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
|
|
|
93
93
|
|
|
94
94
|
const IOS_PACKET_LENGTH = 128;
|
|
95
95
|
const ANDROID_PACKET_LENGTH = 192;
|
|
96
|
-
const
|
|
96
|
+
const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
97
|
+
const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
97
98
|
const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
|
|
98
99
|
const OneKeyServices = {
|
|
99
100
|
classic: {
|
|
@@ -117,36 +118,38 @@ const getInfosForServiceUuid = (serviceUuid, deviceType) => {
|
|
|
117
118
|
return null;
|
|
118
119
|
}
|
|
119
120
|
const normalizedServiceUuid = normalizeBleUuid(serviceUuid);
|
|
120
|
-
const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid
|
|
121
|
+
const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid ||
|
|
122
|
+
hdShared.matchesKnownBleUuid(serviceUuid, hdShared.createKnownBleUuidAliases(item.serviceUuid)));
|
|
121
123
|
if (!service) {
|
|
122
124
|
return null;
|
|
123
125
|
}
|
|
124
126
|
return service;
|
|
125
127
|
};
|
|
126
128
|
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
129
|
const isSameBleUuid = (left, right) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return (
|
|
135
|
-
(getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
|
|
130
|
+
if (!left || !right)
|
|
131
|
+
return false;
|
|
132
|
+
return hdShared.matchesKnownBleUuid(left, hdShared.createKnownBleUuidAliases(right));
|
|
136
133
|
};
|
|
137
134
|
|
|
138
135
|
function hasWritableCapability(characteristic) {
|
|
139
136
|
return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
|
|
140
137
|
}
|
|
141
|
-
function resolveProtocolV2PacketCapacity({ platform, iosPacketLength =
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
138
|
+
function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PROTOCOL_V2_PACKET_LENGTH, androidPacketLength = ANDROID_PROTOCOL_V2_PACKET_LENGTH, mtu, }) {
|
|
139
|
+
const negotiatedMtu = typeof mtu === 'number' && Number.isFinite(mtu) && mtu > 3 ? Math.floor(mtu) : 23;
|
|
140
|
+
const payloadLength = negotiatedMtu - 3;
|
|
141
|
+
const configuredPacketLength = platform === 'ios' ? iosPacketLength : androidPacketLength;
|
|
142
|
+
return Math.min(configuredPacketLength, payloadLength);
|
|
143
|
+
}
|
|
144
|
+
function shouldRefreshNegotiatedMtu(mtu) {
|
|
145
|
+
return typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= 23;
|
|
146
|
+
}
|
|
147
|
+
function shouldWriteProtocolV2WithResponse({ platform, highThroughput, requestedWithResponse, characteristic, }) {
|
|
148
|
+
if (!characteristic.isWritableWithResponse)
|
|
149
|
+
return false;
|
|
150
|
+
if (!characteristic.isWritableWithoutResponse)
|
|
151
|
+
return true;
|
|
152
|
+
return requestedWithResponse === true || (platform === 'ios' && !highThroughput);
|
|
150
153
|
}
|
|
151
154
|
|
|
152
155
|
const timer = process.env.NODE_ENV === 'development'
|
|
@@ -203,59 +206,20 @@ const isHeaderChunk = (chunk) => {
|
|
|
203
206
|
return false;
|
|
204
207
|
};
|
|
205
208
|
|
|
206
|
-
const Log$1 = bleLogger;
|
|
207
209
|
class BleTransport {
|
|
208
210
|
constructor(device, writeCharacteristic, notifyCharacteristic) {
|
|
209
211
|
this.name = 'ReactNativeBleTransport';
|
|
210
|
-
this.mtuSize = 23;
|
|
211
212
|
this.id = device.id;
|
|
212
213
|
this.device = device;
|
|
213
214
|
this.writeCharacteristic = writeCharacteristic;
|
|
214
215
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
215
216
|
}
|
|
216
|
-
writeWithRetry(data
|
|
217
|
+
writeWithRetry(data) {
|
|
217
218
|
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
-
|
|
219
|
-
yield this.writeCharacteristic.writeWithoutResponse(data);
|
|
220
|
-
}
|
|
221
|
-
catch (error) {
|
|
222
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`);
|
|
223
|
-
if (retryCount > 0) {
|
|
224
|
-
yield hdShared.wait(BleTransport.RETRY_DELAY);
|
|
225
|
-
if (error.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
226
|
-
error.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
227
|
-
try {
|
|
228
|
-
yield this.device.connect();
|
|
229
|
-
yield this.device.discoverAllServicesAndCharacteristics();
|
|
230
|
-
}
|
|
231
|
-
catch (e) {
|
|
232
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Connect or discoverAllServicesAndCharacteristics error: ${e}`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
else {
|
|
236
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`writeCharacteristic error: ${error}`);
|
|
237
|
-
}
|
|
238
|
-
return this.writeWithRetry(data, retryCount - 1);
|
|
239
|
-
}
|
|
240
|
-
throw error;
|
|
241
|
-
}
|
|
219
|
+
yield this.writeCharacteristic.writeWithoutResponse(data);
|
|
242
220
|
});
|
|
243
221
|
}
|
|
244
222
|
}
|
|
245
|
-
BleTransport.MAX_RETRIES = 5;
|
|
246
|
-
BleTransport.RETRY_DELAY = 2000;
|
|
247
|
-
|
|
248
|
-
function createTransportCallLog(name, protocol, data) {
|
|
249
|
-
if (name === 'ResourceUpdate' || name === 'ResourceAck') {
|
|
250
|
-
return {
|
|
251
|
-
name,
|
|
252
|
-
protocol,
|
|
253
|
-
file_name: data.file_name,
|
|
254
|
-
hash: data.hash,
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
return { name, protocol };
|
|
258
|
-
}
|
|
259
223
|
|
|
260
224
|
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
261
225
|
const Log = bleLogger;
|
|
@@ -264,10 +228,35 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 :
|
|
|
264
228
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
265
229
|
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
|
|
266
230
|
const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
|
|
267
|
-
const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
|
|
268
231
|
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
269
232
|
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
270
233
|
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
234
|
+
const isAsciiWhitespace = (code) => code === 0x09 ||
|
|
235
|
+
code === 0x0a ||
|
|
236
|
+
code === 0x0b ||
|
|
237
|
+
code === 0x0c ||
|
|
238
|
+
code === 0x0d ||
|
|
239
|
+
code === 0x20;
|
|
240
|
+
const hasGattCongestedStatus = (text) => {
|
|
241
|
+
let searchFrom = 0;
|
|
242
|
+
while (searchFrom < text.length) {
|
|
243
|
+
const statusIndex = text.indexOf('status', searchFrom);
|
|
244
|
+
if (statusIndex < 0)
|
|
245
|
+
return false;
|
|
246
|
+
let cursor = statusIndex + 'status'.length;
|
|
247
|
+
while (cursor < text.length && isAsciiWhitespace(text.charCodeAt(cursor)))
|
|
248
|
+
cursor += 1;
|
|
249
|
+
if (text[cursor] === ':' || text[cursor] === '=') {
|
|
250
|
+
cursor += 1;
|
|
251
|
+
while (cursor < text.length && isAsciiWhitespace(text.charCodeAt(cursor)))
|
|
252
|
+
cursor += 1;
|
|
253
|
+
}
|
|
254
|
+
if (text.startsWith(String(ANDROID_GATT_CONGESTED_STATUS), cursor))
|
|
255
|
+
return true;
|
|
256
|
+
searchFrom = statusIndex + 'status'.length;
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
};
|
|
271
260
|
const delay = (ms) => new Promise(resolve => {
|
|
272
261
|
setTimeout(resolve, ms);
|
|
273
262
|
});
|
|
@@ -275,10 +264,6 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
275
264
|
if (!error || typeof error !== 'object')
|
|
276
265
|
return null;
|
|
277
266
|
const bleWriteError = error;
|
|
278
|
-
if (bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
279
|
-
bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
280
|
-
return 'reconnectable';
|
|
281
|
-
}
|
|
282
267
|
if (bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
|
|
283
268
|
bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS) {
|
|
284
269
|
return 'congested';
|
|
@@ -286,18 +271,23 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
286
271
|
const text = [bleWriteError.reason, bleWriteError.message, bleWriteError.name]
|
|
287
272
|
.filter(value => typeof value === 'string')
|
|
288
273
|
.join(' ');
|
|
289
|
-
return
|
|
274
|
+
return text.includes('GATT_CONGESTED') || hasGattCongestedStatus(text) ? 'congested' : null;
|
|
290
275
|
};
|
|
291
276
|
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
292
|
-
const
|
|
293
|
-
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
277
|
+
const PROTOCOL_PROBE_TIMEOUT_MS = 3000;
|
|
294
278
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
295
|
-
const
|
|
279
|
+
const BLE_WRITE_PACKET_TIMEOUT_MS = 10000;
|
|
280
|
+
const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
281
|
+
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
282
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
283
|
+
error.message.startsWith(WEDGED_WRITE_MESSAGE);
|
|
284
|
+
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
285
|
+
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
296
286
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
297
287
|
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
298
288
|
const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
|
|
299
|
-
iosPacketLength:
|
|
300
|
-
androidPacketLength:
|
|
289
|
+
iosPacketLength: IOS_PROTOCOL_V2_PACKET_LENGTH,
|
|
290
|
+
androidPacketLength: ANDROID_PROTOCOL_V2_PACKET_LENGTH,
|
|
301
291
|
};
|
|
302
292
|
let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
303
293
|
const normalizePositiveInteger = (value, fallback) => {
|
|
@@ -326,19 +316,29 @@ function inferProtocolHintFromDeviceName(name) {
|
|
|
326
316
|
function getDeviceDisplayName(device) {
|
|
327
317
|
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
328
318
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
const ANDROID_REQUEST_MTU = 256;
|
|
319
|
+
const IOS_REQUEST_MTU = 247;
|
|
320
|
+
const ANDROID_REQUEST_MTU = 517;
|
|
321
|
+
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
322
|
+
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
323
|
+
const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
324
|
+
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
337
325
|
const connectOptions = {
|
|
338
|
-
requestMTU:
|
|
339
|
-
timeout:
|
|
326
|
+
requestMTU: getRequestedBleMtu(),
|
|
327
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
340
328
|
refreshGatt: 'OnConnected',
|
|
341
329
|
};
|
|
330
|
+
const fallbackConnectOptions = {
|
|
331
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
332
|
+
};
|
|
333
|
+
const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
334
|
+
const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
335
|
+
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
336
|
+
const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
337
|
+
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
338
|
+
const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
|
|
339
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
340
|
+
error.message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
341
|
+
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
342
342
|
const tryToGetConfiguration = (device) => {
|
|
343
343
|
if (!device || !device.serviceUUIDs)
|
|
344
344
|
return null;
|
|
@@ -350,23 +350,25 @@ const tryToGetConfiguration = (device) => {
|
|
|
350
350
|
return null;
|
|
351
351
|
return infos;
|
|
352
352
|
};
|
|
353
|
-
const
|
|
354
|
-
if (reactNative.Platform.OS !== 'android')
|
|
353
|
+
const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
|
|
354
|
+
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
355
355
|
return device;
|
|
356
356
|
try {
|
|
357
|
-
const mtuDevice = yield device.requestMTU(
|
|
358
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU configured', {
|
|
359
|
-
deviceId: device.id,
|
|
360
|
-
requested: ANDROID_REQUEST_MTU,
|
|
361
|
-
actual: mtuDevice.mtu,
|
|
362
|
-
});
|
|
357
|
+
const mtuDevice = yield device.requestMTU(getRequestedBleMtu());
|
|
363
358
|
return mtuDevice;
|
|
364
359
|
}
|
|
365
360
|
catch (error) {
|
|
366
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
361
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
|
|
362
|
+
platform: reactNative.Platform.OS,
|
|
363
|
+
stage,
|
|
364
|
+
attempt,
|
|
365
|
+
actual: device.mtu,
|
|
366
|
+
error: error instanceof Error ? error.message : String(error),
|
|
367
|
+
});
|
|
367
368
|
return device;
|
|
368
369
|
}
|
|
369
370
|
});
|
|
371
|
+
const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
|
|
370
372
|
function remapError(error) {
|
|
371
373
|
var _a;
|
|
372
374
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -393,9 +395,15 @@ class ReactNativeBleTransport {
|
|
|
393
395
|
this.stopped = false;
|
|
394
396
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
395
397
|
this.runPromise = null;
|
|
398
|
+
this.runPromiseDeviceId = null;
|
|
396
399
|
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
397
400
|
this.deviceProtocol = new Map();
|
|
401
|
+
this.probingProtocols = new Map();
|
|
402
|
+
this.writeTimeoutCounts = new Map();
|
|
403
|
+
this.connectionSetupTimeoutCounts = new Map();
|
|
398
404
|
this.deviceProtocolHints = new Map();
|
|
405
|
+
this.sessionProtocols = new Map();
|
|
406
|
+
this.protocolReprobeFailures = new Map();
|
|
399
407
|
this.protocolV2Assemblers = new Map();
|
|
400
408
|
this.protocolV2FrameQueues = new Map();
|
|
401
409
|
this.protocolV2FramePromises = new Map();
|
|
@@ -416,12 +424,17 @@ class ReactNativeBleTransport {
|
|
|
416
424
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
417
425
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
418
426
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
419
|
-
yield this.
|
|
427
|
+
yield this.releaseNative(uuid, true);
|
|
420
428
|
}
|
|
421
429
|
}),
|
|
422
430
|
});
|
|
423
431
|
this.monitorTokens = new Map();
|
|
432
|
+
this.disconnectEventTokens = new Map();
|
|
433
|
+
this.protocolV2HighVolumeLogSignatures = new Map();
|
|
434
|
+
this.androidHighPriorityDevices = new Set();
|
|
435
|
+
this.androidPriorityResetTimers = new Map();
|
|
424
436
|
this.nextMonitorToken = 1;
|
|
437
|
+
this.lifecycleOperations = new Map();
|
|
425
438
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
426
439
|
}
|
|
427
440
|
init(logger, emitter) {
|
|
@@ -434,10 +447,18 @@ class ReactNativeBleTransport {
|
|
|
434
447
|
this._messages = messages;
|
|
435
448
|
}
|
|
436
449
|
configureProtocolV2(signedData) {
|
|
450
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
451
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
437
455
|
this._messagesV2 = parseConfigure(signedData);
|
|
438
|
-
this.
|
|
439
|
-
|
|
440
|
-
.
|
|
456
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
457
|
+
if (isReconfiguration) {
|
|
458
|
+
this.protocolV2Links
|
|
459
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
460
|
+
.catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
|
|
461
|
+
}
|
|
441
462
|
}
|
|
442
463
|
listen() {
|
|
443
464
|
}
|
|
@@ -448,7 +469,6 @@ class ReactNativeBleTransport {
|
|
|
448
469
|
return Promise.resolve(this.blePlxManager);
|
|
449
470
|
}
|
|
450
471
|
resolveCharacteristics(device) {
|
|
451
|
-
var _a, _b, _c, _d;
|
|
452
472
|
return __awaiter(this, void 0, void 0, function* () {
|
|
453
473
|
yield device.discoverAllServicesAndCharacteristics();
|
|
454
474
|
let infos = tryToGetConfiguration(device);
|
|
@@ -465,19 +485,11 @@ class ReactNativeBleTransport {
|
|
|
465
485
|
}
|
|
466
486
|
}
|
|
467
487
|
}
|
|
468
|
-
let fallbackServiceUuid;
|
|
469
488
|
if (!infos) {
|
|
470
489
|
const services = yield device.services();
|
|
471
490
|
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));
|
|
472
|
-
const knownService = services.find(service => getInfosForServiceUuid(service.uuid, 'classic'));
|
|
473
|
-
const fallbackService = (_a = knownService !== null && knownService !== void 0 ? knownService : services.find(service => !isGenericBleService(service.uuid))) !== null && _a !== void 0 ? _a : services[0];
|
|
474
|
-
if (fallbackService) {
|
|
475
|
-
fallbackServiceUuid = fallbackService.uuid;
|
|
476
|
-
characteristics = yield device.characteristicsForService(fallbackService.uuid);
|
|
477
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
478
|
-
}
|
|
479
491
|
}
|
|
480
|
-
if (!infos
|
|
492
|
+
if (!infos) {
|
|
481
493
|
try {
|
|
482
494
|
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
483
495
|
yield device.cancelConnection();
|
|
@@ -487,9 +499,7 @@ class ReactNativeBleTransport {
|
|
|
487
499
|
}
|
|
488
500
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
489
501
|
}
|
|
490
|
-
const serviceUuid
|
|
491
|
-
const writeUuid = (_c = infos === null || infos === void 0 ? void 0 : infos.writeUuid) !== null && _c !== void 0 ? _c : '00000002-0000-1000-8000-00805f9b34fb';
|
|
492
|
-
const notifyUuid = (_d = infos === null || infos === void 0 ? void 0 : infos.notifyUuid) !== null && _d !== void 0 ? _d : '00000003-0000-1000-8000-00805f9b34fb';
|
|
502
|
+
const { serviceUuid, writeUuid, notifyUuid } = infos;
|
|
493
503
|
if (!serviceUuid) {
|
|
494
504
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
495
505
|
}
|
|
@@ -530,8 +540,8 @@ class ReactNativeBleTransport {
|
|
|
530
540
|
attachDisconnectSubscription(transport, device, uuid) {
|
|
531
541
|
var _a;
|
|
532
542
|
(_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
543
|
+
const { monitorToken } = transport;
|
|
533
544
|
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
534
|
-
var _a;
|
|
535
545
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
536
546
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
537
547
|
return;
|
|
@@ -540,17 +550,16 @@ class ReactNativeBleTransport {
|
|
|
540
550
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale transport: ', device === null || device === void 0 ? void 0 : device.id);
|
|
541
551
|
return;
|
|
542
552
|
}
|
|
553
|
+
if (this.monitorTokens.get(uuid) !== monitorToken) {
|
|
554
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale generation: ', device === null || device === void 0 ? void 0 : device.id);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
543
557
|
try {
|
|
544
558
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
545
|
-
(
|
|
546
|
-
|
|
547
|
-
id: device === null || device === void 0 ? void 0 : device.id,
|
|
548
|
-
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
549
|
-
});
|
|
550
|
-
if (this.runPromise) {
|
|
559
|
+
this.emitDeviceDisconnect(uuid, device === null || device === void 0 ? void 0 : device.name, monitorToken);
|
|
560
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
551
561
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
552
562
|
this.runPromise.reject(error);
|
|
553
|
-
this.rejectAllProtocolV2Frames(error);
|
|
554
563
|
}
|
|
555
564
|
}
|
|
556
565
|
catch (e) {
|
|
@@ -561,6 +570,22 @@ class ReactNativeBleTransport {
|
|
|
561
570
|
}
|
|
562
571
|
});
|
|
563
572
|
}
|
|
573
|
+
emitDeviceDisconnect(uuid, name, token) {
|
|
574
|
+
var _a;
|
|
575
|
+
if (token === undefined || this.disconnectEventTokens.get(uuid) === token) {
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
if (this.monitorTokens.get(uuid) !== token) {
|
|
579
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect event ignored for stale generation: ', uuid);
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
this.disconnectEventTokens.set(uuid, token);
|
|
583
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
584
|
+
name,
|
|
585
|
+
id: uuid,
|
|
586
|
+
connectId: uuid,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
564
589
|
reconnectFirmwareUploadTransport(uuid, transport) {
|
|
565
590
|
var _a, _b;
|
|
566
591
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -574,19 +599,19 @@ class ReactNativeBleTransport {
|
|
|
574
599
|
const isConnected = yield device.isConnected().catch(() => false);
|
|
575
600
|
if (!isConnected) {
|
|
576
601
|
try {
|
|
577
|
-
device = yield device.connect(connectOptions);
|
|
602
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect(connectOptions));
|
|
578
603
|
}
|
|
579
604
|
catch (e) {
|
|
580
605
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
581
606
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
582
|
-
device = yield device.connect();
|
|
607
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect());
|
|
583
608
|
}
|
|
584
609
|
else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
585
610
|
throw e;
|
|
586
611
|
}
|
|
587
612
|
}
|
|
588
613
|
}
|
|
589
|
-
const { writeCharacteristic, notifyCharacteristic } = yield this.
|
|
614
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, device);
|
|
590
615
|
transport.device = device;
|
|
591
616
|
transport.writeCharacteristic = writeCharacteristic;
|
|
592
617
|
transport.notifyCharacteristic = notifyCharacteristic;
|
|
@@ -634,7 +659,7 @@ class ReactNativeBleTransport {
|
|
|
634
659
|
allowDuplicates: true,
|
|
635
660
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
636
661
|
}, (error, device) => {
|
|
637
|
-
var _a, _b
|
|
662
|
+
var _a, _b;
|
|
638
663
|
if (error) {
|
|
639
664
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
640
665
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
@@ -655,9 +680,14 @@ class ReactNativeBleTransport {
|
|
|
655
680
|
return;
|
|
656
681
|
}
|
|
657
682
|
const displayName = getDeviceDisplayName(device);
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
683
|
+
const isUnnamedIOSPeripheral = reactNative.Platform.OS === 'ios' && !(displayName === null || displayName === void 0 ? void 0 : displayName.trim());
|
|
684
|
+
const isOneKey = !isUnnamedIOSPeripheral &&
|
|
685
|
+
hdShared.isOnekeyBluetoothDevice({
|
|
686
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
687
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
688
|
+
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
689
|
+
serviceUuids: (_b = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _b !== void 0 ? _b : getBluetoothServiceUuids(),
|
|
690
|
+
});
|
|
661
691
|
if (isOneKey) {
|
|
662
692
|
addDevice(device);
|
|
663
693
|
}
|
|
@@ -672,10 +702,15 @@ class ReactNativeBleTransport {
|
|
|
672
702
|
});
|
|
673
703
|
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
674
704
|
for (const device of devices) {
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
if (
|
|
705
|
+
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
706
|
+
? device.localName
|
|
707
|
+
: null;
|
|
708
|
+
if (hdShared.isOnekeyBluetoothDevice({
|
|
709
|
+
id: device.id,
|
|
710
|
+
name: device.name,
|
|
711
|
+
localName,
|
|
712
|
+
serviceUuids: device.serviceUUIDs,
|
|
713
|
+
})) {
|
|
679
714
|
Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
|
|
680
715
|
addDevice(device);
|
|
681
716
|
}
|
|
@@ -705,13 +740,70 @@ class ReactNativeBleTransport {
|
|
|
705
740
|
}));
|
|
706
741
|
});
|
|
707
742
|
}
|
|
743
|
+
installTransportForAcquire(uuid, device, characteristics) {
|
|
744
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
745
|
+
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
|
|
746
|
+
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
747
|
+
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
|
|
748
|
+
const monitorToken = this.nextMonitorToken;
|
|
749
|
+
this.nextMonitorToken += 1;
|
|
750
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
751
|
+
transport$1.monitorToken = monitorToken;
|
|
752
|
+
transport$1.notifyTransactionId = notifyTransactionId;
|
|
753
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
754
|
+
transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
755
|
+
transportCache[uuid] = transport$1;
|
|
756
|
+
this.protocolV2HighVolumeLogSignatures.set(uuid, new Set());
|
|
757
|
+
this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
758
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
759
|
+
yield new Promise(resolve => {
|
|
760
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
else if (reactNative.Platform.OS === 'android') {
|
|
764
|
+
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
765
|
+
}
|
|
766
|
+
const initialMtu = transport$1.mtuSize;
|
|
767
|
+
let refreshAttempts = 0;
|
|
768
|
+
if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
|
|
769
|
+
shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
770
|
+
refreshAttempts += 1;
|
|
771
|
+
let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
|
|
772
|
+
transport$1.device = refreshedDevice;
|
|
773
|
+
transport$1.mtuSize =
|
|
774
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
775
|
+
if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
776
|
+
yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
777
|
+
refreshAttempts += 1;
|
|
778
|
+
refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
|
|
779
|
+
transport$1.device = refreshedDevice;
|
|
780
|
+
transport$1.mtuSize =
|
|
781
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
785
|
+
platform: reactNative.Platform.OS,
|
|
786
|
+
requested: getRequestedBleMtu(),
|
|
787
|
+
initial: initialMtu,
|
|
788
|
+
actual: transport$1.mtuSize,
|
|
789
|
+
refreshAttempts,
|
|
790
|
+
});
|
|
791
|
+
return transport$1;
|
|
792
|
+
});
|
|
793
|
+
}
|
|
708
794
|
acquire(input) {
|
|
709
|
-
var _a, _b;
|
|
710
795
|
return __awaiter(this, void 0, void 0, function* () {
|
|
711
|
-
const { uuid
|
|
796
|
+
const { uuid } = input;
|
|
712
797
|
if (!uuid) {
|
|
713
798
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
714
799
|
}
|
|
800
|
+
return this.runLifecycleOperation(uuid, () => this.acquireUnlocked(input));
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
acquireUnlocked(input) {
|
|
804
|
+
var _a, _b;
|
|
805
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
806
|
+
const { uuid, forceCleanRunPromise, expectedProtocol } = input;
|
|
715
807
|
const cachedTransport = transportCache[uuid];
|
|
716
808
|
if (cachedTransport) {
|
|
717
809
|
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
@@ -723,14 +815,14 @@ class ReactNativeBleTransport {
|
|
|
723
815
|
return { uuid, protocolType: cachedProtocol };
|
|
724
816
|
}
|
|
725
817
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
726
|
-
yield this.
|
|
818
|
+
yield this.releaseUnlocked(uuid, true);
|
|
727
819
|
}
|
|
728
820
|
let device = null;
|
|
729
821
|
if (forceCleanRunPromise && this.runPromise) {
|
|
730
822
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
731
823
|
this.runPromise.reject(error);
|
|
732
|
-
this.rejectAllProtocolV2Frames(error);
|
|
733
824
|
this.runPromise = null;
|
|
825
|
+
this.runPromiseDeviceId = null;
|
|
734
826
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
735
827
|
}
|
|
736
828
|
const blePlxManager = yield this.getPlxManager();
|
|
@@ -763,14 +855,17 @@ class ReactNativeBleTransport {
|
|
|
763
855
|
if (!device) {
|
|
764
856
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
|
|
765
857
|
try {
|
|
766
|
-
device = yield blePlxManager.connectToDevice(uuid, connectOptions);
|
|
858
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, connectOptions));
|
|
767
859
|
}
|
|
768
860
|
catch (e) {
|
|
769
861
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
862
|
+
if (isConnectTimeoutError(e)) {
|
|
863
|
+
throw e;
|
|
864
|
+
}
|
|
770
865
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
771
866
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
772
867
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
773
|
-
device = yield blePlxManager.connectToDevice(uuid);
|
|
868
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
774
869
|
}
|
|
775
870
|
else if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
776
871
|
Log === null || Log === void 0 ? void 0 : Log.debug('device already connected');
|
|
@@ -786,23 +881,27 @@ class ReactNativeBleTransport {
|
|
|
786
881
|
}
|
|
787
882
|
if (!(yield device.isConnected())) {
|
|
788
883
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
884
|
+
const disconnectedDevice = device;
|
|
789
885
|
try {
|
|
790
|
-
device = yield
|
|
886
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(connectOptions));
|
|
791
887
|
}
|
|
792
888
|
catch (e) {
|
|
793
889
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
890
|
+
if (isConnectTimeoutError(e)) {
|
|
891
|
+
throw e;
|
|
892
|
+
}
|
|
794
893
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
795
894
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
796
895
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
797
896
|
try {
|
|
798
|
-
device = yield
|
|
897
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
799
898
|
}
|
|
800
899
|
catch (e) {
|
|
801
900
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
|
|
802
901
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
803
902
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
804
|
-
yield
|
|
805
|
-
device = yield
|
|
903
|
+
yield disconnectedDevice.cancelConnection();
|
|
904
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
806
905
|
}
|
|
807
906
|
}
|
|
808
907
|
}
|
|
@@ -811,44 +910,35 @@ class ReactNativeBleTransport {
|
|
|
811
910
|
}
|
|
812
911
|
}
|
|
813
912
|
}
|
|
814
|
-
device = yield
|
|
815
|
-
const
|
|
913
|
+
device = yield resolveNegotiatedMtu(device);
|
|
914
|
+
const acquiredDevice = device;
|
|
915
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
|
|
816
916
|
const protocolHint = expectedProtocol
|
|
817
917
|
? undefined
|
|
818
|
-
: (_a = this.deviceProtocolHints.get(uuid)) !== null &&
|
|
819
|
-
yield this.
|
|
918
|
+
: (_b = (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
|
|
919
|
+
yield this.releaseUnlocked(uuid, true);
|
|
820
920
|
if (protocolHint) {
|
|
821
921
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
822
922
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
yield new Promise(resolve => {
|
|
838
|
-
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
839
|
-
});
|
|
923
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice, {
|
|
924
|
+
writeCharacteristic,
|
|
925
|
+
notifyCharacteristic,
|
|
926
|
+
});
|
|
927
|
+
try {
|
|
928
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
929
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
930
|
+
}));
|
|
931
|
+
const currentTransport = transportCache[uuid];
|
|
932
|
+
if (!currentTransport) {
|
|
933
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
934
|
+
}
|
|
935
|
+
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
936
|
+
return { uuid, protocolType };
|
|
840
937
|
}
|
|
841
|
-
|
|
842
|
-
yield
|
|
938
|
+
catch (error) {
|
|
939
|
+
yield this.releaseUnlocked(uuid, true);
|
|
940
|
+
throw error;
|
|
843
941
|
}
|
|
844
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
845
|
-
(_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
|
|
846
|
-
name: device.name,
|
|
847
|
-
id: device.id,
|
|
848
|
-
connectId: device.id,
|
|
849
|
-
});
|
|
850
|
-
this.attachDisconnectSubscription(transport$1, device, uuid);
|
|
851
|
-
return { uuid, protocolType };
|
|
852
942
|
});
|
|
853
943
|
}
|
|
854
944
|
_monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
|
|
@@ -867,7 +957,7 @@ class ReactNativeBleTransport {
|
|
|
867
957
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
868
958
|
return;
|
|
869
959
|
}
|
|
870
|
-
if (this.
|
|
960
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
871
961
|
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
872
962
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
873
963
|
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
@@ -885,7 +975,7 @@ class ReactNativeBleTransport {
|
|
|
885
975
|
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
886
976
|
return;
|
|
887
977
|
}
|
|
888
|
-
if (this.runPromise) {
|
|
978
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
889
979
|
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
890
980
|
if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
|
|
891
981
|
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
@@ -900,13 +990,11 @@ class ReactNativeBleTransport {
|
|
|
900
990
|
((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
|
|
901
991
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
902
992
|
this.runPromise.reject(notifyError);
|
|
903
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
904
993
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
905
994
|
return;
|
|
906
995
|
}
|
|
907
996
|
const notifyError = hdShared.ERRORS.TypedError(ERROR);
|
|
908
997
|
this.runPromise.reject(notifyError);
|
|
909
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
910
998
|
Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
911
999
|
}
|
|
912
1000
|
return;
|
|
@@ -920,7 +1008,7 @@ class ReactNativeBleTransport {
|
|
|
920
1008
|
}
|
|
921
1009
|
try {
|
|
922
1010
|
const data = buffer.Buffer.from(c.value, 'base64');
|
|
923
|
-
const protocol = this.
|
|
1011
|
+
const protocol = this.getActiveProtocol(uuid);
|
|
924
1012
|
if (!protocol) {
|
|
925
1013
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
|
|
926
1014
|
return;
|
|
@@ -940,16 +1028,18 @@ class ReactNativeBleTransport {
|
|
|
940
1028
|
const value = buffer.Buffer.from(buffer$1);
|
|
941
1029
|
bufferLength = 0;
|
|
942
1030
|
buffer$1 = [];
|
|
943
|
-
(
|
|
1031
|
+
if (this.runPromiseDeviceId === uuid) {
|
|
1032
|
+
(_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
|
|
1033
|
+
}
|
|
944
1034
|
}
|
|
945
1035
|
}
|
|
946
1036
|
catch (error) {
|
|
947
1037
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
948
1038
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
949
|
-
if (this.
|
|
1039
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
950
1040
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
951
1041
|
}
|
|
952
|
-
else {
|
|
1042
|
+
else if (this.runPromiseDeviceId === uuid) {
|
|
953
1043
|
(_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
|
|
954
1044
|
}
|
|
955
1045
|
}
|
|
@@ -957,15 +1047,26 @@ class ReactNativeBleTransport {
|
|
|
957
1047
|
return subscription;
|
|
958
1048
|
}
|
|
959
1049
|
release(uuid, onclose = false) {
|
|
1050
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1051
|
+
return this.runLifecycleOperation(uuid, () => this.releaseUnlocked(uuid, onclose));
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
releaseUnlocked(uuid, onclose = false) {
|
|
1055
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1056
|
+
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
1057
|
+
return this.releaseNative(uuid, onclose);
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
releaseNative(uuid, onclose = false) {
|
|
960
1061
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
961
1062
|
return __awaiter(this, void 0, void 0, function* () {
|
|
962
1063
|
const transport = transportCache[uuid];
|
|
963
|
-
|
|
964
|
-
if (this.runPromise) {
|
|
1064
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
965
1065
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
966
1066
|
this.runPromise.reject(error);
|
|
967
1067
|
this.runPromise = null;
|
|
968
|
-
this.
|
|
1068
|
+
this.runPromiseDeviceId = null;
|
|
1069
|
+
this.rejectProtocolV2Frames(uuid, error);
|
|
969
1070
|
}
|
|
970
1071
|
else {
|
|
971
1072
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -975,6 +1076,7 @@ class ReactNativeBleTransport {
|
|
|
975
1076
|
this.resetProtocolV2Frames(uuid);
|
|
976
1077
|
return Promise.resolve(true);
|
|
977
1078
|
}
|
|
1079
|
+
yield this.restoreAndroidConnectionPriority(uuid, transport);
|
|
978
1080
|
if (transport) {
|
|
979
1081
|
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
980
1082
|
this.monitorTokens.delete(uuid);
|
|
@@ -995,7 +1097,9 @@ class ReactNativeBleTransport {
|
|
|
995
1097
|
}
|
|
996
1098
|
delete transportCache[uuid];
|
|
997
1099
|
}
|
|
1100
|
+
this.protocolV2HighVolumeLogSignatures.delete(uuid);
|
|
998
1101
|
this.deviceProtocol.delete(uuid);
|
|
1102
|
+
this.probingProtocols.delete(uuid);
|
|
999
1103
|
(_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
|
|
1000
1104
|
this.protocolV2Assemblers.delete(uuid);
|
|
1001
1105
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -1010,6 +1114,10 @@ class ReactNativeBleTransport {
|
|
|
1010
1114
|
}
|
|
1011
1115
|
post(session, name, data) {
|
|
1012
1116
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1117
|
+
if (this.getProtocolType(session) === 'V2') {
|
|
1118
|
+
yield this.protocolV2Links.sendFlowControl(session, () => this.createProtocolV2Adapter(session), name, data);
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1013
1121
|
yield this.call(session, name, data);
|
|
1014
1122
|
});
|
|
1015
1123
|
}
|
|
@@ -1025,7 +1133,6 @@ class ReactNativeBleTransport {
|
|
|
1025
1133
|
if (!protocol) {
|
|
1026
1134
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1027
1135
|
}
|
|
1028
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport call', createTransportCallLog(name, protocol, data));
|
|
1029
1136
|
if (protocol === 'V2') {
|
|
1030
1137
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1031
1138
|
}
|
|
@@ -1044,7 +1151,19 @@ class ReactNativeBleTransport {
|
|
|
1044
1151
|
const transport = this.getCachedTransport(uuid);
|
|
1045
1152
|
const runPromise = hdShared.createDeferred();
|
|
1046
1153
|
runPromise.promise.catch(() => undefined);
|
|
1154
|
+
const supersededRunPromise = this.runPromise;
|
|
1155
|
+
if (supersededRunPromise) {
|
|
1156
|
+
supersededRunPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
|
|
1157
|
+
}
|
|
1047
1158
|
this.runPromise = runPromise;
|
|
1159
|
+
this.runPromiseDeviceId = uuid;
|
|
1160
|
+
const releaseOwnershipIfCurrent = () => {
|
|
1161
|
+
if (this.runPromise === runPromise) {
|
|
1162
|
+
this.runPromise = null;
|
|
1163
|
+
this.runPromiseDeviceId = null;
|
|
1164
|
+
}
|
|
1165
|
+
};
|
|
1166
|
+
const isCurrentOwner = () => this.runPromise === runPromise;
|
|
1048
1167
|
const messages = this._messages;
|
|
1049
1168
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1050
1169
|
let timeout;
|
|
@@ -1065,6 +1184,9 @@ class ReactNativeBleTransport {
|
|
|
1065
1184
|
}
|
|
1066
1185
|
catch (e) {
|
|
1067
1186
|
onError(e);
|
|
1187
|
+
if (isWedgedWriteError(e)) {
|
|
1188
|
+
throw e;
|
|
1189
|
+
}
|
|
1068
1190
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1069
1191
|
}
|
|
1070
1192
|
}
|
|
@@ -1092,6 +1214,9 @@ class ReactNativeBleTransport {
|
|
|
1092
1214
|
}
|
|
1093
1215
|
catch (e) {
|
|
1094
1216
|
onError(e);
|
|
1217
|
+
if (isWedgedWriteError(e)) {
|
|
1218
|
+
throw e;
|
|
1219
|
+
}
|
|
1095
1220
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1096
1221
|
}
|
|
1097
1222
|
}
|
|
@@ -1102,8 +1227,8 @@ class ReactNativeBleTransport {
|
|
|
1102
1227
|
});
|
|
1103
1228
|
}
|
|
1104
1229
|
if (name === 'EmmcFileWrite') {
|
|
1105
|
-
yield writeChunkedData(buffers, data => transport.writeWithRetry(
|
|
1106
|
-
|
|
1230
|
+
yield writeChunkedData(buffers, data => this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner), e => {
|
|
1231
|
+
releaseOwnershipIfCurrent();
|
|
1107
1232
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1108
1233
|
});
|
|
1109
1234
|
}
|
|
@@ -1119,7 +1244,7 @@ class ReactNativeBleTransport {
|
|
|
1119
1244
|
let attempt = 0;
|
|
1120
1245
|
while (true) {
|
|
1121
1246
|
try {
|
|
1122
|
-
yield transport.
|
|
1247
|
+
yield this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner);
|
|
1123
1248
|
return;
|
|
1124
1249
|
}
|
|
1125
1250
|
catch (error) {
|
|
@@ -1127,36 +1252,18 @@ class ReactNativeBleTransport {
|
|
|
1127
1252
|
if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1128
1253
|
throw error;
|
|
1129
1254
|
}
|
|
1130
|
-
const
|
|
1131
|
-
const delayMs = shouldReconnect
|
|
1132
|
-
? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
|
|
1133
|
-
: resolveFirmwareUploadRetryDelay(attempt);
|
|
1255
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1134
1256
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
|
|
1135
1257
|
attempt: attempt + 1,
|
|
1136
1258
|
delayMs,
|
|
1137
|
-
reconnect: shouldReconnect,
|
|
1138
1259
|
error,
|
|
1139
1260
|
});
|
|
1140
|
-
if (shouldReconnect) {
|
|
1141
|
-
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
1142
|
-
}
|
|
1143
1261
|
yield delay(delayMs);
|
|
1144
1262
|
attempt += 1;
|
|
1145
|
-
if (shouldReconnect) {
|
|
1146
|
-
try {
|
|
1147
|
-
yield this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
1148
|
-
}
|
|
1149
|
-
catch (e) {
|
|
1150
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
1151
|
-
if (attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1152
|
-
throw e;
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
1263
|
}
|
|
1157
1264
|
}
|
|
1158
1265
|
}), e => {
|
|
1159
|
-
|
|
1266
|
+
releaseOwnershipIfCurrent();
|
|
1160
1267
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1161
1268
|
});
|
|
1162
1269
|
}
|
|
@@ -1164,11 +1271,17 @@ class ReactNativeBleTransport {
|
|
|
1164
1271
|
for (const o of buffers) {
|
|
1165
1272
|
const outData = o.toString('base64');
|
|
1166
1273
|
try {
|
|
1167
|
-
|
|
1274
|
+
const shouldUseWriteWithResponse = reactNative.Platform.OS === 'ios' && transport.writeCharacteristic.isWritableWithResponse;
|
|
1275
|
+
yield this.writeBlePacket(uuid, outData, payload => shouldUseWriteWithResponse
|
|
1276
|
+
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
1277
|
+
: transport.writeCharacteristic.writeWithoutResponse(payload), isCurrentOwner);
|
|
1168
1278
|
}
|
|
1169
1279
|
catch (e) {
|
|
1170
1280
|
Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
|
|
1171
|
-
|
|
1281
|
+
releaseOwnershipIfCurrent();
|
|
1282
|
+
if (isWedgedWriteError(e)) {
|
|
1283
|
+
throw e;
|
|
1284
|
+
}
|
|
1172
1285
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected) {
|
|
1173
1286
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded);
|
|
1174
1287
|
}
|
|
@@ -1201,12 +1314,19 @@ class ReactNativeBleTransport {
|
|
|
1201
1314
|
return check.call(jsonData);
|
|
1202
1315
|
}
|
|
1203
1316
|
catch (e) {
|
|
1204
|
-
if (name === '
|
|
1205
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1317
|
+
if (name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
|
|
1318
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
|
|
1206
1319
|
}
|
|
1207
1320
|
else {
|
|
1208
1321
|
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1209
1322
|
}
|
|
1323
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1324
|
+
const isStaleCall = this.runPromise !== runPromise;
|
|
1325
|
+
if (!isProbeTimeout &&
|
|
1326
|
+
!isStaleCall &&
|
|
1327
|
+
(e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1328
|
+
yield this.disconnect(uuid);
|
|
1329
|
+
}
|
|
1210
1330
|
throw e;
|
|
1211
1331
|
}
|
|
1212
1332
|
finally {
|
|
@@ -1214,6 +1334,7 @@ class ReactNativeBleTransport {
|
|
|
1214
1334
|
clearTimeout(timeout);
|
|
1215
1335
|
if (this.runPromise === runPromise) {
|
|
1216
1336
|
this.runPromise = null;
|
|
1337
|
+
this.runPromiseDeviceId = null;
|
|
1217
1338
|
}
|
|
1218
1339
|
}
|
|
1219
1340
|
});
|
|
@@ -1222,10 +1343,16 @@ class ReactNativeBleTransport {
|
|
|
1222
1343
|
this.stopped = true;
|
|
1223
1344
|
}
|
|
1224
1345
|
disconnect(session) {
|
|
1346
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1347
|
+
return this.runLifecycleOperation(session, () => this.disconnectUnlocked(session));
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
disconnectUnlocked(session) {
|
|
1225
1351
|
var _a, _b, _c, _d, _e;
|
|
1226
1352
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1227
1353
|
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1228
1354
|
const transport = transportCache[session];
|
|
1355
|
+
const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
|
|
1229
1356
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
1230
1357
|
try {
|
|
1231
1358
|
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing disconnect subscription');
|
|
@@ -1238,7 +1365,7 @@ class ReactNativeBleTransport {
|
|
|
1238
1365
|
}
|
|
1239
1366
|
if (transport === null || transport === void 0 ? void 0 : transport.notifySubscription) {
|
|
1240
1367
|
try {
|
|
1241
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (
|
|
1368
|
+
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);
|
|
1242
1369
|
transport.notifySubscription.remove();
|
|
1243
1370
|
transport.notifySubscription = undefined;
|
|
1244
1371
|
}
|
|
@@ -1248,7 +1375,7 @@ class ReactNativeBleTransport {
|
|
|
1248
1375
|
}
|
|
1249
1376
|
if (session) {
|
|
1250
1377
|
try {
|
|
1251
|
-
yield ((
|
|
1378
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(session));
|
|
1252
1379
|
}
|
|
1253
1380
|
catch (e) {
|
|
1254
1381
|
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1263,7 +1390,7 @@ class ReactNativeBleTransport {
|
|
|
1263
1390
|
}
|
|
1264
1391
|
}
|
|
1265
1392
|
try {
|
|
1266
|
-
yield ((
|
|
1393
|
+
yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelDeviceConnection(session));
|
|
1267
1394
|
}
|
|
1268
1395
|
catch (e) {
|
|
1269
1396
|
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1272,26 +1399,136 @@ class ReactNativeBleTransport {
|
|
|
1272
1399
|
delete transportCache[session];
|
|
1273
1400
|
}
|
|
1274
1401
|
this.deviceProtocol.delete(session);
|
|
1402
|
+
this.probingProtocols.delete(session);
|
|
1275
1403
|
this.deviceProtocolHints.delete(session);
|
|
1404
|
+
this.sessionProtocols.delete(session);
|
|
1405
|
+
this.protocolReprobeFailures.delete(session);
|
|
1276
1406
|
this.protocolV2Assemblers.delete(session);
|
|
1277
1407
|
this.resetProtocolV2Frames(session);
|
|
1278
1408
|
try {
|
|
1279
|
-
(
|
|
1280
|
-
name: (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name,
|
|
1281
|
-
id: session,
|
|
1282
|
-
connectId: session,
|
|
1283
|
-
});
|
|
1409
|
+
this.emitDeviceDisconnect(session, (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name, monitorToken);
|
|
1284
1410
|
}
|
|
1285
1411
|
catch (e) {
|
|
1286
1412
|
Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
|
|
1287
1413
|
}
|
|
1414
|
+
if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
|
|
1415
|
+
this.monitorTokens.delete(session);
|
|
1416
|
+
}
|
|
1288
1417
|
yield new Promise(resolve => setTimeout(() => resolve(), 100));
|
|
1289
1418
|
});
|
|
1290
1419
|
}
|
|
1420
|
+
runLifecycleOperation(uuid, operation) {
|
|
1421
|
+
var _a;
|
|
1422
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1423
|
+
const previousOperation = (_a = this.lifecycleOperations.get(uuid)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
1424
|
+
let completeOperation;
|
|
1425
|
+
const operationGate = new Promise(resolve => {
|
|
1426
|
+
completeOperation = resolve;
|
|
1427
|
+
});
|
|
1428
|
+
const operationTail = previousOperation.catch(() => undefined).then(() => operationGate);
|
|
1429
|
+
this.lifecycleOperations.set(uuid, operationTail);
|
|
1430
|
+
yield previousOperation.catch(() => undefined);
|
|
1431
|
+
try {
|
|
1432
|
+
return yield operation();
|
|
1433
|
+
}
|
|
1434
|
+
finally {
|
|
1435
|
+
completeOperation();
|
|
1436
|
+
if (this.lifecycleOperations.get(uuid) === operationTail) {
|
|
1437
|
+
this.lifecycleOperations.delete(uuid);
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1291
1442
|
cancel() {
|
|
1292
1443
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1293
1444
|
if (this.runPromise) ;
|
|
1294
1445
|
this.runPromise = null;
|
|
1446
|
+
this.runPromiseDeviceId = null;
|
|
1447
|
+
}
|
|
1448
|
+
connectWithTimeout(uuid, connect) {
|
|
1449
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1450
|
+
let timer;
|
|
1451
|
+
let timedOut = false;
|
|
1452
|
+
const pending = connect();
|
|
1453
|
+
pending.catch(() => undefined);
|
|
1454
|
+
try {
|
|
1455
|
+
const result = yield Promise.race([
|
|
1456
|
+
pending,
|
|
1457
|
+
new Promise((_, reject) => {
|
|
1458
|
+
timer = setTimeout(() => {
|
|
1459
|
+
timedOut = true;
|
|
1460
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `BLE connect timeout after ${BLE_CONNECT_TIMEOUT_MS}ms for ${uuid}`));
|
|
1461
|
+
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1462
|
+
}),
|
|
1463
|
+
]);
|
|
1464
|
+
return result;
|
|
1465
|
+
}
|
|
1466
|
+
catch (error) {
|
|
1467
|
+
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1468
|
+
this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1469
|
+
}
|
|
1470
|
+
throw error;
|
|
1471
|
+
}
|
|
1472
|
+
finally {
|
|
1473
|
+
if (timer)
|
|
1474
|
+
clearTimeout(timer);
|
|
1475
|
+
}
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1478
|
+
resolveCharacteristicsWithTimeout(uuid, device) {
|
|
1479
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1480
|
+
let timer;
|
|
1481
|
+
let timedOut = false;
|
|
1482
|
+
const pending = this.resolveCharacteristics(device);
|
|
1483
|
+
pending.catch(() => undefined);
|
|
1484
|
+
try {
|
|
1485
|
+
const result = yield Promise.race([
|
|
1486
|
+
pending,
|
|
1487
|
+
new Promise((_, reject) => {
|
|
1488
|
+
timer = setTimeout(() => {
|
|
1489
|
+
timedOut = true;
|
|
1490
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `BLE GATT setup timeout after ${BLE_GATT_SETUP_TIMEOUT_MS}ms for ${uuid}`));
|
|
1491
|
+
}, BLE_GATT_SETUP_TIMEOUT_MS);
|
|
1492
|
+
}),
|
|
1493
|
+
]);
|
|
1494
|
+
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1495
|
+
return result;
|
|
1496
|
+
}
|
|
1497
|
+
catch (error) {
|
|
1498
|
+
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1499
|
+
this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1500
|
+
}
|
|
1501
|
+
throw error;
|
|
1502
|
+
}
|
|
1503
|
+
finally {
|
|
1504
|
+
if (timer)
|
|
1505
|
+
clearTimeout(timer);
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
}
|
|
1509
|
+
abandonStalledConnection(uuid, stage) {
|
|
1510
|
+
var _a, _b;
|
|
1511
|
+
const timeouts = ((_a = this.connectionSetupTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1512
|
+
this.connectionSetupTimeoutCounts.set(uuid, timeouts);
|
|
1513
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup timed out:', uuid, {
|
|
1514
|
+
stage,
|
|
1515
|
+
setupTimeoutsSinceSuccess: timeouts,
|
|
1516
|
+
});
|
|
1517
|
+
(_b = this.blePlxManager) === null || _b === void 0 ? void 0 : _b.cancelDeviceConnection(uuid).catch(() => {
|
|
1518
|
+
});
|
|
1519
|
+
const stalled = transportCache[uuid];
|
|
1520
|
+
if (stalled) {
|
|
1521
|
+
delete transportCache[uuid];
|
|
1522
|
+
}
|
|
1523
|
+
this.deviceProtocol.delete(uuid);
|
|
1524
|
+
this.probingProtocols.delete(uuid);
|
|
1525
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1526
|
+
this.resetProtocolV2Frames(uuid);
|
|
1527
|
+
if (timeouts >= BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1528
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
|
|
1529
|
+
this.resetPlxManager();
|
|
1530
|
+
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1531
|
+
}
|
|
1295
1532
|
}
|
|
1296
1533
|
getCachedTransport(uuid) {
|
|
1297
1534
|
const transport = transportCache[uuid];
|
|
@@ -1300,22 +1537,118 @@ class ReactNativeBleTransport {
|
|
|
1300
1537
|
}
|
|
1301
1538
|
return transport;
|
|
1302
1539
|
}
|
|
1540
|
+
writeBlePacket(uuid, data, write, isCurrentOwner) {
|
|
1541
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1542
|
+
let timer;
|
|
1543
|
+
let timedOut = false;
|
|
1544
|
+
try {
|
|
1545
|
+
yield Promise.race([
|
|
1546
|
+
write(data),
|
|
1547
|
+
new Promise((_, reject) => {
|
|
1548
|
+
timer = setTimeout(() => {
|
|
1549
|
+
timedOut = true;
|
|
1550
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write timeout after ${BLE_WRITE_PACKET_TIMEOUT_MS}ms`));
|
|
1551
|
+
}, BLE_WRITE_PACKET_TIMEOUT_MS);
|
|
1552
|
+
}),
|
|
1553
|
+
]);
|
|
1554
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1555
|
+
}
|
|
1556
|
+
catch (error) {
|
|
1557
|
+
if (timedOut) {
|
|
1558
|
+
if (isCurrentOwner && !isCurrentOwner()) {
|
|
1559
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] stale BLE write timed out, link kept:', uuid);
|
|
1560
|
+
}
|
|
1561
|
+
else {
|
|
1562
|
+
this.tearDownWedgedLink(uuid);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
throw error;
|
|
1566
|
+
}
|
|
1567
|
+
finally {
|
|
1568
|
+
if (timer)
|
|
1569
|
+
clearTimeout(timer);
|
|
1570
|
+
}
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
tearDownWedgedLink(uuid) {
|
|
1574
|
+
var _a;
|
|
1575
|
+
const timeouts = ((_a = this.writeTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1576
|
+
this.writeTimeoutCounts.set(uuid, timeouts);
|
|
1577
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE write timed out, tearing down link:', uuid, {
|
|
1578
|
+
consecutiveWriteTimeouts: timeouts,
|
|
1579
|
+
});
|
|
1580
|
+
const wedged = transportCache[uuid];
|
|
1581
|
+
this.disconnect(uuid).catch(error => {
|
|
1582
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] wedged link teardown failed (ignored):', error);
|
|
1583
|
+
});
|
|
1584
|
+
if (wedged && transportCache[uuid] === wedged) {
|
|
1585
|
+
delete transportCache[uuid];
|
|
1586
|
+
}
|
|
1587
|
+
this.deviceProtocol.delete(uuid);
|
|
1588
|
+
this.probingProtocols.delete(uuid);
|
|
1589
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1590
|
+
this.resetProtocolV2Frames(uuid);
|
|
1591
|
+
if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1592
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE writes wedged repeatedly, resetting BLE manager');
|
|
1593
|
+
this.resetPlxManager();
|
|
1594
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
resetPlxManager() {
|
|
1598
|
+
const manager = this.blePlxManager;
|
|
1599
|
+
this.blePlxManager = undefined;
|
|
1600
|
+
Object.keys(transportCache).forEach(key => {
|
|
1601
|
+
delete transportCache[key];
|
|
1602
|
+
});
|
|
1603
|
+
this.deviceProtocol.clear();
|
|
1604
|
+
this.probingProtocols.clear();
|
|
1605
|
+
this.sessionProtocols.clear();
|
|
1606
|
+
this.protocolReprobeFailures.clear();
|
|
1607
|
+
this.writeTimeoutCounts.clear();
|
|
1608
|
+
this.connectionSetupTimeoutCounts.clear();
|
|
1609
|
+
this.monitorTokens.clear();
|
|
1610
|
+
this.protocolV2Assemblers.clear();
|
|
1611
|
+
try {
|
|
1612
|
+
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
1613
|
+
}
|
|
1614
|
+
catch (error) {
|
|
1615
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1303
1618
|
createProtocolMismatchError(expected) {
|
|
1304
1619
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1305
1620
|
}
|
|
1306
1621
|
createProtocolDetectionError() {
|
|
1307
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1622
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
1308
1623
|
}
|
|
1309
1624
|
clearProbeProtocol(uuid, protocol) {
|
|
1625
|
+
if (this.probingProtocols.get(uuid) === protocol) {
|
|
1626
|
+
this.probingProtocols.delete(uuid);
|
|
1627
|
+
}
|
|
1310
1628
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1311
1629
|
this.deviceProtocol.delete(uuid);
|
|
1312
1630
|
}
|
|
1313
1631
|
}
|
|
1314
|
-
|
|
1632
|
+
getActiveProtocol(uuid) {
|
|
1633
|
+
var _a;
|
|
1634
|
+
return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
|
|
1635
|
+
}
|
|
1636
|
+
detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
|
|
1637
|
+
var _a;
|
|
1315
1638
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1639
|
+
if (reactNative.Platform.OS === 'ios' && expectedProtocol === 'V1') {
|
|
1640
|
+
this.deviceProtocol.set(uuid, expectedProtocol);
|
|
1641
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
|
|
1642
|
+
deviceId: uuid,
|
|
1643
|
+
protocol: expectedProtocol,
|
|
1644
|
+
source: 'expected',
|
|
1645
|
+
});
|
|
1646
|
+
return expectedProtocol;
|
|
1647
|
+
}
|
|
1316
1648
|
if (expectedProtocol === 'V1') {
|
|
1317
1649
|
if (yield this.probeProtocolV1(uuid)) {
|
|
1318
1650
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1651
|
+
this.sessionProtocols.set(uuid, 'V1');
|
|
1319
1652
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1320
1653
|
deviceId: uuid,
|
|
1321
1654
|
protocol: 'V1',
|
|
@@ -1326,23 +1659,41 @@ class ReactNativeBleTransport {
|
|
|
1326
1659
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1327
1660
|
}
|
|
1328
1661
|
if (expectedProtocol === 'V2') {
|
|
1329
|
-
this.
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1662
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1663
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1664
|
+
this.sessionProtocols.set(uuid, 'V2');
|
|
1665
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1666
|
+
deviceId: uuid,
|
|
1667
|
+
protocol: 'V2',
|
|
1668
|
+
source: 'expected',
|
|
1669
|
+
});
|
|
1670
|
+
return 'V2';
|
|
1671
|
+
}
|
|
1672
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1336
1673
|
}
|
|
1337
|
-
const
|
|
1674
|
+
const sessionProtocol = this.sessionProtocols.get(uuid);
|
|
1675
|
+
const reprobeFailures = (_a = this.protocolReprobeFailures.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1676
|
+
const fullProbeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1677
|
+
const trustSessionProtocol = sessionProtocol !== undefined &&
|
|
1678
|
+
!protocolHint &&
|
|
1679
|
+
reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1680
|
+
const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
|
|
1338
1681
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1339
1682
|
const protocol = probeOrder[i];
|
|
1340
1683
|
if (i > 0) {
|
|
1341
1684
|
yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
1685
|
+
if (!transportCache[uuid]) {
|
|
1686
|
+
if (!rebuildTransport) {
|
|
1687
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
1688
|
+
}
|
|
1689
|
+
yield rebuildTransport();
|
|
1690
|
+
}
|
|
1342
1691
|
}
|
|
1343
1692
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
|
|
1344
1693
|
if (detected) {
|
|
1345
1694
|
this.deviceProtocol.set(uuid, protocol);
|
|
1695
|
+
this.sessionProtocols.set(uuid, protocol);
|
|
1696
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
1346
1697
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1347
1698
|
deviceId: uuid,
|
|
1348
1699
|
protocol,
|
|
@@ -1351,7 +1702,14 @@ class ReactNativeBleTransport {
|
|
|
1351
1702
|
return protocol;
|
|
1352
1703
|
}
|
|
1353
1704
|
}
|
|
1705
|
+
if (trustSessionProtocol) {
|
|
1706
|
+
this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
|
|
1707
|
+
}
|
|
1708
|
+
else {
|
|
1709
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
1710
|
+
}
|
|
1354
1711
|
this.deviceProtocol.delete(uuid);
|
|
1712
|
+
this.probingProtocols.delete(uuid);
|
|
1355
1713
|
throw this.createProtocolDetectionError();
|
|
1356
1714
|
});
|
|
1357
1715
|
}
|
|
@@ -1403,13 +1761,17 @@ class ReactNativeBleTransport {
|
|
|
1403
1761
|
return false;
|
|
1404
1762
|
}
|
|
1405
1763
|
try {
|
|
1406
|
-
this.
|
|
1407
|
-
yield this.callProtocolV1(uuid, '
|
|
1764
|
+
this.probingProtocols.set(uuid, 'V1');
|
|
1765
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1766
|
+
this.probingProtocols.delete(uuid);
|
|
1408
1767
|
return true;
|
|
1409
1768
|
}
|
|
1410
1769
|
catch (error) {
|
|
1411
1770
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1412
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1771
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1772
|
+
if (isWedgedWriteError(error)) {
|
|
1773
|
+
throw error;
|
|
1774
|
+
}
|
|
1413
1775
|
return false;
|
|
1414
1776
|
}
|
|
1415
1777
|
});
|
|
@@ -1420,7 +1782,7 @@ class ReactNativeBleTransport {
|
|
|
1420
1782
|
if (!this._messages || !this._messagesV2) {
|
|
1421
1783
|
return false;
|
|
1422
1784
|
}
|
|
1423
|
-
this.
|
|
1785
|
+
this.probingProtocols.set(uuid, 'V2');
|
|
1424
1786
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1425
1787
|
const detected = yield transport.probeProtocolV2({
|
|
1426
1788
|
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
@@ -1436,6 +1798,9 @@ class ReactNativeBleTransport {
|
|
|
1436
1798
|
if (!detected) {
|
|
1437
1799
|
this.clearProbeProtocol(uuid, 'V2');
|
|
1438
1800
|
}
|
|
1801
|
+
else {
|
|
1802
|
+
this.probingProtocols.delete(uuid);
|
|
1803
|
+
}
|
|
1439
1804
|
return detected;
|
|
1440
1805
|
});
|
|
1441
1806
|
}
|
|
@@ -1478,16 +1843,8 @@ class ReactNativeBleTransport {
|
|
|
1478
1843
|
}
|
|
1479
1844
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1480
1845
|
}
|
|
1481
|
-
rejectAllProtocolV2Frames(error) {
|
|
1482
|
-
this.protocolV2FrameQueues.clear();
|
|
1483
|
-
for (const framePromise of this.protocolV2FramePromises.values()) {
|
|
1484
|
-
framePromise.reject(error);
|
|
1485
|
-
}
|
|
1486
|
-
this.protocolV2FramePromises.clear();
|
|
1487
|
-
}
|
|
1488
1846
|
resetProtocolV2Frames(uuid) {
|
|
1489
|
-
this.
|
|
1490
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1847
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1491
1848
|
}
|
|
1492
1849
|
rejectProtocolV2Frames(uuid, error) {
|
|
1493
1850
|
this.protocolV2FrameQueues.delete(uuid);
|
|
@@ -1515,20 +1872,70 @@ class ReactNativeBleTransport {
|
|
|
1515
1872
|
}
|
|
1516
1873
|
});
|
|
1517
1874
|
}
|
|
1518
|
-
|
|
1875
|
+
writeProtocolV2Packet(uuid, transport, base64, context, assertCurrentGeneration) {
|
|
1876
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1877
|
+
const shouldUseWriteWithResponse = shouldWriteProtocolV2WithResponse({
|
|
1878
|
+
platform: reactNative.Platform.OS,
|
|
1879
|
+
highThroughput: context.highThroughput,
|
|
1880
|
+
requestedWithResponse: context.writeWithResponse,
|
|
1881
|
+
characteristic: transport.writeCharacteristic,
|
|
1882
|
+
});
|
|
1883
|
+
let attempt = 0;
|
|
1884
|
+
for (;;) {
|
|
1885
|
+
assertCurrentGeneration();
|
|
1886
|
+
if (context.signal.aborted) {
|
|
1887
|
+
throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
|
|
1888
|
+
}
|
|
1889
|
+
try {
|
|
1890
|
+
yield this.writeBlePacket(uuid, base64, payload => shouldUseWriteWithResponse
|
|
1891
|
+
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
1892
|
+
: transport.writeCharacteristic.writeWithoutResponse(payload), () => {
|
|
1893
|
+
try {
|
|
1894
|
+
assertCurrentGeneration();
|
|
1895
|
+
return !context.signal.aborted;
|
|
1896
|
+
}
|
|
1897
|
+
catch (_a) {
|
|
1898
|
+
return false;
|
|
1899
|
+
}
|
|
1900
|
+
});
|
|
1901
|
+
assertCurrentGeneration();
|
|
1902
|
+
return;
|
|
1903
|
+
}
|
|
1904
|
+
catch (error) {
|
|
1905
|
+
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
1906
|
+
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1907
|
+
throw error;
|
|
1908
|
+
}
|
|
1909
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1910
|
+
attempt += 1;
|
|
1911
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 congested write retry:', {
|
|
1912
|
+
name: context.messageName,
|
|
1913
|
+
attempt,
|
|
1914
|
+
delayMs,
|
|
1915
|
+
});
|
|
1916
|
+
yield delay(delayMs);
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1921
|
+
writeProtocolV2Frame(uuid, transport$1, frame, context, assertCurrentGeneration) {
|
|
1519
1922
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1520
1923
|
const tuning = getProtocolV2BleTuning();
|
|
1521
1924
|
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1522
1925
|
platform: reactNative.Platform.OS,
|
|
1523
1926
|
iosPacketLength: tuning.iosPacketLength,
|
|
1524
1927
|
androidPacketLength: tuning.androidPacketLength,
|
|
1525
|
-
mtu:
|
|
1928
|
+
mtu: transport$1.mtuSize,
|
|
1929
|
+
});
|
|
1930
|
+
yield transport.writeProtocolV2BleFrame({
|
|
1931
|
+
frame,
|
|
1932
|
+
packetCapacity,
|
|
1933
|
+
assertActive: assertCurrentGeneration,
|
|
1934
|
+
signal: context.signal,
|
|
1935
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1936
|
+
wait: delay,
|
|
1937
|
+
writePacket: packet => this.writeProtocolV2Packet(uuid, transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
|
|
1526
1938
|
});
|
|
1527
|
-
for (let offset = 0; offset < frame.length; offset += packetCapacity) {
|
|
1528
|
-
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1529
|
-
const base64 = buffer.Buffer.from(chunk).toString('base64');
|
|
1530
|
-
yield transport.writeCharacteristic.writeWithoutResponse(base64);
|
|
1531
|
-
}
|
|
1532
1939
|
});
|
|
1533
1940
|
}
|
|
1534
1941
|
callProtocolV2(uuid, name, data, options) {
|
|
@@ -1537,15 +1944,40 @@ class ReactNativeBleTransport {
|
|
|
1537
1944
|
if (!this._messages || !this._messagesV2) {
|
|
1538
1945
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1539
1946
|
}
|
|
1540
|
-
const callOptions =
|
|
1541
|
-
const
|
|
1542
|
-
if (
|
|
1947
|
+
const callOptions = options;
|
|
1948
|
+
const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
|
|
1949
|
+
if (highThroughputWrite) {
|
|
1950
|
+
yield this.ensureProtocolV2HighThroughputMtu(uuid);
|
|
1543
1951
|
const tuning = getProtocolV2BleTuning();
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1952
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
1953
|
+
const writeWithResponse = shouldWriteProtocolV2WithResponse({
|
|
1954
|
+
platform: reactNative.Platform.OS,
|
|
1955
|
+
highThroughput: true,
|
|
1956
|
+
requestedWithResponse: options === null || options === void 0 ? void 0 : options.writeWithResponse,
|
|
1957
|
+
characteristic: currentTransport.writeCharacteristic,
|
|
1958
|
+
});
|
|
1959
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1960
|
+
platform: reactNative.Platform.OS,
|
|
1961
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
1962
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
1963
|
+
mtu: currentTransport.mtuSize,
|
|
1548
1964
|
});
|
|
1965
|
+
const writeMode = writeWithResponse ? 'withResponse' : 'withoutResponse';
|
|
1966
|
+
const logSignature = `${name}:${writeMode}:${String(currentTransport.mtuSize)}:${packetCapacity}`;
|
|
1967
|
+
const loggedSignatures = (_a = this.protocolV2HighVolumeLogSignatures.get(uuid)) !== null && _a !== void 0 ? _a : new Set();
|
|
1968
|
+
if (!loggedSignatures.has(logSignature)) {
|
|
1969
|
+
loggedSignatures.add(logSignature);
|
|
1970
|
+
this.protocolV2HighVolumeLogSignatures.set(uuid, loggedSignatures);
|
|
1971
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
|
|
1972
|
+
name,
|
|
1973
|
+
writeMode,
|
|
1974
|
+
reportedMtu: currentTransport.mtuSize,
|
|
1975
|
+
packetCapacity,
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
if (highThroughputWrite) {
|
|
1980
|
+
yield this.enableAndroidHighConnectionPriority(uuid);
|
|
1549
1981
|
}
|
|
1550
1982
|
try {
|
|
1551
1983
|
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
@@ -1554,6 +1986,85 @@ class ReactNativeBleTransport {
|
|
|
1554
1986
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1555
1987
|
throw e;
|
|
1556
1988
|
}
|
|
1989
|
+
finally {
|
|
1990
|
+
if (highThroughputWrite) {
|
|
1991
|
+
this.scheduleAndroidBalancedConnectionPriority(uuid);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
ensureProtocolV2HighThroughputMtu(uuid) {
|
|
1997
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1998
|
+
const transport = this.getCachedTransport(uuid);
|
|
1999
|
+
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
2000
|
+
return;
|
|
2001
|
+
const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1);
|
|
2002
|
+
transport.device = refreshedDevice;
|
|
2003
|
+
transport.mtuSize =
|
|
2004
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
2005
|
+
if (shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
2006
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `Protocol V2 high-throughput BLE MTU unavailable: ${String(transport.mtuSize)}`);
|
|
2007
|
+
}
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
clearAndroidPriorityResetTimer(uuid) {
|
|
2011
|
+
const timerId = this.androidPriorityResetTimers.get(uuid);
|
|
2012
|
+
if (timerId !== undefined) {
|
|
2013
|
+
clearTimeout(timerId);
|
|
2014
|
+
this.androidPriorityResetTimers.delete(uuid);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
enableAndroidHighConnectionPriority(uuid) {
|
|
2018
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2019
|
+
if (reactNative.Platform.OS !== 'android')
|
|
2020
|
+
return;
|
|
2021
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
2022
|
+
if (this.androidHighPriorityDevices.has(uuid))
|
|
2023
|
+
return;
|
|
2024
|
+
const transport = transportCache[uuid];
|
|
2025
|
+
if (!transport)
|
|
2026
|
+
return;
|
|
2027
|
+
try {
|
|
2028
|
+
transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.High);
|
|
2029
|
+
this.androidHighPriorityDevices.add(uuid);
|
|
2030
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
|
|
2031
|
+
priority: 'high',
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
catch (error) {
|
|
2035
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE high priority request failed', {
|
|
2036
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
scheduleAndroidBalancedConnectionPriority(uuid) {
|
|
2042
|
+
if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.has(uuid))
|
|
2043
|
+
return;
|
|
2044
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
2045
|
+
const timerId = setTimeout(() => {
|
|
2046
|
+
this.androidPriorityResetTimers.delete(uuid);
|
|
2047
|
+
this.restoreAndroidConnectionPriority(uuid, transportCache[uuid]).catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE priority restore failed', error));
|
|
2048
|
+
}, ANDROID_HIGH_PRIORITY_IDLE_MS);
|
|
2049
|
+
this.androidPriorityResetTimers.set(uuid, timerId);
|
|
2050
|
+
}
|
|
2051
|
+
restoreAndroidConnectionPriority(uuid, transport) {
|
|
2052
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2053
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
2054
|
+
if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.delete(uuid) || !transport) {
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
try {
|
|
2058
|
+
transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.Balanced);
|
|
2059
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
|
|
2060
|
+
priority: 'balanced',
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
catch (error) {
|
|
2064
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE balanced priority request failed', {
|
|
2065
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2066
|
+
});
|
|
2067
|
+
}
|
|
1557
2068
|
});
|
|
1558
2069
|
}
|
|
1559
2070
|
createProtocolV2Adapter(uuid) {
|
|
@@ -1574,10 +2085,10 @@ class ReactNativeBleTransport {
|
|
|
1574
2085
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1575
2086
|
this.resetProtocolV2Frames(uuid);
|
|
1576
2087
|
},
|
|
1577
|
-
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
2088
|
+
writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
|
|
1578
2089
|
assertCurrentGeneration();
|
|
1579
2090
|
const currentTransport = this.getCachedTransport(uuid);
|
|
1580
|
-
yield this.writeProtocolV2Frame(currentTransport, frame);
|
|
2091
|
+
yield this.writeProtocolV2Frame(uuid, currentTransport, frame, context, assertCurrentGeneration);
|
|
1581
2092
|
}),
|
|
1582
2093
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1583
2094
|
assertCurrentGeneration();
|
|
@@ -1598,11 +2109,18 @@ class ReactNativeBleTransport {
|
|
|
1598
2109
|
};
|
|
1599
2110
|
}
|
|
1600
2111
|
getProtocolType(path) {
|
|
1601
|
-
return this.
|
|
2112
|
+
return this.getActiveProtocol(path);
|
|
1602
2113
|
}
|
|
1603
2114
|
}
|
|
1604
2115
|
|
|
2116
|
+
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2117
|
+
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2118
|
+
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|
|
2119
|
+
exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
|
|
2120
|
+
exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2121
|
+
exports.PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1605
2122
|
exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
|
|
1606
2123
|
exports["default"] = ReactNativeBleTransport;
|
|
2124
|
+
exports.getFirmwareUploadWriteRetryType = getFirmwareUploadWriteRetryType;
|
|
1607
2125
|
exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
|
|
1608
2126
|
exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;
|