@onekeyfe/hd-transport-react-native 1.2.0-alpha.7 → 1.2.0-alpha.71
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 +6 -2
- 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 +107 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +850 -405
- package/dist/subscribeBleOn.d.ts.map +1 -1
- package/dist/transportLog.d.ts +2 -0
- package/dist/transportLog.d.ts.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/jest.config.js +10 -0
- package/package.json +7 -6
- package/src/BleTransport.ts +7 -42
- package/src/__tests__/BleTransport.test.ts +93 -0
- package/src/__tests__/bleStrategy.test.ts +73 -8
- package/src/__tests__/connectTimeout.test.ts +281 -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 +890 -0
- package/src/__tests__/staleCallTimeout.test.ts +210 -0
- package/src/__tests__/writePacketTimeout.test.ts +305 -0
- package/src/bleStrategy.ts +23 -35
- package/src/constants.ts +9 -14
- package/src/index.ts +1088 -412
- package/src/subscribeBleOn.ts +0 -2
- package/src/transportLog.ts +1 -0
- 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 = 514;
|
|
97
98
|
const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
|
|
98
99
|
const OneKeyServices = {
|
|
99
100
|
classic: {
|
|
@@ -117,51 +118,37 @@ 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
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
if (preferredMode === 'withResponse' && characteristic.isWritableWithResponse) {
|
|
146
|
-
return 'withResponse';
|
|
138
|
+
function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PROTOCOL_V2_PACKET_LENGTH, androidPacketLength = ANDROID_PROTOCOL_V2_PACKET_LENGTH, mtu, }) {
|
|
139
|
+
if (typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= 3) {
|
|
140
|
+
throw new Error(`Protocol V2 BLE requires a negotiated MTU, received: ${String(mtu)}`);
|
|
147
141
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (characteristic.isWritableWithResponse) {
|
|
152
|
-
return 'withResponse';
|
|
153
|
-
}
|
|
154
|
-
return preferredMode;
|
|
142
|
+
const payloadLength = Math.floor(mtu) - 3;
|
|
143
|
+
const configuredPacketLength = platform === 'ios' ? iosPacketLength : androidPacketLength;
|
|
144
|
+
return Math.min(configuredPacketLength, payloadLength);
|
|
155
145
|
}
|
|
156
|
-
function
|
|
157
|
-
if (
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return Math.min(androidPacketLength, payloadLength);
|
|
163
|
-
}
|
|
164
|
-
return androidPacketLength;
|
|
146
|
+
function shouldWriteProtocolV2WithResponse({ platform, highVolume, requestedWithResponse, characteristic, }) {
|
|
147
|
+
if (!characteristic.isWritableWithResponse)
|
|
148
|
+
return false;
|
|
149
|
+
if (!characteristic.isWritableWithoutResponse)
|
|
150
|
+
return true;
|
|
151
|
+
return requestedWithResponse === true || (platform === 'ios' && !highVolume);
|
|
165
152
|
}
|
|
166
153
|
|
|
167
154
|
const timer = process.env.NODE_ENV === 'development'
|
|
@@ -189,7 +176,6 @@ const timer = process.env.NODE_ENV === 'development'
|
|
|
189
176
|
const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
|
|
190
177
|
let done = false;
|
|
191
178
|
const subscription = bleManager.onStateChange(state => {
|
|
192
|
-
console.log('ble state -> ', state);
|
|
193
179
|
if (state === 'PoweredOn') {
|
|
194
180
|
if (done)
|
|
195
181
|
return;
|
|
@@ -219,47 +205,24 @@ const isHeaderChunk = (chunk) => {
|
|
|
219
205
|
return false;
|
|
220
206
|
};
|
|
221
207
|
|
|
222
|
-
const Log$1 = bleLogger;
|
|
223
208
|
class BleTransport {
|
|
224
209
|
constructor(device, writeCharacteristic, notifyCharacteristic) {
|
|
225
210
|
this.name = 'ReactNativeBleTransport';
|
|
226
|
-
this.mtuSize = 23;
|
|
227
211
|
this.id = device.id;
|
|
228
212
|
this.device = device;
|
|
229
213
|
this.writeCharacteristic = writeCharacteristic;
|
|
230
214
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
231
215
|
}
|
|
232
|
-
writeWithRetry(data
|
|
216
|
+
writeWithRetry(data) {
|
|
233
217
|
return __awaiter(this, void 0, void 0, function* () {
|
|
234
|
-
|
|
235
|
-
yield this.writeCharacteristic.
|
|
236
|
-
|
|
237
|
-
catch (error) {
|
|
238
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`);
|
|
239
|
-
if (retryCount > 0) {
|
|
240
|
-
yield hdShared.wait(BleTransport.RETRY_DELAY);
|
|
241
|
-
if (error.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
242
|
-
error.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
243
|
-
try {
|
|
244
|
-
yield this.device.connect();
|
|
245
|
-
yield this.device.discoverAllServicesAndCharacteristics();
|
|
246
|
-
}
|
|
247
|
-
catch (e) {
|
|
248
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Connect or discoverAllServicesAndCharacteristics error: ${e}`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`writeCharacteristic error: ${error}`);
|
|
253
|
-
}
|
|
254
|
-
return this.writeWithRetry(data, retryCount - 1);
|
|
255
|
-
}
|
|
256
|
-
throw error;
|
|
218
|
+
if (reactNative.Platform.OS === 'ios' && this.writeCharacteristic.isWritableWithResponse) {
|
|
219
|
+
yield this.writeCharacteristic.writeWithResponse(data);
|
|
220
|
+
return;
|
|
257
221
|
}
|
|
222
|
+
yield this.writeCharacteristic.writeWithoutResponse(data);
|
|
258
223
|
});
|
|
259
224
|
}
|
|
260
225
|
}
|
|
261
|
-
BleTransport.MAX_RETRIES = 5;
|
|
262
|
-
BleTransport.RETRY_DELAY = 2000;
|
|
263
226
|
|
|
264
227
|
const { check, ProtocolV1, parseConfigure } = transport__default["default"];
|
|
265
228
|
const Log = bleLogger;
|
|
@@ -268,10 +231,35 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 :
|
|
|
268
231
|
const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
|
|
269
232
|
const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
|
|
270
233
|
const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
|
|
271
|
-
const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
|
|
272
234
|
const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
|
|
273
235
|
const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
|
|
274
236
|
const ANDROID_GATT_CONGESTED_STATUS = 143;
|
|
237
|
+
const isAsciiWhitespace = (code) => code === 0x09 ||
|
|
238
|
+
code === 0x0a ||
|
|
239
|
+
code === 0x0b ||
|
|
240
|
+
code === 0x0c ||
|
|
241
|
+
code === 0x0d ||
|
|
242
|
+
code === 0x20;
|
|
243
|
+
const hasGattCongestedStatus = (text) => {
|
|
244
|
+
let searchFrom = 0;
|
|
245
|
+
while (searchFrom < text.length) {
|
|
246
|
+
const statusIndex = text.indexOf('status', searchFrom);
|
|
247
|
+
if (statusIndex < 0)
|
|
248
|
+
return false;
|
|
249
|
+
let cursor = statusIndex + 'status'.length;
|
|
250
|
+
while (cursor < text.length && isAsciiWhitespace(text.charCodeAt(cursor)))
|
|
251
|
+
cursor += 1;
|
|
252
|
+
if (text[cursor] === ':' || text[cursor] === '=') {
|
|
253
|
+
cursor += 1;
|
|
254
|
+
while (cursor < text.length && isAsciiWhitespace(text.charCodeAt(cursor)))
|
|
255
|
+
cursor += 1;
|
|
256
|
+
}
|
|
257
|
+
if (text.startsWith(String(ANDROID_GATT_CONGESTED_STATUS), cursor))
|
|
258
|
+
return true;
|
|
259
|
+
searchFrom = statusIndex + 'status'.length;
|
|
260
|
+
}
|
|
261
|
+
return false;
|
|
262
|
+
};
|
|
275
263
|
const delay = (ms) => new Promise(resolve => {
|
|
276
264
|
setTimeout(resolve, ms);
|
|
277
265
|
});
|
|
@@ -279,10 +267,6 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
279
267
|
if (!error || typeof error !== 'object')
|
|
280
268
|
return null;
|
|
281
269
|
const bleWriteError = error;
|
|
282
|
-
if (bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
|
|
283
|
-
bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
|
|
284
|
-
return 'reconnectable';
|
|
285
|
-
}
|
|
286
270
|
if (bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
|
|
287
271
|
bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS) {
|
|
288
272
|
return 'congested';
|
|
@@ -290,25 +274,23 @@ const getFirmwareUploadWriteRetryType = (error) => {
|
|
|
290
274
|
const text = [bleWriteError.reason, bleWriteError.message, bleWriteError.name]
|
|
291
275
|
.filter(value => typeof value === 'string')
|
|
292
276
|
.join(' ');
|
|
293
|
-
return
|
|
277
|
+
return text.includes('GATT_CONGESTED') || hasGattCongestedStatus(text) ? 'congested' : null;
|
|
294
278
|
};
|
|
295
279
|
const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
|
|
296
|
-
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
297
280
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
298
281
|
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
299
|
-
const
|
|
282
|
+
const BLE_WRITE_PACKET_TIMEOUT_MS = 10000;
|
|
283
|
+
const WEDGED_WRITE_MESSAGE = 'BLE write timeout after';
|
|
284
|
+
const isWedgedWriteError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleWriteCharacteristicError &&
|
|
285
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
286
|
+
error.message.startsWith(WEDGED_WRITE_MESSAGE);
|
|
287
|
+
const BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
288
|
+
const DEVICE_SCAN_TIMEOUT_MS = 3000;
|
|
300
289
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
301
290
|
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
302
|
-
const HIGH_VOLUME_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 6;
|
|
303
|
-
const HIGH_VOLUME_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 6 : 2;
|
|
304
|
-
const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 20 : 8;
|
|
305
291
|
const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
|
|
306
|
-
iosPacketLength:
|
|
307
|
-
androidPacketLength:
|
|
308
|
-
highVolumeWriteBurstSize: HIGH_VOLUME_WRITE_BURST_SIZE,
|
|
309
|
-
highVolumeWritePauseMs: HIGH_VOLUME_WRITE_PAUSE_MS,
|
|
310
|
-
highVolumeWriteFlushDelayMs: HIGH_VOLUME_WRITE_FLUSH_DELAY_MS,
|
|
311
|
-
highVolumeWriteWithResponse: false,
|
|
292
|
+
iosPacketLength: IOS_PROTOCOL_V2_PACKET_LENGTH,
|
|
293
|
+
androidPacketLength: ANDROID_PROTOCOL_V2_PACKET_LENGTH,
|
|
312
294
|
};
|
|
313
295
|
let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
314
296
|
const normalizePositiveInteger = (value, fallback) => {
|
|
@@ -318,20 +300,15 @@ const normalizePositiveInteger = (value, fallback) => {
|
|
|
318
300
|
return Math.floor(normalized);
|
|
319
301
|
};
|
|
320
302
|
function configureProtocolV2BleTuning(tuning = {}) {
|
|
321
|
-
var _a;
|
|
322
303
|
protocolV2BleTuning = {
|
|
323
304
|
iosPacketLength: normalizePositiveInteger(tuning.iosPacketLength, protocolV2BleTuning.iosPacketLength),
|
|
324
305
|
androidPacketLength: normalizePositiveInteger(tuning.androidPacketLength, protocolV2BleTuning.androidPacketLength),
|
|
325
|
-
highVolumeWriteBurstSize: normalizePositiveInteger(tuning.highVolumeWriteBurstSize, protocolV2BleTuning.highVolumeWriteBurstSize),
|
|
326
|
-
highVolumeWritePauseMs: normalizePositiveInteger(tuning.highVolumeWritePauseMs, protocolV2BleTuning.highVolumeWritePauseMs),
|
|
327
|
-
highVolumeWriteFlushDelayMs: normalizePositiveInteger(tuning.highVolumeWriteFlushDelayMs, protocolV2BleTuning.highVolumeWriteFlushDelayMs),
|
|
328
|
-
highVolumeWriteWithResponse: (_a = tuning.highVolumeWriteWithResponse) !== null && _a !== void 0 ? _a : protocolV2BleTuning.highVolumeWriteWithResponse,
|
|
329
306
|
};
|
|
330
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
307
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning configured', protocolV2BleTuning);
|
|
331
308
|
}
|
|
332
309
|
function resetProtocolV2BleTuning() {
|
|
333
310
|
protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
|
|
334
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
311
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning reset', protocolV2BleTuning);
|
|
335
312
|
}
|
|
336
313
|
function getProtocolV2BleTuning() {
|
|
337
314
|
return Object.assign({}, protocolV2BleTuning);
|
|
@@ -342,19 +319,30 @@ function inferProtocolHintFromDeviceName(name) {
|
|
|
342
319
|
function getDeviceDisplayName(device) {
|
|
343
320
|
return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
|
|
344
321
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const ANDROID_REQUEST_MTU = 256;
|
|
322
|
+
const IOS_REQUEST_MTU = 247;
|
|
323
|
+
const ANDROID_REQUEST_MTU = 517;
|
|
324
|
+
const BLE_MTU_REFRESH_THRESHOLD = 247;
|
|
325
|
+
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
326
|
+
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
327
|
+
const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
328
|
+
const BLE_NATIVE_CONNECT_TIMEOUT_MS = 3000;
|
|
353
329
|
const connectOptions = {
|
|
354
|
-
requestMTU:
|
|
355
|
-
timeout:
|
|
330
|
+
requestMTU: getRequestedBleMtu(),
|
|
331
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
356
332
|
refreshGatt: 'OnConnected',
|
|
357
333
|
};
|
|
334
|
+
const fallbackConnectOptions = {
|
|
335
|
+
timeout: BLE_NATIVE_CONNECT_TIMEOUT_MS,
|
|
336
|
+
};
|
|
337
|
+
const BLE_CONNECT_TIMEOUT_MS = BLE_NATIVE_CONNECT_TIMEOUT_MS * 2 + 2000;
|
|
338
|
+
const BLE_GATT_SETUP_TIMEOUT_MS = 10000;
|
|
339
|
+
const PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = 3;
|
|
340
|
+
const BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = 2;
|
|
341
|
+
const CONNECT_TIMEOUT_MESSAGE = 'BLE connect timeout after';
|
|
342
|
+
const isConnectTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === hdShared.HardwareErrorCode.BleConnectedError &&
|
|
343
|
+
typeof (error === null || error === void 0 ? void 0 : error.message) === 'string' &&
|
|
344
|
+
error.message.startsWith(CONNECT_TIMEOUT_MESSAGE);
|
|
345
|
+
const isNativeOperationTimeoutError = (error) => (error === null || error === void 0 ? void 0 : error.errorCode) === reactNativeBlePlx.BleErrorCode.OperationTimedOut;
|
|
358
346
|
const tryToGetConfiguration = (device) => {
|
|
359
347
|
if (!device || !device.serviceUUIDs)
|
|
360
348
|
return null;
|
|
@@ -366,22 +354,25 @@ const tryToGetConfiguration = (device) => {
|
|
|
366
354
|
return null;
|
|
367
355
|
return infos;
|
|
368
356
|
};
|
|
369
|
-
const
|
|
370
|
-
if (reactNative.Platform.OS !== 'android')
|
|
357
|
+
const requestNegotiatedMtu = (device, stage, attempt) => __awaiter(void 0, void 0, void 0, function* () {
|
|
358
|
+
if (reactNative.Platform.OS !== 'ios' && reactNative.Platform.OS !== 'android')
|
|
371
359
|
return device;
|
|
372
360
|
try {
|
|
373
|
-
const mtuDevice = yield device.requestMTU(
|
|
374
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU requested:', {
|
|
375
|
-
requested: ANDROID_REQUEST_MTU,
|
|
376
|
-
mtu: mtuDevice.mtu,
|
|
377
|
-
});
|
|
361
|
+
const mtuDevice = yield device.requestMTU(getRequestedBleMtu());
|
|
378
362
|
return mtuDevice;
|
|
379
363
|
}
|
|
380
364
|
catch (error) {
|
|
381
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
365
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU refresh failed, continuing with current value', {
|
|
366
|
+
platform: reactNative.Platform.OS,
|
|
367
|
+
stage,
|
|
368
|
+
attempt,
|
|
369
|
+
actual: device.mtu,
|
|
370
|
+
error: error instanceof Error ? error.message : String(error),
|
|
371
|
+
});
|
|
382
372
|
return device;
|
|
383
373
|
}
|
|
384
374
|
});
|
|
375
|
+
const resolveNegotiatedMtu = (device) => requestNegotiatedMtu(device, 'connected', 0);
|
|
385
376
|
function remapError(error) {
|
|
386
377
|
var _a;
|
|
387
378
|
if (error instanceof reactNativeBlePlx.BleError) {
|
|
@@ -408,15 +399,44 @@ class ReactNativeBleTransport {
|
|
|
408
399
|
this.stopped = false;
|
|
409
400
|
this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
|
|
410
401
|
this.runPromise = null;
|
|
402
|
+
this.runPromiseDeviceId = null;
|
|
411
403
|
this.firmwareUploadWriteRecoveryIds = new Set();
|
|
412
404
|
this.deviceProtocol = new Map();
|
|
405
|
+
this.probingProtocols = new Map();
|
|
406
|
+
this.writeTimeoutCounts = new Map();
|
|
407
|
+
this.connectionSetupTimeoutCounts = new Map();
|
|
413
408
|
this.deviceProtocolHints = new Map();
|
|
409
|
+
this.sessionProtocols = new Map();
|
|
410
|
+
this.protocolReprobeFailures = new Map();
|
|
414
411
|
this.protocolV2Assemblers = new Map();
|
|
415
412
|
this.protocolV2FrameQueues = new Map();
|
|
416
413
|
this.protocolV2FramePromises = new Map();
|
|
417
|
-
this.
|
|
418
|
-
|
|
414
|
+
this.protocolV2Links = new transport.ProtocolV2LinkManager({
|
|
415
|
+
getSchemas: () => {
|
|
416
|
+
if (!this._messages || !this._messagesV2) {
|
|
417
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
protocolV1: this._messages,
|
|
421
|
+
protocolV2: this._messagesV2,
|
|
422
|
+
};
|
|
423
|
+
},
|
|
424
|
+
classifyError: () => 'link-fatal',
|
|
425
|
+
onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
|
|
426
|
+
var _b;
|
|
427
|
+
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
428
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
429
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
|
|
430
|
+
if (reason.startsWith('Protocol V2 link-fatal error:')) {
|
|
431
|
+
yield this.releaseNative(uuid, true);
|
|
432
|
+
}
|
|
433
|
+
}),
|
|
434
|
+
});
|
|
419
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();
|
|
420
440
|
this.nextMonitorToken = 1;
|
|
421
441
|
this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
|
|
422
442
|
}
|
|
@@ -430,8 +450,18 @@ class ReactNativeBleTransport {
|
|
|
430
450
|
this._messages = messages;
|
|
431
451
|
}
|
|
432
452
|
configureProtocolV2(signedData) {
|
|
453
|
+
const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
|
|
454
|
+
if (this.protocolV2SchemaConfiguration === configuration) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
|
|
433
458
|
this._messagesV2 = parseConfigure(signedData);
|
|
434
|
-
|
|
459
|
+
this.protocolV2SchemaConfiguration = configuration;
|
|
460
|
+
if (isReconfiguration) {
|
|
461
|
+
this.protocolV2Links
|
|
462
|
+
.invalidateAllLinks('Protocol V2 schema reconfigured')
|
|
463
|
+
.catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
|
|
464
|
+
}
|
|
435
465
|
}
|
|
436
466
|
listen() {
|
|
437
467
|
}
|
|
@@ -442,7 +472,6 @@ class ReactNativeBleTransport {
|
|
|
442
472
|
return Promise.resolve(this.blePlxManager);
|
|
443
473
|
}
|
|
444
474
|
resolveCharacteristics(device) {
|
|
445
|
-
var _a, _b, _c, _d;
|
|
446
475
|
return __awaiter(this, void 0, void 0, function* () {
|
|
447
476
|
yield device.discoverAllServicesAndCharacteristics();
|
|
448
477
|
let infos = tryToGetConfiguration(device);
|
|
@@ -459,19 +488,11 @@ class ReactNativeBleTransport {
|
|
|
459
488
|
}
|
|
460
489
|
}
|
|
461
490
|
}
|
|
462
|
-
let fallbackServiceUuid;
|
|
463
491
|
if (!infos) {
|
|
464
492
|
const services = yield device.services();
|
|
465
493
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Known OneKey service UUID not found, discovered services:', services === null || services === void 0 ? void 0 : services.map(service => service.uuid));
|
|
466
|
-
const knownService = services.find(service => getInfosForServiceUuid(service.uuid, 'classic'));
|
|
467
|
-
const fallbackService = (_a = knownService !== null && knownService !== void 0 ? knownService : services.find(service => !isGenericBleService(service.uuid))) !== null && _a !== void 0 ? _a : services[0];
|
|
468
|
-
if (fallbackService) {
|
|
469
|
-
fallbackServiceUuid = fallbackService.uuid;
|
|
470
|
-
characteristics = yield device.characteristicsForService(fallbackService.uuid);
|
|
471
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
|
|
472
|
-
}
|
|
473
494
|
}
|
|
474
|
-
if (!infos
|
|
495
|
+
if (!infos) {
|
|
475
496
|
try {
|
|
476
497
|
Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
|
|
477
498
|
yield device.cancelConnection();
|
|
@@ -481,9 +502,7 @@ class ReactNativeBleTransport {
|
|
|
481
502
|
}
|
|
482
503
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
483
504
|
}
|
|
484
|
-
const serviceUuid
|
|
485
|
-
const writeUuid = (_c = infos === null || infos === void 0 ? void 0 : infos.writeUuid) !== null && _c !== void 0 ? _c : '00000002-0000-1000-8000-00805f9b34fb';
|
|
486
|
-
const notifyUuid = (_d = infos === null || infos === void 0 ? void 0 : infos.notifyUuid) !== null && _d !== void 0 ? _d : '00000003-0000-1000-8000-00805f9b34fb';
|
|
505
|
+
const { serviceUuid, writeUuid, notifyUuid } = infos;
|
|
487
506
|
if (!serviceUuid) {
|
|
488
507
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
|
|
489
508
|
}
|
|
@@ -524,8 +543,8 @@ class ReactNativeBleTransport {
|
|
|
524
543
|
attachDisconnectSubscription(transport, device, uuid) {
|
|
525
544
|
var _a;
|
|
526
545
|
(_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
|
|
546
|
+
const { monitorToken } = transport;
|
|
527
547
|
transport.disconnectSubscription = device.onDisconnected(() => {
|
|
528
|
-
var _a;
|
|
529
548
|
if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
|
|
530
549
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
|
|
531
550
|
return;
|
|
@@ -534,17 +553,16 @@ class ReactNativeBleTransport {
|
|
|
534
553
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale transport: ', device === null || device === void 0 ? void 0 : device.id);
|
|
535
554
|
return;
|
|
536
555
|
}
|
|
556
|
+
if (this.monitorTokens.get(uuid) !== monitorToken) {
|
|
557
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale generation: ', device === null || device === void 0 ? void 0 : device.id);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
537
560
|
try {
|
|
538
561
|
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
|
|
539
|
-
(
|
|
540
|
-
|
|
541
|
-
id: device === null || device === void 0 ? void 0 : device.id,
|
|
542
|
-
connectId: device === null || device === void 0 ? void 0 : device.id,
|
|
543
|
-
});
|
|
544
|
-
if (this.runPromise) {
|
|
562
|
+
this.emitDeviceDisconnect(uuid, device === null || device === void 0 ? void 0 : device.name, monitorToken);
|
|
563
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
545
564
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
|
|
546
565
|
this.runPromise.reject(error);
|
|
547
|
-
this.rejectAllProtocolV2Frames(error);
|
|
548
566
|
}
|
|
549
567
|
}
|
|
550
568
|
catch (e) {
|
|
@@ -555,6 +573,22 @@ class ReactNativeBleTransport {
|
|
|
555
573
|
}
|
|
556
574
|
});
|
|
557
575
|
}
|
|
576
|
+
emitDeviceDisconnect(uuid, name, token) {
|
|
577
|
+
var _a;
|
|
578
|
+
if (token === undefined || this.disconnectEventTokens.get(uuid) === token) {
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (this.monitorTokens.get(uuid) !== token) {
|
|
582
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect event ignored for stale generation: ', uuid);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
this.disconnectEventTokens.set(uuid, token);
|
|
586
|
+
(_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
|
|
587
|
+
name,
|
|
588
|
+
id: uuid,
|
|
589
|
+
connectId: uuid,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
558
592
|
reconnectFirmwareUploadTransport(uuid, transport) {
|
|
559
593
|
var _a, _b;
|
|
560
594
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -568,19 +602,19 @@ class ReactNativeBleTransport {
|
|
|
568
602
|
const isConnected = yield device.isConnected().catch(() => false);
|
|
569
603
|
if (!isConnected) {
|
|
570
604
|
try {
|
|
571
|
-
device = yield device.connect(connectOptions);
|
|
605
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect(connectOptions));
|
|
572
606
|
}
|
|
573
607
|
catch (e) {
|
|
574
608
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
575
609
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
576
|
-
device = yield device.connect();
|
|
610
|
+
device = yield this.connectWithTimeout(uuid, () => device.connect());
|
|
577
611
|
}
|
|
578
612
|
else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
579
613
|
throw e;
|
|
580
614
|
}
|
|
581
615
|
}
|
|
582
616
|
}
|
|
583
|
-
const { writeCharacteristic, notifyCharacteristic } = yield this.
|
|
617
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, device);
|
|
584
618
|
transport.device = device;
|
|
585
619
|
transport.writeCharacteristic = writeCharacteristic;
|
|
586
620
|
transport.notifyCharacteristic = notifyCharacteristic;
|
|
@@ -624,13 +658,12 @@ class ReactNativeBleTransport {
|
|
|
624
658
|
return;
|
|
625
659
|
}
|
|
626
660
|
}
|
|
627
|
-
blePlxManager.startDeviceScan(
|
|
661
|
+
blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
|
|
628
662
|
allowDuplicates: true,
|
|
629
663
|
scanMode: reactNativeBlePlx.ScanMode.LowLatency,
|
|
630
664
|
}, (error, device) => {
|
|
631
|
-
var _a
|
|
665
|
+
var _a;
|
|
632
666
|
if (error) {
|
|
633
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan manager: ', blePlxManager);
|
|
634
667
|
Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
|
|
635
668
|
if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
|
|
636
669
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
@@ -650,25 +683,19 @@ class ReactNativeBleTransport {
|
|
|
650
683
|
return;
|
|
651
684
|
}
|
|
652
685
|
const displayName = getDeviceDisplayName(device);
|
|
653
|
-
const
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
686
|
+
const isUnnamedIOSPeripheral = reactNative.Platform.OS === 'ios' && !(displayName === null || displayName === void 0 ? void 0 : displayName.trim());
|
|
687
|
+
const isFindMyPeripheral = hdShared.isPro2FindMyAdvertisementName(device === null || device === void 0 ? void 0 : device.name) ||
|
|
688
|
+
hdShared.isPro2FindMyAdvertisementName(device === null || device === void 0 ? void 0 : device.localName);
|
|
689
|
+
const isOneKey = !isUnnamedIOSPeripheral &&
|
|
690
|
+
!isFindMyPeripheral &&
|
|
691
|
+
hdShared.isOnekeyBluetoothDevice({
|
|
692
|
+
id: device === null || device === void 0 ? void 0 : device.id,
|
|
659
693
|
name: device === null || device === void 0 ? void 0 : device.name,
|
|
660
694
|
localName: device === null || device === void 0 ? void 0 : device.localName,
|
|
661
|
-
|
|
662
|
-
serviceUUIDs: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
663
|
-
accepted: isOneKey,
|
|
695
|
+
serviceUuids: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
|
|
664
696
|
});
|
|
665
|
-
}
|
|
666
697
|
if (isOneKey) {
|
|
667
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('search device start ======================');
|
|
668
|
-
const { name, localName, id, serviceUUIDs } = device !== null && device !== void 0 ? device : {};
|
|
669
|
-
Log === null || Log === void 0 ? void 0 : Log.debug(`device name: ${name !== null && name !== void 0 ? name : ''}\nlocalName: ${localName !== null && localName !== void 0 ? localName : ''}\nid: ${id !== null && id !== void 0 ? id : ''}\nserviceUUIDs: ${(serviceUUIDs !== null && serviceUUIDs !== void 0 ? serviceUUIDs : []).join(',')}`);
|
|
670
698
|
addDevice(device);
|
|
671
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('search device end ======================\n');
|
|
672
699
|
}
|
|
673
700
|
else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
|
|
674
701
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Pro2-like BLE device was not accepted:', {
|
|
@@ -679,10 +706,23 @@ class ReactNativeBleTransport {
|
|
|
679
706
|
});
|
|
680
707
|
}
|
|
681
708
|
});
|
|
682
|
-
getConnectedDeviceIds(getBluetoothServiceUuids()).then(devices => {
|
|
709
|
+
getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
|
|
683
710
|
for (const device of devices) {
|
|
684
|
-
|
|
685
|
-
|
|
711
|
+
const localName = 'localName' in device && typeof device.localName === 'string'
|
|
712
|
+
? device.localName
|
|
713
|
+
: null;
|
|
714
|
+
const isFindMyPeripheral = hdShared.isPro2FindMyAdvertisementName(device.name) ||
|
|
715
|
+
hdShared.isPro2FindMyAdvertisementName(localName);
|
|
716
|
+
if (!isFindMyPeripheral &&
|
|
717
|
+
hdShared.isOnekeyBluetoothDevice({
|
|
718
|
+
id: device.id,
|
|
719
|
+
name: device.name,
|
|
720
|
+
localName,
|
|
721
|
+
serviceUuids: device.serviceUUIDs,
|
|
722
|
+
})) {
|
|
723
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
|
|
724
|
+
addDevice(device);
|
|
725
|
+
}
|
|
686
726
|
}
|
|
687
727
|
});
|
|
688
728
|
const addDevice = (device) => {
|
|
@@ -694,6 +734,12 @@ class ReactNativeBleTransport {
|
|
|
694
734
|
this.deviceProtocolHints.set(device.id, protocolHint);
|
|
695
735
|
}
|
|
696
736
|
deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
|
|
737
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
|
|
738
|
+
deviceId: device.id,
|
|
739
|
+
name: displayName,
|
|
740
|
+
serviceUUIDs: device.serviceUUIDs,
|
|
741
|
+
protocolHint,
|
|
742
|
+
});
|
|
697
743
|
}
|
|
698
744
|
};
|
|
699
745
|
timer.timeout(() => {
|
|
@@ -703,6 +749,57 @@ class ReactNativeBleTransport {
|
|
|
703
749
|
}));
|
|
704
750
|
});
|
|
705
751
|
}
|
|
752
|
+
installTransportForAcquire(uuid, device, characteristics) {
|
|
753
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
754
|
+
const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristicsWithTimeout(uuid, device));
|
|
755
|
+
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
756
|
+
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : undefined;
|
|
757
|
+
const monitorToken = this.nextMonitorToken;
|
|
758
|
+
this.nextMonitorToken += 1;
|
|
759
|
+
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
760
|
+
transport$1.monitorToken = monitorToken;
|
|
761
|
+
transport$1.notifyTransactionId = notifyTransactionId;
|
|
762
|
+
this.monitorTokens.set(uuid, monitorToken);
|
|
763
|
+
transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
|
|
764
|
+
transportCache[uuid] = transport$1;
|
|
765
|
+
this.protocolV2HighVolumeLogSignatures.set(uuid, new Set());
|
|
766
|
+
this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
|
|
767
|
+
if (reactNative.Platform.OS === 'ios') {
|
|
768
|
+
yield new Promise(resolve => {
|
|
769
|
+
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
else if (reactNative.Platform.OS === 'android') {
|
|
773
|
+
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
774
|
+
}
|
|
775
|
+
const initialMtu = transport$1.mtuSize;
|
|
776
|
+
let refreshAttempts = 0;
|
|
777
|
+
if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
|
|
778
|
+
(typeof transport$1.mtuSize !== 'number' || transport$1.mtuSize < BLE_MTU_REFRESH_THRESHOLD)) {
|
|
779
|
+
refreshAttempts += 1;
|
|
780
|
+
let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
|
|
781
|
+
transport$1.device = refreshedDevice;
|
|
782
|
+
transport$1.mtuSize =
|
|
783
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
784
|
+
if (typeof transport$1.mtuSize !== 'number' || transport$1.mtuSize < BLE_MTU_REFRESH_THRESHOLD) {
|
|
785
|
+
yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
786
|
+
refreshAttempts += 1;
|
|
787
|
+
refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
|
|
788
|
+
transport$1.device = refreshedDevice;
|
|
789
|
+
transport$1.mtuSize =
|
|
790
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE MTU ready', {
|
|
794
|
+
platform: reactNative.Platform.OS,
|
|
795
|
+
requested: getRequestedBleMtu(),
|
|
796
|
+
initial: initialMtu,
|
|
797
|
+
actual: transport$1.mtuSize,
|
|
798
|
+
refreshAttempts,
|
|
799
|
+
});
|
|
800
|
+
return transport$1;
|
|
801
|
+
});
|
|
802
|
+
}
|
|
706
803
|
acquire(input) {
|
|
707
804
|
var _a, _b;
|
|
708
805
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -727,9 +824,8 @@ class ReactNativeBleTransport {
|
|
|
727
824
|
if (forceCleanRunPromise && this.runPromise) {
|
|
728
825
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
729
826
|
this.runPromise.reject(error);
|
|
730
|
-
this.rejectAllProtocolV2Frames(error);
|
|
731
827
|
this.runPromise = null;
|
|
732
|
-
this.
|
|
828
|
+
this.runPromiseDeviceId = null;
|
|
733
829
|
Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
|
|
734
830
|
}
|
|
735
831
|
const blePlxManager = yield this.getPlxManager();
|
|
@@ -762,14 +858,17 @@ class ReactNativeBleTransport {
|
|
|
762
858
|
if (!device) {
|
|
763
859
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device: ', uuid);
|
|
764
860
|
try {
|
|
765
|
-
device = yield blePlxManager.connectToDevice(uuid, connectOptions);
|
|
861
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, connectOptions));
|
|
766
862
|
}
|
|
767
863
|
catch (e) {
|
|
768
864
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
865
|
+
if (isConnectTimeoutError(e)) {
|
|
866
|
+
throw e;
|
|
867
|
+
}
|
|
769
868
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
770
869
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
771
870
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
772
|
-
device = yield blePlxManager.connectToDevice(uuid);
|
|
871
|
+
device = yield this.connectWithTimeout(uuid, () => blePlxManager.connectToDevice(uuid, fallbackConnectOptions));
|
|
773
872
|
}
|
|
774
873
|
else if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
|
|
775
874
|
Log === null || Log === void 0 ? void 0 : Log.debug('device already connected');
|
|
@@ -785,23 +884,27 @@ class ReactNativeBleTransport {
|
|
|
785
884
|
}
|
|
786
885
|
if (!(yield device.isConnected())) {
|
|
787
886
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
|
|
887
|
+
const disconnectedDevice = device;
|
|
788
888
|
try {
|
|
789
|
-
device = yield
|
|
889
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(connectOptions));
|
|
790
890
|
}
|
|
791
891
|
catch (e) {
|
|
792
892
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
893
|
+
if (isConnectTimeoutError(e)) {
|
|
894
|
+
throw e;
|
|
895
|
+
}
|
|
793
896
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
794
897
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
795
898
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
796
899
|
try {
|
|
797
|
-
device = yield
|
|
900
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
798
901
|
}
|
|
799
902
|
catch (e) {
|
|
800
903
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
|
|
801
904
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
802
905
|
Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
|
|
803
|
-
yield
|
|
804
|
-
device = yield
|
|
906
|
+
yield disconnectedDevice.cancelConnection();
|
|
907
|
+
device = yield this.connectWithTimeout(uuid, () => disconnectedDevice.connect(fallbackConnectOptions));
|
|
805
908
|
}
|
|
806
909
|
}
|
|
807
910
|
}
|
|
@@ -810,51 +913,42 @@ class ReactNativeBleTransport {
|
|
|
810
913
|
}
|
|
811
914
|
}
|
|
812
915
|
}
|
|
813
|
-
device = yield
|
|
814
|
-
const
|
|
916
|
+
device = yield resolveNegotiatedMtu(device);
|
|
917
|
+
const acquiredDevice = device;
|
|
918
|
+
const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristicsWithTimeout(uuid, acquiredDevice);
|
|
815
919
|
const protocolHint = expectedProtocol
|
|
816
920
|
? undefined
|
|
817
|
-
: (_a = this.deviceProtocolHints.get(uuid)) !== null &&
|
|
921
|
+
: (_b = (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
|
|
818
922
|
yield this.release(uuid, true);
|
|
819
923
|
if (protocolHint) {
|
|
820
924
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
821
925
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
yield new Promise(resolve => {
|
|
837
|
-
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
838
|
-
});
|
|
926
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice, {
|
|
927
|
+
writeCharacteristic,
|
|
928
|
+
notifyCharacteristic,
|
|
929
|
+
});
|
|
930
|
+
try {
|
|
931
|
+
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
|
|
932
|
+
yield this.installTransportForAcquire(uuid, acquiredDevice);
|
|
933
|
+
}));
|
|
934
|
+
const currentTransport = transportCache[uuid];
|
|
935
|
+
if (!currentTransport) {
|
|
936
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
937
|
+
}
|
|
938
|
+
this.attachDisconnectSubscription(currentTransport, currentTransport.device, uuid);
|
|
939
|
+
return { uuid, protocolType };
|
|
839
940
|
}
|
|
840
|
-
|
|
841
|
-
yield
|
|
941
|
+
catch (error) {
|
|
942
|
+
yield this.release(uuid, true);
|
|
943
|
+
throw error;
|
|
842
944
|
}
|
|
843
|
-
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
844
|
-
(_b = this.emitter) === null || _b === void 0 ? void 0 : _b.emit('device-connect', {
|
|
845
|
-
name: device.name,
|
|
846
|
-
id: device.id,
|
|
847
|
-
connectId: device.id,
|
|
848
|
-
});
|
|
849
|
-
this.attachDisconnectSubscription(transport$1, device, uuid);
|
|
850
|
-
return { uuid, protocolType };
|
|
851
945
|
});
|
|
852
946
|
}
|
|
853
947
|
_monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
|
|
854
948
|
let bufferLength = 0;
|
|
855
949
|
let buffer$1 = [];
|
|
856
950
|
const subscription = characteristic.monitor((error, c) => {
|
|
857
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
951
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
858
952
|
const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
|
|
859
953
|
if (error) {
|
|
860
954
|
Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
|
|
@@ -866,28 +960,44 @@ class ReactNativeBleTransport {
|
|
|
866
960
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
|
|
867
961
|
return;
|
|
868
962
|
}
|
|
869
|
-
if (this.
|
|
870
|
-
let
|
|
963
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
964
|
+
let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
871
965
|
if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
|
|
872
|
-
|
|
966
|
+
errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
873
967
|
}
|
|
874
|
-
if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
875
|
-
|
|
968
|
+
else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
|
|
969
|
+
errorCode = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
876
970
|
}
|
|
877
|
-
if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
971
|
+
else if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
|
|
878
972
|
((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('Cannot find client characteristic config descriptor')) ||
|
|
879
973
|
((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
|
|
880
974
|
((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
|
|
881
975
|
((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
|
|
976
|
+
errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
|
|
977
|
+
}
|
|
978
|
+
this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
981
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
982
|
+
let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
|
|
983
|
+
if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
|
|
984
|
+
ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
|
|
985
|
+
}
|
|
986
|
+
if ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Encryption is insufficient')) {
|
|
987
|
+
ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
|
|
988
|
+
}
|
|
989
|
+
if (((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('Cannot write client characteristic config descriptor')) ||
|
|
990
|
+
((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Cannot find client characteristic config descriptor')) ||
|
|
991
|
+
((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
|
|
992
|
+
((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
|
|
993
|
+
((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
|
|
882
994
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
|
|
883
995
|
this.runPromise.reject(notifyError);
|
|
884
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
885
996
|
Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
|
|
886
997
|
return;
|
|
887
998
|
}
|
|
888
999
|
const notifyError = hdShared.ERRORS.TypedError(ERROR);
|
|
889
1000
|
this.runPromise.reject(notifyError);
|
|
890
|
-
this.rejectAllProtocolV2Frames(notifyError);
|
|
891
1001
|
Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
|
|
892
1002
|
}
|
|
893
1003
|
return;
|
|
@@ -901,13 +1011,13 @@ class ReactNativeBleTransport {
|
|
|
901
1011
|
}
|
|
902
1012
|
try {
|
|
903
1013
|
const data = buffer.Buffer.from(c.value, 'base64');
|
|
904
|
-
const protocol = this.
|
|
1014
|
+
const protocol = this.getActiveProtocol(uuid);
|
|
905
1015
|
if (!protocol) {
|
|
906
1016
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
|
|
907
1017
|
return;
|
|
908
1018
|
}
|
|
909
1019
|
if (protocol === 'V2') {
|
|
910
|
-
this.handleProtocolV2Notification(uuid, new Uint8Array(data));
|
|
1020
|
+
this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
|
|
911
1021
|
return;
|
|
912
1022
|
}
|
|
913
1023
|
if (isHeaderChunk(data)) {
|
|
@@ -921,28 +1031,40 @@ class ReactNativeBleTransport {
|
|
|
921
1031
|
const value = buffer.Buffer.from(buffer$1);
|
|
922
1032
|
bufferLength = 0;
|
|
923
1033
|
buffer$1 = [];
|
|
924
|
-
(
|
|
1034
|
+
if (this.runPromiseDeviceId === uuid) {
|
|
1035
|
+
(_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
|
|
1036
|
+
}
|
|
925
1037
|
}
|
|
926
1038
|
}
|
|
927
1039
|
catch (error) {
|
|
928
1040
|
Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
|
|
929
1041
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
930
|
-
(
|
|
931
|
-
|
|
1042
|
+
if (this.getActiveProtocol(uuid) === 'V2') {
|
|
1043
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1044
|
+
}
|
|
1045
|
+
else if (this.runPromiseDeviceId === uuid) {
|
|
1046
|
+
(_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
|
|
1047
|
+
}
|
|
932
1048
|
}
|
|
933
1049
|
}, notifyTransactionId);
|
|
934
1050
|
return subscription;
|
|
935
1051
|
}
|
|
936
1052
|
release(uuid, onclose = false) {
|
|
937
|
-
|
|
1053
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1054
|
+
yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
|
|
1055
|
+
return this.releaseNative(uuid, onclose);
|
|
1056
|
+
});
|
|
1057
|
+
}
|
|
1058
|
+
releaseNative(uuid, onclose = false) {
|
|
1059
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
938
1060
|
return __awaiter(this, void 0, void 0, function* () {
|
|
939
1061
|
const transport = transportCache[uuid];
|
|
940
|
-
if (this.runPromise) {
|
|
1062
|
+
if (this.runPromise && this.runPromiseDeviceId === uuid) {
|
|
941
1063
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
942
1064
|
this.runPromise.reject(error);
|
|
943
1065
|
this.runPromise = null;
|
|
944
|
-
this.
|
|
945
|
-
this.
|
|
1066
|
+
this.runPromiseDeviceId = null;
|
|
1067
|
+
this.rejectProtocolV2Frames(uuid, error);
|
|
946
1068
|
}
|
|
947
1069
|
else {
|
|
948
1070
|
this.resetProtocolV2Frames(uuid);
|
|
@@ -950,24 +1072,22 @@ class ReactNativeBleTransport {
|
|
|
950
1072
|
if (reactNative.Platform.OS === 'android' && !onclose && transport) {
|
|
951
1073
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
952
1074
|
this.resetProtocolV2Frames(uuid);
|
|
953
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
954
|
-
this.activeProtocolV2Call = null;
|
|
955
|
-
}
|
|
956
1075
|
return Promise.resolve(true);
|
|
957
1076
|
}
|
|
1077
|
+
yield this.restoreAndroidConnectionPriority(uuid, transport);
|
|
958
1078
|
if (transport) {
|
|
959
1079
|
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
960
1080
|
this.monitorTokens.delete(uuid);
|
|
961
1081
|
}
|
|
962
1082
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
|
|
963
|
-
(
|
|
1083
|
+
(_b = transport.disconnectSubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
964
1084
|
transport.disconnectSubscription = undefined;
|
|
965
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (
|
|
966
|
-
(
|
|
1085
|
+
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);
|
|
1086
|
+
(_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
|
|
967
1087
|
transport.notifySubscription = undefined;
|
|
968
1088
|
if (transport.notifyTransactionId) {
|
|
969
1089
|
try {
|
|
970
|
-
yield ((
|
|
1090
|
+
yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
|
|
971
1091
|
}
|
|
972
1092
|
catch (e) {
|
|
973
1093
|
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);
|
|
@@ -975,13 +1095,14 @@ class ReactNativeBleTransport {
|
|
|
975
1095
|
}
|
|
976
1096
|
delete transportCache[uuid];
|
|
977
1097
|
}
|
|
1098
|
+
this.protocolV2HighVolumeLogSignatures.delete(uuid);
|
|
978
1099
|
this.deviceProtocol.delete(uuid);
|
|
979
|
-
this.
|
|
980
|
-
(
|
|
1100
|
+
this.probingProtocols.delete(uuid);
|
|
1101
|
+
(_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
|
|
981
1102
|
this.protocolV2Assemblers.delete(uuid);
|
|
982
1103
|
this.resetProtocolV2Frames(uuid);
|
|
983
1104
|
try {
|
|
984
|
-
yield ((
|
|
1105
|
+
yield ((_g = this.blePlxManager) === null || _g === void 0 ? void 0 : _g.cancelTransaction(uuid));
|
|
985
1106
|
}
|
|
986
1107
|
catch (e) {
|
|
987
1108
|
Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1002,30 +1123,18 @@ class ReactNativeBleTransport {
|
|
|
1002
1123
|
if (this._messages == null) {
|
|
1003
1124
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1004
1125
|
}
|
|
1005
|
-
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1006
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native call this.runPromise', this.runPromise);
|
|
1007
|
-
if (this.runPromise && !forceRun) {
|
|
1008
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1009
|
-
}
|
|
1010
1126
|
const protocol = this.getProtocolType(uuid);
|
|
1011
1127
|
if (!protocol) {
|
|
1012
1128
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
|
|
1013
1129
|
}
|
|
1014
|
-
|
|
1015
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', {
|
|
1016
|
-
file_name: data === null || data === void 0 ? void 0 : data.file_name,
|
|
1017
|
-
hash: data === null || data === void 0 ? void 0 : data.hash,
|
|
1018
|
-
});
|
|
1019
|
-
}
|
|
1020
|
-
else if (transport.LogBlockCommand.has(name)) {
|
|
1021
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' protocol: ', protocol);
|
|
1022
|
-
}
|
|
1023
|
-
else {
|
|
1024
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
|
|
1025
|
-
}
|
|
1130
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('transport call', transport.createTransportCallLog(name, protocol, data));
|
|
1026
1131
|
if (protocol === 'V2') {
|
|
1027
1132
|
return this.callProtocolV2(uuid, name, data, options);
|
|
1028
1133
|
}
|
|
1134
|
+
const forceRun = name === 'Initialize' || name === 'Cancel';
|
|
1135
|
+
if (this.runPromise && !forceRun) {
|
|
1136
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1137
|
+
}
|
|
1029
1138
|
return this.callProtocolV1(uuid, name, data, options);
|
|
1030
1139
|
});
|
|
1031
1140
|
}
|
|
@@ -1037,7 +1146,19 @@ class ReactNativeBleTransport {
|
|
|
1037
1146
|
const transport = this.getCachedTransport(uuid);
|
|
1038
1147
|
const runPromise = hdShared.createDeferred();
|
|
1039
1148
|
runPromise.promise.catch(() => undefined);
|
|
1149
|
+
const supersededRunPromise = this.runPromise;
|
|
1150
|
+
if (supersededRunPromise) {
|
|
1151
|
+
supersededRunPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
|
|
1152
|
+
}
|
|
1040
1153
|
this.runPromise = runPromise;
|
|
1154
|
+
this.runPromiseDeviceId = uuid;
|
|
1155
|
+
const releaseOwnershipIfCurrent = () => {
|
|
1156
|
+
if (this.runPromise === runPromise) {
|
|
1157
|
+
this.runPromise = null;
|
|
1158
|
+
this.runPromiseDeviceId = null;
|
|
1159
|
+
}
|
|
1160
|
+
};
|
|
1161
|
+
const isCurrentOwner = () => this.runPromise === runPromise;
|
|
1041
1162
|
const messages = this._messages;
|
|
1042
1163
|
const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
|
|
1043
1164
|
let timeout;
|
|
@@ -1058,6 +1179,9 @@ class ReactNativeBleTransport {
|
|
|
1058
1179
|
}
|
|
1059
1180
|
catch (e) {
|
|
1060
1181
|
onError(e);
|
|
1182
|
+
if (isWedgedWriteError(e)) {
|
|
1183
|
+
throw e;
|
|
1184
|
+
}
|
|
1061
1185
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1062
1186
|
}
|
|
1063
1187
|
}
|
|
@@ -1085,6 +1209,9 @@ class ReactNativeBleTransport {
|
|
|
1085
1209
|
}
|
|
1086
1210
|
catch (e) {
|
|
1087
1211
|
onError(e);
|
|
1212
|
+
if (isWedgedWriteError(e)) {
|
|
1213
|
+
throw e;
|
|
1214
|
+
}
|
|
1088
1215
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1089
1216
|
}
|
|
1090
1217
|
}
|
|
@@ -1095,13 +1222,13 @@ class ReactNativeBleTransport {
|
|
|
1095
1222
|
});
|
|
1096
1223
|
}
|
|
1097
1224
|
if (name === 'EmmcFileWrite') {
|
|
1098
|
-
yield writeChunkedData(buffers, data => transport.writeWithRetry(
|
|
1099
|
-
|
|
1225
|
+
yield writeChunkedData(buffers, data => this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner), e => {
|
|
1226
|
+
releaseOwnershipIfCurrent();
|
|
1100
1227
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1101
1228
|
});
|
|
1102
1229
|
}
|
|
1103
1230
|
else if (name === 'FirmwareUpload') {
|
|
1104
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport]
|
|
1231
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Firmware upload transport configured', {
|
|
1105
1232
|
packetCapacity: FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY,
|
|
1106
1233
|
burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
|
|
1107
1234
|
pauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
|
|
@@ -1112,7 +1239,7 @@ class ReactNativeBleTransport {
|
|
|
1112
1239
|
let attempt = 0;
|
|
1113
1240
|
while (true) {
|
|
1114
1241
|
try {
|
|
1115
|
-
yield transport.
|
|
1242
|
+
yield this.writeBlePacket(uuid, data, payload => transport.writeWithRetry(payload), isCurrentOwner);
|
|
1116
1243
|
return;
|
|
1117
1244
|
}
|
|
1118
1245
|
catch (error) {
|
|
@@ -1120,36 +1247,18 @@ class ReactNativeBleTransport {
|
|
|
1120
1247
|
if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1121
1248
|
throw error;
|
|
1122
1249
|
}
|
|
1123
|
-
const
|
|
1124
|
-
const delayMs = shouldReconnect
|
|
1125
|
-
? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
|
|
1126
|
-
: resolveFirmwareUploadRetryDelay(attempt);
|
|
1250
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1127
1251
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
|
|
1128
1252
|
attempt: attempt + 1,
|
|
1129
1253
|
delayMs,
|
|
1130
|
-
reconnect: shouldReconnect,
|
|
1131
1254
|
error,
|
|
1132
1255
|
});
|
|
1133
|
-
if (shouldReconnect) {
|
|
1134
|
-
this.firmwareUploadWriteRecoveryIds.add(uuid);
|
|
1135
|
-
}
|
|
1136
1256
|
yield delay(delayMs);
|
|
1137
1257
|
attempt += 1;
|
|
1138
|
-
if (shouldReconnect) {
|
|
1139
|
-
try {
|
|
1140
|
-
yield this.reconnectFirmwareUploadTransport(uuid, transport);
|
|
1141
|
-
}
|
|
1142
|
-
catch (e) {
|
|
1143
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
|
|
1144
|
-
if (attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1145
|
-
throw e;
|
|
1146
|
-
}
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
1258
|
}
|
|
1150
1259
|
}
|
|
1151
1260
|
}), e => {
|
|
1152
|
-
|
|
1261
|
+
releaseOwnershipIfCurrent();
|
|
1153
1262
|
Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
|
|
1154
1263
|
});
|
|
1155
1264
|
}
|
|
@@ -1157,11 +1266,17 @@ class ReactNativeBleTransport {
|
|
|
1157
1266
|
for (const o of buffers) {
|
|
1158
1267
|
const outData = o.toString('base64');
|
|
1159
1268
|
try {
|
|
1160
|
-
|
|
1269
|
+
const shouldUseWriteWithResponse = reactNative.Platform.OS === 'ios' && transport.writeCharacteristic.isWritableWithResponse;
|
|
1270
|
+
yield this.writeBlePacket(uuid, outData, payload => shouldUseWriteWithResponse
|
|
1271
|
+
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
1272
|
+
: transport.writeCharacteristic.writeWithoutResponse(payload), isCurrentOwner);
|
|
1161
1273
|
}
|
|
1162
1274
|
catch (e) {
|
|
1163
1275
|
Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
|
|
1164
|
-
|
|
1276
|
+
releaseOwnershipIfCurrent();
|
|
1277
|
+
if (isWedgedWriteError(e)) {
|
|
1278
|
+
throw e;
|
|
1279
|
+
}
|
|
1165
1280
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected) {
|
|
1166
1281
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded);
|
|
1167
1282
|
}
|
|
@@ -1190,17 +1305,23 @@ class ReactNativeBleTransport {
|
|
|
1190
1305
|
if (typeof response !== 'string') {
|
|
1191
1306
|
throw new Error('Returning data is not string.');
|
|
1192
1307
|
}
|
|
1193
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('receive data: ', response);
|
|
1194
1308
|
const jsonData = ProtocolV1.decodeMessage(messages, response);
|
|
1195
1309
|
return check.call(jsonData);
|
|
1196
1310
|
}
|
|
1197
1311
|
catch (e) {
|
|
1198
|
-
if (name === '
|
|
1199
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1312
|
+
if (name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
|
|
1313
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
|
|
1200
1314
|
}
|
|
1201
1315
|
else {
|
|
1202
1316
|
Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
|
|
1203
1317
|
}
|
|
1318
|
+
const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
|
|
1319
|
+
const isStaleCall = this.runPromise !== runPromise;
|
|
1320
|
+
if (!isProbeTimeout &&
|
|
1321
|
+
!isStaleCall &&
|
|
1322
|
+
(e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
|
|
1323
|
+
yield this.disconnect(uuid);
|
|
1324
|
+
}
|
|
1204
1325
|
throw e;
|
|
1205
1326
|
}
|
|
1206
1327
|
finally {
|
|
@@ -1208,6 +1329,7 @@ class ReactNativeBleTransport {
|
|
|
1208
1329
|
clearTimeout(timeout);
|
|
1209
1330
|
if (this.runPromise === runPromise) {
|
|
1210
1331
|
this.runPromise = null;
|
|
1332
|
+
this.runPromiseDeviceId = null;
|
|
1211
1333
|
}
|
|
1212
1334
|
}
|
|
1213
1335
|
});
|
|
@@ -1216,10 +1338,11 @@ class ReactNativeBleTransport {
|
|
|
1216
1338
|
this.stopped = true;
|
|
1217
1339
|
}
|
|
1218
1340
|
disconnect(session) {
|
|
1219
|
-
var _a, _b, _c, _d, _e
|
|
1341
|
+
var _a, _b, _c, _d, _e;
|
|
1220
1342
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1221
|
-
|
|
1343
|
+
yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
|
|
1222
1344
|
const transport = transportCache[session];
|
|
1345
|
+
const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
|
|
1223
1346
|
if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
|
|
1224
1347
|
try {
|
|
1225
1348
|
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing disconnect subscription');
|
|
@@ -1232,7 +1355,7 @@ class ReactNativeBleTransport {
|
|
|
1232
1355
|
}
|
|
1233
1356
|
if (transport === null || transport === void 0 ? void 0 : transport.notifySubscription) {
|
|
1234
1357
|
try {
|
|
1235
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (
|
|
1358
|
+
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
1359
|
transport.notifySubscription.remove();
|
|
1237
1360
|
transport.notifySubscription = undefined;
|
|
1238
1361
|
}
|
|
@@ -1242,7 +1365,7 @@ class ReactNativeBleTransport {
|
|
|
1242
1365
|
}
|
|
1243
1366
|
if (session) {
|
|
1244
1367
|
try {
|
|
1245
|
-
yield ((
|
|
1368
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(session));
|
|
1246
1369
|
}
|
|
1247
1370
|
catch (e) {
|
|
1248
1371
|
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 +1380,7 @@ class ReactNativeBleTransport {
|
|
|
1257
1380
|
}
|
|
1258
1381
|
}
|
|
1259
1382
|
try {
|
|
1260
|
-
yield ((
|
|
1383
|
+
yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelDeviceConnection(session));
|
|
1261
1384
|
}
|
|
1262
1385
|
catch (e) {
|
|
1263
1386
|
Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
|
|
@@ -1266,22 +1389,21 @@ class ReactNativeBleTransport {
|
|
|
1266
1389
|
delete transportCache[session];
|
|
1267
1390
|
}
|
|
1268
1391
|
this.deviceProtocol.delete(session);
|
|
1392
|
+
this.probingProtocols.delete(session);
|
|
1269
1393
|
this.deviceProtocolHints.delete(session);
|
|
1394
|
+
this.sessionProtocols.delete(session);
|
|
1395
|
+
this.protocolReprobeFailures.delete(session);
|
|
1270
1396
|
this.protocolV2Assemblers.delete(session);
|
|
1271
1397
|
this.resetProtocolV2Frames(session);
|
|
1272
|
-
if (((_d = this.activeProtocolV2Call) === null || _d === void 0 ? void 0 : _d.uuid) === session) {
|
|
1273
|
-
this.activeProtocolV2Call = null;
|
|
1274
|
-
}
|
|
1275
1398
|
try {
|
|
1276
|
-
(_e =
|
|
1277
|
-
name: (_f = transport === null || transport === void 0 ? void 0 : transport.device) === null || _f === void 0 ? void 0 : _f.name,
|
|
1278
|
-
id: session,
|
|
1279
|
-
connectId: session,
|
|
1280
|
-
});
|
|
1399
|
+
this.emitDeviceDisconnect(session, (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name, monitorToken);
|
|
1281
1400
|
}
|
|
1282
1401
|
catch (e) {
|
|
1283
1402
|
Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
|
|
1284
1403
|
}
|
|
1404
|
+
if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
|
|
1405
|
+
this.monitorTokens.delete(session);
|
|
1406
|
+
}
|
|
1285
1407
|
yield new Promise(resolve => setTimeout(() => resolve(), 100));
|
|
1286
1408
|
});
|
|
1287
1409
|
}
|
|
@@ -1289,6 +1411,92 @@ class ReactNativeBleTransport {
|
|
|
1289
1411
|
Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
|
|
1290
1412
|
if (this.runPromise) ;
|
|
1291
1413
|
this.runPromise = null;
|
|
1414
|
+
this.runPromiseDeviceId = null;
|
|
1415
|
+
}
|
|
1416
|
+
connectWithTimeout(uuid, connect) {
|
|
1417
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1418
|
+
let timer;
|
|
1419
|
+
let timedOut = false;
|
|
1420
|
+
const pending = connect();
|
|
1421
|
+
pending.catch(() => undefined);
|
|
1422
|
+
try {
|
|
1423
|
+
const result = yield Promise.race([
|
|
1424
|
+
pending,
|
|
1425
|
+
new Promise((_, reject) => {
|
|
1426
|
+
timer = setTimeout(() => {
|
|
1427
|
+
timedOut = true;
|
|
1428
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `BLE connect timeout after ${BLE_CONNECT_TIMEOUT_MS}ms for ${uuid}`));
|
|
1429
|
+
}, BLE_CONNECT_TIMEOUT_MS);
|
|
1430
|
+
}),
|
|
1431
|
+
]);
|
|
1432
|
+
return result;
|
|
1433
|
+
}
|
|
1434
|
+
catch (error) {
|
|
1435
|
+
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1436
|
+
this.abandonStalledConnection(uuid, timedOut ? 'connect-backstop' : 'connect-native');
|
|
1437
|
+
}
|
|
1438
|
+
throw error;
|
|
1439
|
+
}
|
|
1440
|
+
finally {
|
|
1441
|
+
if (timer)
|
|
1442
|
+
clearTimeout(timer);
|
|
1443
|
+
}
|
|
1444
|
+
});
|
|
1445
|
+
}
|
|
1446
|
+
resolveCharacteristicsWithTimeout(uuid, device) {
|
|
1447
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1448
|
+
let timer;
|
|
1449
|
+
let timedOut = false;
|
|
1450
|
+
const pending = this.resolveCharacteristics(device);
|
|
1451
|
+
pending.catch(() => undefined);
|
|
1452
|
+
try {
|
|
1453
|
+
const result = yield Promise.race([
|
|
1454
|
+
pending,
|
|
1455
|
+
new Promise((_, reject) => {
|
|
1456
|
+
timer = setTimeout(() => {
|
|
1457
|
+
timedOut = true;
|
|
1458
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `BLE GATT setup timeout after ${BLE_GATT_SETUP_TIMEOUT_MS}ms for ${uuid}`));
|
|
1459
|
+
}, BLE_GATT_SETUP_TIMEOUT_MS);
|
|
1460
|
+
}),
|
|
1461
|
+
]);
|
|
1462
|
+
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1463
|
+
return result;
|
|
1464
|
+
}
|
|
1465
|
+
catch (error) {
|
|
1466
|
+
if (timedOut || isNativeOperationTimeoutError(error)) {
|
|
1467
|
+
this.abandonStalledConnection(uuid, timedOut ? 'gatt-backstop' : 'gatt-native');
|
|
1468
|
+
}
|
|
1469
|
+
throw error;
|
|
1470
|
+
}
|
|
1471
|
+
finally {
|
|
1472
|
+
if (timer)
|
|
1473
|
+
clearTimeout(timer);
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
abandonStalledConnection(uuid, stage) {
|
|
1478
|
+
var _a, _b;
|
|
1479
|
+
const timeouts = ((_a = this.connectionSetupTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1480
|
+
this.connectionSetupTimeoutCounts.set(uuid, timeouts);
|
|
1481
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup timed out:', uuid, {
|
|
1482
|
+
stage,
|
|
1483
|
+
setupTimeoutsSinceSuccess: timeouts,
|
|
1484
|
+
});
|
|
1485
|
+
(_b = this.blePlxManager) === null || _b === void 0 ? void 0 : _b.cancelDeviceConnection(uuid).catch(() => {
|
|
1486
|
+
});
|
|
1487
|
+
const stalled = transportCache[uuid];
|
|
1488
|
+
if (stalled) {
|
|
1489
|
+
delete transportCache[uuid];
|
|
1490
|
+
}
|
|
1491
|
+
this.deviceProtocol.delete(uuid);
|
|
1492
|
+
this.probingProtocols.delete(uuid);
|
|
1493
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1494
|
+
this.resetProtocolV2Frames(uuid);
|
|
1495
|
+
if (timeouts >= BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1496
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE setup wedged repeatedly, resetting BLE manager');
|
|
1497
|
+
this.resetPlxManager();
|
|
1498
|
+
this.connectionSetupTimeoutCounts.delete(uuid);
|
|
1499
|
+
}
|
|
1292
1500
|
}
|
|
1293
1501
|
getCachedTransport(uuid) {
|
|
1294
1502
|
const transport = transportCache[uuid];
|
|
@@ -1297,58 +1505,187 @@ class ReactNativeBleTransport {
|
|
|
1297
1505
|
}
|
|
1298
1506
|
return transport;
|
|
1299
1507
|
}
|
|
1508
|
+
writeBlePacket(uuid, data, write, isCurrentOwner) {
|
|
1509
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1510
|
+
let timer;
|
|
1511
|
+
let timedOut = false;
|
|
1512
|
+
try {
|
|
1513
|
+
yield Promise.race([
|
|
1514
|
+
write(data),
|
|
1515
|
+
new Promise((_, reject) => {
|
|
1516
|
+
timer = setTimeout(() => {
|
|
1517
|
+
timedOut = true;
|
|
1518
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError, `BLE write timeout after ${BLE_WRITE_PACKET_TIMEOUT_MS}ms`));
|
|
1519
|
+
}, BLE_WRITE_PACKET_TIMEOUT_MS);
|
|
1520
|
+
}),
|
|
1521
|
+
]);
|
|
1522
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1523
|
+
}
|
|
1524
|
+
catch (error) {
|
|
1525
|
+
if (timedOut) {
|
|
1526
|
+
if (isCurrentOwner && !isCurrentOwner()) {
|
|
1527
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] stale BLE write timed out, link kept:', uuid);
|
|
1528
|
+
}
|
|
1529
|
+
else {
|
|
1530
|
+
this.tearDownWedgedLink(uuid);
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
throw error;
|
|
1534
|
+
}
|
|
1535
|
+
finally {
|
|
1536
|
+
if (timer)
|
|
1537
|
+
clearTimeout(timer);
|
|
1538
|
+
}
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
tearDownWedgedLink(uuid) {
|
|
1542
|
+
var _a;
|
|
1543
|
+
const timeouts = ((_a = this.writeTimeoutCounts.get(uuid)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
1544
|
+
this.writeTimeoutCounts.set(uuid, timeouts);
|
|
1545
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE write timed out, tearing down link:', uuid, {
|
|
1546
|
+
consecutiveWriteTimeouts: timeouts,
|
|
1547
|
+
});
|
|
1548
|
+
const wedged = transportCache[uuid];
|
|
1549
|
+
this.disconnect(uuid).catch(error => {
|
|
1550
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] wedged link teardown failed (ignored):', error);
|
|
1551
|
+
});
|
|
1552
|
+
if (wedged && transportCache[uuid] === wedged) {
|
|
1553
|
+
delete transportCache[uuid];
|
|
1554
|
+
}
|
|
1555
|
+
this.deviceProtocol.delete(uuid);
|
|
1556
|
+
this.probingProtocols.delete(uuid);
|
|
1557
|
+
this.protocolV2Assemblers.delete(uuid);
|
|
1558
|
+
this.resetProtocolV2Frames(uuid);
|
|
1559
|
+
if (timeouts >= BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD) {
|
|
1560
|
+
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] BLE writes wedged repeatedly, resetting BLE manager');
|
|
1561
|
+
this.resetPlxManager();
|
|
1562
|
+
this.writeTimeoutCounts.delete(uuid);
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
resetPlxManager() {
|
|
1566
|
+
const manager = this.blePlxManager;
|
|
1567
|
+
this.blePlxManager = undefined;
|
|
1568
|
+
Object.keys(transportCache).forEach(key => {
|
|
1569
|
+
delete transportCache[key];
|
|
1570
|
+
});
|
|
1571
|
+
this.deviceProtocol.clear();
|
|
1572
|
+
this.probingProtocols.clear();
|
|
1573
|
+
this.sessionProtocols.clear();
|
|
1574
|
+
this.protocolReprobeFailures.clear();
|
|
1575
|
+
this.monitorTokens.clear();
|
|
1576
|
+
this.protocolV2Assemblers.clear();
|
|
1577
|
+
try {
|
|
1578
|
+
manager === null || manager === void 0 ? void 0 : manager.destroy();
|
|
1579
|
+
}
|
|
1580
|
+
catch (error) {
|
|
1581
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE manager destroy failed (ignored):', error);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1300
1584
|
createProtocolMismatchError(expected) {
|
|
1301
1585
|
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
|
|
1302
1586
|
}
|
|
1303
1587
|
createProtocolDetectionError() {
|
|
1304
|
-
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1
|
|
1588
|
+
return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 GetFeatures or Protocol V2 Ping');
|
|
1305
1589
|
}
|
|
1306
1590
|
clearProbeProtocol(uuid, protocol) {
|
|
1591
|
+
if (this.probingProtocols.get(uuid) === protocol) {
|
|
1592
|
+
this.probingProtocols.delete(uuid);
|
|
1593
|
+
}
|
|
1307
1594
|
if (this.deviceProtocol.get(uuid) === protocol) {
|
|
1308
1595
|
this.deviceProtocol.delete(uuid);
|
|
1309
1596
|
}
|
|
1310
1597
|
}
|
|
1311
|
-
|
|
1598
|
+
getActiveProtocol(uuid) {
|
|
1599
|
+
var _a;
|
|
1600
|
+
return (_a = this.deviceProtocol.get(uuid)) !== null && _a !== void 0 ? _a : this.probingProtocols.get(uuid);
|
|
1601
|
+
}
|
|
1602
|
+
detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
|
|
1603
|
+
var _a;
|
|
1312
1604
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1605
|
+
if (reactNative.Platform.OS === 'ios' && expectedProtocol) {
|
|
1606
|
+
this.deviceProtocol.set(uuid, expectedProtocol);
|
|
1607
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol selected', {
|
|
1608
|
+
deviceId: uuid,
|
|
1609
|
+
protocol: expectedProtocol,
|
|
1610
|
+
source: 'expected',
|
|
1611
|
+
});
|
|
1612
|
+
return expectedProtocol;
|
|
1613
|
+
}
|
|
1313
1614
|
if (expectedProtocol === 'V1') {
|
|
1314
1615
|
if (yield this.probeProtocolV1(uuid)) {
|
|
1315
1616
|
this.deviceProtocol.set(uuid, 'V1');
|
|
1316
|
-
|
|
1617
|
+
this.sessionProtocols.set(uuid, 'V1');
|
|
1618
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1619
|
+
deviceId: uuid,
|
|
1620
|
+
protocol: 'V1',
|
|
1621
|
+
source: 'expected',
|
|
1622
|
+
});
|
|
1317
1623
|
return 'V1';
|
|
1318
1624
|
}
|
|
1319
1625
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1320
1626
|
}
|
|
1321
1627
|
if (expectedProtocol === 'V2') {
|
|
1322
|
-
this.
|
|
1323
|
-
|
|
1324
|
-
|
|
1628
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1629
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1630
|
+
this.sessionProtocols.set(uuid, 'V2');
|
|
1631
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1632
|
+
deviceId: uuid,
|
|
1633
|
+
protocol: 'V2',
|
|
1634
|
+
source: 'expected',
|
|
1635
|
+
});
|
|
1636
|
+
return 'V2';
|
|
1637
|
+
}
|
|
1638
|
+
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1325
1639
|
}
|
|
1326
|
-
const
|
|
1640
|
+
const sessionProtocol = this.sessionProtocols.get(uuid);
|
|
1641
|
+
const reprobeFailures = (_a = this.protocolReprobeFailures.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
1642
|
+
const fullProbeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
|
|
1643
|
+
const trustSessionProtocol = sessionProtocol !== undefined &&
|
|
1644
|
+
!protocolHint &&
|
|
1645
|
+
reprobeFailures < PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1646
|
+
const probeOrder = trustSessionProtocol ? [sessionProtocol] : fullProbeOrder;
|
|
1327
1647
|
for (let i = 0; i < probeOrder.length; i += 1) {
|
|
1328
1648
|
const protocol = probeOrder[i];
|
|
1329
1649
|
if (i > 0) {
|
|
1330
1650
|
yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
|
|
1651
|
+
if (!transportCache[uuid]) {
|
|
1652
|
+
if (!rebuildTransport) {
|
|
1653
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
|
|
1654
|
+
}
|
|
1655
|
+
yield rebuildTransport();
|
|
1656
|
+
}
|
|
1331
1657
|
}
|
|
1332
1658
|
const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
|
|
1333
1659
|
if (detected) {
|
|
1334
1660
|
this.deviceProtocol.set(uuid, protocol);
|
|
1335
|
-
|
|
1661
|
+
this.sessionProtocols.set(uuid, protocol);
|
|
1662
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
1663
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
|
|
1664
|
+
deviceId: uuid,
|
|
1665
|
+
protocol,
|
|
1666
|
+
source: 'probe',
|
|
1667
|
+
});
|
|
1336
1668
|
return protocol;
|
|
1337
1669
|
}
|
|
1338
1670
|
}
|
|
1671
|
+
if (trustSessionProtocol) {
|
|
1672
|
+
this.protocolReprobeFailures.set(uuid, reprobeFailures + 1);
|
|
1673
|
+
}
|
|
1674
|
+
else {
|
|
1675
|
+
this.protocolReprobeFailures.delete(uuid);
|
|
1676
|
+
}
|
|
1339
1677
|
this.deviceProtocol.delete(uuid);
|
|
1678
|
+
this.probingProtocols.delete(uuid);
|
|
1340
1679
|
throw this.createProtocolDetectionError();
|
|
1341
1680
|
});
|
|
1342
1681
|
}
|
|
1343
1682
|
resetProbeStateAfterProtocolProbe(uuid, protocol) {
|
|
1344
|
-
var _a, _b, _c
|
|
1683
|
+
var _a, _b, _c;
|
|
1345
1684
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1346
1685
|
const transport = transportCache[uuid];
|
|
1686
|
+
yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
|
|
1347
1687
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1348
1688
|
this.resetProtocolV2Frames(uuid);
|
|
1349
|
-
if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
|
|
1350
|
-
this.activeProtocolV2Call = null;
|
|
1351
|
-
}
|
|
1352
1689
|
if (this.runPromise) {
|
|
1353
1690
|
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1354
1691
|
this.runPromise.reject(error);
|
|
@@ -1360,11 +1697,11 @@ class ReactNativeBleTransport {
|
|
|
1360
1697
|
if (this.monitorTokens.get(uuid) === transport.monitorToken) {
|
|
1361
1698
|
this.monitorTokens.delete(uuid);
|
|
1362
1699
|
}
|
|
1363
|
-
(
|
|
1700
|
+
(_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
|
|
1364
1701
|
transport.notifySubscription = undefined;
|
|
1365
1702
|
if (previousNotifyTransactionId) {
|
|
1366
1703
|
try {
|
|
1367
|
-
yield ((
|
|
1704
|
+
yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(previousNotifyTransactionId));
|
|
1368
1705
|
}
|
|
1369
1706
|
catch (error) {
|
|
1370
1707
|
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] cancel notify after Protocol ${protocol} probe failed:`, (error === null || error === void 0 ? void 0 : error.message) || error);
|
|
@@ -1390,13 +1727,17 @@ class ReactNativeBleTransport {
|
|
|
1390
1727
|
return false;
|
|
1391
1728
|
}
|
|
1392
1729
|
try {
|
|
1393
|
-
this.
|
|
1394
|
-
yield this.callProtocolV1(uuid, '
|
|
1730
|
+
this.probingProtocols.set(uuid, 'V1');
|
|
1731
|
+
yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
|
|
1732
|
+
this.probingProtocols.delete(uuid);
|
|
1395
1733
|
return true;
|
|
1396
1734
|
}
|
|
1397
1735
|
catch (error) {
|
|
1398
1736
|
this.clearProbeProtocol(uuid, 'V1');
|
|
1399
|
-
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1
|
|
1737
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
|
|
1738
|
+
if (isWedgedWriteError(error)) {
|
|
1739
|
+
throw error;
|
|
1740
|
+
}
|
|
1400
1741
|
return false;
|
|
1401
1742
|
}
|
|
1402
1743
|
});
|
|
@@ -1407,7 +1748,7 @@ class ReactNativeBleTransport {
|
|
|
1407
1748
|
if (!this._messages || !this._messagesV2) {
|
|
1408
1749
|
return false;
|
|
1409
1750
|
}
|
|
1410
|
-
this.
|
|
1751
|
+
this.probingProtocols.set(uuid, 'V2');
|
|
1411
1752
|
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1412
1753
|
const detected = yield transport.probeProtocolV2({
|
|
1413
1754
|
call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
|
|
@@ -1423,17 +1764,16 @@ class ReactNativeBleTransport {
|
|
|
1423
1764
|
if (!detected) {
|
|
1424
1765
|
this.clearProbeProtocol(uuid, 'V2');
|
|
1425
1766
|
}
|
|
1767
|
+
else {
|
|
1768
|
+
this.probingProtocols.delete(uuid);
|
|
1769
|
+
}
|
|
1426
1770
|
return detected;
|
|
1427
1771
|
});
|
|
1428
1772
|
}
|
|
1429
|
-
handleProtocolV2Notification(uuid, data) {
|
|
1430
|
-
var _a, _b, _c;
|
|
1773
|
+
handleProtocolV2Notification(uuid, monitorToken, data) {
|
|
1431
1774
|
try {
|
|
1432
|
-
if (
|
|
1433
|
-
(_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
|
|
1434
|
-
this.resetProtocolV2Frames(uuid);
|
|
1775
|
+
if (this.monitorTokens.get(uuid) !== monitorToken)
|
|
1435
1776
|
return;
|
|
1436
|
-
}
|
|
1437
1777
|
if (data.length === 0)
|
|
1438
1778
|
return;
|
|
1439
1779
|
const assembler = this.protocolV2Assemblers.get(uuid);
|
|
@@ -1446,8 +1786,10 @@ class ReactNativeBleTransport {
|
|
|
1446
1786
|
catch (error) {
|
|
1447
1787
|
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
|
|
1448
1788
|
const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
|
|
1449
|
-
|
|
1450
|
-
this.
|
|
1789
|
+
this.rejectProtocolV2Frames(uuid, notifyError);
|
|
1790
|
+
this.protocolV2Links
|
|
1791
|
+
.invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
|
|
1792
|
+
.catch(invalidateError => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notify cleanup failed:', invalidateError));
|
|
1451
1793
|
}
|
|
1452
1794
|
}
|
|
1453
1795
|
getProtocolV2FrameQueue(uuid) {
|
|
@@ -1467,20 +1809,16 @@ class ReactNativeBleTransport {
|
|
|
1467
1809
|
}
|
|
1468
1810
|
this.getProtocolV2FrameQueue(uuid).push(frame);
|
|
1469
1811
|
}
|
|
1470
|
-
rejectAllProtocolV2Frames(error) {
|
|
1471
|
-
this.protocolV2FrameQueues.clear();
|
|
1472
|
-
for (const framePromise of this.protocolV2FramePromises.values()) {
|
|
1473
|
-
framePromise.reject(error);
|
|
1474
|
-
}
|
|
1475
|
-
this.protocolV2FramePromises.clear();
|
|
1476
|
-
}
|
|
1477
1812
|
resetProtocolV2Frames(uuid) {
|
|
1478
|
-
this.
|
|
1479
|
-
this.protocolV2FramePromises.delete(uuid);
|
|
1813
|
+
this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
|
|
1480
1814
|
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1815
|
+
rejectProtocolV2Frames(uuid, error) {
|
|
1816
|
+
this.protocolV2FrameQueues.delete(uuid);
|
|
1817
|
+
const framePromise = this.protocolV2FramePromises.get(uuid);
|
|
1818
|
+
if (framePromise) {
|
|
1819
|
+
this.protocolV2FramePromises.delete(uuid);
|
|
1820
|
+
framePromise.reject(error);
|
|
1821
|
+
}
|
|
1484
1822
|
}
|
|
1485
1823
|
readProtocolV2Frame(uuid) {
|
|
1486
1824
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -1500,133 +1838,240 @@ class ReactNativeBleTransport {
|
|
|
1500
1838
|
}
|
|
1501
1839
|
});
|
|
1502
1840
|
}
|
|
1503
|
-
|
|
1841
|
+
writeProtocolV2Packet(uuid, transport, base64, context, assertCurrentGeneration) {
|
|
1504
1842
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1505
|
-
const
|
|
1506
|
-
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1843
|
+
const shouldUseWriteWithResponse = shouldWriteProtocolV2WithResponse({
|
|
1507
1844
|
platform: reactNative.Platform.OS,
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1845
|
+
highVolume: context.highVolume,
|
|
1846
|
+
requestedWithResponse: context.writeWithResponse,
|
|
1847
|
+
characteristic: transport.writeCharacteristic,
|
|
1511
1848
|
});
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1518
|
-
const base64 = buffer.Buffer.from(chunk).toString('base64');
|
|
1519
|
-
if (writeMode === 'withResponse') {
|
|
1520
|
-
yield transport.writeCharacteristic.writeWithResponse(base64);
|
|
1849
|
+
let attempt = 0;
|
|
1850
|
+
for (;;) {
|
|
1851
|
+
assertCurrentGeneration();
|
|
1852
|
+
if (context.signal.aborted) {
|
|
1853
|
+
throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
|
|
1521
1854
|
}
|
|
1522
|
-
|
|
1523
|
-
yield
|
|
1855
|
+
try {
|
|
1856
|
+
yield this.writeBlePacket(uuid, base64, payload => shouldUseWriteWithResponse
|
|
1857
|
+
? transport.writeCharacteristic.writeWithResponse(payload)
|
|
1858
|
+
: transport.writeCharacteristic.writeWithoutResponse(payload), () => {
|
|
1859
|
+
try {
|
|
1860
|
+
assertCurrentGeneration();
|
|
1861
|
+
return !context.signal.aborted;
|
|
1862
|
+
}
|
|
1863
|
+
catch (_a) {
|
|
1864
|
+
return false;
|
|
1865
|
+
}
|
|
1866
|
+
});
|
|
1867
|
+
assertCurrentGeneration();
|
|
1868
|
+
return;
|
|
1524
1869
|
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1870
|
+
catch (error) {
|
|
1871
|
+
if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
|
|
1872
|
+
attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
|
|
1873
|
+
throw error;
|
|
1874
|
+
}
|
|
1875
|
+
const delayMs = resolveFirmwareUploadRetryDelay(attempt);
|
|
1876
|
+
attempt += 1;
|
|
1877
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 congested write retry:', {
|
|
1878
|
+
name: context.messageName,
|
|
1879
|
+
attempt,
|
|
1880
|
+
delayMs,
|
|
1881
|
+
});
|
|
1882
|
+
yield delay(delayMs);
|
|
1530
1883
|
}
|
|
1531
1884
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1885
|
+
});
|
|
1886
|
+
}
|
|
1887
|
+
writeProtocolV2Frame(uuid, transport$1, frame, context, assertCurrentGeneration) {
|
|
1888
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1889
|
+
const tuning = getProtocolV2BleTuning();
|
|
1890
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1891
|
+
platform: reactNative.Platform.OS,
|
|
1892
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
1893
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
1894
|
+
mtu: transport$1.mtuSize,
|
|
1895
|
+
});
|
|
1896
|
+
yield transport.writeProtocolV2BleFrame({
|
|
1897
|
+
frame,
|
|
1898
|
+
packetCapacity,
|
|
1899
|
+
assertActive: assertCurrentGeneration,
|
|
1900
|
+
signal: context.signal,
|
|
1901
|
+
abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
|
|
1902
|
+
wait: delay,
|
|
1903
|
+
writePacket: packet => this.writeProtocolV2Packet(uuid, transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
|
|
1904
|
+
});
|
|
1535
1905
|
});
|
|
1536
1906
|
}
|
|
1537
1907
|
callProtocolV2(uuid, name, data, options) {
|
|
1538
|
-
var _a
|
|
1908
|
+
var _a;
|
|
1539
1909
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1540
1910
|
if (!this._messages || !this._messagesV2) {
|
|
1541
1911
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1542
1912
|
}
|
|
1543
|
-
const
|
|
1544
|
-
if (this.runPromise) {
|
|
1545
|
-
if (!forceRun) {
|
|
1546
|
-
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
|
|
1547
|
-
}
|
|
1548
|
-
const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
|
|
1549
|
-
this.runPromise.reject(error);
|
|
1550
|
-
this.rejectAllProtocolV2Frames(error);
|
|
1551
|
-
this.runPromise = null;
|
|
1552
|
-
this.activeProtocolV2Call = null;
|
|
1553
|
-
}
|
|
1554
|
-
const transport$1 = this.getCachedTransport(uuid);
|
|
1555
|
-
const runPromise = hdShared.createDeferred();
|
|
1556
|
-
runPromise.promise.catch(() => undefined);
|
|
1557
|
-
this.runPromise = runPromise;
|
|
1558
|
-
const callToken = this.nextProtocolV2CallToken++;
|
|
1559
|
-
this.activeProtocolV2Call = { uuid, token: callToken };
|
|
1560
|
-
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
1561
|
-
this.resetProtocolV2Frames(uuid);
|
|
1562
|
-
let completed = false;
|
|
1563
|
-
const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
|
|
1913
|
+
const callOptions = options;
|
|
1564
1914
|
const highVolumeWrite = transport.LogBlockCommand.has(name);
|
|
1565
1915
|
if (highVolumeWrite) {
|
|
1566
1916
|
const tuning = getProtocolV2BleTuning();
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1917
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
1918
|
+
const writeWithResponse = shouldWriteProtocolV2WithResponse({
|
|
1919
|
+
platform: reactNative.Platform.OS,
|
|
1920
|
+
highVolume: true,
|
|
1921
|
+
requestedWithResponse: options === null || options === void 0 ? void 0 : options.writeWithResponse,
|
|
1922
|
+
characteristic: currentTransport.writeCharacteristic,
|
|
1923
|
+
});
|
|
1924
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1925
|
+
platform: reactNative.Platform.OS,
|
|
1926
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
1927
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
1928
|
+
mtu: currentTransport.mtuSize,
|
|
1573
1929
|
});
|
|
1930
|
+
const writeMode = writeWithResponse ? 'withResponse' : 'withoutResponse';
|
|
1931
|
+
const logSignature = `${name}:${writeMode}:${String(currentTransport.mtuSize)}:${packetCapacity}`;
|
|
1932
|
+
const loggedSignatures = (_a = this.protocolV2HighVolumeLogSignatures.get(uuid)) !== null && _a !== void 0 ? _a : new Set();
|
|
1933
|
+
if (!loggedSignatures.has(logSignature)) {
|
|
1934
|
+
loggedSignatures.add(logSignature);
|
|
1935
|
+
this.protocolV2HighVolumeLogSignatures.set(uuid, loggedSignatures);
|
|
1936
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
|
|
1937
|
+
name,
|
|
1938
|
+
writeMode,
|
|
1939
|
+
reportedMtu: currentTransport.mtuSize,
|
|
1940
|
+
packetCapacity,
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
}
|
|
1944
|
+
if (highVolumeWrite) {
|
|
1945
|
+
yield this.enableAndroidHighConnectionPriority(uuid);
|
|
1574
1946
|
}
|
|
1575
1947
|
try {
|
|
1576
|
-
|
|
1577
|
-
schemas: {
|
|
1578
|
-
protocolV1: this._messages,
|
|
1579
|
-
protocolV2: this._messagesV2,
|
|
1580
|
-
},
|
|
1581
|
-
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1582
|
-
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
1583
|
-
yield this.writeProtocolV2Frame(transport$1, frame, {
|
|
1584
|
-
highVolume: highVolumeWrite,
|
|
1585
|
-
});
|
|
1586
|
-
}),
|
|
1587
|
-
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1588
|
-
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1589
|
-
if (!(rxFrame instanceof Uint8Array)) {
|
|
1590
|
-
throw new Error('Protocol V2 response is not Uint8Array');
|
|
1591
|
-
}
|
|
1592
|
-
return rxFrame;
|
|
1593
|
-
}),
|
|
1594
|
-
logger: Log,
|
|
1595
|
-
logPrefix: 'ProtocolV2 RN-BLE',
|
|
1596
|
-
createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
|
|
1597
|
-
});
|
|
1598
|
-
const result = yield session.call(name, data, callOptions);
|
|
1599
|
-
completed = true;
|
|
1600
|
-
return result;
|
|
1948
|
+
return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
|
|
1601
1949
|
}
|
|
1602
1950
|
catch (e) {
|
|
1603
|
-
if (this.isActiveProtocolV2Call(uuid, callToken)) {
|
|
1604
|
-
(_c = this.protocolV2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
|
|
1605
|
-
this.resetProtocolV2Frames(uuid);
|
|
1606
|
-
}
|
|
1607
1951
|
Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
1608
1952
|
throw e;
|
|
1609
1953
|
}
|
|
1610
1954
|
finally {
|
|
1611
|
-
if (
|
|
1612
|
-
|
|
1613
|
-
(_d = this.protocolV2Assemblers.get(uuid)) === null || _d === void 0 ? void 0 : _d.reset();
|
|
1614
|
-
}
|
|
1615
|
-
this.resetProtocolV2Frames(uuid);
|
|
1616
|
-
this.activeProtocolV2Call = null;
|
|
1617
|
-
}
|
|
1618
|
-
if (this.runPromise === runPromise) {
|
|
1619
|
-
this.runPromise = null;
|
|
1955
|
+
if (highVolumeWrite) {
|
|
1956
|
+
this.scheduleAndroidBalancedConnectionPriority(uuid);
|
|
1620
1957
|
}
|
|
1621
1958
|
}
|
|
1622
1959
|
});
|
|
1623
1960
|
}
|
|
1961
|
+
clearAndroidPriorityResetTimer(uuid) {
|
|
1962
|
+
const timerId = this.androidPriorityResetTimers.get(uuid);
|
|
1963
|
+
if (timerId !== undefined) {
|
|
1964
|
+
clearTimeout(timerId);
|
|
1965
|
+
this.androidPriorityResetTimers.delete(uuid);
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
enableAndroidHighConnectionPriority(uuid) {
|
|
1969
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1970
|
+
if (reactNative.Platform.OS !== 'android')
|
|
1971
|
+
return;
|
|
1972
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
1973
|
+
if (this.androidHighPriorityDevices.has(uuid))
|
|
1974
|
+
return;
|
|
1975
|
+
const transport = transportCache[uuid];
|
|
1976
|
+
if (!transport)
|
|
1977
|
+
return;
|
|
1978
|
+
try {
|
|
1979
|
+
transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.High);
|
|
1980
|
+
this.androidHighPriorityDevices.add(uuid);
|
|
1981
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
|
|
1982
|
+
priority: 'high',
|
|
1983
|
+
});
|
|
1984
|
+
}
|
|
1985
|
+
catch (error) {
|
|
1986
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE high priority request failed', {
|
|
1987
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
});
|
|
1991
|
+
}
|
|
1992
|
+
scheduleAndroidBalancedConnectionPriority(uuid) {
|
|
1993
|
+
if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.has(uuid))
|
|
1994
|
+
return;
|
|
1995
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
1996
|
+
const timerId = setTimeout(() => {
|
|
1997
|
+
this.androidPriorityResetTimers.delete(uuid);
|
|
1998
|
+
this.restoreAndroidConnectionPriority(uuid, transportCache[uuid]).catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE priority restore failed', error));
|
|
1999
|
+
}, ANDROID_HIGH_PRIORITY_IDLE_MS);
|
|
2000
|
+
this.androidPriorityResetTimers.set(uuid, timerId);
|
|
2001
|
+
}
|
|
2002
|
+
restoreAndroidConnectionPriority(uuid, transport) {
|
|
2003
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
2004
|
+
this.clearAndroidPriorityResetTimer(uuid);
|
|
2005
|
+
if (reactNative.Platform.OS !== 'android' || !this.androidHighPriorityDevices.delete(uuid) || !transport) {
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
2008
|
+
try {
|
|
2009
|
+
transport.device = yield transport.device.requestConnectionPriority(reactNativeBlePlx.ConnectionPriority.Balanced);
|
|
2010
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE connection priority changed', {
|
|
2011
|
+
priority: 'balanced',
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
catch (error) {
|
|
2015
|
+
Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android BLE balanced priority request failed', {
|
|
2016
|
+
error: error instanceof Error ? error.message : String(error),
|
|
2017
|
+
});
|
|
2018
|
+
}
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
createProtocolV2Adapter(uuid) {
|
|
2022
|
+
var _a;
|
|
2023
|
+
const generation = (_a = this.monitorTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
|
|
2024
|
+
const assertCurrentGeneration = () => {
|
|
2025
|
+
if (this.monitorTokens.get(uuid) !== generation) {
|
|
2026
|
+
throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
|
|
2027
|
+
}
|
|
2028
|
+
};
|
|
2029
|
+
return {
|
|
2030
|
+
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
2031
|
+
maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
2032
|
+
generation,
|
|
2033
|
+
prepareCall: () => {
|
|
2034
|
+
var _a;
|
|
2035
|
+
assertCurrentGeneration();
|
|
2036
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
2037
|
+
this.resetProtocolV2Frames(uuid);
|
|
2038
|
+
},
|
|
2039
|
+
writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
|
|
2040
|
+
assertCurrentGeneration();
|
|
2041
|
+
const currentTransport = this.getCachedTransport(uuid);
|
|
2042
|
+
yield this.writeProtocolV2Frame(uuid, currentTransport, frame, context, assertCurrentGeneration);
|
|
2043
|
+
}),
|
|
2044
|
+
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
2045
|
+
assertCurrentGeneration();
|
|
2046
|
+
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
2047
|
+
if (!(rxFrame instanceof Uint8Array)) {
|
|
2048
|
+
throw new Error('Protocol V2 response is not Uint8Array');
|
|
2049
|
+
}
|
|
2050
|
+
return rxFrame;
|
|
2051
|
+
}),
|
|
2052
|
+
reset: (reason) => {
|
|
2053
|
+
var _a;
|
|
2054
|
+
(_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
|
|
2055
|
+
this.rejectProtocolV2Frames(uuid, new Error(reason));
|
|
2056
|
+
},
|
|
2057
|
+
logger: Log,
|
|
2058
|
+
logPrefix: 'ProtocolV2 RN-BLE',
|
|
2059
|
+
createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
1624
2062
|
getProtocolType(path) {
|
|
1625
|
-
return this.
|
|
2063
|
+
return this.getActiveProtocol(path);
|
|
1626
2064
|
}
|
|
1627
2065
|
}
|
|
1628
2066
|
|
|
2067
|
+
exports.BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_CONNECT_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2068
|
+
exports.BLE_CONNECT_TIMEOUT_MS = BLE_CONNECT_TIMEOUT_MS;
|
|
2069
|
+
exports.BLE_GATT_SETUP_TIMEOUT_MS = BLE_GATT_SETUP_TIMEOUT_MS;
|
|
2070
|
+
exports.BLE_WRITE_PACKET_TIMEOUT_MS = BLE_WRITE_PACKET_TIMEOUT_MS;
|
|
2071
|
+
exports.BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD = BLE_WRITE_TIMEOUT_MANAGER_RESET_THRESHOLD;
|
|
2072
|
+
exports.PROTOCOL_REPROBE_FALLBACK_ATTEMPTS = PROTOCOL_REPROBE_FALLBACK_ATTEMPTS;
|
|
1629
2073
|
exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
|
|
1630
2074
|
exports["default"] = ReactNativeBleTransport;
|
|
2075
|
+
exports.getFirmwareUploadWriteRetryType = getFirmwareUploadWriteRetryType;
|
|
1631
2076
|
exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
|
|
1632
2077
|
exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;
|