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