@onekeyfe/hd-transport-react-native 1.2.0-alpha.18 → 1.2.0-alpha.180
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 +137 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +950 -318
- 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 +303 -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 +942 -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 +1276 -302
- 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,24 @@ 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 BLE_NATIVE_TEARDOWN_TIMEOUT_MS = 3000;
|
|
281
|
+
const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
282
|
+
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
283
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
284
|
+
error.message.startsWith(WEDGED_WRITE_MESSAGE);
|
|
285
|
+
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
286
|
+
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
296
287
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
297
288
|
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
298
289
|
const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
|
|
299
|
-
iosPacketLength:
|
|
300
|
-
androidPacketLength:
|
|
290
|
+
iosPacketLength: IOS_PROTOCOL_V2_PACKET_LENGTH,
|
|
291
|
+
androidPacketLength: ANDROID_PROTOCOL_V2_PACKET_LENGTH,
|
|
301
292
|
};
|
|
302
293
|
let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
303
294
|
const normalizePositiveInteger = (value, fallback) => {
|
|
@@ -320,25 +311,37 @@ function resetProtocolV2BleTuning() {
|
|
|
320
311
|
function getProtocolV2BleTuning() {
|
|
321
312
|
return Object.assign({}, protocolV2BleTuning);
|
|
322
313
|
}
|
|
323
|
-
function inferProtocolHintFromDeviceName(name) {
|
|
324
|
-
return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
|
|
325
|
-
}
|
|
326
314
|
function getDeviceDisplayName(device) {
|
|
327
315
|
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
328
316
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
336
|
-
const ANDROID_REQUEST_MTU = 256;
|
|
317
|
+
const IOS_REQUEST_MTU = 247;
|
|
318
|
+
const ANDROID_REQUEST_MTU = 517;
|
|
319
|
+
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
320
|
+
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
321
|
+
const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
322
|
+
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
337
323
|
const connectOptions = {
|
|
338
|
-
requestMTU:
|
|
339
|
-
timeout:
|
|
324
|
+
requestMTU: getRequestedBleMtu(),
|
|
325
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
340
326
|
refreshGatt: 'OnConnected',
|
|
341
327
|
};
|
|
328
|
+
const fallbackConnectOptions = {
|
|
329
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
330
|
+
};
|
|
331
|
+
const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
332
|
+
const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
333
|
+
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
334
|
+
const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
335
|
+
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
336
|
+
const BLE_SETUP_WEDGED_MESSAGE = 'BLE setup wedged repeatedly';
|
|
337
|
+
const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
|
|
338
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
339
|
+
error.message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
340
|
+
const isWedgedBleSetupError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.PollingTimeout &&
|
|
341
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
342
|
+
error.message.startsWith(BLE_SETUP_WEDGED_MESSAGE);
|
|
343
|
+
const shouldRethrowBleSetupError = (error) => isConnectTimeoutError(error) || isWedgedBleSetupError(error);
|
|
344
|
+
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
342
345
|
const tryToGetConfiguration = (device) => {
|
|
343
346
|
if (!device || !device.serviceUUIDs)
|
|
344
347
|
return null;
|
|
@@ -350,23 +353,25 @@ const tryToGetConfiguration = (device) => {
|
|
|
350
353
|
return null;
|
|
351
354
|
return infos;
|
|
352
355
|
};
|
|
353
|
-
const
|
|
354
|
-
if (reactNative.Platform.OS !== 'android')
|
|
356
|
+
const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
|
|
357
|
+
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
355
358
|
return device;
|
|
356
359
|
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
|
-
});
|
|
360
|
+
const mtuDevice = yield device.requestMTU(getRequestedBleMtu());
|
|
363
361
|
return mtuDevice;
|
|
364
362
|
}
|
|
365
363
|
catch (error) {
|
|
366
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
364
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
|
|
365
|
+
platform: reactNative.Platform.OS,
|
|
366
|
+
stage,
|
|
367
|
+
attempt,
|
|
368
|
+
actual: device.mtu,
|
|
369
|
+
error: error instanceof Error ? error.message : String(error),
|
|
370
|
+
});
|
|
367
371
|
return device;
|
|
368
372
|
}
|
|
369
373
|
});
|
|
374
|
+
const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
|
|
370
375
|
function remapError(error) {
|
|
371
376
|
var _a;
|
|
372
377
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -393,9 +398,16 @@ class ReactNativeBleTransport {
|
|
|
393
398
|
this.stopped = false;
|
|
394
399
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
395
400
|
this.runPromise = null;
|
|
401
|
+
this.runPromiseDeviceId = null;
|
|
396
402
|
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
397
403
|
this.deviceProtocol = new Map();
|
|
404
|
+
this.probingProtocols = new Map();
|
|
405
|
+
this.writeTimeoutCounts = new Map();
|
|
406
|
+
this.connectionSetupTimeoutCounts = new Map();
|
|
398
407
|
this.deviceProtocolHints = new Map();
|
|
408
|
+
this.sessionProtocols = new Map();
|
|
409
|
+
this.confirmedProtocolV2 = new Set();
|
|
410
|
+
this.protocolReprobeFailures = new Map();
|
|
399
411
|
this.protocolV2Assemblers = new Map();
|
|
400
412
|
this.protocolV2FrameQueues = new Map();
|
|
401
413
|
this.protocolV2FramePromises = new Map();
|
|
@@ -416,12 +428,17 @@ class ReactNativeBleTransport {
|
|
|
416
428
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
417
429
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
418
430
|
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
419
|
-
yield this.
|
|
431
|
+
yield this.releaseNative(uuid, true);
|
|
420
432
|
}
|
|
421
433
|
}),
|
|
422
434
|
});
|
|
423
435
|
this.monitorTokens = new Map();
|
|
436
|
+
this.disconnectEventTokens = new Map();
|
|
437
|
+
this.protocolV2HighVolumeLogSignatures = new Map();
|
|
438
|
+
this.androidHighPriorityDevices = new Set();
|
|
439
|
+
this.androidPriorityResetTimers = new Map();
|
|
424
440
|
this.nextMonitorToken = 1;
|
|
441
|
+
this.lifecycleOperations = new Map();
|
|
425
442
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
426
443
|
}
|
|
427
444
|
init(logger, emitter) {
|
|
@@ -434,10 +451,18 @@ class ReactNativeBleTransport {
|
|
|
434
451
|
this._messages = messages;
|
|
435
452
|
}
|
|
436
453
|
configureProtocolV2(signedData) {
|
|
454
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
455
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
437
459
|
this._messagesV2 = parseConfigure(signedData);
|
|
438
|
-
this.
|
|
439
|
-
|
|
440
|
-
.
|
|
460
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
461
|
+
if (isReconfiguration) {
|
|
462
|
+
this.protocolV2Links
|
|
463
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
464
|
+
.catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
|
|
465
|
+
}
|
|
441
466
|
}
|
|
442
467
|
listen() {
|
|
443
468
|
}
|
|
@@ -448,7 +473,6 @@ class ReactNativeBleTransport {
|
|
|
448
473
|
return Promise.resolve(this.blePlxManager);
|
|
449
474
|
}
|
|
450
475
|
resolveCharacteristics(device) {
|
|
451
|
-
var _a, _b, _c, _d;
|
|
452
476
|
return __awaiter(this, void 0, void 0, function* () {
|
|
453
477
|
yield device.discoverAllServicesAndCharacteristics();
|
|
454
478
|
let infos = tryToGetConfiguration(device);
|
|
@@ -465,19 +489,11 @@ class ReactNativeBleTransport {
|
|
|
465
489
|
}
|
|
466
490
|
}
|
|
467
491
|
}
|
|
468
|
-
let fallbackServiceUuid;
|
|
469
492
|
if (!infos) {
|
|
470
493
|
const services = yield device.services();
|
|
471
494
|
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
495
|
}
|
|
480
|
-
if (!infos
|
|
496
|
+
if (!infos) {
|
|
481
497
|
try {
|
|
482
498
|
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
483
499
|
yield device.cancelConnection();
|
|
@@ -487,9 +503,7 @@ class ReactNativeBleTransport {
|
|
|
487
503
|
}
|
|
488
504
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
489
505
|
}
|
|
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';
|
|
506
|
+
const { serviceUuid, writeUuid, notifyUuid } = infos;
|
|
493
507
|
if (!serviceUuid) {
|
|
494
508
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
495
509
|
}
|
|
@@ -530,8 +544,8 @@ class ReactNativeBleTransport {
|
|
|
530
544
|
attachDisconnectSubscription(transport, device, uuid) {
|
|
531
545
|
var _a;
|
|
532
546
|
(_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
547
|
+
const { monitorToken } = transport;
|
|
533
548
|
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
534
|
-
var _a;
|
|
535
549
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
536
550
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
537
551
|
return;
|
|
@@ -540,17 +554,16 @@ class ReactNativeBleTransport {
|
|
|
540
554
|
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
555
|
return;
|
|
542
556
|
}
|
|
557
|
+
if (this.monitorTokens.get(uuid) !== monitorToken) {
|
|
558
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale generation: ', device === null || device === void 0 ? void 0 : device.id);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
543
561
|
try {
|
|
544
562
|
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) {
|
|
563
|
+
this.emitDeviceDisconnect(uuid, device === null || device === void 0 ? void 0 : device.name, monitorToken);
|
|
564
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
551
565
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
552
566
|
this.runPromise.reject(error);
|
|
553
|
-
this.rejectAllProtocolV2Frames(error);
|
|
554
567
|
}
|
|
555
568
|
}
|
|
556
569
|
catch (e) {
|
|
@@ -561,6 +574,22 @@ class ReactNativeBleTransport {
|
|
|
561
574
|
}
|
|
562
575
|
});
|
|
563
576
|
}
|
|
577
|
+
emitDeviceDisconnect(uuid, name, token) {
|
|
578
|
+
var _a;
|
|
579
|
+
if (token === undefined || this.disconnectEventTokens.get(uuid) === token) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (this.monitorTokens.get(uuid) !== token) {
|
|
583
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect event ignored for stale generation: ', uuid);
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
this.disconnectEventTokens.set(uuid, token);
|
|
587
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
588
|
+
name,
|
|
589
|
+
id: uuid,
|
|
590
|
+
connectId: uuid,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
564
593
|
reconnectFirmwareUploadTransport(uuid, transport) {
|
|
565
594
|
var _a, _b;
|
|
566
595
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -574,19 +603,19 @@ class ReactNativeBleTransport {
|
|
|
574
603
|
const isConnected = yield device.isConnected().catch(() => false);
|
|
575
604
|
if (!isConnected) {
|
|
576
605
|
try {
|
|
577
|
-
device = yield device.connect(connectOptions);
|
|
606
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect(connectOptions));
|
|
578
607
|
}
|
|
579
608
|
catch (e) {
|
|
580
609
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
581
610
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
582
|
-
device = yield device.connect();
|
|
611
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect());
|
|
583
612
|
}
|
|
584
613
|
else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
585
614
|
throw e;
|
|
586
615
|
}
|
|
587
616
|
}
|
|
588
617
|
}
|
|
589
|
-
const { writeCharacteristic, notifyCharacteristic } = yield this.
|
|
618
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, device);
|
|
590
619
|
transport.device = device;
|
|
591
620
|
transport.writeCharacteristic = writeCharacteristic;
|
|
592
621
|
transport.notifyCharacteristic = notifyCharacteristic;
|
|
@@ -634,7 +663,7 @@ class ReactNativeBleTransport {
|
|
|
634
663
|
allowDuplicates: true,
|
|
635
664
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
636
665
|
}, (error, device) => {
|
|
637
|
-
var _a, _b
|
|
666
|
+
var _a, _b;
|
|
638
667
|
if (error) {
|
|
639
668
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
640
669
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
@@ -655,9 +684,14 @@ class ReactNativeBleTransport {
|
|
|
655
684
|
return;
|
|
656
685
|
}
|
|
657
686
|
const displayName = getDeviceDisplayName(device);
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
687
|
+
const isUnnamedIOSPeripheral = reactNative.Platform.OS === 'ios' && !(displayName === null || displayName === void 0 ? void 0 : displayName.trim());
|
|
688
|
+
const isOneKey = !isUnnamedIOSPeripheral &&
|
|
689
|
+
hdShared.isOnekeyBluetoothDevice({
|
|
690
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
691
|
+
name: device === null || device === void 0 ? void 0 : device.name,
|
|
692
|
+
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
693
|
+
serviceUuids: (_b = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _b !== void 0 ? _b : getBluetoothServiceUuids(),
|
|
694
|
+
});
|
|
661
695
|
if (isOneKey) {
|
|
662
696
|
addDevice(device);
|
|
663
697
|
}
|
|
@@ -672,10 +706,15 @@ class ReactNativeBleTransport {
|
|
|
672
706
|
});
|
|
673
707
|
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
674
708
|
for (const device of devices) {
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
if (
|
|
709
|
+
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
710
|
+
? device.localName
|
|
711
|
+
: null;
|
|
712
|
+
if (hdShared.isOnekeyBluetoothDevice({
|
|
713
|
+
id: device.id,
|
|
714
|
+
name: device.name,
|
|
715
|
+
localName,
|
|
716
|
+
serviceUuids: device.serviceUUIDs,
|
|
717
|
+
})) {
|
|
679
718
|
Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
|
|
680
719
|
addDevice(device);
|
|
681
720
|
}
|
|
@@ -685,16 +724,11 @@ class ReactNativeBleTransport {
|
|
|
685
724
|
var _a;
|
|
686
725
|
if (deviceList.every(d => d.id !== device.id)) {
|
|
687
726
|
const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
|
|
688
|
-
const protocolHint = inferProtocolHintFromDeviceName(displayName);
|
|
689
|
-
if (protocolHint) {
|
|
690
|
-
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
691
|
-
}
|
|
692
727
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
693
728
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
694
729
|
deviceId: device.id,
|
|
695
730
|
name: displayName,
|
|
696
731
|
serviceUUIDs: device.serviceUUIDs,
|
|
697
|
-
protocolHint,
|
|
698
732
|
});
|
|
699
733
|
}
|
|
700
734
|
};
|
|
@@ -705,32 +739,113 @@ class ReactNativeBleTransport {
|
|
|
705
739
|
}));
|
|
706
740
|
});
|
|
707
741
|
}
|
|
742
|
+
installTransportForAcquire(uuid, device, characteristics) {
|
|
743
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
744
|
+
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
|
|
745
|
+
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
746
|
+
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
|
|
747
|
+
const monitorToken = this.nextMonitorToken;
|
|
748
|
+
this.nextMonitorToken += 1;
|
|
749
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
750
|
+
transport$1.monitorToken = monitorToken;
|
|
751
|
+
transport$1.notifyTransactionId = notifyTransactionId;
|
|
752
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
753
|
+
transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
754
|
+
transportCache[uuid] = transport$1;
|
|
755
|
+
this.protocolV2HighVolumeLogSignatures.set(uuid, new Set());
|
|
756
|
+
this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
757
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
758
|
+
yield new Promise(resolve => {
|
|
759
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
else if (reactNative.Platform.OS === 'android') {
|
|
763
|
+
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
764
|
+
}
|
|
765
|
+
const initialMtu = transport$1.mtuSize;
|
|
766
|
+
let refreshAttempts = 0;
|
|
767
|
+
if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
|
|
768
|
+
shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
769
|
+
refreshAttempts += 1;
|
|
770
|
+
let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
|
|
771
|
+
transport$1.device = refreshedDevice;
|
|
772
|
+
transport$1.mtuSize =
|
|
773
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
774
|
+
if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
775
|
+
yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
776
|
+
refreshAttempts += 1;
|
|
777
|
+
refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
|
|
778
|
+
transport$1.device = refreshedDevice;
|
|
779
|
+
transport$1.mtuSize =
|
|
780
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
784
|
+
platform: reactNative.Platform.OS,
|
|
785
|
+
requested: getRequestedBleMtu(),
|
|
786
|
+
initial: initialMtu,
|
|
787
|
+
actual: transport$1.mtuSize,
|
|
788
|
+
refreshAttempts,
|
|
789
|
+
});
|
|
790
|
+
return transport$1;
|
|
791
|
+
});
|
|
792
|
+
}
|
|
708
793
|
acquire(input) {
|
|
709
|
-
var _a, _b;
|
|
710
794
|
return __awaiter(this, void 0, void 0, function* () {
|
|
711
|
-
const { uuid
|
|
795
|
+
const { uuid } = input;
|
|
712
796
|
if (!uuid) {
|
|
713
797
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
|
|
714
798
|
}
|
|
799
|
+
return this.runLifecycleOperation(uuid, () => this.acquireUnlocked(input));
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
acquireUnlocked(input) {
|
|
803
|
+
var _a;
|
|
804
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
805
|
+
const { uuid, forceCleanRunPromise, expectedProtocol, skipProtocolProbe } = input;
|
|
715
806
|
const cachedTransport = transportCache[uuid];
|
|
807
|
+
if (skipProtocolProbe && !cachedTransport && this.blePlxManager) {
|
|
808
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] refresh uncached BLE connection for firmware install:', uuid);
|
|
809
|
+
const manager = this.blePlxManager;
|
|
810
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
811
|
+
yield this.runBestEffortNativeOperation('firmware install reconnect: cancel uncached device connection', () => manager.cancelDeviceConnection(uuid));
|
|
812
|
+
}));
|
|
813
|
+
}
|
|
716
814
|
if (cachedTransport) {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
(
|
|
722
|
-
|
|
723
|
-
|
|
815
|
+
if (skipProtocolProbe) {
|
|
816
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] refresh cached BLE connection for firmware install:', uuid);
|
|
817
|
+
const manager = this.blePlxManager;
|
|
818
|
+
yield this.releaseUnlocked(uuid, true);
|
|
819
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
820
|
+
const operations = [];
|
|
821
|
+
if (manager) {
|
|
822
|
+
operations.push(this.runBestEffortNativeOperation('firmware install reconnect: cancel device connection', () => manager.cancelDeviceConnection(uuid)));
|
|
823
|
+
}
|
|
824
|
+
operations.push(this.runBestEffortNativeOperation('firmware install reconnect: device cancel connection', () => cachedTransport.device.cancelConnection()));
|
|
825
|
+
yield Promise.all(operations);
|
|
826
|
+
}));
|
|
827
|
+
}
|
|
828
|
+
else {
|
|
829
|
+
const cachedProtocol = this.deviceProtocol.get(uuid);
|
|
830
|
+
const isCachedDeviceConnected = yield cachedTransport.device
|
|
831
|
+
.isConnected()
|
|
832
|
+
.catch(() => false);
|
|
833
|
+
if (isCachedDeviceConnected &&
|
|
834
|
+
cachedProtocol &&
|
|
835
|
+
(!expectedProtocol || cachedProtocol === expectedProtocol)) {
|
|
836
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
|
|
837
|
+
return { uuid, protocolType: cachedProtocol };
|
|
838
|
+
}
|
|
839
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
840
|
+
yield this.releaseUnlocked(uuid, true);
|
|
724
841
|
}
|
|
725
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
|
|
726
|
-
yield this.release(uuid, true);
|
|
727
842
|
}
|
|
728
843
|
let device = null;
|
|
729
844
|
if (forceCleanRunPromise && this.runPromise) {
|
|
730
845
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
731
846
|
this.runPromise.reject(error);
|
|
732
|
-
this.rejectAllProtocolV2Frames(error);
|
|
733
847
|
this.runPromise = null;
|
|
848
|
+
this.runPromiseDeviceId = null;
|
|
734
849
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
735
850
|
}
|
|
736
851
|
const blePlxManager = yield this.getPlxManager();
|
|
@@ -763,14 +878,17 @@ class ReactNativeBleTransport {
|
|
|
763
878
|
if (!device) {
|
|
764
879
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
|
|
765
880
|
try {
|
|
766
|
-
device = yield blePlxManager.connectToDevice(uuid, connectOptions);
|
|
881
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, connectOptions));
|
|
767
882
|
}
|
|
768
883
|
catch (e) {
|
|
769
884
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
885
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
886
|
+
throw e;
|
|
887
|
+
}
|
|
770
888
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
771
889
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
772
890
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
773
|
-
device = yield blePlxManager.connectToDevice(uuid);
|
|
891
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
774
892
|
}
|
|
775
893
|
else if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
776
894
|
Log === null || Log === void 0 ? void 0 : Log.debug('device already connected');
|
|
@@ -786,23 +904,27 @@ class ReactNativeBleTransport {
|
|
|
786
904
|
}
|
|
787
905
|
if (!(yield device.isConnected())) {
|
|
788
906
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
907
|
+
const disconnectedDevice = device;
|
|
789
908
|
try {
|
|
790
|
-
device = yield
|
|
909
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(connectOptions));
|
|
791
910
|
}
|
|
792
911
|
catch (e) {
|
|
793
912
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
913
|
+
if (shouldRethrowBleSetupError(e)) {
|
|
914
|
+
throw e;
|
|
915
|
+
}
|
|
794
916
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
795
917
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
796
918
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
797
919
|
try {
|
|
798
|
-
device = yield
|
|
920
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
799
921
|
}
|
|
800
922
|
catch (e) {
|
|
801
923
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
|
|
802
924
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
803
925
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
804
|
-
yield
|
|
805
|
-
device = yield
|
|
926
|
+
yield disconnectedDevice.cancelConnection();
|
|
927
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
806
928
|
}
|
|
807
929
|
}
|
|
808
930
|
}
|
|
@@ -811,44 +933,62 @@ class ReactNativeBleTransport {
|
|
|
811
933
|
}
|
|
812
934
|
}
|
|
813
935
|
}
|
|
814
|
-
device = yield
|
|
815
|
-
const
|
|
936
|
+
device = yield resolveNegotiatedMtu(device);
|
|
937
|
+
const acquiredDevice = device;
|
|
938
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
|
|
816
939
|
const protocolHint = expectedProtocol
|
|
817
940
|
? undefined
|
|
818
|
-
: (_a =
|
|
819
|
-
yield this.
|
|
941
|
+
: (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid);
|
|
942
|
+
yield this.releaseUnlocked(uuid, true);
|
|
820
943
|
if (protocolHint) {
|
|
821
944
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
822
945
|
}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
946
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice, {
|
|
947
|
+
writeCharacteristic,
|
|
948
|
+
notifyCharacteristic,
|
|
949
|
+
});
|
|
950
|
+
try {
|
|
951
|
+
if (skipProtocolProbe) {
|
|
952
|
+
if (!expectedProtocol) {
|
|
953
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'skipProtocolProbe requires an expected BLE protocol');
|
|
954
|
+
}
|
|
955
|
+
if (this.sessionProtocols.get(uuid) !== expectedProtocol) {
|
|
956
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'skipProtocolProbe requires a previously confirmed protocol for this BLE endpoint');
|
|
957
|
+
}
|
|
958
|
+
this.deviceProtocol.set(uuid, expectedProtocol);
|
|
959
|
+
this.sessionProtocols.set(uuid, expectedProtocol);
|
|
960
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
961
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected without probe', {
|
|
962
|
+
deviceId: uuid,
|
|
963
|
+
protocol: expectedProtocol,
|
|
964
|
+
source: 'firmware-install-reconnect',
|
|
965
|
+
});
|
|
966
|
+
const currentTransport = transportCache[uuid];
|
|
967
|
+
if (!currentTransport) {
|
|
968
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
969
|
+
}
|
|
970
|
+
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
971
|
+
return { uuid, protocolType: expectedProtocol };
|
|
972
|
+
}
|
|
973
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
974
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
975
|
+
}));
|
|
976
|
+
const currentTransport = transportCache[uuid];
|
|
977
|
+
if (!currentTransport) {
|
|
978
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
979
|
+
}
|
|
980
|
+
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
981
|
+
return { uuid, protocolType };
|
|
840
982
|
}
|
|
841
|
-
|
|
842
|
-
|
|
983
|
+
catch (error) {
|
|
984
|
+
if ((error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleDeviceBondError) {
|
|
985
|
+
yield this.disconnectUnlocked(uuid);
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
yield this.releaseUnlocked(uuid, true);
|
|
989
|
+
}
|
|
990
|
+
throw error;
|
|
843
991
|
}
|
|
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
992
|
});
|
|
853
993
|
}
|
|
854
994
|
_monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
|
|
@@ -867,7 +1007,7 @@ class ReactNativeBleTransport {
|
|
|
867
1007
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
868
1008
|
return;
|
|
869
1009
|
}
|
|
870
|
-
if (this.
|
|
1010
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
871
1011
|
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
872
1012
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
873
1013
|
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
@@ -885,7 +1025,7 @@ class ReactNativeBleTransport {
|
|
|
885
1025
|
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
886
1026
|
return;
|
|
887
1027
|
}
|
|
888
|
-
if (this.runPromise) {
|
|
1028
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
889
1029
|
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
890
1030
|
if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
|
|
891
1031
|
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
@@ -900,13 +1040,11 @@ class ReactNativeBleTransport {
|
|
|
900
1040
|
((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
|
|
901
1041
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
902
1042
|
this.runPromise.reject(notifyError);
|
|
903
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
904
1043
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
905
1044
|
return;
|
|
906
1045
|
}
|
|
907
1046
|
const notifyError = hdShared.ERRORS.TypedError(ERROR);
|
|
908
1047
|
this.runPromise.reject(notifyError);
|
|
909
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
910
1048
|
Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
911
1049
|
}
|
|
912
1050
|
return;
|
|
@@ -920,7 +1058,7 @@ class ReactNativeBleTransport {
|
|
|
920
1058
|
}
|
|
921
1059
|
try {
|
|
922
1060
|
const data = buffer.Buffer.from(c.value, 'base64');
|
|
923
|
-
const protocol = this.
|
|
1061
|
+
const protocol = this.getActiveProtocol(uuid);
|
|
924
1062
|
if (!protocol) {
|
|
925
1063
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
|
|
926
1064
|
return;
|
|
@@ -940,16 +1078,18 @@ class ReactNativeBleTransport {
|
|
|
940
1078
|
const value = buffer.Buffer.from(buffer$1);
|
|
941
1079
|
bufferLength = 0;
|
|
942
1080
|
buffer$1 = [];
|
|
943
|
-
(
|
|
1081
|
+
if (this.runPromiseDeviceId === uuid) {
|
|
1082
|
+
(_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
|
|
1083
|
+
}
|
|
944
1084
|
}
|
|
945
1085
|
}
|
|
946
1086
|
catch (error) {
|
|
947
1087
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
948
1088
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
949
|
-
if (this.
|
|
1089
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
950
1090
|
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
951
1091
|
}
|
|
952
|
-
else {
|
|
1092
|
+
else if (this.runPromiseDeviceId === uuid) {
|
|
953
1093
|
(_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
|
|
954
1094
|
}
|
|
955
1095
|
}
|
|
@@ -957,15 +1097,27 @@ class ReactNativeBleTransport {
|
|
|
957
1097
|
return subscription;
|
|
958
1098
|
}
|
|
959
1099
|
release(uuid, onclose = false) {
|
|
960
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
961
1100
|
return __awaiter(this, void 0, void 0, function* () {
|
|
962
|
-
|
|
1101
|
+
return this.runLifecycleOperation(uuid, () => this.releaseUnlocked(uuid, onclose));
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
1104
|
+
releaseUnlocked(uuid, onclose = false) {
|
|
1105
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
963
1106
|
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
964
|
-
|
|
1107
|
+
return this.releaseNative(uuid, onclose);
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
releaseNative(uuid, onclose = false) {
|
|
1111
|
+
var _a, _b, _c, _d, _e;
|
|
1112
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1113
|
+
const transport = transportCache[uuid];
|
|
1114
|
+
const manager = this.blePlxManager;
|
|
1115
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
965
1116
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
966
1117
|
this.runPromise.reject(error);
|
|
967
1118
|
this.runPromise = null;
|
|
968
|
-
this.
|
|
1119
|
+
this.runPromiseDeviceId = null;
|
|
1120
|
+
this.rejectProtocolV2Frames(uuid, error);
|
|
969
1121
|
}
|
|
970
1122
|
else {
|
|
971
1123
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -985,31 +1137,37 @@ class ReactNativeBleTransport {
|
|
|
985
1137
|
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);
|
|
986
1138
|
(_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
|
|
987
1139
|
transport.notifySubscription = undefined;
|
|
988
|
-
if (transport
|
|
989
|
-
|
|
990
|
-
yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
|
|
991
|
-
}
|
|
992
|
-
catch (e) {
|
|
993
|
-
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);
|
|
994
|
-
}
|
|
1140
|
+
if (transportCache[uuid] === transport) {
|
|
1141
|
+
delete transportCache[uuid];
|
|
995
1142
|
}
|
|
996
|
-
delete transportCache[uuid];
|
|
997
1143
|
}
|
|
1144
|
+
this.protocolV2HighVolumeLogSignatures.delete(uuid);
|
|
998
1145
|
this.deviceProtocol.delete(uuid);
|
|
999
|
-
|
|
1146
|
+
this.probingProtocols.delete(uuid);
|
|
1147
|
+
(_e = this.protocolV2Assemblers.get(uuid)) === null || _e === void 0 ? void 0 : _e.reset();
|
|
1000
1148
|
this.protocolV2Assemblers.delete(uuid);
|
|
1001
1149
|
this.resetProtocolV2Frames(uuid);
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1150
|
+
yield this.runNativeTeardown(uuid, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1151
|
+
const operations = [
|
|
1152
|
+
this.runBestEffortNativeOperation('release: restore connection priority', () => this.restoreAndroidConnectionPriority(uuid, transport)),
|
|
1153
|
+
];
|
|
1154
|
+
if ((transport === null || transport === void 0 ? void 0 : transport.notifyTransactionId) && manager) {
|
|
1155
|
+
operations.push(this.runBestEffortNativeOperation('release: cancel notify transaction', () => manager.cancelTransaction(transport.notifyTransactionId)));
|
|
1156
|
+
}
|
|
1157
|
+
if (manager) {
|
|
1158
|
+
operations.push(this.runBestEffortNativeOperation('release: cancel transaction', () => manager.cancelTransaction(uuid)));
|
|
1159
|
+
}
|
|
1160
|
+
yield Promise.all(operations);
|
|
1161
|
+
}));
|
|
1008
1162
|
return Promise.resolve(true);
|
|
1009
1163
|
});
|
|
1010
1164
|
}
|
|
1011
1165
|
post(session, name, data) {
|
|
1012
1166
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1167
|
+
if (this.getProtocolType(session) === 'V2') {
|
|
1168
|
+
yield this.protocolV2Links.sendFlowControl(session, () => this.createProtocolV2Adapter(session), name, data);
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1013
1171
|
yield this.call(session, name, data);
|
|
1014
1172
|
});
|
|
1015
1173
|
}
|
|
@@ -1025,7 +1183,6 @@ class ReactNativeBleTransport {
|
|
|
1025
1183
|
if (!protocol) {
|
|
1026
1184
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1027
1185
|
}
|
|
1028
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport call', createTransportCallLog(name, protocol, data));
|
|
1029
1186
|
if (protocol === 'V2') {
|
|
1030
1187
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1031
1188
|
}
|
|
@@ -1044,7 +1201,19 @@ class ReactNativeBleTransport {
|
|
|
1044
1201
|
const transport = this.getCachedTransport(uuid);
|
|
1045
1202
|
const runPromise = hdShared.createDeferred();
|
|
1046
1203
|
runPromise.promise.catch(() => undefined);
|
|
1204
|
+
const supersededRunPromise = this.runPromise;
|
|
1205
|
+
if (supersededRunPromise) {
|
|
1206
|
+
supersededRunPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
|
|
1207
|
+
}
|
|
1047
1208
|
this.runPromise = runPromise;
|
|
1209
|
+
this.runPromiseDeviceId = uuid;
|
|
1210
|
+
const releaseOwnershipIfCurrent = () => {
|
|
1211
|
+
if (this.runPromise === runPromise) {
|
|
1212
|
+
this.runPromise = null;
|
|
1213
|
+
this.runPromiseDeviceId = null;
|
|
1214
|
+
}
|
|
1215
|
+
};
|
|
1216
|
+
const isCurrentOwner = () => this.runPromise === runPromise;
|
|
1048
1217
|
const messages = this._messages;
|
|
1049
1218
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1050
1219
|
let timeout;
|
|
@@ -1065,6 +1234,9 @@ class ReactNativeBleTransport {
|
|
|
1065
1234
|
}
|
|
1066
1235
|
catch (e) {
|
|
1067
1236
|
onError(e);
|
|
1237
|
+
if (isWedgedWriteError(e)) {
|
|
1238
|
+
throw e;
|
|
1239
|
+
}
|
|
1068
1240
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1069
1241
|
}
|
|
1070
1242
|
}
|
|
@@ -1092,6 +1264,9 @@ class ReactNativeBleTransport {
|
|
|
1092
1264
|
}
|
|
1093
1265
|
catch (e) {
|
|
1094
1266
|
onError(e);
|
|
1267
|
+
if (isWedgedWriteError(e)) {
|
|
1268
|
+
throw e;
|
|
1269
|
+
}
|
|
1095
1270
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1096
1271
|
}
|
|
1097
1272
|
}
|
|
@@ -1102,8 +1277,8 @@ class ReactNativeBleTransport {
|
|
|
1102
1277
|
});
|
|
1103
1278
|
}
|
|
1104
1279
|
if (name === 'EmmcFileWrite') {
|
|
1105
|
-
yield writeChunkedData(buffers, data => transport.writeWithRetry(
|
|
1106
|
-
|
|
1280
|
+
yield writeChunkedData(buffers, data => this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner), e => {
|
|
1281
|
+
releaseOwnershipIfCurrent();
|
|
1107
1282
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1108
1283
|
});
|
|
1109
1284
|
}
|
|
@@ -1119,7 +1294,7 @@ class ReactNativeBleTransport {
|
|
|
1119
1294
|
let attempt = 0;
|
|
1120
1295
|
while (true) {
|
|
1121
1296
|
try {
|
|
1122
|
-
yield transport.
|
|
1297
|
+
yield this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner);
|
|
1123
1298
|
return;
|
|
1124
1299
|
}
|
|
1125
1300
|
catch (error) {
|
|
@@ -1127,36 +1302,18 @@ class ReactNativeBleTransport {
|
|
|
1127
1302
|
if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1128
1303
|
throw error;
|
|
1129
1304
|
}
|
|
1130
|
-
const
|
|
1131
|
-
const delayMs = shouldReconnect
|
|
1132
|
-
? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
|
|
1133
|
-
: resolveFirmwareUploadRetryDelay(attempt);
|
|
1305
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1134
1306
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
|
|
1135
1307
|
attempt: attempt + 1,
|
|
1136
1308
|
delayMs,
|
|
1137
|
-
reconnect: shouldReconnect,
|
|
1138
1309
|
error,
|
|
1139
1310
|
});
|
|
1140
|
-
if (shouldReconnect) {
|
|
1141
|
-
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
1142
|
-
}
|
|
1143
1311
|
yield delay(delayMs);
|
|
1144
1312
|
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
1313
|
}
|
|
1157
1314
|
}
|
|
1158
1315
|
}), e => {
|
|
1159
|
-
|
|
1316
|
+
releaseOwnershipIfCurrent();
|
|
1160
1317
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1161
1318
|
});
|
|
1162
1319
|
}
|
|
@@ -1164,11 +1321,17 @@ class ReactNativeBleTransport {
|
|
|
1164
1321
|
for (const o of buffers) {
|
|
1165
1322
|
const outData = o.toString('base64');
|
|
1166
1323
|
try {
|
|
1167
|
-
|
|
1324
|
+
const shouldUseWriteWithResponse = reactNative.Platform.OS === 'ios' && transport.writeCharacteristic.isWritableWithResponse;
|
|
1325
|
+
yield this.writeBlePacket(uuid, outData, payload => shouldUseWriteWithResponse
|
|
1326
|
+
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
1327
|
+
: transport.writeCharacteristic.writeWithoutResponse(payload), isCurrentOwner);
|
|
1168
1328
|
}
|
|
1169
1329
|
catch (e) {
|
|
1170
1330
|
Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
|
|
1171
|
-
|
|
1331
|
+
releaseOwnershipIfCurrent();
|
|
1332
|
+
if (isWedgedWriteError(e)) {
|
|
1333
|
+
throw e;
|
|
1334
|
+
}
|
|
1172
1335
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected) {
|
|
1173
1336
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded);
|
|
1174
1337
|
}
|
|
@@ -1201,12 +1364,19 @@ class ReactNativeBleTransport {
|
|
|
1201
1364
|
return check.call(jsonData);
|
|
1202
1365
|
}
|
|
1203
1366
|
catch (e) {
|
|
1204
|
-
if (name === '
|
|
1205
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1367
|
+
if (name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
|
|
1368
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
|
|
1206
1369
|
}
|
|
1207
1370
|
else {
|
|
1208
1371
|
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1209
1372
|
}
|
|
1373
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1374
|
+
const isStaleCall = this.runPromise !== runPromise;
|
|
1375
|
+
if (!isProbeTimeout &&
|
|
1376
|
+
!isStaleCall &&
|
|
1377
|
+
(e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1378
|
+
yield this.disconnect(uuid);
|
|
1379
|
+
}
|
|
1210
1380
|
throw e;
|
|
1211
1381
|
}
|
|
1212
1382
|
finally {
|
|
@@ -1214,6 +1384,7 @@ class ReactNativeBleTransport {
|
|
|
1214
1384
|
clearTimeout(timeout);
|
|
1215
1385
|
if (this.runPromise === runPromise) {
|
|
1216
1386
|
this.runPromise = null;
|
|
1387
|
+
this.runPromiseDeviceId = null;
|
|
1217
1388
|
}
|
|
1218
1389
|
}
|
|
1219
1390
|
});
|
|
@@ -1222,10 +1393,17 @@ class ReactNativeBleTransport {
|
|
|
1222
1393
|
this.stopped = true;
|
|
1223
1394
|
}
|
|
1224
1395
|
disconnect(session) {
|
|
1225
|
-
|
|
1396
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1397
|
+
return this.runLifecycleOperation(session, () => this.disconnectUnlocked(session));
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
disconnectUnlocked(session) {
|
|
1401
|
+
var _a, _b, _c;
|
|
1226
1402
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1227
1403
|
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1228
1404
|
const transport = transportCache[session];
|
|
1405
|
+
const manager = this.blePlxManager;
|
|
1406
|
+
const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
|
|
1229
1407
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
1230
1408
|
try {
|
|
1231
1409
|
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing disconnect subscription');
|
|
@@ -1238,7 +1416,7 @@ class ReactNativeBleTransport {
|
|
|
1238
1416
|
}
|
|
1239
1417
|
if (transport === null || transport === void 0 ? void 0 : transport.notifySubscription) {
|
|
1240
1418
|
try {
|
|
1241
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (
|
|
1419
|
+
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
1420
|
transport.notifySubscription.remove();
|
|
1243
1421
|
transport.notifySubscription = undefined;
|
|
1244
1422
|
}
|
|
@@ -1246,52 +1424,201 @@ class ReactNativeBleTransport {
|
|
|
1246
1424
|
Log === null || Log === void 0 ? void 0 : Log.error('disconnect: remove notify subscription error: ', e);
|
|
1247
1425
|
}
|
|
1248
1426
|
}
|
|
1249
|
-
if (session) {
|
|
1250
|
-
try {
|
|
1251
|
-
yield ((_b = this.blePlxManager) === null || _b === void 0 ? void 0 : _b.cancelTransaction(session));
|
|
1252
|
-
}
|
|
1253
|
-
catch (e) {
|
|
1254
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
if (transport === null || transport === void 0 ? void 0 : transport.device) {
|
|
1258
|
-
try {
|
|
1259
|
-
yield transport.device.cancelConnection();
|
|
1260
|
-
}
|
|
1261
|
-
catch (e) {
|
|
1262
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: device.cancelConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
try {
|
|
1266
|
-
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelDeviceConnection(session));
|
|
1267
|
-
}
|
|
1268
|
-
catch (e) {
|
|
1269
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
1270
|
-
}
|
|
1271
|
-
if (transportCache[session]) {
|
|
1427
|
+
if (!transport || transportCache[session] === transport) {
|
|
1272
1428
|
delete transportCache[session];
|
|
1273
1429
|
}
|
|
1274
1430
|
this.deviceProtocol.delete(session);
|
|
1431
|
+
this.probingProtocols.delete(session);
|
|
1275
1432
|
this.deviceProtocolHints.delete(session);
|
|
1433
|
+
this.sessionProtocols.delete(session);
|
|
1434
|
+
this.protocolReprobeFailures.delete(session);
|
|
1276
1435
|
this.protocolV2Assemblers.delete(session);
|
|
1277
1436
|
this.resetProtocolV2Frames(session);
|
|
1278
1437
|
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
|
-
});
|
|
1438
|
+
this.emitDeviceDisconnect(session, (_c = transport === null || transport === void 0 ? void 0 : transport.device) === null || _c === void 0 ? void 0 : _c.name, monitorToken);
|
|
1284
1439
|
}
|
|
1285
1440
|
catch (e) {
|
|
1286
1441
|
Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
|
|
1287
1442
|
}
|
|
1443
|
+
if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
|
|
1444
|
+
this.monitorTokens.delete(session);
|
|
1445
|
+
}
|
|
1446
|
+
yield this.runNativeTeardown(session, manager, () => __awaiter(this, void 0, void 0, function* () {
|
|
1447
|
+
const operations = [];
|
|
1448
|
+
if (manager) {
|
|
1449
|
+
operations.push(this.runBestEffortNativeOperation('disconnect: cancel transaction', () => manager.cancelTransaction(session)));
|
|
1450
|
+
operations.push(this.runBestEffortNativeOperation('disconnect: cancel device connection', () => manager.cancelDeviceConnection(session)));
|
|
1451
|
+
}
|
|
1452
|
+
if (transport === null || transport === void 0 ? void 0 : transport.device) {
|
|
1453
|
+
operations.push(this.runBestEffortNativeOperation('disconnect: device cancel connection', () => transport.device.cancelConnection()));
|
|
1454
|
+
}
|
|
1455
|
+
yield Promise.all(operations);
|
|
1456
|
+
}));
|
|
1288
1457
|
yield new Promise(resolve => setTimeout(() => resolve(), 100));
|
|
1289
1458
|
});
|
|
1290
1459
|
}
|
|
1460
|
+
runNativeTeardown(uuid, manager, teardown) {
|
|
1461
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1462
|
+
let timer;
|
|
1463
|
+
let timedOut = false;
|
|
1464
|
+
const pending = Promise.resolve()
|
|
1465
|
+
.then(teardown)
|
|
1466
|
+
.catch(error => {
|
|
1467
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE native teardown error (ignored): ', (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
1468
|
+
});
|
|
1469
|
+
try {
|
|
1470
|
+
yield Promise.race([
|
|
1471
|
+
pending,
|
|
1472
|
+
new Promise(resolve => {
|
|
1473
|
+
timer = setTimeout(() => {
|
|
1474
|
+
timedOut = true;
|
|
1475
|
+
resolve();
|
|
1476
|
+
}, BLE_NATIVE_TEARDOWN_TIMEOUT_MS);
|
|
1477
|
+
}),
|
|
1478
|
+
]);
|
|
1479
|
+
}
|
|
1480
|
+
finally {
|
|
1481
|
+
if (timer)
|
|
1482
|
+
clearTimeout(timer);
|
|
1483
|
+
}
|
|
1484
|
+
if (timedOut) {
|
|
1485
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE native teardown timed out:', uuid);
|
|
1486
|
+
if (this.blePlxManager === manager) {
|
|
1487
|
+
this.resetPlxManager();
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
runBestEffortNativeOperation(label, operation) {
|
|
1493
|
+
return Promise.resolve()
|
|
1494
|
+
.then(operation)
|
|
1495
|
+
.catch(error => {
|
|
1496
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`${label} error (ignored): `, (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
runLifecycleOperation(uuid, operation) {
|
|
1500
|
+
var _a;
|
|
1501
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1502
|
+
const previousOperation = (_a = this.lifecycleOperations.get(uuid)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
1503
|
+
let completeOperation;
|
|
1504
|
+
const operationGate = new Promise(resolve => {
|
|
1505
|
+
completeOperation = resolve;
|
|
1506
|
+
});
|
|
1507
|
+
const operationTail = previousOperation.catch(() => undefined).then(() => operationGate);
|
|
1508
|
+
this.lifecycleOperations.set(uuid, operationTail);
|
|
1509
|
+
yield previousOperation.catch(() => undefined);
|
|
1510
|
+
try {
|
|
1511
|
+
return yield operation();
|
|
1512
|
+
}
|
|
1513
|
+
finally {
|
|
1514
|
+
completeOperation();
|
|
1515
|
+
if (this.lifecycleOperations.get(uuid) === operationTail) {
|
|
1516
|
+
this.lifecycleOperations.delete(uuid);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1291
1521
|
cancel() {
|
|
1292
1522
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1293
1523
|
if (this.runPromise) ;
|
|
1294
1524
|
this.runPromise = null;
|
|
1525
|
+
this.runPromiseDeviceId = null;
|
|
1526
|
+
}
|
|
1527
|
+
connectWithTimeout(uuid, connect) {
|
|
1528
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1529
|
+
let timer;
|
|
1530
|
+
let timedOut = false;
|
|
1531
|
+
const pending = connect();
|
|
1532
|
+
pending.catch(() => undefined);
|
|
1533
|
+
try {
|
|
1534
|
+
const result = yield Promise.race([
|
|
1535
|
+
pending,
|
|
1536
|
+
new Promise((_, reject) => {
|
|
1537
|
+
timer = setTimeout(() => {
|
|
1538
|
+
timedOut = true;
|
|
1539
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `BLE connect timeout after ${BLE_CONNECT_TIMEOUT_MS}ms for ${uuid}`));
|
|
1540
|
+
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1541
|
+
}),
|
|
1542
|
+
]);
|
|
1543
|
+
return result;
|
|
1544
|
+
}
|
|
1545
|
+
catch (error) {
|
|
1546
|
+
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1547
|
+
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1548
|
+
if (resetManager) {
|
|
1549
|
+
throw this.createWedgedBleSetupError();
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
throw error;
|
|
1553
|
+
}
|
|
1554
|
+
finally {
|
|
1555
|
+
if (timer)
|
|
1556
|
+
clearTimeout(timer);
|
|
1557
|
+
}
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
resolveCharacteristicsWithTimeout(uuid, device) {
|
|
1561
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1562
|
+
let timer;
|
|
1563
|
+
let timedOut = false;
|
|
1564
|
+
const pending = this.resolveCharacteristics(device);
|
|
1565
|
+
pending.catch(() => undefined);
|
|
1566
|
+
try {
|
|
1567
|
+
const result = yield Promise.race([
|
|
1568
|
+
pending,
|
|
1569
|
+
new Promise((_, reject) => {
|
|
1570
|
+
timer = setTimeout(() => {
|
|
1571
|
+
timedOut = true;
|
|
1572
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `BLE GATT setup timeout after ${BLE_GATT_SETUP_TIMEOUT_MS}ms for ${uuid}`));
|
|
1573
|
+
}, BLE_GATT_SETUP_TIMEOUT_MS);
|
|
1574
|
+
}),
|
|
1575
|
+
]);
|
|
1576
|
+
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1577
|
+
return result;
|
|
1578
|
+
}
|
|
1579
|
+
catch (error) {
|
|
1580
|
+
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1581
|
+
const resetManager = this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1582
|
+
if (resetManager) {
|
|
1583
|
+
throw this.createWedgedBleSetupError();
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
throw error;
|
|
1587
|
+
}
|
|
1588
|
+
finally {
|
|
1589
|
+
if (timer)
|
|
1590
|
+
clearTimeout(timer);
|
|
1591
|
+
}
|
|
1592
|
+
});
|
|
1593
|
+
}
|
|
1594
|
+
abandonStalledConnection(uuid, stage) {
|
|
1595
|
+
var _a, _b;
|
|
1596
|
+
const timeouts = ((_a = this.connectionSetupTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1597
|
+
this.connectionSetupTimeoutCounts.set(uuid, timeouts);
|
|
1598
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup timed out:', uuid, {
|
|
1599
|
+
stage,
|
|
1600
|
+
setupTimeoutsSinceSuccess: timeouts,
|
|
1601
|
+
});
|
|
1602
|
+
(_b = this.blePlxManager) === null || _b === void 0 ? void 0 : _b.cancelDeviceConnection(uuid).catch(() => {
|
|
1603
|
+
});
|
|
1604
|
+
const stalled = transportCache[uuid];
|
|
1605
|
+
if (stalled) {
|
|
1606
|
+
delete transportCache[uuid];
|
|
1607
|
+
}
|
|
1608
|
+
this.deviceProtocol.delete(uuid);
|
|
1609
|
+
this.probingProtocols.delete(uuid);
|
|
1610
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1611
|
+
this.resetProtocolV2Frames(uuid);
|
|
1612
|
+
if (timeouts >= BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1613
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
|
|
1614
|
+
this.resetPlxManager();
|
|
1615
|
+
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1616
|
+
return true;
|
|
1617
|
+
}
|
|
1618
|
+
return false;
|
|
1619
|
+
}
|
|
1620
|
+
createWedgedBleSetupError() {
|
|
1621
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.PollingTimeout, BLE_SETUP_WEDGED_MESSAGE);
|
|
1295
1622
|
}
|
|
1296
1623
|
getCachedTransport(uuid) {
|
|
1297
1624
|
const transport = transportCache[uuid];
|
|
@@ -1300,49 +1627,183 @@ class ReactNativeBleTransport {
|
|
|
1300
1627
|
}
|
|
1301
1628
|
return transport;
|
|
1302
1629
|
}
|
|
1303
|
-
|
|
1304
|
-
return
|
|
1630
|
+
writeBlePacket(uuid, data, write, isCurrentOwner) {
|
|
1631
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1632
|
+
let timer;
|
|
1633
|
+
let timedOut = false;
|
|
1634
|
+
try {
|
|
1635
|
+
yield Promise.race([
|
|
1636
|
+
write(data),
|
|
1637
|
+
new Promise((_, reject) => {
|
|
1638
|
+
timer = setTimeout(() => {
|
|
1639
|
+
timedOut = true;
|
|
1640
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write timeout after ${BLE_WRITE_PACKET_TIMEOUT_MS}ms`));
|
|
1641
|
+
}, BLE_WRITE_PACKET_TIMEOUT_MS);
|
|
1642
|
+
}),
|
|
1643
|
+
]);
|
|
1644
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1645
|
+
}
|
|
1646
|
+
catch (error) {
|
|
1647
|
+
if (timedOut) {
|
|
1648
|
+
if (isCurrentOwner && !isCurrentOwner()) {
|
|
1649
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] stale BLE write timed out, link kept:', uuid);
|
|
1650
|
+
}
|
|
1651
|
+
else {
|
|
1652
|
+
this.tearDownWedgedLink(uuid);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
throw error;
|
|
1656
|
+
}
|
|
1657
|
+
finally {
|
|
1658
|
+
if (timer)
|
|
1659
|
+
clearTimeout(timer);
|
|
1660
|
+
}
|
|
1661
|
+
});
|
|
1662
|
+
}
|
|
1663
|
+
tearDownWedgedLink(uuid) {
|
|
1664
|
+
var _a;
|
|
1665
|
+
const timeouts = ((_a = this.writeTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1666
|
+
this.writeTimeoutCounts.set(uuid, timeouts);
|
|
1667
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE write timed out, tearing down link:', uuid, {
|
|
1668
|
+
consecutiveWriteTimeouts: timeouts,
|
|
1669
|
+
});
|
|
1670
|
+
const wedged = transportCache[uuid];
|
|
1671
|
+
this.disconnect(uuid).catch(error => {
|
|
1672
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] wedged link teardown failed (ignored):', error);
|
|
1673
|
+
});
|
|
1674
|
+
if (wedged && transportCache[uuid] === wedged) {
|
|
1675
|
+
delete transportCache[uuid];
|
|
1676
|
+
}
|
|
1677
|
+
this.deviceProtocol.delete(uuid);
|
|
1678
|
+
this.probingProtocols.delete(uuid);
|
|
1679
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1680
|
+
this.resetProtocolV2Frames(uuid);
|
|
1681
|
+
if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1682
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE writes wedged repeatedly, resetting BLE manager');
|
|
1683
|
+
this.resetPlxManager();
|
|
1684
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
resetPlxManager() {
|
|
1688
|
+
const manager = this.blePlxManager;
|
|
1689
|
+
this.blePlxManager = undefined;
|
|
1690
|
+
const reason = 'React Native BLE manager reset';
|
|
1691
|
+
Object.entries(transportCache).forEach(([uuid, cachedTransport]) => {
|
|
1692
|
+
var _a, _b, _c, _d;
|
|
1693
|
+
try {
|
|
1694
|
+
(_a = cachedTransport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
1695
|
+
}
|
|
1696
|
+
catch (error) {
|
|
1697
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset disconnect subscription removal failed:', error);
|
|
1698
|
+
}
|
|
1699
|
+
cachedTransport.disconnectSubscription = undefined;
|
|
1700
|
+
try {
|
|
1701
|
+
(_b = cachedTransport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1702
|
+
}
|
|
1703
|
+
catch (error) {
|
|
1704
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset notify subscription removal failed:', error);
|
|
1705
|
+
}
|
|
1706
|
+
cachedTransport.notifySubscription = undefined;
|
|
1707
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1708
|
+
try {
|
|
1709
|
+
this.emitDeviceDisconnect(uuid, (_c = cachedTransport.device) === null || _c === void 0 ? void 0 : _c.name, (_d = cachedTransport.monitorToken) !== null && _d !== void 0 ? _d : this.monitorTokens.get(uuid));
|
|
1710
|
+
}
|
|
1711
|
+
catch (error) {
|
|
1712
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('BLE manager reset disconnect event failed:', error);
|
|
1713
|
+
}
|
|
1714
|
+
delete transportCache[uuid];
|
|
1715
|
+
});
|
|
1716
|
+
this.protocolV2Links.invalidateAllLinks(reason).catch(error => {
|
|
1717
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager link invalidation failed:', error);
|
|
1718
|
+
});
|
|
1719
|
+
this.deviceProtocol.clear();
|
|
1720
|
+
this.probingProtocols.clear();
|
|
1721
|
+
this.sessionProtocols.clear();
|
|
1722
|
+
this.confirmedProtocolV2.clear();
|
|
1723
|
+
this.protocolReprobeFailures.clear();
|
|
1724
|
+
this.writeTimeoutCounts.clear();
|
|
1725
|
+
this.connectionSetupTimeoutCounts.clear();
|
|
1726
|
+
this.monitorTokens.clear();
|
|
1727
|
+
this.protocolV2Assemblers.clear();
|
|
1728
|
+
try {
|
|
1729
|
+
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
1730
|
+
}
|
|
1731
|
+
catch (error) {
|
|
1732
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
createProtocolMismatchError(expected, uuid) {
|
|
1736
|
+
const isStaleV2Bond = expected === 'V2' && this.confirmedProtocolV2.has(uuid);
|
|
1737
|
+
return hdShared.ERRORS.TypedError(isStaleV2Bond ? hdShared.HardwareErrorCode.BleDeviceBondError : hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1305
1738
|
}
|
|
1306
1739
|
createProtocolDetectionError() {
|
|
1307
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1740
|
+
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
1741
|
}
|
|
1309
1742
|
clearProbeProtocol(uuid, protocol) {
|
|
1743
|
+
if (this.probingProtocols.get(uuid) === protocol) {
|
|
1744
|
+
this.probingProtocols.delete(uuid);
|
|
1745
|
+
}
|
|
1310
1746
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1311
1747
|
this.deviceProtocol.delete(uuid);
|
|
1312
1748
|
}
|
|
1313
1749
|
}
|
|
1314
|
-
|
|
1750
|
+
getActiveProtocol(uuid) {
|
|
1751
|
+
var _a;
|
|
1752
|
+
return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
|
|
1753
|
+
}
|
|
1754
|
+
detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
|
|
1755
|
+
var _a;
|
|
1315
1756
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1316
1757
|
if (expectedProtocol === 'V1') {
|
|
1317
|
-
|
|
1318
|
-
|
|
1758
|
+
this.deviceProtocol.set(uuid, 'V1');
|
|
1759
|
+
this.sessionProtocols.set(uuid, 'V1');
|
|
1760
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
|
|
1761
|
+
deviceId: uuid,
|
|
1762
|
+
protocol: 'V1',
|
|
1763
|
+
source: 'expected',
|
|
1764
|
+
});
|
|
1765
|
+
return 'V1';
|
|
1766
|
+
}
|
|
1767
|
+
if (expectedProtocol === 'V2') {
|
|
1768
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1769
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1770
|
+
this.sessionProtocols.set(uuid, 'V2');
|
|
1771
|
+
this.confirmedProtocolV2.add(uuid);
|
|
1319
1772
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1320
1773
|
deviceId: uuid,
|
|
1321
|
-
protocol: '
|
|
1774
|
+
protocol: 'V2',
|
|
1322
1775
|
source: 'expected',
|
|
1323
1776
|
});
|
|
1324
|
-
return '
|
|
1777
|
+
return 'V2';
|
|
1325
1778
|
}
|
|
1326
|
-
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
return 'V2';
|
|
1336
|
-
}
|
|
1337
|
-
const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1779
|
+
throw this.createProtocolMismatchError(expectedProtocol, uuid);
|
|
1780
|
+
}
|
|
1781
|
+
const sessionProtocol = this.sessionProtocols.get(uuid);
|
|
1782
|
+
const reprobeFailures = (_a = this.protocolReprobeFailures.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1783
|
+
const fullProbeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1784
|
+
const trustSessionProtocol = sessionProtocol !== undefined &&
|
|
1785
|
+
!protocolHint &&
|
|
1786
|
+
reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1787
|
+
const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
|
|
1338
1788
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1339
1789
|
const protocol = probeOrder[i];
|
|
1340
1790
|
if (i > 0) {
|
|
1341
1791
|
yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
1792
|
+
if (!transportCache[uuid]) {
|
|
1793
|
+
if (!rebuildTransport) {
|
|
1794
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
1795
|
+
}
|
|
1796
|
+
yield rebuildTransport();
|
|
1797
|
+
}
|
|
1342
1798
|
}
|
|
1343
1799
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
|
|
1344
1800
|
if (detected) {
|
|
1345
1801
|
this.deviceProtocol.set(uuid, protocol);
|
|
1802
|
+
this.sessionProtocols.set(uuid, protocol);
|
|
1803
|
+
if (protocol === 'V2') {
|
|
1804
|
+
this.confirmedProtocolV2.add(uuid);
|
|
1805
|
+
}
|
|
1806
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
1346
1807
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1347
1808
|
deviceId: uuid,
|
|
1348
1809
|
protocol,
|
|
@@ -1351,7 +1812,14 @@ class ReactNativeBleTransport {
|
|
|
1351
1812
|
return protocol;
|
|
1352
1813
|
}
|
|
1353
1814
|
}
|
|
1815
|
+
if (trustSessionProtocol) {
|
|
1816
|
+
this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
|
|
1817
|
+
}
|
|
1818
|
+
else {
|
|
1819
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
1820
|
+
}
|
|
1354
1821
|
this.deviceProtocol.delete(uuid);
|
|
1822
|
+
this.probingProtocols.delete(uuid);
|
|
1355
1823
|
throw this.createProtocolDetectionError();
|
|
1356
1824
|
});
|
|
1357
1825
|
}
|
|
@@ -1403,13 +1871,17 @@ class ReactNativeBleTransport {
|
|
|
1403
1871
|
return false;
|
|
1404
1872
|
}
|
|
1405
1873
|
try {
|
|
1406
|
-
this.
|
|
1407
|
-
yield this.callProtocolV1(uuid, '
|
|
1874
|
+
this.probingProtocols.set(uuid, 'V1');
|
|
1875
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1876
|
+
this.probingProtocols.delete(uuid);
|
|
1408
1877
|
return true;
|
|
1409
1878
|
}
|
|
1410
1879
|
catch (error) {
|
|
1411
1880
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1412
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1881
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1882
|
+
if (isWedgedWriteError(error)) {
|
|
1883
|
+
throw error;
|
|
1884
|
+
}
|
|
1413
1885
|
return false;
|
|
1414
1886
|
}
|
|
1415
1887
|
});
|
|
@@ -1420,7 +1892,7 @@ class ReactNativeBleTransport {
|
|
|
1420
1892
|
if (!this._messages || !this._messagesV2) {
|
|
1421
1893
|
return false;
|
|
1422
1894
|
}
|
|
1423
|
-
this.
|
|
1895
|
+
this.probingProtocols.set(uuid, 'V2');
|
|
1424
1896
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1425
1897
|
const detected = yield transport.probeProtocolV2({
|
|
1426
1898
|
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
@@ -1436,6 +1908,9 @@ class ReactNativeBleTransport {
|
|
|
1436
1908
|
if (!detected) {
|
|
1437
1909
|
this.clearProbeProtocol(uuid, 'V2');
|
|
1438
1910
|
}
|
|
1911
|
+
else {
|
|
1912
|
+
this.probingProtocols.delete(uuid);
|
|
1913
|
+
}
|
|
1439
1914
|
return detected;
|
|
1440
1915
|
});
|
|
1441
1916
|
}
|
|
@@ -1478,16 +1953,8 @@ class ReactNativeBleTransport {
|
|
|
1478
1953
|
}
|
|
1479
1954
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1480
1955
|
}
|
|
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
1956
|
resetProtocolV2Frames(uuid) {
|
|
1489
|
-
this.
|
|
1490
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1957
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1491
1958
|
}
|
|
1492
1959
|
rejectProtocolV2Frames(uuid, error) {
|
|
1493
1960
|
this.protocolV2FrameQueues.delete(uuid);
|
|
@@ -1515,20 +1982,70 @@ class ReactNativeBleTransport {
|
|
|
1515
1982
|
}
|
|
1516
1983
|
});
|
|
1517
1984
|
}
|
|
1518
|
-
|
|
1985
|
+
writeProtocolV2Packet(uuid, transport, base64, context, assertCurrentGeneration) {
|
|
1986
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1987
|
+
const shouldUseWriteWithResponse = shouldWriteProtocolV2WithResponse({
|
|
1988
|
+
platform: reactNative.Platform.OS,
|
|
1989
|
+
highThroughput: context.highThroughput,
|
|
1990
|
+
requestedWithResponse: context.writeWithResponse,
|
|
1991
|
+
characteristic: transport.writeCharacteristic,
|
|
1992
|
+
});
|
|
1993
|
+
let attempt = 0;
|
|
1994
|
+
for (;;) {
|
|
1995
|
+
assertCurrentGeneration();
|
|
1996
|
+
if (context.signal.aborted) {
|
|
1997
|
+
throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
|
|
1998
|
+
}
|
|
1999
|
+
try {
|
|
2000
|
+
yield this.writeBlePacket(uuid, base64, payload => shouldUseWriteWithResponse
|
|
2001
|
+
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
2002
|
+
: transport.writeCharacteristic.writeWithoutResponse(payload), () => {
|
|
2003
|
+
try {
|
|
2004
|
+
assertCurrentGeneration();
|
|
2005
|
+
return !context.signal.aborted;
|
|
2006
|
+
}
|
|
2007
|
+
catch (_a) {
|
|
2008
|
+
return false;
|
|
2009
|
+
}
|
|
2010
|
+
});
|
|
2011
|
+
assertCurrentGeneration();
|
|
2012
|
+
return;
|
|
2013
|
+
}
|
|
2014
|
+
catch (error) {
|
|
2015
|
+
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
2016
|
+
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
2017
|
+
throw error;
|
|
2018
|
+
}
|
|
2019
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
2020
|
+
attempt += 1;
|
|
2021
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 congested write retry:', {
|
|
2022
|
+
name: context.messageName,
|
|
2023
|
+
attempt,
|
|
2024
|
+
delayMs,
|
|
2025
|
+
});
|
|
2026
|
+
yield delay(delayMs);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
});
|
|
2030
|
+
}
|
|
2031
|
+
writeProtocolV2Frame(uuid, transport$1, frame, context, assertCurrentGeneration) {
|
|
1519
2032
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1520
2033
|
const tuning = getProtocolV2BleTuning();
|
|
1521
2034
|
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1522
2035
|
platform: reactNative.Platform.OS,
|
|
1523
2036
|
iosPacketLength: tuning.iosPacketLength,
|
|
1524
2037
|
androidPacketLength: tuning.androidPacketLength,
|
|
1525
|
-
mtu:
|
|
2038
|
+
mtu: transport$1.mtuSize,
|
|
2039
|
+
});
|
|
2040
|
+
yield transport.writeProtocolV2BleFrame({
|
|
2041
|
+
frame,
|
|
2042
|
+
packetCapacity,
|
|
2043
|
+
assertActive: assertCurrentGeneration,
|
|
2044
|
+
signal: context.signal,
|
|
2045
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
2046
|
+
wait: delay,
|
|
2047
|
+
writePacket: packet => this.writeProtocolV2Packet(uuid, transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
|
|
1526
2048
|
});
|
|
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
2049
|
});
|
|
1533
2050
|
}
|
|
1534
2051
|
callProtocolV2(uuid, name, data, options) {
|
|
@@ -1537,15 +2054,40 @@ class ReactNativeBleTransport {
|
|
|
1537
2054
|
if (!this._messages || !this._messagesV2) {
|
|
1538
2055
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1539
2056
|
}
|
|
1540
|
-
const callOptions =
|
|
1541
|
-
const
|
|
1542
|
-
if (
|
|
2057
|
+
const callOptions = options;
|
|
2058
|
+
const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
|
|
2059
|
+
if (highThroughputWrite) {
|
|
2060
|
+
yield this.ensureProtocolV2HighThroughputMtu(uuid);
|
|
1543
2061
|
const tuning = getProtocolV2BleTuning();
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
2062
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
2063
|
+
const writeWithResponse = shouldWriteProtocolV2WithResponse({
|
|
2064
|
+
platform: reactNative.Platform.OS,
|
|
2065
|
+
highThroughput: true,
|
|
2066
|
+
requestedWithResponse: options === null || options === void 0 ? void 0 : options.writeWithResponse,
|
|
2067
|
+
characteristic: currentTransport.writeCharacteristic,
|
|
2068
|
+
});
|
|
2069
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
2070
|
+
platform: reactNative.Platform.OS,
|
|
2071
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
2072
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
2073
|
+
mtu: currentTransport.mtuSize,
|
|
1548
2074
|
});
|
|
2075
|
+
const writeMode = writeWithResponse ? 'withResponse' : 'withoutResponse';
|
|
2076
|
+
const logSignature = `${name}:${writeMode}:${String(currentTransport.mtuSize)}:${packetCapacity}`;
|
|
2077
|
+
const loggedSignatures = (_a = this.protocolV2HighVolumeLogSignatures.get(uuid)) !== null && _a !== void 0 ? _a : new Set();
|
|
2078
|
+
if (!loggedSignatures.has(logSignature)) {
|
|
2079
|
+
loggedSignatures.add(logSignature);
|
|
2080
|
+
this.protocolV2HighVolumeLogSignatures.set(uuid, loggedSignatures);
|
|
2081
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
|
|
2082
|
+
name,
|
|
2083
|
+
writeMode,
|
|
2084
|
+
reportedMtu: currentTransport.mtuSize,
|
|
2085
|
+
packetCapacity,
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
if (highThroughputWrite) {
|
|
2090
|
+
yield this.enableAndroidHighConnectionPriority(uuid);
|
|
1549
2091
|
}
|
|
1550
2092
|
try {
|
|
1551
2093
|
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
@@ -1554,6 +2096,85 @@ class ReactNativeBleTransport {
|
|
|
1554
2096
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1555
2097
|
throw e;
|
|
1556
2098
|
}
|
|
2099
|
+
finally {
|
|
2100
|
+
if (highThroughputWrite) {
|
|
2101
|
+
this.scheduleAndroidBalancedConnectionPriority(uuid);
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
});
|
|
2105
|
+
}
|
|
2106
|
+
ensureProtocolV2HighThroughputMtu(uuid) {
|
|
2107
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2108
|
+
const transport = this.getCachedTransport(uuid);
|
|
2109
|
+
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
2110
|
+
return;
|
|
2111
|
+
const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1);
|
|
2112
|
+
transport.device = refreshedDevice;
|
|
2113
|
+
transport.mtuSize =
|
|
2114
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
2115
|
+
if (shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
2116
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `Protocol V2 high-throughput BLE MTU unavailable: ${String(transport.mtuSize)}`);
|
|
2117
|
+
}
|
|
2118
|
+
});
|
|
2119
|
+
}
|
|
2120
|
+
clearAndroidPriorityResetTimer(uuid) {
|
|
2121
|
+
const timerId = this.androidPriorityResetTimers.get(uuid);
|
|
2122
|
+
if (timerId !== undefined) {
|
|
2123
|
+
clearTimeout(timerId);
|
|
2124
|
+
this.androidPriorityResetTimers.delete(uuid);
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
enableAndroidHighConnectionPriority(uuid) {
|
|
2128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2129
|
+
if (reactNative.Platform.OS !== 'android')
|
|
2130
|
+
return;
|
|
2131
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
2132
|
+
if (this.androidHighPriorityDevices.has(uuid))
|
|
2133
|
+
return;
|
|
2134
|
+
const transport = transportCache[uuid];
|
|
2135
|
+
if (!transport)
|
|
2136
|
+
return;
|
|
2137
|
+
try {
|
|
2138
|
+
transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.High);
|
|
2139
|
+
this.androidHighPriorityDevices.add(uuid);
|
|
2140
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
|
|
2141
|
+
priority: 'high',
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
catch (error) {
|
|
2145
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE high priority request failed', {
|
|
2146
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
scheduleAndroidBalancedConnectionPriority(uuid) {
|
|
2152
|
+
if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.has(uuid))
|
|
2153
|
+
return;
|
|
2154
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
2155
|
+
const timerId = setTimeout(() => {
|
|
2156
|
+
this.androidPriorityResetTimers.delete(uuid);
|
|
2157
|
+
this.restoreAndroidConnectionPriority(uuid, transportCache[uuid]).catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE priority restore failed', error));
|
|
2158
|
+
}, ANDROID_HIGH_PRIORITY_IDLE_MS);
|
|
2159
|
+
this.androidPriorityResetTimers.set(uuid, timerId);
|
|
2160
|
+
}
|
|
2161
|
+
restoreAndroidConnectionPriority(uuid, transport) {
|
|
2162
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2163
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
2164
|
+
if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.delete(uuid) || !transport) {
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
try {
|
|
2168
|
+
transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.Balanced);
|
|
2169
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
|
|
2170
|
+
priority: 'balanced',
|
|
2171
|
+
});
|
|
2172
|
+
}
|
|
2173
|
+
catch (error) {
|
|
2174
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE balanced priority request failed', {
|
|
2175
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2176
|
+
});
|
|
2177
|
+
}
|
|
1557
2178
|
});
|
|
1558
2179
|
}
|
|
1559
2180
|
createProtocolV2Adapter(uuid) {
|
|
@@ -1574,10 +2195,10 @@ class ReactNativeBleTransport {
|
|
|
1574
2195
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1575
2196
|
this.resetProtocolV2Frames(uuid);
|
|
1576
2197
|
},
|
|
1577
|
-
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
2198
|
+
writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
|
|
1578
2199
|
assertCurrentGeneration();
|
|
1579
2200
|
const currentTransport = this.getCachedTransport(uuid);
|
|
1580
|
-
yield this.writeProtocolV2Frame(currentTransport, frame);
|
|
2201
|
+
yield this.writeProtocolV2Frame(uuid, currentTransport, frame, context, assertCurrentGeneration);
|
|
1581
2202
|
}),
|
|
1582
2203
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1583
2204
|
assertCurrentGeneration();
|
|
@@ -1589,6 +2210,8 @@ class ReactNativeBleTransport {
|
|
|
1589
2210
|
}),
|
|
1590
2211
|
reset: (reason) => {
|
|
1591
2212
|
var _a;
|
|
2213
|
+
if (this.monitorTokens.get(uuid) !== generation)
|
|
2214
|
+
return;
|
|
1592
2215
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1593
2216
|
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
1594
2217
|
},
|
|
@@ -1598,11 +2221,20 @@ class ReactNativeBleTransport {
|
|
|
1598
2221
|
};
|
|
1599
2222
|
}
|
|
1600
2223
|
getProtocolType(path) {
|
|
1601
|
-
return this.
|
|
2224
|
+
return this.getActiveProtocol(path);
|
|
1602
2225
|
}
|
|
1603
2226
|
}
|
|
1604
2227
|
|
|
2228
|
+
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2229
|
+
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2230
|
+
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|
|
2231
|
+
exports.BLE_NATIVE_TEARDOWN_TIMEOUT_MS = BLE_NATIVE_TEARDOWN_TIMEOUT_MS;
|
|
2232
|
+
exports.BLE_SETUP_WEDGED_MESSAGE = BLE_SETUP_WEDGED_MESSAGE;
|
|
2233
|
+
exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
|
|
2234
|
+
exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2235
|
+
exports.PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1605
2236
|
exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
|
|
1606
2237
|
exports["default"] = ReactNativeBleTransport;
|
|
2238
|
+
exports.getFirmwareUploadWriteRetryType = getFirmwareUploadWriteRetryType;
|
|
1607
2239
|
exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
|
|
1608
2240
|
exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;
|