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