@onekeyfe/hd-transport-react-native 1.2.0-alpha.4 → 1.2.0-alpha.40

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/index.js CHANGED
@@ -117,42 +117,23 @@ const getInfosForServiceUuid = (serviceUuid, deviceType) => {
117
117
  return null;
118
118
  }
119
119
  const normalizedServiceUuid = normalizeBleUuid(serviceUuid);
120
- const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid);
120
+ const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid ||
121
+ hdShared.matchesKnownBleUuid(serviceUuid, hdShared.createKnownBleUuidAliases(item.serviceUuid)));
121
122
  if (!service) {
122
123
  return null;
123
124
  }
124
125
  return service;
125
126
  };
126
127
  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
128
  const isSameBleUuid = (left, right) => {
132
- const normalizedLeft = normalizeBleUuid(left);
133
- const normalizedRight = normalizeBleUuid(right);
134
- return (normalizedLeft === normalizedRight ||
135
- (getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
129
+ if (!left || !right)
130
+ return false;
131
+ return hdShared.matchesKnownBleUuid(left, hdShared.createKnownBleUuidAliases(right));
136
132
  };
137
133
 
138
134
  function hasWritableCapability(characteristic) {
139
135
  return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
140
136
  }
141
- function resolveBleWriteMode(characteristic, preferredMode = 'withoutResponse') {
142
- if (preferredMode === 'withoutResponse' && characteristic.isWritableWithoutResponse) {
143
- return 'withoutResponse';
144
- }
145
- if (preferredMode === 'withResponse' && characteristic.isWritableWithResponse) {
146
- return 'withResponse';
147
- }
148
- if (characteristic.isWritableWithoutResponse) {
149
- return 'withoutResponse';
150
- }
151
- if (characteristic.isWritableWithResponse) {
152
- return 'withResponse';
153
- }
154
- return preferredMode;
155
- }
156
137
  function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PACKET_LENGTH, androidPacketLength = ANDROID_PACKET_LENGTH, mtu, }) {
157
138
  if (platform === 'ios') {
158
139
  return iosPacketLength;
@@ -189,7 +170,6 @@ const timer = process.env.NODE_ENV === 'development'
189
170
  const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
190
171
  let done = false;
191
172
  const subscription = bleManager.onStateChange(state => {
192
- console.log('ble state -> ', state);
193
173
  if (state === 'PoweredOn') {
194
174
  if (done)
195
175
  return;
@@ -219,7 +199,6 @@ const isHeaderChunk = (chunk) => {
219
199
  return false;
220
200
  };
221
201
 
222
- const Log$1 = bleLogger;
223
202
  class BleTransport {
224
203
  constructor(device, writeCharacteristic, notifyCharacteristic) {
225
204
  this.name = 'ReactNativeBleTransport';
@@ -229,37 +208,12 @@ class BleTransport {
229
208
  this.writeCharacteristic = writeCharacteristic;
230
209
  this.notifyCharacteristic = notifyCharacteristic;
231
210
  }
232
- writeWithRetry(data, retryCount = BleTransport.MAX_RETRIES) {
211
+ writeWithRetry(data) {
233
212
  return __awaiter(this, void 0, void 0, function* () {
234
- try {
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
- }
213
+ yield this.writeCharacteristic.writeWithoutResponse(data);
258
214
  });
259
215
  }
260
216
  }
261
- BleTransport.MAX_RETRIES = 5;
262
- BleTransport.RETRY_DELAY = 2000;
263
217
 
264
218
  const { check, ProtocolV1, parseConfigure } = transport__default["default"];
265
219
  const Log = bleLogger;
@@ -268,7 +222,6 @@ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 :
268
222
  const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
269
223
  const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
270
224
  const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
271
- const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
272
225
  const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
273
226
  const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
274
227
  const ANDROID_GATT_CONGESTED_STATUS = 143;
@@ -279,10 +232,6 @@ const getFirmwareUploadWriteRetryType = (error) => {
279
232
  if (!error || typeof error !== 'object')
280
233
  return null;
281
234
  const bleWriteError = error;
282
- if (bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
283
- bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
284
- return 'reconnectable';
285
- }
286
235
  if (bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
287
236
  bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS) {
288
237
  return 'congested';
@@ -293,22 +242,14 @@ const getFirmwareUploadWriteRetryType = (error) => {
293
242
  return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
294
243
  };
295
244
  const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
296
- const BLE_RESPONSE_TIMEOUT_MS = 30000;
297
245
  const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
298
246
  const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
299
- const DEVICE_SCAN_TIMEOUT_MS = 8000;
247
+ const DEVICE_SCAN_TIMEOUT_MS = 3000;
300
248
  const IOS_NOTIFY_READY_DELAY_MS = 150;
301
249
  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
250
  const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
306
251
  iosPacketLength: IOS_PACKET_LENGTH,
307
252
  androidPacketLength: ANDROID_PACKET_LENGTH,
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,
312
253
  };
313
254
  let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
314
255
  const normalizePositiveInteger = (value, fallback) => {
@@ -318,20 +259,15 @@ const normalizePositiveInteger = (value, fallback) => {
318
259
  return Math.floor(normalized);
319
260
  };
320
261
  function configureProtocolV2BleTuning(tuning = {}) {
321
- var _a;
322
262
  protocolV2BleTuning = {
323
263
  iosPacketLength: normalizePositiveInteger(tuning.iosPacketLength, protocolV2BleTuning.iosPacketLength),
324
264
  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
265
  };
330
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning configured:', protocolV2BleTuning);
266
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning configured', protocolV2BleTuning);
331
267
  }
332
268
  function resetProtocolV2BleTuning() {
333
269
  protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
334
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning reset:', protocolV2BleTuning);
270
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] BLE tuning reset', protocolV2BleTuning);
335
271
  }
336
272
  function getProtocolV2BleTuning() {
337
273
  return Object.assign({}, protocolV2BleTuning);
@@ -342,13 +278,6 @@ function inferProtocolHintFromDeviceName(name) {
342
278
  function getDeviceDisplayName(device) {
343
279
  return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
344
280
  }
345
- function isGenericBleService(uuid) {
346
- return ['1800', '1801', '180a'].includes(getBleUuidKey(uuid));
347
- }
348
- function hasKnownOneKeyService(device) {
349
- var _a;
350
- return ((_a = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _a !== void 0 ? _a : []).some(serviceUuid => getInfosForServiceUuid(serviceUuid, 'classic'));
351
- }
352
281
  const ANDROID_REQUEST_MTU = 256;
353
282
  const connectOptions = {
354
283
  requestMTU: ANDROID_REQUEST_MTU,
@@ -371,9 +300,10 @@ const requestAndroidMtu = (device) => __awaiter(void 0, void 0, void 0, function
371
300
  return device;
372
301
  try {
373
302
  const mtuDevice = yield device.requestMTU(ANDROID_REQUEST_MTU);
374
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU requested:', {
303
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] MTU configured', {
304
+ deviceId: device.id,
375
305
  requested: ANDROID_REQUEST_MTU,
376
- mtu: mtuDevice.mtu,
306
+ actual: mtuDevice.mtu,
377
307
  });
378
308
  return mtuDevice;
379
309
  }
@@ -408,15 +338,36 @@ class ReactNativeBleTransport {
408
338
  this.stopped = false;
409
339
  this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
410
340
  this.runPromise = null;
341
+ this.runPromiseDeviceId = null;
411
342
  this.firmwareUploadWriteRecoveryIds = new Set();
412
343
  this.deviceProtocol = new Map();
413
344
  this.deviceProtocolHints = new Map();
414
345
  this.protocolV2Assemblers = new Map();
415
346
  this.protocolV2FrameQueues = new Map();
416
347
  this.protocolV2FramePromises = new Map();
417
- this.activeProtocolV2Call = null;
418
- this.nextProtocolV2CallToken = 1;
348
+ this.protocolV2Links = new transport.ProtocolV2LinkManager({
349
+ getSchemas: () => {
350
+ if (!this._messages || !this._messagesV2) {
351
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
352
+ }
353
+ return {
354
+ protocolV1: this._messages,
355
+ protocolV2: this._messagesV2,
356
+ };
357
+ },
358
+ classifyError: () => 'link-fatal',
359
+ onLinkInvalidated: (uuid, reason) => __awaiter(this, void 0, void 0, function* () {
360
+ var _b;
361
+ (_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
362
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
363
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 link invalidated:', uuid, reason);
364
+ if (reason.startsWith('Protocol V2 link-fatal error:')) {
365
+ yield this.releaseNative(uuid, true);
366
+ }
367
+ }),
368
+ });
419
369
  this.monitorTokens = new Map();
370
+ this.disconnectEventTokens = new Map();
420
371
  this.nextMonitorToken = 1;
421
372
  this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
422
373
  }
@@ -430,8 +381,18 @@ class ReactNativeBleTransport {
430
381
  this._messages = messages;
431
382
  }
432
383
  configureProtocolV2(signedData) {
384
+ const configuration = typeof signedData === 'string' ? signedData : JSON.stringify(signedData);
385
+ if (this.protocolV2SchemaConfiguration === configuration) {
386
+ return;
387
+ }
388
+ const isReconfiguration = this.protocolV2SchemaConfiguration !== undefined;
433
389
  this._messagesV2 = parseConfigure(signedData);
434
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
390
+ this.protocolV2SchemaConfiguration = configuration;
391
+ if (isReconfiguration) {
392
+ this.protocolV2Links
393
+ .invalidateAllLinks('Protocol V2 schema reconfigured')
394
+ .catch(error => Log === null || Log === void 0 ? void 0 : Log.debug('Protocol V2 schema link cleanup failed:', error));
395
+ }
435
396
  }
436
397
  listen() {
437
398
  }
@@ -442,7 +403,6 @@ class ReactNativeBleTransport {
442
403
  return Promise.resolve(this.blePlxManager);
443
404
  }
444
405
  resolveCharacteristics(device) {
445
- var _a, _b, _c, _d;
446
406
  return __awaiter(this, void 0, void 0, function* () {
447
407
  yield device.discoverAllServicesAndCharacteristics();
448
408
  let infos = tryToGetConfiguration(device);
@@ -459,19 +419,11 @@ class ReactNativeBleTransport {
459
419
  }
460
420
  }
461
421
  }
462
- let fallbackServiceUuid;
463
422
  if (!infos) {
464
423
  const services = yield device.services();
465
424
  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
425
  }
474
- if (!infos && !fallbackServiceUuid) {
426
+ if (!infos) {
475
427
  try {
476
428
  Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
477
429
  yield device.cancelConnection();
@@ -481,9 +433,7 @@ class ReactNativeBleTransport {
481
433
  }
482
434
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
483
435
  }
484
- const serviceUuid = (_b = infos === null || infos === void 0 ? void 0 : infos.serviceUuid) !== null && _b !== void 0 ? _b : fallbackServiceUuid;
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';
436
+ const { serviceUuid, writeUuid, notifyUuid } = infos;
487
437
  if (!serviceUuid) {
488
438
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
489
439
  }
@@ -524,8 +474,8 @@ class ReactNativeBleTransport {
524
474
  attachDisconnectSubscription(transport, device, uuid) {
525
475
  var _a;
526
476
  (_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
477
+ const { monitorToken } = transport;
527
478
  transport.disconnectSubscription = device.onDisconnected(() => {
528
- var _a;
529
479
  if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
530
480
  Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
531
481
  return;
@@ -534,17 +484,16 @@ class ReactNativeBleTransport {
534
484
  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
485
  return;
536
486
  }
487
+ if (this.monitorTokens.get(uuid) !== monitorToken) {
488
+ Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale generation: ', device === null || device === void 0 ? void 0 : device.id);
489
+ return;
490
+ }
537
491
  try {
538
492
  Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
539
- (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
540
- name: device === null || device === void 0 ? void 0 : device.name,
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) {
493
+ this.emitDeviceDisconnect(uuid, device === null || device === void 0 ? void 0 : device.name, monitorToken);
494
+ if (this.runPromise && this.runPromiseDeviceId === uuid) {
545
495
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
546
496
  this.runPromise.reject(error);
547
- this.rejectAllProtocolV2Frames(error);
548
497
  }
549
498
  }
550
499
  catch (e) {
@@ -555,6 +504,22 @@ class ReactNativeBleTransport {
555
504
  }
556
505
  });
557
506
  }
507
+ emitDeviceDisconnect(uuid, name, token) {
508
+ var _a;
509
+ if (token === undefined || this.disconnectEventTokens.get(uuid) === token) {
510
+ return;
511
+ }
512
+ if (this.monitorTokens.get(uuid) !== token) {
513
+ Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect event ignored for stale generation: ', uuid);
514
+ return;
515
+ }
516
+ this.disconnectEventTokens.set(uuid, token);
517
+ (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit(transport.TRANSPORT_EVENT.DEVICE_DISCONNECT, {
518
+ name,
519
+ id: uuid,
520
+ connectId: uuid,
521
+ });
522
+ }
558
523
  reconnectFirmwareUploadTransport(uuid, transport) {
559
524
  var _a, _b;
560
525
  return __awaiter(this, void 0, void 0, function* () {
@@ -624,13 +589,12 @@ class ReactNativeBleTransport {
624
589
  return;
625
590
  }
626
591
  }
627
- blePlxManager.startDeviceScan(null, {
592
+ blePlxManager.startDeviceScan(getBluetoothServiceUuids(), {
628
593
  allowDuplicates: true,
629
594
  scanMode: reactNativeBlePlx.ScanMode.LowLatency,
630
595
  }, (error, device) => {
631
- var _a, _b, _c;
596
+ var _a;
632
597
  if (error) {
633
- Log === null || Log === void 0 ? void 0 : Log.debug('ble scan manager: ', blePlxManager);
634
598
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
635
599
  if ([reactNativeBlePlx.BleErrorCode.BluetoothPoweredOff, reactNativeBlePlx.BleErrorCode.BluetoothInUnknownState].includes(error.errorCode)) {
636
600
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
@@ -650,25 +614,14 @@ class ReactNativeBleTransport {
650
614
  return;
651
615
  }
652
616
  const displayName = getDeviceDisplayName(device);
653
- const isOneKey = hdShared.isOnekeyDevice((_b = device === null || device === void 0 ? void 0 : device.name) !== null && _b !== void 0 ? _b : null, device === null || device === void 0 ? void 0 : device.id) ||
654
- hdShared.isOnekeyDevice((_c = device === null || device === void 0 ? void 0 : device.localName) !== null && _c !== void 0 ? _c : null, device === null || device === void 0 ? void 0 : device.id) ||
655
- hasKnownOneKeyService(device);
656
- const shouldTraceCandidate = !!displayName && /onekey|bixinkey|pro\s*2|pro\b|touch|^k\d|^t\d/i.test(displayName);
657
- if (shouldTraceCandidate) {
658
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan candidate', {
659
- name: device === null || device === void 0 ? void 0 : device.name,
660
- localName: device === null || device === void 0 ? void 0 : device.localName,
661
- id: device === null || device === void 0 ? void 0 : device.id,
662
- serviceUUIDs: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
663
- accepted: isOneKey,
664
- });
665
- }
617
+ const isOneKey = hdShared.isOnekeyBluetoothDevice({
618
+ id: device === null || device === void 0 ? void 0 : device.id,
619
+ name: device === null || device === void 0 ? void 0 : device.name,
620
+ localName: device === null || device === void 0 ? void 0 : device.localName,
621
+ serviceUuids: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
622
+ });
666
623
  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
624
  addDevice(device);
671
- Log === null || Log === void 0 ? void 0 : Log.debug('search device end ======================\n');
672
625
  }
673
626
  else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
674
627
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Pro2-like BLE device was not accepted:', {
@@ -679,10 +632,20 @@ class ReactNativeBleTransport {
679
632
  });
680
633
  }
681
634
  });
682
- getConnectedDeviceIds(getBluetoothServiceUuids()).then(devices => {
635
+ getConnectedDeviceIds(reactNative.Platform.OS === 'ios' ? getBluetoothServiceUuids() : []).then(devices => {
683
636
  for (const device of devices) {
684
- Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
685
- addDevice(device);
637
+ const localName = 'localName' in device && typeof device.localName === 'string'
638
+ ? device.localName
639
+ : null;
640
+ if (hdShared.isOnekeyBluetoothDevice({
641
+ id: device.id,
642
+ name: device.name,
643
+ localName,
644
+ serviceUuids: device.serviceUUIDs,
645
+ })) {
646
+ Log === null || Log === void 0 ? void 0 : Log.debug('search connected peripheral: ', device.id);
647
+ addDevice(device);
648
+ }
686
649
  }
687
650
  });
688
651
  const addDevice = (device) => {
@@ -694,6 +657,12 @@ class ReactNativeBleTransport {
694
657
  this.deviceProtocolHints.set(device.id, protocolHint);
695
658
  }
696
659
  deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
660
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] OneKey BLE device discovered', {
661
+ deviceId: device.id,
662
+ name: displayName,
663
+ serviceUUIDs: device.serviceUUIDs,
664
+ protocolHint,
665
+ });
697
666
  }
698
667
  };
699
668
  timer.timeout(() => {
@@ -703,6 +672,33 @@ class ReactNativeBleTransport {
703
672
  }));
704
673
  });
705
674
  }
675
+ installTransportForAcquire(uuid, device, characteristics) {
676
+ return __awaiter(this, void 0, void 0, function* () {
677
+ const { writeCharacteristic, notifyCharacteristic } = characteristics !== null && characteristics !== void 0 ? characteristics : (yield this.resolveCharacteristics(device));
678
+ const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
679
+ if (reactNative.Platform.OS === 'android') {
680
+ transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
681
+ }
682
+ const monitorToken = this.nextMonitorToken;
683
+ this.nextMonitorToken += 1;
684
+ const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
685
+ transport$1.monitorToken = monitorToken;
686
+ transport$1.notifyTransactionId = notifyTransactionId;
687
+ this.monitorTokens.set(uuid, monitorToken);
688
+ transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
689
+ transportCache[uuid] = transport$1;
690
+ this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler(transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES));
691
+ if (reactNative.Platform.OS === 'ios') {
692
+ yield new Promise(resolve => {
693
+ setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
694
+ });
695
+ }
696
+ else if (reactNative.Platform.OS === 'android') {
697
+ yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
698
+ }
699
+ return transport$1;
700
+ });
701
+ }
706
702
  acquire(input) {
707
703
  var _a, _b;
708
704
  return __awaiter(this, void 0, void 0, function* () {
@@ -727,9 +723,8 @@ class ReactNativeBleTransport {
727
723
  if (forceCleanRunPromise && this.runPromise) {
728
724
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
729
725
  this.runPromise.reject(error);
730
- this.rejectAllProtocolV2Frames(error);
731
726
  this.runPromise = null;
732
- this.activeProtocolV2Call = null;
727
+ this.runPromiseDeviceId = null;
733
728
  Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
734
729
  }
735
730
  const blePlxManager = yield this.getPlxManager();
@@ -811,50 +806,41 @@ class ReactNativeBleTransport {
811
806
  }
812
807
  }
813
808
  device = yield requestAndroidMtu(device);
814
- const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(device);
809
+ const acquiredDevice = device;
810
+ const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(acquiredDevice);
815
811
  const protocolHint = expectedProtocol
816
812
  ? undefined
817
- : (_a = this.deviceProtocolHints.get(uuid)) !== null && _a !== void 0 ? _a : inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
813
+ : (_b = (_a = input.protocolHint) !== null && _a !== void 0 ? _a : this.deviceProtocolHints.get(uuid)) !== null && _b !== void 0 ? _b : inferProtocolHintFromDeviceName(getDeviceDisplayName(acquiredDevice));
818
814
  yield this.release(uuid, true);
819
815
  if (protocolHint) {
820
816
  this.deviceProtocolHints.set(uuid, protocolHint);
821
817
  }
822
- const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
823
- if (reactNative.Platform.OS === 'android') {
824
- transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
825
- }
826
- const monitorToken = this.nextMonitorToken;
827
- this.nextMonitorToken += 1;
828
- const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
829
- transport$1.monitorToken = monitorToken;
830
- transport$1.notifyTransactionId = notifyTransactionId;
831
- this.monitorTokens.set(uuid, monitorToken);
832
- transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
833
- transportCache[uuid] = transport$1;
834
- this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
835
- if (reactNative.Platform.OS === 'ios') {
836
- yield new Promise(resolve => {
837
- setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
838
- });
818
+ yield this.installTransportForAcquire(uuid, acquiredDevice, {
819
+ writeCharacteristic,
820
+ notifyCharacteristic,
821
+ });
822
+ try {
823
+ const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint, () => __awaiter(this, void 0, void 0, function* () {
824
+ yield this.installTransportForAcquire(uuid, acquiredDevice);
825
+ }));
826
+ const currentTransport = transportCache[uuid];
827
+ if (!currentTransport) {
828
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
829
+ }
830
+ this.attachDisconnectSubscription(currentTransport, acquiredDevice, uuid);
831
+ return { uuid, protocolType };
839
832
  }
840
- else if (reactNative.Platform.OS === 'android') {
841
- yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
833
+ catch (error) {
834
+ yield this.release(uuid, true);
835
+ throw error;
842
836
  }
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
837
  });
852
838
  }
853
839
  _monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
854
840
  let bufferLength = 0;
855
841
  let buffer$1 = [];
856
842
  const subscription = characteristic.monitor((error, c) => {
857
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
843
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
858
844
  const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
859
845
  if (error) {
860
846
  Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
@@ -866,28 +852,44 @@ class ReactNativeBleTransport {
866
852
  Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
867
853
  return;
868
854
  }
869
- if (this.runPromise) {
870
- let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
855
+ if (this.deviceProtocol.get(uuid) === 'V2') {
856
+ let errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
871
857
  if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
872
- ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
858
+ errorCode = hdShared.HardwareErrorCode.BleTimeoutError;
873
859
  }
874
- if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
875
- ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
860
+ else if ((_b = error.reason) === null || _b === void 0 ? void 0 : _b.includes('Encryption is insufficient')) {
861
+ errorCode = hdShared.HardwareErrorCode.BleDeviceBondError;
876
862
  }
877
- if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
863
+ else if (((_c = error.reason) === null || _c === void 0 ? void 0 : _c.includes('Cannot write client characteristic config descriptor')) ||
878
864
  ((_d = error.reason) === null || _d === void 0 ? void 0 : _d.includes('Cannot find client characteristic config descriptor')) ||
879
865
  ((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
880
866
  ((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
881
867
  ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
868
+ errorCode = hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure;
869
+ }
870
+ this.rejectProtocolV2Frames(uuid, hdShared.ERRORS.TypedError(errorCode));
871
+ return;
872
+ }
873
+ if (this.runPromise && this.runPromiseDeviceId === uuid) {
874
+ let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
875
+ if ((_h = error.reason) === null || _h === void 0 ? void 0 : _h.includes('The connection has timed out unexpectedly')) {
876
+ ERROR = hdShared.HardwareErrorCode.BleTimeoutError;
877
+ }
878
+ if ((_j = error.reason) === null || _j === void 0 ? void 0 : _j.includes('Encryption is insufficient')) {
879
+ ERROR = hdShared.HardwareErrorCode.BleDeviceBondError;
880
+ }
881
+ if (((_k = error.reason) === null || _k === void 0 ? void 0 : _k.includes('Cannot write client characteristic config descriptor')) ||
882
+ ((_l = error.reason) === null || _l === void 0 ? void 0 : _l.includes('Cannot find client characteristic config descriptor')) ||
883
+ ((_m = error.reason) === null || _m === void 0 ? void 0 : _m.includes('The handle is invalid')) ||
884
+ ((_o = error.reason) === null || _o === void 0 ? void 0 : _o.includes('Writing is not permitted')) ||
885
+ ((_p = error.reason) === null || _p === void 0 ? void 0 : _p.includes('notify change failed for device'))) {
882
886
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
883
887
  this.runPromise.reject(notifyError);
884
- this.rejectAllProtocolV2Frames(notifyError);
885
888
  Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
886
889
  return;
887
890
  }
888
891
  const notifyError = hdShared.ERRORS.TypedError(ERROR);
889
892
  this.runPromise.reject(notifyError);
890
- this.rejectAllProtocolV2Frames(notifyError);
891
893
  Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
892
894
  }
893
895
  return;
@@ -907,7 +909,7 @@ class ReactNativeBleTransport {
907
909
  return;
908
910
  }
909
911
  if (protocol === 'V2') {
910
- this.handleProtocolV2Notification(uuid, new Uint8Array(data));
912
+ this.handleProtocolV2Notification(uuid, monitorToken, new Uint8Array(data));
911
913
  return;
912
914
  }
913
915
  if (isHeaderChunk(data)) {
@@ -921,28 +923,40 @@ class ReactNativeBleTransport {
921
923
  const value = buffer.Buffer.from(buffer$1);
922
924
  bufferLength = 0;
923
925
  buffer$1 = [];
924
- (_h = this.runPromise) === null || _h === void 0 ? void 0 : _h.resolve(value.toString('hex'));
926
+ if (this.runPromiseDeviceId === uuid) {
927
+ (_q = this.runPromise) === null || _q === void 0 ? void 0 : _q.resolve(value.toString('hex'));
928
+ }
925
929
  }
926
930
  }
927
931
  catch (error) {
928
932
  Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
929
933
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
930
- (_j = this.runPromise) === null || _j === void 0 ? void 0 : _j.reject(notifyError);
931
- this.rejectAllProtocolV2Frames(notifyError);
934
+ if (this.deviceProtocol.get(uuid) === 'V2') {
935
+ this.rejectProtocolV2Frames(uuid, notifyError);
936
+ }
937
+ else if (this.runPromiseDeviceId === uuid) {
938
+ (_r = this.runPromise) === null || _r === void 0 ? void 0 : _r.reject(notifyError);
939
+ }
932
940
  }
933
941
  }, notifyTransactionId);
934
942
  return subscription;
935
943
  }
936
944
  release(uuid, onclose = false) {
937
- var _a, _b, _c, _d, _e, _f, _g, _h;
945
+ return __awaiter(this, void 0, void 0, function* () {
946
+ yield this.protocolV2Links.invalidateLink(uuid, 'React Native BLE transport released');
947
+ return this.releaseNative(uuid, onclose);
948
+ });
949
+ }
950
+ releaseNative(uuid, onclose = false) {
951
+ var _a, _b, _c, _d, _e, _f, _g;
938
952
  return __awaiter(this, void 0, void 0, function* () {
939
953
  const transport = transportCache[uuid];
940
- if (this.runPromise) {
954
+ if (this.runPromise && this.runPromiseDeviceId === uuid) {
941
955
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
942
956
  this.runPromise.reject(error);
943
957
  this.runPromise = null;
944
- this.rejectAllProtocolV2Frames(error);
945
- this.activeProtocolV2Call = null;
958
+ this.runPromiseDeviceId = null;
959
+ this.rejectProtocolV2Frames(uuid, error);
946
960
  }
947
961
  else {
948
962
  this.resetProtocolV2Frames(uuid);
@@ -950,9 +964,6 @@ class ReactNativeBleTransport {
950
964
  if (reactNative.Platform.OS === 'android' && !onclose && transport) {
951
965
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
952
966
  this.resetProtocolV2Frames(uuid);
953
- if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
954
- this.activeProtocolV2Call = null;
955
- }
956
967
  return Promise.resolve(true);
957
968
  }
958
969
  if (transport) {
@@ -960,14 +971,14 @@ class ReactNativeBleTransport {
960
971
  this.monitorTokens.delete(uuid);
961
972
  }
962
973
  Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
963
- (_c = transport.disconnectSubscription) === null || _c === void 0 ? void 0 : _c.remove();
974
+ (_b = transport.disconnectSubscription) === null || _b === void 0 ? void 0 : _b.remove();
964
975
  transport.disconnectSubscription = undefined;
965
- Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_d = transport.notifyCharacteristic) === null || _d === void 0 ? void 0 : _d.uuid);
966
- (_e = transport.notifySubscription) === null || _e === void 0 ? void 0 : _e.remove();
976
+ 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);
977
+ (_d = transport.notifySubscription) === null || _d === void 0 ? void 0 : _d.remove();
967
978
  transport.notifySubscription = undefined;
968
979
  if (transport.notifyTransactionId) {
969
980
  try {
970
- yield ((_f = this.blePlxManager) === null || _f === void 0 ? void 0 : _f.cancelTransaction(transport.notifyTransactionId));
981
+ yield ((_e = this.blePlxManager) === null || _e === void 0 ? void 0 : _e.cancelTransaction(transport.notifyTransactionId));
971
982
  }
972
983
  catch (e) {
973
984
  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);
@@ -976,12 +987,11 @@ class ReactNativeBleTransport {
976
987
  delete transportCache[uuid];
977
988
  }
978
989
  this.deviceProtocol.delete(uuid);
979
- this.deviceProtocolHints.delete(uuid);
980
- (_g = this.protocolV2Assemblers.get(uuid)) === null || _g === void 0 ? void 0 : _g.reset();
990
+ (_f = this.protocolV2Assemblers.get(uuid)) === null || _f === void 0 ? void 0 : _f.reset();
981
991
  this.protocolV2Assemblers.delete(uuid);
982
992
  this.resetProtocolV2Frames(uuid);
983
993
  try {
984
- yield ((_h = this.blePlxManager) === null || _h === void 0 ? void 0 : _h.cancelTransaction(uuid));
994
+ yield ((_g = this.blePlxManager) === null || _g === void 0 ? void 0 : _g.cancelTransaction(uuid));
985
995
  }
986
996
  catch (e) {
987
997
  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 +1012,18 @@ class ReactNativeBleTransport {
1002
1012
  if (this._messages == null) {
1003
1013
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1004
1014
  }
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
1015
  const protocol = this.getProtocolType(uuid);
1011
1016
  if (!protocol) {
1012
1017
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
1013
1018
  }
1014
- if (name === 'ResourceUpdate' || name === 'ResourceAck') {
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
- }
1019
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport call', transport.createTransportCallLog(name, protocol, data));
1026
1020
  if (protocol === 'V2') {
1027
1021
  return this.callProtocolV2(uuid, name, data, options);
1028
1022
  }
1023
+ const forceRun = name === 'Initialize' || name === 'Cancel';
1024
+ if (this.runPromise && !forceRun) {
1025
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1026
+ }
1029
1027
  return this.callProtocolV1(uuid, name, data, options);
1030
1028
  });
1031
1029
  }
@@ -1038,6 +1036,7 @@ class ReactNativeBleTransport {
1038
1036
  const runPromise = hdShared.createDeferred();
1039
1037
  runPromise.promise.catch(() => undefined);
1040
1038
  this.runPromise = runPromise;
1039
+ this.runPromiseDeviceId = uuid;
1041
1040
  const messages = this._messages;
1042
1041
  const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
1043
1042
  let timeout;
@@ -1101,7 +1100,7 @@ class ReactNativeBleTransport {
1101
1100
  });
1102
1101
  }
1103
1102
  else if (name === 'FirmwareUpload') {
1104
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write uses throttled BLE packets:', {
1103
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Firmware upload transport configured', {
1105
1104
  packetCapacity: FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY,
1106
1105
  burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
1107
1106
  pauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
@@ -1120,32 +1119,14 @@ class ReactNativeBleTransport {
1120
1119
  if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
1121
1120
  throw error;
1122
1121
  }
1123
- const shouldReconnect = retryType === 'reconnectable';
1124
- const delayMs = shouldReconnect
1125
- ? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
1126
- : resolveFirmwareUploadRetryDelay(attempt);
1122
+ const delayMs = resolveFirmwareUploadRetryDelay(attempt);
1127
1123
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
1128
1124
  attempt: attempt + 1,
1129
1125
  delayMs,
1130
- reconnect: shouldReconnect,
1131
1126
  error,
1132
1127
  });
1133
- if (shouldReconnect) {
1134
- this.firmwareUploadWriteRecoveryIds.add(uuid);
1135
- }
1136
1128
  yield delay(delayMs);
1137
1129
  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
1130
  }
1150
1131
  }
1151
1132
  }), e => {
@@ -1190,17 +1171,21 @@ class ReactNativeBleTransport {
1190
1171
  if (typeof response !== 'string') {
1191
1172
  throw new Error('Returning data is not string.');
1192
1173
  }
1193
- Log === null || Log === void 0 ? void 0 : Log.debug('receive data: ', response);
1194
1174
  const jsonData = ProtocolV1.decodeMessage(messages, response);
1195
1175
  return check.call(jsonData);
1196
1176
  }
1197
1177
  catch (e) {
1198
- if (name === 'Initialize' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
1199
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe call failed:', e);
1178
+ if (name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
1179
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe call failed:', e);
1200
1180
  }
1201
1181
  else {
1202
1182
  Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
1203
1183
  }
1184
+ const isProbeTimeout = name === 'GetFeatures' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS;
1185
+ if (!isProbeTimeout &&
1186
+ (e === null || e === void 0 ? void 0 : e.errorCode) === hdShared.HardwareErrorCode.BleTimeoutError) {
1187
+ yield this.disconnect(uuid);
1188
+ }
1204
1189
  throw e;
1205
1190
  }
1206
1191
  finally {
@@ -1208,6 +1193,7 @@ class ReactNativeBleTransport {
1208
1193
  clearTimeout(timeout);
1209
1194
  if (this.runPromise === runPromise) {
1210
1195
  this.runPromise = null;
1196
+ this.runPromiseDeviceId = null;
1211
1197
  }
1212
1198
  }
1213
1199
  });
@@ -1216,10 +1202,11 @@ class ReactNativeBleTransport {
1216
1202
  this.stopped = true;
1217
1203
  }
1218
1204
  disconnect(session) {
1219
- var _a, _b, _c, _d, _e, _f;
1205
+ var _a, _b, _c, _d, _e;
1220
1206
  return __awaiter(this, void 0, void 0, function* () {
1221
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport resetSession: ', session);
1207
+ yield this.protocolV2Links.invalidateLink(session, 'React Native BLE transport disconnected');
1222
1208
  const transport = transportCache[session];
1209
+ const monitorToken = (_a = transport === null || transport === void 0 ? void 0 : transport.monitorToken) !== null && _a !== void 0 ? _a : this.monitorTokens.get(session);
1223
1210
  if (transport === null || transport === void 0 ? void 0 : transport.disconnectSubscription) {
1224
1211
  try {
1225
1212
  Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing disconnect subscription');
@@ -1232,7 +1219,7 @@ class ReactNativeBleTransport {
1232
1219
  }
1233
1220
  if (transport === null || transport === void 0 ? void 0 : transport.notifySubscription) {
1234
1221
  try {
1235
- Log === null || Log === void 0 ? void 0 : Log.debug('disconnect: removing notify subscription, characteristic: ', (_a = transport.notifyCharacteristic) === null || _a === void 0 ? void 0 : _a.uuid);
1222
+ 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
1223
  transport.notifySubscription.remove();
1237
1224
  transport.notifySubscription = undefined;
1238
1225
  }
@@ -1242,7 +1229,7 @@ class ReactNativeBleTransport {
1242
1229
  }
1243
1230
  if (session) {
1244
1231
  try {
1245
- yield ((_b = this.blePlxManager) === null || _b === void 0 ? void 0 : _b.cancelTransaction(session));
1232
+ yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(session));
1246
1233
  }
1247
1234
  catch (e) {
1248
1235
  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 +1244,7 @@ class ReactNativeBleTransport {
1257
1244
  }
1258
1245
  }
1259
1246
  try {
1260
- yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelDeviceConnection(session));
1247
+ yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelDeviceConnection(session));
1261
1248
  }
1262
1249
  catch (e) {
1263
1250
  Log === null || Log === void 0 ? void 0 : Log.debug('resetSession: manager.cancelDeviceConnection error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
@@ -1269,19 +1256,15 @@ class ReactNativeBleTransport {
1269
1256
  this.deviceProtocolHints.delete(session);
1270
1257
  this.protocolV2Assemblers.delete(session);
1271
1258
  this.resetProtocolV2Frames(session);
1272
- if (((_d = this.activeProtocolV2Call) === null || _d === void 0 ? void 0 : _d.uuid) === session) {
1273
- this.activeProtocolV2Call = null;
1274
- }
1275
1259
  try {
1276
- (_e = this.emitter) === null || _e === void 0 ? void 0 : _e.emit('device-disconnect', {
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
- });
1260
+ this.emitDeviceDisconnect(session, (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name, monitorToken);
1281
1261
  }
1282
1262
  catch (e) {
1283
1263
  Log === null || Log === void 0 ? void 0 : Log.error('resetSession: emit disconnect event error: ', e);
1284
1264
  }
1265
+ if (monitorToken !== undefined && this.monitorTokens.get(session) === monitorToken) {
1266
+ this.monitorTokens.delete(session);
1267
+ }
1285
1268
  yield new Promise(resolve => setTimeout(() => resolve(), 100));
1286
1269
  });
1287
1270
  }
@@ -1289,6 +1272,7 @@ class ReactNativeBleTransport {
1289
1272
  Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport cancel');
1290
1273
  if (this.runPromise) ;
1291
1274
  this.runPromise = null;
1275
+ this.runPromiseDeviceId = null;
1292
1276
  }
1293
1277
  getCachedTransport(uuid) {
1294
1278
  const transport = transportCache[uuid];
@@ -1301,38 +1285,59 @@ class ReactNativeBleTransport {
1301
1285
  return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
1302
1286
  }
1303
1287
  createProtocolDetectionError() {
1304
- return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
1288
+ 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
1289
  }
1306
1290
  clearProbeProtocol(uuid, protocol) {
1307
1291
  if (this.deviceProtocol.get(uuid) === protocol) {
1308
1292
  this.deviceProtocol.delete(uuid);
1309
1293
  }
1310
1294
  }
1311
- detectProtocol(uuid, expectedProtocol, protocolHint) {
1295
+ detectProtocol(uuid, expectedProtocol, protocolHint, rebuildTransport) {
1312
1296
  return __awaiter(this, void 0, void 0, function* () {
1313
1297
  if (expectedProtocol === 'V1') {
1314
1298
  if (yield this.probeProtocolV1(uuid)) {
1315
1299
  this.deviceProtocol.set(uuid, 'V1');
1316
- Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V1 (expected)`);
1300
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1301
+ deviceId: uuid,
1302
+ protocol: 'V1',
1303
+ source: 'expected',
1304
+ });
1317
1305
  return 'V1';
1318
1306
  }
1319
1307
  throw this.createProtocolMismatchError(expectedProtocol);
1320
1308
  }
1321
1309
  if (expectedProtocol === 'V2') {
1322
- this.deviceProtocol.set(uuid, 'V2');
1323
- Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (expected)`);
1324
- return 'V2';
1310
+ if (yield this.probeProtocolV2(uuid)) {
1311
+ this.deviceProtocol.set(uuid, 'V2');
1312
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1313
+ deviceId: uuid,
1314
+ protocol: 'V2',
1315
+ source: 'expected',
1316
+ });
1317
+ return 'V2';
1318
+ }
1319
+ throw this.createProtocolMismatchError(expectedProtocol);
1325
1320
  }
1326
1321
  const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
1327
1322
  for (let i = 0; i < probeOrder.length; i += 1) {
1328
1323
  const protocol = probeOrder[i];
1329
1324
  if (i > 0) {
1330
1325
  yield this.resetProbeStateAfterProtocolProbe(uuid, probeOrder[i - 1]);
1326
+ if (!transportCache[uuid]) {
1327
+ if (!rebuildTransport) {
1328
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
1329
+ }
1330
+ yield rebuildTransport();
1331
+ }
1331
1332
  }
1332
1333
  const detected = protocol === 'V1' ? yield this.probeProtocolV1(uuid) : yield this.probeProtocolV2(uuid);
1333
1334
  if (detected) {
1334
1335
  this.deviceProtocol.set(uuid, protocol);
1335
- Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> ${protocol}`);
1336
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1337
+ deviceId: uuid,
1338
+ protocol,
1339
+ source: 'probe',
1340
+ });
1336
1341
  return protocol;
1337
1342
  }
1338
1343
  }
@@ -1341,14 +1346,12 @@ class ReactNativeBleTransport {
1341
1346
  });
1342
1347
  }
1343
1348
  resetProbeStateAfterProtocolProbe(uuid, protocol) {
1344
- var _a, _b, _c, _d;
1349
+ var _a, _b, _c;
1345
1350
  return __awaiter(this, void 0, void 0, function* () {
1346
1351
  const transport = transportCache[uuid];
1352
+ yield this.protocolV2Links.invalidateLink(uuid, `Reset notify state after Protocol ${protocol} probe`);
1347
1353
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1348
1354
  this.resetProtocolV2Frames(uuid);
1349
- if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
1350
- this.activeProtocolV2Call = null;
1351
- }
1352
1355
  if (this.runPromise) {
1353
1356
  const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1354
1357
  this.runPromise.reject(error);
@@ -1360,11 +1363,11 @@ class ReactNativeBleTransport {
1360
1363
  if (this.monitorTokens.get(uuid) === transport.monitorToken) {
1361
1364
  this.monitorTokens.delete(uuid);
1362
1365
  }
1363
- (_c = transport.notifySubscription) === null || _c === void 0 ? void 0 : _c.remove();
1366
+ (_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
1364
1367
  transport.notifySubscription = undefined;
1365
1368
  if (previousNotifyTransactionId) {
1366
1369
  try {
1367
- yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelTransaction(previousNotifyTransactionId));
1370
+ yield ((_c = this.blePlxManager) === null || _c === void 0 ? void 0 : _c.cancelTransaction(previousNotifyTransactionId));
1368
1371
  }
1369
1372
  catch (error) {
1370
1373
  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);
@@ -1391,12 +1394,12 @@ class ReactNativeBleTransport {
1391
1394
  }
1392
1395
  try {
1393
1396
  this.deviceProtocol.set(uuid, 'V1');
1394
- yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
1397
+ yield this.callProtocolV1(uuid, 'GetFeatures', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
1395
1398
  return true;
1396
1399
  }
1397
1400
  catch (error) {
1398
1401
  this.clearProbeProtocol(uuid, 'V1');
1399
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe failed:', error);
1402
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 GetFeatures probe failed:', error);
1400
1403
  return false;
1401
1404
  }
1402
1405
  });
@@ -1426,14 +1429,10 @@ class ReactNativeBleTransport {
1426
1429
  return detected;
1427
1430
  });
1428
1431
  }
1429
- handleProtocolV2Notification(uuid, data) {
1430
- var _a, _b, _c;
1432
+ handleProtocolV2Notification(uuid, monitorToken, data) {
1431
1433
  try {
1432
- if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== uuid) {
1433
- (_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
1434
- this.resetProtocolV2Frames(uuid);
1434
+ if (this.monitorTokens.get(uuid) !== monitorToken)
1435
1435
  return;
1436
- }
1437
1436
  if (data.length === 0)
1438
1437
  return;
1439
1438
  const assembler = this.protocolV2Assemblers.get(uuid);
@@ -1446,8 +1445,10 @@ class ReactNativeBleTransport {
1446
1445
  catch (error) {
1447
1446
  Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
1448
1447
  const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
1449
- (_c = this.runPromise) === null || _c === void 0 ? void 0 : _c.reject(notifyError);
1450
- this.rejectAllProtocolV2Frames(notifyError);
1448
+ this.rejectProtocolV2Frames(uuid, notifyError);
1449
+ this.protocolV2Links
1450
+ .invalidateLink(uuid, `Protocol V2 notification error: ${error}`)
1451
+ .catch(invalidateError => Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notify cleanup failed:', invalidateError));
1451
1452
  }
1452
1453
  }
1453
1454
  getProtocolV2FrameQueue(uuid) {
@@ -1467,20 +1468,16 @@ class ReactNativeBleTransport {
1467
1468
  }
1468
1469
  this.getProtocolV2FrameQueue(uuid).push(frame);
1469
1470
  }
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
1471
  resetProtocolV2Frames(uuid) {
1478
- this.protocolV2FrameQueues.delete(uuid);
1479
- this.protocolV2FramePromises.delete(uuid);
1472
+ this.rejectProtocolV2Frames(uuid, new Error(`Protocol V2 frame state reset for ${uuid}`));
1480
1473
  }
1481
- isActiveProtocolV2Call(uuid, token) {
1482
- var _a;
1483
- return ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === uuid && this.activeProtocolV2Call.token === token;
1474
+ rejectProtocolV2Frames(uuid, error) {
1475
+ this.protocolV2FrameQueues.delete(uuid);
1476
+ const framePromise = this.protocolV2FramePromises.get(uuid);
1477
+ if (framePromise) {
1478
+ this.protocolV2FramePromises.delete(uuid);
1479
+ framePromise.reject(error);
1480
+ }
1484
1481
  }
1485
1482
  readProtocolV2Frame(uuid) {
1486
1483
  return __awaiter(this, void 0, void 0, function* () {
@@ -1500,127 +1497,124 @@ class ReactNativeBleTransport {
1500
1497
  }
1501
1498
  });
1502
1499
  }
1503
- writeProtocolV2Frame(transport, frame, options) {
1500
+ writeProtocolV2Packet(transport, base64, context, assertCurrentGeneration) {
1501
+ return __awaiter(this, void 0, void 0, function* () {
1502
+ let attempt = 0;
1503
+ for (;;) {
1504
+ assertCurrentGeneration();
1505
+ if (context.signal.aborted) {
1506
+ throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
1507
+ }
1508
+ try {
1509
+ yield transport.writeCharacteristic.writeWithoutResponse(base64);
1510
+ assertCurrentGeneration();
1511
+ return;
1512
+ }
1513
+ catch (error) {
1514
+ if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
1515
+ attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
1516
+ throw error;
1517
+ }
1518
+ const delayMs = resolveFirmwareUploadRetryDelay(attempt);
1519
+ attempt += 1;
1520
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 congested write retry:', {
1521
+ name: context.messageName,
1522
+ attempt,
1523
+ delayMs,
1524
+ });
1525
+ yield delay(delayMs);
1526
+ }
1527
+ }
1528
+ });
1529
+ }
1530
+ writeProtocolV2Frame(transport$1, frame, context, assertCurrentGeneration) {
1504
1531
  return __awaiter(this, void 0, void 0, function* () {
1505
1532
  const tuning = getProtocolV2BleTuning();
1506
1533
  const packetCapacity = resolveProtocolV2PacketCapacity({
1507
1534
  platform: reactNative.Platform.OS,
1508
1535
  iosPacketLength: tuning.iosPacketLength,
1509
1536
  androidPacketLength: tuning.androidPacketLength,
1510
- mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
1537
+ mtu: reactNative.Platform.OS === 'android' ? transport$1.mtuSize : undefined,
1538
+ });
1539
+ yield transport.writeProtocolV2BleFrame({
1540
+ frame,
1541
+ packetCapacity,
1542
+ assertActive: assertCurrentGeneration,
1543
+ signal: context.signal,
1544
+ abortMessage: `Protocol V2 BLE write aborted for ${context.messageName}`,
1545
+ burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
1546
+ burstPauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
1547
+ flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
1548
+ wait: delay,
1549
+ writePacket: packet => this.writeProtocolV2Packet(transport$1, buffer.Buffer.from(packet).toString('base64'), context, assertCurrentGeneration),
1511
1550
  });
1512
- const writeWithResponse = !!(options === null || options === void 0 ? void 0 : options.writeWithResponse) || (!!(options === null || options === void 0 ? void 0 : options.highVolume) && tuning.highVolumeWriteWithResponse);
1513
- const writeMode = resolveBleWriteMode(transport.writeCharacteristic, writeWithResponse ? 'withResponse' : 'withoutResponse');
1514
- const shouldThrottle = !!(options === null || options === void 0 ? void 0 : options.highVolume) && writeMode === 'withoutResponse';
1515
- let packetsWritten = 0;
1516
- for (let offset = 0; offset < frame.length; offset += packetCapacity) {
1517
- const chunk = frame.slice(offset, offset + packetCapacity);
1518
- const base64 = buffer.Buffer.from(chunk).toString('base64');
1519
- if (writeMode === 'withResponse') {
1520
- yield transport.writeCharacteristic.writeWithResponse(base64);
1521
- }
1522
- else {
1523
- yield transport.writeCharacteristic.writeWithoutResponse(base64);
1524
- }
1525
- packetsWritten += 1;
1526
- if (shouldThrottle &&
1527
- packetsWritten % tuning.highVolumeWriteBurstSize === 0 &&
1528
- offset + packetCapacity < frame.length) {
1529
- yield delay(tuning.highVolumeWritePauseMs);
1530
- }
1531
- }
1532
- if (shouldThrottle) {
1533
- yield delay(tuning.highVolumeWriteFlushDelayMs);
1534
- }
1535
1551
  });
1536
1552
  }
1537
1553
  callProtocolV2(uuid, name, data, options) {
1538
- var _a, _b, _c, _d;
1539
1554
  return __awaiter(this, void 0, void 0, function* () {
1540
1555
  if (!this._messages || !this._messagesV2) {
1541
1556
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1542
1557
  }
1543
- const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'Ping';
1544
- if (this.runPromise) {
1545
- if (!forceRun) {
1546
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1547
- }
1548
- const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1549
- this.runPromise.reject(error);
1550
- this.rejectAllProtocolV2Frames(error);
1551
- this.runPromise = null;
1552
- this.activeProtocolV2Call = null;
1553
- }
1554
- const transport$1 = this.getCachedTransport(uuid);
1555
- const runPromise = hdShared.createDeferred();
1556
- runPromise.promise.catch(() => undefined);
1557
- this.runPromise = runPromise;
1558
- const callToken = this.nextProtocolV2CallToken++;
1559
- this.activeProtocolV2Call = { uuid, token: callToken };
1560
- (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1561
- this.resetProtocolV2Frames(uuid);
1562
- let completed = false;
1563
- const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_b = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _b !== void 0 ? _b : BLE_RESPONSE_TIMEOUT_MS });
1558
+ const callOptions = options;
1564
1559
  const highVolumeWrite = transport.LogBlockCommand.has(name);
1565
1560
  if (highVolumeWrite) {
1566
1561
  const tuning = getProtocolV2BleTuning();
1567
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write uses throttled writeWithoutResponse:', name, {
1562
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write configured', {
1563
+ name,
1564
+ writeMode: 'withoutResponse',
1568
1565
  packetCapacity: reactNative.Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
1569
- burstSize: tuning.highVolumeWriteBurstSize,
1570
- pauseMs: tuning.highVolumeWritePauseMs,
1571
- flushDelayMs: tuning.highVolumeWriteFlushDelayMs,
1572
- writeWithResponse: tuning.highVolumeWriteWithResponse,
1573
1566
  });
1574
1567
  }
1575
1568
  try {
1576
- const session = new transport.ProtocolV2Session({
1577
- schemas: {
1578
- protocolV1: this._messages,
1579
- protocolV2: this._messagesV2,
1580
- },
1581
- router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1582
- writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
1583
- yield this.writeProtocolV2Frame(transport$1, frame, {
1584
- highVolume: highVolumeWrite,
1585
- });
1586
- }),
1587
- readFrame: () => __awaiter(this, void 0, void 0, function* () {
1588
- const rxFrame = yield this.readProtocolV2Frame(uuid);
1589
- if (!(rxFrame instanceof Uint8Array)) {
1590
- throw new Error('Protocol V2 response is not Uint8Array');
1591
- }
1592
- return rxFrame;
1593
- }),
1594
- logger: Log,
1595
- logPrefix: 'ProtocolV2 RN-BLE',
1596
- createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
1597
- });
1598
- const result = yield session.call(name, data, callOptions);
1599
- completed = true;
1600
- return result;
1569
+ return yield this.protocolV2Links.call(uuid, () => this.createProtocolV2Adapter(uuid), name, data, callOptions);
1601
1570
  }
1602
1571
  catch (e) {
1603
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1604
- (_c = this.protocolV2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
1605
- this.resetProtocolV2Frames(uuid);
1606
- }
1607
1572
  Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
1608
1573
  throw e;
1609
1574
  }
1610
- finally {
1611
- if (this.isActiveProtocolV2Call(uuid, callToken)) {
1612
- if (!completed) {
1613
- (_d = this.protocolV2Assemblers.get(uuid)) === null || _d === void 0 ? void 0 : _d.reset();
1614
- }
1615
- this.resetProtocolV2Frames(uuid);
1616
- this.activeProtocolV2Call = null;
1617
- }
1618
- if (this.runPromise === runPromise) {
1619
- this.runPromise = null;
1620
- }
1621
- }
1622
1575
  });
1623
1576
  }
1577
+ createProtocolV2Adapter(uuid) {
1578
+ var _a;
1579
+ const generation = (_a = this.monitorTokens.get(uuid)) !== null && _a !== void 0 ? _a : 0;
1580
+ const assertCurrentGeneration = () => {
1581
+ if (this.monitorTokens.get(uuid) !== generation) {
1582
+ throw new Error(`Protocol V2 monitor generation changed for ${uuid}`);
1583
+ }
1584
+ };
1585
+ return {
1586
+ router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1587
+ maxFrameBytes: transport.PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
1588
+ generation,
1589
+ prepareCall: () => {
1590
+ var _a;
1591
+ assertCurrentGeneration();
1592
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1593
+ this.resetProtocolV2Frames(uuid);
1594
+ },
1595
+ writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
1596
+ assertCurrentGeneration();
1597
+ const currentTransport = this.getCachedTransport(uuid);
1598
+ yield this.writeProtocolV2Frame(currentTransport, frame, context, assertCurrentGeneration);
1599
+ }),
1600
+ readFrame: () => __awaiter(this, void 0, void 0, function* () {
1601
+ assertCurrentGeneration();
1602
+ const rxFrame = yield this.readProtocolV2Frame(uuid);
1603
+ if (!(rxFrame instanceof Uint8Array)) {
1604
+ throw new Error('Protocol V2 response is not Uint8Array');
1605
+ }
1606
+ return rxFrame;
1607
+ }),
1608
+ reset: (reason) => {
1609
+ var _a;
1610
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1611
+ this.rejectProtocolV2Frames(uuid, new Error(reason));
1612
+ },
1613
+ logger: Log,
1614
+ logPrefix: 'ProtocolV2 RN-BLE',
1615
+ createTimeoutError: (messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${messageName}`),
1616
+ };
1617
+ }
1624
1618
  getProtocolType(path) {
1625
1619
  return this.deviceProtocol.get(path);
1626
1620
  }
@@ -1628,5 +1622,6 @@ class ReactNativeBleTransport {
1628
1622
 
1629
1623
  exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
1630
1624
  exports["default"] = ReactNativeBleTransport;
1625
+ exports.getFirmwareUploadWriteRetryType = getFirmwareUploadWriteRetryType;
1631
1626
  exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
1632
1627
  exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;