@onekeyfe/hd-transport-react-native 1.1.27-alpha.4 → 1.1.27-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
@@ -1,12 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
3
5
  var reactNative = require('react-native');
4
6
  var buffer = require('buffer');
5
7
  var reactNativeBlePlx = require('react-native-ble-plx');
6
8
  var ByteBuffer = require('bytebuffer');
7
9
  var transport = require('@onekeyfe/hd-transport');
8
10
  var hdShared = require('@onekeyfe/hd-shared');
9
- var hdCore = require('@onekeyfe/hd-core');
10
11
  var BleUtils = require('@onekeyfe/react-native-ble-utils');
11
12
 
12
13
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -45,44 +46,126 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
45
46
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
46
47
  };
47
48
 
48
- const Logger = hdCore.getLogger(hdCore.LoggerNames.HdBleTransport);
49
+ let activeLogger;
50
+ const setBleLogger = (logger) => {
51
+ activeLogger = logger;
52
+ };
53
+ const bleLogger = {
54
+ debug: (...args) => { var _a; return (_a = activeLogger === null || activeLogger === void 0 ? void 0 : activeLogger.debug) === null || _a === void 0 ? void 0 : _a.call(activeLogger, ...args); },
55
+ error: (...args) => { var _a; return (_a = activeLogger === null || activeLogger === void 0 ? void 0 : activeLogger.error) === null || _a === void 0 ? void 0 : _a.call(activeLogger, ...args); },
56
+ warn: (...args) => { var _a; return (_a = activeLogger === null || activeLogger === void 0 ? void 0 : activeLogger.warn) === null || _a === void 0 ? void 0 : _a.call(activeLogger, ...args); },
57
+ };
58
+
59
+ const Logger = bleLogger;
49
60
  const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
50
61
  const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
51
62
  const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
52
63
  let timeout;
53
- const cleanup = (cleanupListener) => {
64
+ let cleanupListener;
65
+ const cleanup = () => {
54
66
  if (timeout) {
55
67
  clearTimeout(timeout);
56
68
  }
57
69
  if (cleanupListener)
58
70
  cleanupListener();
59
71
  };
60
- const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
72
+ timeout = setTimeout(() => {
73
+ cleanup();
74
+ reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
75
+ }, 60 * 1000);
76
+ cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
61
77
  var _a;
62
78
  if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
63
79
  return;
64
80
  }
65
81
  const { bondState } = peripheral;
66
- if (bondState.preState === 'BOND_NONE' && bondState.state === 'BOND_BONDING') {
67
- timeout = setTimeout(() => {
68
- cleanup(cleanupListener);
69
- reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
70
- }, 60 * 1000);
71
- }
72
82
  const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
73
83
  const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
74
84
  Logger.debug('onDeviceBondState bondState:', bondState);
75
85
  if (hasBonded) {
76
- cleanup(cleanupListener);
86
+ cleanup();
77
87
  resolve(peripheral);
78
88
  }
79
89
  else if (hasCanceled) {
80
- cleanup(cleanupListener);
90
+ cleanup();
81
91
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
82
92
  }
83
93
  });
84
94
  });
85
95
 
96
+ const IOS_PACKET_LENGTH = 128;
97
+ const ANDROID_PACKET_LENGTH = 192;
98
+ const ANDROID_DEFAULT_MTU = 23;
99
+ const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
100
+ const OneKeyServices = {
101
+ classic: {
102
+ [ClassicServiceUUID]: {
103
+ serviceUuid: ClassicServiceUUID,
104
+ writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
105
+ notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
106
+ },
107
+ },
108
+ };
109
+ const bluetoothServices = [];
110
+ for (const deviceType of Object.keys(OneKeyServices)) {
111
+ const services = OneKeyServices[deviceType];
112
+ bluetoothServices.push(...Object.keys(services));
113
+ }
114
+ const getBluetoothServiceUuids = () => bluetoothServices;
115
+ const getInfosForServiceUuid = (serviceUuid, deviceType) => {
116
+ var _a;
117
+ const services = OneKeyServices[deviceType];
118
+ if (!services) {
119
+ return null;
120
+ }
121
+ const normalizedServiceUuid = normalizeBleUuid(serviceUuid);
122
+ const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid);
123
+ if (!service) {
124
+ return null;
125
+ }
126
+ return service;
127
+ };
128
+ const normalizeBleUuid = (uuid) => (uuid !== null && uuid !== void 0 ? uuid : '').replace(/-/g, '').toLowerCase();
129
+ const getBleUuidKey = (uuid) => {
130
+ const normalized = normalizeBleUuid(uuid);
131
+ return normalized.length >= 8 ? normalized.substring(4, 8) : normalized;
132
+ };
133
+ const isSameBleUuid = (left, right) => {
134
+ const normalizedLeft = normalizeBleUuid(left);
135
+ const normalizedRight = normalizeBleUuid(right);
136
+ return (normalizedLeft === normalizedRight ||
137
+ (getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
138
+ };
139
+
140
+ function hasWritableCapability(characteristic) {
141
+ return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
142
+ }
143
+ function resolveBleWriteMode(characteristic, preferredMode = 'withoutResponse') {
144
+ if (preferredMode === 'withoutResponse' && characteristic.isWritableWithoutResponse) {
145
+ return 'withoutResponse';
146
+ }
147
+ if (preferredMode === 'withResponse' && characteristic.isWritableWithResponse) {
148
+ return 'withResponse';
149
+ }
150
+ if (characteristic.isWritableWithoutResponse) {
151
+ return 'withoutResponse';
152
+ }
153
+ if (characteristic.isWritableWithResponse) {
154
+ return 'withResponse';
155
+ }
156
+ return preferredMode;
157
+ }
158
+ function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PACKET_LENGTH, androidPacketLength = ANDROID_PACKET_LENGTH, mtu, }) {
159
+ if (platform === 'ios') {
160
+ return iosPacketLength;
161
+ }
162
+ if (platform === 'android') {
163
+ const payloadLength = Math.max((mtu !== null && mtu !== void 0 ? mtu : ANDROID_DEFAULT_MTU) - 3, 1);
164
+ return Math.min(androidPacketLength, payloadLength);
165
+ }
166
+ return androidPacketLength;
167
+ }
168
+
86
169
  const timer = process.env.NODE_ENV === 'development'
87
170
  ? {
88
171
  timeout: (fn, ms) => {
@@ -126,58 +209,27 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
126
209
  }, ms);
127
210
  });
128
211
 
129
- const IOS_PACKET_LENGTH = 128;
130
- const ANDROID_PACKET_LENGTH = 192;
131
- const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
132
- const OneKeyServices = {
133
- classic: {
134
- [ClassicServiceUUID]: {
135
- serviceUuid: ClassicServiceUUID,
136
- writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
137
- notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
138
- },
139
- },
140
- };
141
- const bluetoothServices = [];
142
- for (const deviceType of Object.keys(OneKeyServices)) {
143
- const services = OneKeyServices[deviceType];
144
- bluetoothServices.push(...Object.keys(services));
145
- }
146
- const getBluetoothServiceUuids = () => bluetoothServices;
147
- const getInfosForServiceUuid = (serviceUuid, deviceType) => {
148
- const services = OneKeyServices[deviceType];
149
- if (!services) {
150
- return null;
151
- }
152
- const service = services[serviceUuid];
153
- if (!service) {
154
- return null;
155
- }
156
- return service;
157
- };
158
-
159
212
  const isHeaderChunk = (chunk) => {
160
213
  if (chunk.length < 9)
161
214
  return false;
162
215
  const [MagicQuestionMark, sharp1, sharp2] = chunk;
163
- if (String.fromCharCode(MagicQuestionMark) === String.fromCharCode(transport.MESSAGE_TOP_CHAR) &&
164
- String.fromCharCode(sharp1) === String.fromCharCode(transport.MESSAGE_HEADER_BYTE) &&
165
- String.fromCharCode(sharp2) === String.fromCharCode(transport.MESSAGE_HEADER_BYTE)) {
216
+ if (String.fromCharCode(MagicQuestionMark) === String.fromCharCode(transport.PROTOCOL_V1_REPORT_ID) &&
217
+ String.fromCharCode(sharp1) === String.fromCharCode(transport.PROTOCOL_V1_HEADER_BYTE) &&
218
+ String.fromCharCode(sharp2) === String.fromCharCode(transport.PROTOCOL_V1_HEADER_BYTE)) {
166
219
  return true;
167
220
  }
168
221
  return false;
169
222
  };
170
223
 
171
- const Log$1 = hdCore.getLogger(hdCore.LoggerNames.HdBleTransport);
224
+ const Log$1 = bleLogger;
172
225
  class BleTransport {
173
226
  constructor(device, writeCharacteristic, notifyCharacteristic) {
174
227
  this.name = 'ReactNativeBleTransport';
175
- this.mtuSize = 20;
228
+ this.mtuSize = 23;
176
229
  this.id = device.id;
177
230
  this.device = device;
178
231
  this.writeCharacteristic = writeCharacteristic;
179
232
  this.notifyCharacteristic = notifyCharacteristic;
180
- console.log(`BleTransport(${String(this.id)}) new instance`);
181
233
  }
182
234
  writeWithRetry(data, retryCount = BleTransport.MAX_RETRIES) {
183
235
  return __awaiter(this, void 0, void 0, function* () {
@@ -187,7 +239,7 @@ class BleTransport {
187
239
  catch (error) {
188
240
  Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`);
189
241
  if (retryCount > 0) {
190
- yield hdCore.wait(BleTransport.RETRY_DELAY);
242
+ yield hdShared.wait(BleTransport.RETRY_DELAY);
191
243
  if (error.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
192
244
  error.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
193
245
  try {
@@ -211,23 +263,101 @@ class BleTransport {
211
263
  BleTransport.MAX_RETRIES = 5;
212
264
  BleTransport.RETRY_DELAY = 2000;
213
265
 
214
- const { check, buildBuffers, receiveOne, parseConfigure } = transport__default["default"];
215
- const Log = hdCore.getLogger(hdCore.LoggerNames.HdBleTransport);
266
+ const { check, ProtocolV1, parseConfigure } = transport__default["default"];
267
+ const Log = bleLogger;
216
268
  const transportCache = {};
217
- let connectOptions = {
218
- requestMTU: 256,
269
+ const BLE_RESPONSE_TIMEOUT_MS = 30000;
270
+ const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
271
+ const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
272
+ const DEVICE_SCAN_TIMEOUT_MS = 8000;
273
+ const IOS_NOTIFY_READY_DELAY_MS = 150;
274
+ const ANDROID_NOTIFY_READY_DELAY_MS = 300;
275
+ const HIGH_VOLUME_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 6;
276
+ const HIGH_VOLUME_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 6 : 2;
277
+ const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 20 : 8;
278
+ const delay = (ms) => new Promise(resolve => {
279
+ setTimeout(resolve, ms);
280
+ });
281
+ const DEFAULT_PROTOCOL_V2_BLE_TUNING = {
282
+ iosPacketLength: IOS_PACKET_LENGTH,
283
+ androidPacketLength: ANDROID_PACKET_LENGTH,
284
+ highVolumeWriteBurstSize: HIGH_VOLUME_WRITE_BURST_SIZE,
285
+ highVolumeWritePauseMs: HIGH_VOLUME_WRITE_PAUSE_MS,
286
+ highVolumeWriteFlushDelayMs: HIGH_VOLUME_WRITE_FLUSH_DELAY_MS,
287
+ highVolumeWriteWithResponse: false,
288
+ };
289
+ let protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
290
+ const normalizePositiveInteger = (value, fallback) => {
291
+ const normalized = Number(value);
292
+ if (!Number.isFinite(normalized) || normalized <= 0)
293
+ return fallback;
294
+ return Math.floor(normalized);
295
+ };
296
+ function configureProtocolV2BleTuning(tuning = {}) {
297
+ var _a;
298
+ protocolV2BleTuning = {
299
+ iosPacketLength: normalizePositiveInteger(tuning.iosPacketLength, protocolV2BleTuning.iosPacketLength),
300
+ androidPacketLength: normalizePositiveInteger(tuning.androidPacketLength, protocolV2BleTuning.androidPacketLength),
301
+ highVolumeWriteBurstSize: normalizePositiveInteger(tuning.highVolumeWriteBurstSize, protocolV2BleTuning.highVolumeWriteBurstSize),
302
+ highVolumeWritePauseMs: normalizePositiveInteger(tuning.highVolumeWritePauseMs, protocolV2BleTuning.highVolumeWritePauseMs),
303
+ highVolumeWriteFlushDelayMs: normalizePositiveInteger(tuning.highVolumeWriteFlushDelayMs, protocolV2BleTuning.highVolumeWriteFlushDelayMs),
304
+ highVolumeWriteWithResponse: (_a = tuning.highVolumeWriteWithResponse) !== null && _a !== void 0 ? _a : protocolV2BleTuning.highVolumeWriteWithResponse,
305
+ };
306
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning configured:', protocolV2BleTuning);
307
+ }
308
+ function resetProtocolV2BleTuning() {
309
+ protocolV2BleTuning = Object.assign({}, DEFAULT_PROTOCOL_V2_BLE_TUNING);
310
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 BLE tuning reset:', protocolV2BleTuning);
311
+ }
312
+ function getProtocolV2BleTuning() {
313
+ return Object.assign({}, protocolV2BleTuning);
314
+ }
315
+ function inferProtocolHintFromDeviceName(name) {
316
+ return /\bpro\s*2\b/i.test(name !== null && name !== void 0 ? name : '') ? 'V2' : undefined;
317
+ }
318
+ function getDeviceDisplayName(device) {
319
+ return (device === null || device === void 0 ? void 0 : device.name) || (device === null || device === void 0 ? void 0 : device.localName) || null;
320
+ }
321
+ function isGenericBleService(uuid) {
322
+ return ['1800', '1801', '180a'].includes(getBleUuidKey(uuid));
323
+ }
324
+ function hasKnownOneKeyService(device) {
325
+ var _a;
326
+ return ((_a = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _a !== void 0 ? _a : []).some(serviceUuid => getInfosForServiceUuid(serviceUuid, 'classic'));
327
+ }
328
+ const ANDROID_REQUEST_MTU = 256;
329
+ const connectOptions = {
330
+ requestMTU: ANDROID_REQUEST_MTU,
219
331
  timeout: 3000,
220
332
  refreshGatt: 'OnConnected',
221
333
  };
222
334
  const tryToGetConfiguration = (device) => {
223
335
  if (!device || !device.serviceUUIDs)
224
336
  return null;
225
- const [serviceUUID] = device.serviceUUIDs;
337
+ const serviceUUID = device.serviceUUIDs.find(uuid => getInfosForServiceUuid(uuid, 'classic'));
338
+ if (!serviceUUID)
339
+ return null;
226
340
  const infos = getInfosForServiceUuid(serviceUUID, 'classic');
227
341
  if (!infos)
228
342
  return null;
229
343
  return infos;
230
344
  };
345
+ const requestAndroidMtu = (device) => __awaiter(void 0, void 0, void 0, function* () {
346
+ if (reactNative.Platform.OS !== 'android')
347
+ return device;
348
+ try {
349
+ const mtuDevice = yield device.requestMTU(ANDROID_REQUEST_MTU);
350
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU requested:', {
351
+ requested: ANDROID_REQUEST_MTU,
352
+ mtu: mtuDevice.mtu,
353
+ });
354
+ return mtuDevice;
355
+ }
356
+ catch (error) {
357
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Android MTU request failed:', error);
358
+ return device;
359
+ }
360
+ });
231
361
  function remapError(error) {
232
362
  var _a;
233
363
  if (error instanceof reactNativeBlePlx.BleError) {
@@ -252,11 +382,21 @@ class ReactNativeBleTransport {
252
382
  this.name = 'ReactNativeBleTransport';
253
383
  this.configured = false;
254
384
  this.stopped = false;
255
- this.scanTimeout = 3000;
385
+ this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
256
386
  this.runPromise = null;
257
- this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : 3000;
387
+ this.deviceProtocol = new Map();
388
+ this.deviceProtocolHints = new Map();
389
+ this.protocolV2Assemblers = new Map();
390
+ this.protocolV2FrameQueues = new Map();
391
+ this.protocolV2FramePromises = new Map();
392
+ this.activeProtocolV2Call = null;
393
+ this.nextProtocolV2CallToken = 1;
394
+ this.monitorTokens = new Map();
395
+ this.nextMonitorToken = 1;
396
+ this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : DEVICE_SCAN_TIMEOUT_MS;
258
397
  }
259
- init(_logger, emitter) {
398
+ init(logger, emitter) {
399
+ setBleLogger(logger);
260
400
  this.emitter = emitter;
261
401
  }
262
402
  configure(signedData) {
@@ -264,6 +404,10 @@ class ReactNativeBleTransport {
264
404
  this.configured = true;
265
405
  this._messages = messages;
266
406
  }
407
+ configureProtocolV2(signedData) {
408
+ this._messagesV2 = parseConfigure(signedData);
409
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
410
+ }
267
411
  listen() {
268
412
  }
269
413
  getPlxManager() {
@@ -299,9 +443,10 @@ class ReactNativeBleTransport {
299
443
  }
300
444
  }
301
445
  blePlxManager.startDeviceScan(null, {
446
+ allowDuplicates: true,
302
447
  scanMode: reactNativeBlePlx.ScanMode.LowLatency,
303
448
  }, (error, device) => {
304
- var _a, _b;
449
+ var _a, _b, _c;
305
450
  if (error) {
306
451
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan manager: ', blePlxManager);
307
452
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
@@ -322,13 +467,35 @@ class ReactNativeBleTransport {
322
467
  }
323
468
  return;
324
469
  }
325
- if (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)) {
470
+ const displayName = getDeviceDisplayName(device);
471
+ 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) ||
472
+ 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) ||
473
+ hasKnownOneKeyService(device);
474
+ const shouldTraceCandidate = !!displayName && /onekey|bixinkey|pro\s*2|pro\b|touch|^k\d|^t\d/i.test(displayName);
475
+ if (shouldTraceCandidate) {
476
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] scan candidate', {
477
+ name: device === null || device === void 0 ? void 0 : device.name,
478
+ localName: device === null || device === void 0 ? void 0 : device.localName,
479
+ id: device === null || device === void 0 ? void 0 : device.id,
480
+ serviceUUIDs: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
481
+ accepted: isOneKey,
482
+ });
483
+ }
484
+ if (isOneKey) {
326
485
  Log === null || Log === void 0 ? void 0 : Log.debug('search device start ======================');
327
- const { name, localName, id } = device !== null && device !== void 0 ? device : {};
328
- 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 : ''}`);
486
+ const { name, localName, id, serviceUUIDs } = device !== null && device !== void 0 ? device : {};
487
+ 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(',')}`);
329
488
  addDevice(device);
330
489
  Log === null || Log === void 0 ? void 0 : Log.debug('search device end ======================\n');
331
490
  }
491
+ else if (displayName && /\bpro\s*2\b/i.test(displayName)) {
492
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Pro2-like BLE device was not accepted:', {
493
+ name: device === null || device === void 0 ? void 0 : device.name,
494
+ localName: device === null || device === void 0 ? void 0 : device.localName,
495
+ id: device === null || device === void 0 ? void 0 : device.id,
496
+ serviceUUIDs: device === null || device === void 0 ? void 0 : device.serviceUUIDs,
497
+ });
498
+ }
332
499
  });
333
500
  getConnectedDeviceIds(getBluetoothServiceUuids()).then(devices => {
334
501
  for (const device of devices) {
@@ -337,8 +504,14 @@ class ReactNativeBleTransport {
337
504
  }
338
505
  });
339
506
  const addDevice = (device) => {
507
+ var _a;
340
508
  if (deviceList.every(d => d.id !== device.id)) {
341
- deviceList.push(Object.assign(Object.assign({}, device), { commType: 'ble' }));
509
+ const displayName = (_a = getDeviceDisplayName(device)) !== null && _a !== void 0 ? _a : 'Unknown BLE Device';
510
+ const protocolHint = inferProtocolHintFromDeviceName(displayName);
511
+ if (protocolHint) {
512
+ this.deviceProtocolHints.set(device.id, protocolHint);
513
+ }
514
+ deviceList.push(Object.assign(Object.assign({}, device), { name: displayName, commType: 'ble' }));
342
515
  }
343
516
  };
344
517
  timer.timeout(() => {
@@ -349,19 +522,32 @@ class ReactNativeBleTransport {
349
522
  });
350
523
  }
351
524
  acquire(input) {
352
- var _a;
525
+ var _a, _b, _c, _d, _e, _f;
353
526
  return __awaiter(this, void 0, void 0, function* () {
354
- const { uuid, forceCleanRunPromise } = input;
527
+ const { uuid, forceCleanRunPromise, expectedProtocol } = input;
355
528
  if (!uuid) {
356
529
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
357
530
  }
358
- let device = null;
359
- if (transportCache[uuid]) {
360
- Log === null || Log === void 0 ? void 0 : Log.debug('transport not be released, will release: ', uuid);
361
- yield this.release(uuid);
531
+ const cachedTransport = transportCache[uuid];
532
+ if (cachedTransport) {
533
+ const cachedProtocol = this.deviceProtocol.get(uuid);
534
+ const isCachedDeviceConnected = yield cachedTransport.device.isConnected().catch(() => false);
535
+ if (isCachedDeviceConnected &&
536
+ cachedProtocol &&
537
+ (!expectedProtocol || cachedProtocol === expectedProtocol)) {
538
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] reuse cached BLE transport:', uuid, cachedProtocol);
539
+ return { uuid, protocolType: cachedProtocol };
540
+ }
541
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport not reusable, will release: ', uuid);
542
+ yield this.release(uuid, true);
362
543
  }
544
+ let device = null;
363
545
  if (forceCleanRunPromise && this.runPromise) {
364
- this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
546
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
547
+ this.runPromise.reject(error);
548
+ this.rejectAllProtocolV2Frames(error);
549
+ this.runPromise = null;
550
+ this.activeProtocolV2Call = null;
365
551
  Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
366
552
  }
367
553
  const blePlxManager = yield this.getPlxManager();
@@ -377,6 +563,9 @@ class ReactNativeBleTransport {
377
563
  if (bondState.bonding) {
378
564
  yield onDeviceBondState(uuid);
379
565
  }
566
+ else if (!bondState.bonded) {
567
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
568
+ }
380
569
  }
381
570
  if (!device) {
382
571
  const devices = yield blePlxManager.devices([uuid]);
@@ -397,7 +586,6 @@ class ReactNativeBleTransport {
397
586
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
398
587
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
399
588
  e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
400
- connectOptions = {};
401
589
  Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
402
590
  device = yield blePlxManager.connectToDevice(uuid);
403
591
  }
@@ -416,23 +604,22 @@ class ReactNativeBleTransport {
416
604
  if (!(yield device.isConnected())) {
417
605
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
418
606
  try {
419
- yield device.connect(connectOptions);
607
+ device = yield device.connect(connectOptions);
420
608
  }
421
609
  catch (e) {
422
610
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
423
611
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
424
612
  e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
425
- connectOptions = {};
426
613
  Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
427
614
  try {
428
- yield device.connect();
615
+ device = yield device.connect();
429
616
  }
430
617
  catch (e) {
431
618
  Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
432
619
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
433
620
  Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
434
621
  yield device.cancelConnection();
435
- yield device.connect();
622
+ device = yield device.connect();
436
623
  }
437
624
  }
438
625
  }
@@ -441,9 +628,11 @@ class ReactNativeBleTransport {
441
628
  }
442
629
  }
443
630
  }
631
+ device = yield requestAndroidMtu(device);
444
632
  yield device.discoverAllServicesAndCharacteristics();
445
633
  let infos = tryToGetConfiguration(device);
446
634
  let characteristics;
635
+ let fallbackServiceUuid;
447
636
  if (!infos) {
448
637
  for (const serviceUuid of getBluetoothServiceUuids()) {
449
638
  try {
@@ -457,16 +646,34 @@ class ReactNativeBleTransport {
457
646
  }
458
647
  }
459
648
  if (!infos) {
460
- try {
461
- Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
462
- yield device.cancelConnection();
649
+ const services = yield device.services();
650
+ 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));
651
+ const knownService = services.find(service => getInfosForServiceUuid(service.uuid, 'classic'));
652
+ const fallbackService = (_a = knownService !== null && knownService !== void 0 ? knownService : services.find(service => !isGenericBleService(service.uuid))) !== null && _a !== void 0 ? _a : services[0];
653
+ if (fallbackService) {
654
+ fallbackServiceUuid = fallbackService.uuid;
655
+ characteristics = yield device.characteristicsForService(fallbackService.uuid);
656
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Using fallback BLE service:', fallbackService.uuid);
463
657
  }
464
- catch (e) {
465
- Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection error when service not found: ', e.message || e.reason);
658
+ }
659
+ if (!infos) {
660
+ if (!fallbackServiceUuid) {
661
+ try {
662
+ Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
663
+ yield device.cancelConnection();
664
+ }
665
+ catch (e) {
666
+ Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection error when service not found: ', e.message || e.reason);
667
+ }
668
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
466
669
  }
670
+ }
671
+ const serviceUuid = (_b = infos === null || infos === void 0 ? void 0 : infos.serviceUuid) !== null && _b !== void 0 ? _b : fallbackServiceUuid;
672
+ const writeUuid = (_c = infos === null || infos === void 0 ? void 0 : infos.writeUuid) !== null && _c !== void 0 ? _c : '00000002-0000-1000-8000-00805f9b34fb';
673
+ const notifyUuid = (_d = infos === null || infos === void 0 ? void 0 : infos.notifyUuid) !== null && _d !== void 0 ? _d : '00000003-0000-1000-8000-00805f9b34fb';
674
+ if (!serviceUuid) {
467
675
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
468
676
  }
469
- const { serviceUuid, writeUuid, notifyUuid } = infos;
470
677
  if (!characteristics) {
471
678
  characteristics = yield device.characteristicsForService(serviceUuid);
472
679
  }
@@ -476,10 +683,10 @@ class ReactNativeBleTransport {
476
683
  let writeCharacteristic;
477
684
  let notifyCharacteristic;
478
685
  for (const c of characteristics) {
479
- if (c.uuid === writeUuid) {
686
+ if (isSameBleUuid(c.uuid, writeUuid)) {
480
687
  writeCharacteristic = c;
481
688
  }
482
- else if (c.uuid === notifyUuid) {
689
+ else if (isSameBleUuid(c.uuid, notifyUuid)) {
483
690
  notifyCharacteristic = c;
484
691
  }
485
692
  }
@@ -489,23 +696,52 @@ class ReactNativeBleTransport {
489
696
  if (!notifyCharacteristic) {
490
697
  throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
491
698
  }
492
- if (!writeCharacteristic.isWritableWithResponse) {
699
+ if (!hasWritableCapability(writeCharacteristic)) {
493
700
  throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
494
701
  }
495
702
  if (!notifyCharacteristic.isNotifiable) {
496
703
  throw hdShared.ERRORS.TypedError('BLECharacteristicNotNotifiable: notify characteristic not notifiable');
497
704
  }
498
- yield this.release(uuid);
499
- const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
500
- transport.notifySubscription = this._monitorCharacteristic(transport.notifyCharacteristic, uuid);
501
- transportCache[uuid] = transport;
502
- (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-connect', {
705
+ const protocolHint = expectedProtocol
706
+ ? undefined
707
+ : (_e = this.deviceProtocolHints.get(uuid)) !== null && _e !== void 0 ? _e : inferProtocolHintFromDeviceName(getDeviceDisplayName(device));
708
+ yield this.release(uuid, true);
709
+ if (protocolHint) {
710
+ this.deviceProtocolHints.set(uuid, protocolHint);
711
+ }
712
+ const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
713
+ if (reactNative.Platform.OS === 'android') {
714
+ transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
715
+ }
716
+ const monitorToken = this.nextMonitorToken;
717
+ this.nextMonitorToken += 1;
718
+ const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
719
+ transport$1.monitorToken = monitorToken;
720
+ transport$1.notifyTransactionId = notifyTransactionId;
721
+ this.monitorTokens.set(uuid, monitorToken);
722
+ transport$1.notifySubscription = this._monitorCharacteristic(transport$1.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
723
+ transportCache[uuid] = transport$1;
724
+ this.protocolV2Assemblers.set(uuid, new transport.ProtocolV2FrameAssembler());
725
+ if (reactNative.Platform.OS === 'ios') {
726
+ yield new Promise(resolve => {
727
+ setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
728
+ });
729
+ }
730
+ else if (reactNative.Platform.OS === 'android') {
731
+ yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
732
+ }
733
+ const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
734
+ (_f = this.emitter) === null || _f === void 0 ? void 0 : _f.emit('device-connect', {
503
735
  name: device.name,
504
736
  id: device.id,
505
737
  connectId: device.id,
506
738
  });
507
- transport.disconnectSubscription = device.onDisconnected(() => {
739
+ transport$1.disconnectSubscription = device.onDisconnected(() => {
508
740
  var _a;
741
+ if (transportCache[uuid] !== transport$1) {
742
+ Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored for stale transport: ', device === null || device === void 0 ? void 0 : device.id);
743
+ return;
744
+ }
509
745
  try {
510
746
  Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
511
747
  (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
@@ -514,26 +750,33 @@ class ReactNativeBleTransport {
514
750
  connectId: device === null || device === void 0 ? void 0 : device.id,
515
751
  });
516
752
  if (this.runPromise) {
517
- this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError));
753
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
754
+ this.runPromise.reject(error);
755
+ this.rejectAllProtocolV2Frames(error);
518
756
  }
519
757
  }
520
758
  catch (e) {
521
759
  Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
522
760
  }
523
761
  finally {
524
- this.release(uuid);
762
+ this.release(uuid, true);
525
763
  }
526
764
  });
527
- return { uuid };
765
+ return { uuid, protocolType };
528
766
  });
529
767
  }
530
- _monitorCharacteristic(characteristic, uuid) {
768
+ _monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
531
769
  let bufferLength = 0;
532
770
  let buffer$1 = [];
533
771
  const subscription = characteristic.monitor((error, c) => {
534
772
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
773
+ const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
535
774
  if (error) {
536
775
  Log === null || Log === void 0 ? void 0 : Log.debug(`error monitor ${characteristic.uuid}, deviceId: ${characteristic.deviceID}: ${error}`);
776
+ if (!isCurrentMonitor) {
777
+ Log === null || Log === void 0 ? void 0 : Log.debug('monitor error ignored for stale transport: ', uuid, notifyTransactionId);
778
+ return;
779
+ }
537
780
  if (this.runPromise) {
538
781
  let ERROR = hdShared.HardwareErrorCode.BleCharacteristicNotifyError;
539
782
  if ((_a = error.reason) === null || _a === void 0 ? void 0 : _a.includes('The connection has timed out unexpectedly')) {
@@ -547,20 +790,37 @@ class ReactNativeBleTransport {
547
790
  ((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
548
791
  ((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
549
792
  ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
550
- this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure));
793
+ const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
794
+ this.runPromise.reject(notifyError);
795
+ this.rejectAllProtocolV2Frames(notifyError);
551
796
  Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
552
797
  return;
553
798
  }
554
- this.runPromise.reject(hdShared.ERRORS.TypedError(ERROR));
799
+ const notifyError = hdShared.ERRORS.TypedError(ERROR);
800
+ this.runPromise.reject(notifyError);
801
+ this.rejectAllProtocolV2Frames(notifyError);
555
802
  Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
556
803
  }
557
804
  return;
558
805
  }
806
+ if (!isCurrentMonitor) {
807
+ Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored for stale transport: ', uuid, notifyTransactionId);
808
+ return;
809
+ }
559
810
  if (!c) {
560
811
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleMonitorError);
561
812
  }
562
813
  try {
563
814
  const data = buffer.Buffer.from(c.value, 'base64');
815
+ const protocol = this.deviceProtocol.get(uuid);
816
+ if (!protocol) {
817
+ Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored before protocol detection: ', uuid);
818
+ return;
819
+ }
820
+ if (protocol === 'V2') {
821
+ this.handleProtocolV2Notification(uuid, new Uint8Array(data));
822
+ return;
823
+ }
564
824
  if (isHeaderChunk(data)) {
565
825
  bufferLength = data.readInt32BE(5);
566
826
  buffer$1 = [...data.subarray(3)];
@@ -568,7 +828,7 @@ class ReactNativeBleTransport {
568
828
  else {
569
829
  buffer$1 = buffer$1.concat([...data]);
570
830
  }
571
- if (buffer$1.length - transport.COMMON_HEADER_SIZE >= bufferLength) {
831
+ if (buffer$1.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferLength) {
572
832
  const value = buffer.Buffer.from(buffer$1);
573
833
  bufferLength = 0;
574
834
  buffer$1 = [];
@@ -577,24 +837,65 @@ class ReactNativeBleTransport {
577
837
  }
578
838
  catch (error) {
579
839
  Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
580
- (_j = this.runPromise) === null || _j === void 0 ? void 0 : _j.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
840
+ const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
841
+ (_j = this.runPromise) === null || _j === void 0 ? void 0 : _j.reject(notifyError);
842
+ this.rejectAllProtocolV2Frames(notifyError);
581
843
  }
582
- }, uuid);
844
+ }, notifyTransactionId);
583
845
  return subscription;
584
846
  }
585
- release(uuid) {
586
- var _a, _b, _c;
847
+ release(uuid, onclose = false) {
848
+ var _a, _b, _c, _d, _e, _f, _g, _h;
587
849
  return __awaiter(this, void 0, void 0, function* () {
588
850
  const transport = transportCache[uuid];
851
+ if (this.runPromise) {
852
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
853
+ this.runPromise.reject(error);
854
+ this.runPromise = null;
855
+ this.rejectAllProtocolV2Frames(error);
856
+ this.activeProtocolV2Call = null;
857
+ }
858
+ else {
859
+ this.resetProtocolV2Frames(uuid);
860
+ }
861
+ if (reactNative.Platform.OS === 'android' && !onclose && transport) {
862
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
863
+ this.resetProtocolV2Frames(uuid);
864
+ if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
865
+ this.activeProtocolV2Call = null;
866
+ }
867
+ return Promise.resolve(true);
868
+ }
589
869
  if (transport) {
870
+ if (this.monitorTokens.get(uuid) === transport.monitorToken) {
871
+ this.monitorTokens.delete(uuid);
872
+ }
590
873
  Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
591
- (_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
874
+ (_c = transport.disconnectSubscription) === null || _c === void 0 ? void 0 : _c.remove();
592
875
  transport.disconnectSubscription = undefined;
593
- Log === null || Log === void 0 ? void 0 : Log.debug('release: removing notify subscription, characteristic: ', (_b = transport.notifyCharacteristic) === null || _b === void 0 ? void 0 : _b.uuid);
594
- (_c = transport.notifySubscription) === null || _c === void 0 ? void 0 : _c.remove();
876
+ 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);
877
+ (_e = transport.notifySubscription) === null || _e === void 0 ? void 0 : _e.remove();
595
878
  transport.notifySubscription = undefined;
879
+ if (transport.notifyTransactionId) {
880
+ try {
881
+ yield ((_f = this.blePlxManager) === null || _f === void 0 ? void 0 : _f.cancelTransaction(transport.notifyTransactionId));
882
+ }
883
+ catch (e) {
884
+ 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);
885
+ }
886
+ }
596
887
  delete transportCache[uuid];
597
- if (reactNative.Platform.OS === 'android') ;
888
+ }
889
+ this.deviceProtocol.delete(uuid);
890
+ this.deviceProtocolHints.delete(uuid);
891
+ (_g = this.protocolV2Assemblers.get(uuid)) === null || _g === void 0 ? void 0 : _g.reset();
892
+ this.protocolV2Assemblers.delete(uuid);
893
+ this.resetProtocolV2Frames(uuid);
894
+ try {
895
+ yield ((_h = this.blePlxManager) === null || _h === void 0 ? void 0 : _h.cancelTransaction(uuid));
896
+ }
897
+ catch (e) {
898
+ Log === null || Log === void 0 ? void 0 : Log.debug('release: cancel transaction error (ignored): ', (e === null || e === void 0 ? void 0 : e.message) || e);
598
899
  }
599
900
  return Promise.resolve(true);
600
901
  });
@@ -604,7 +905,7 @@ class ReactNativeBleTransport {
604
905
  yield this.call(session, name, data);
605
906
  });
606
907
  }
607
- call(uuid, name, data) {
908
+ call(uuid, name, data, options) {
608
909
  return __awaiter(this, void 0, void 0, function* () {
609
910
  if (this.stopped) {
610
911
  return Promise.reject(hdShared.ERRORS.TypedError('Transport stopped.'));
@@ -617,12 +918,10 @@ class ReactNativeBleTransport {
617
918
  if (this.runPromise && !forceRun) {
618
919
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
619
920
  }
620
- const transport$1 = transportCache[uuid];
621
- if (!transport$1) {
622
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
921
+ const protocol = this.getProtocolType(uuid);
922
+ if (!protocol) {
923
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol has not been detected for ${uuid}`);
623
924
  }
624
- this.runPromise = hdShared.createDeferred();
625
- const messages = this._messages;
626
925
  if (name === 'ResourceUpdate' || name === 'ResourceAck') {
627
926
  Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', {
628
927
  file_name: data === null || data === void 0 ? void 0 : data.file_name,
@@ -630,12 +929,29 @@ class ReactNativeBleTransport {
630
929
  });
631
930
  }
632
931
  else if (transport.LogBlockCommand.has(name)) {
633
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name);
932
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' protocol: ', protocol);
634
933
  }
635
934
  else {
636
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data);
935
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data, ' protocol: ', protocol);
936
+ }
937
+ if (protocol === 'V2') {
938
+ return this.callProtocolV2(uuid, name, data, options);
939
+ }
940
+ return this.callProtocolV1(uuid, name, data, options);
941
+ });
942
+ }
943
+ callProtocolV1(uuid, name, data, options) {
944
+ return __awaiter(this, void 0, void 0, function* () {
945
+ if (!this._messages) {
946
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
637
947
  }
638
- const buffers = buildBuffers(messages, name, data);
948
+ const transport = this.getCachedTransport(uuid);
949
+ const runPromise = hdShared.createDeferred();
950
+ runPromise.promise.catch(() => undefined);
951
+ this.runPromise = runPromise;
952
+ const messages = this._messages;
953
+ const buffers = ProtocolV1.encodeTransportPackets(messages, name, data);
954
+ let timeout;
639
955
  function writeChunkedData(buffers, writeFunction, onError) {
640
956
  return __awaiter(this, void 0, void 0, function* () {
641
957
  const packetCapacity = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_PACKET_LENGTH;
@@ -660,14 +976,14 @@ class ReactNativeBleTransport {
660
976
  });
661
977
  }
662
978
  if (name === 'EmmcFileWrite') {
663
- yield writeChunkedData(buffers, data => transport$1.writeWithRetry(data), e => {
979
+ yield writeChunkedData(buffers, data => transport.writeWithRetry(data), e => {
664
980
  this.runPromise = null;
665
981
  Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
666
982
  });
667
983
  }
668
984
  else if (name === 'FirmwareUpload') {
669
985
  yield writeChunkedData(buffers, (data) => __awaiter(this, void 0, void 0, function* () {
670
- yield transport$1.writeCharacteristic.writeWithoutResponse(data);
986
+ yield transport.writeCharacteristic.writeWithoutResponse(data);
671
987
  }), e => {
672
988
  this.runPromise = null;
673
989
  Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
@@ -677,7 +993,7 @@ class ReactNativeBleTransport {
677
993
  for (const o of buffers) {
678
994
  const outData = o.toString('base64');
679
995
  try {
680
- yield transport$1.writeCharacteristic.writeWithoutResponse(outData);
996
+ yield transport.writeCharacteristic.writeWithoutResponse(outData);
681
997
  }
682
998
  catch (e) {
683
999
  Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
@@ -695,20 +1011,40 @@ class ReactNativeBleTransport {
695
1011
  }
696
1012
  }
697
1013
  try {
698
- const response = yield this.runPromise.promise;
1014
+ const response = yield Promise.race([
1015
+ runPromise.promise,
1016
+ new Promise((_, reject) => {
1017
+ if (options === null || options === void 0 ? void 0 : options.timeoutMs) {
1018
+ timeout = setTimeout(() => {
1019
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${options.timeoutMs}ms for ${name}`);
1020
+ runPromise.reject(error);
1021
+ reject(error);
1022
+ }, options.timeoutMs);
1023
+ }
1024
+ }),
1025
+ ]);
699
1026
  if (typeof response !== 'string') {
700
1027
  throw new Error('Returning data is not string.');
701
1028
  }
702
1029
  Log === null || Log === void 0 ? void 0 : Log.debug('receive data: ', response);
703
- const jsonData = receiveOne(messages, response);
1030
+ const jsonData = ProtocolV1.decodeMessage(messages, response);
704
1031
  return check.call(jsonData);
705
1032
  }
706
1033
  catch (e) {
707
- Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
1034
+ if (name === 'Initialize' && (options === null || options === void 0 ? void 0 : options.timeoutMs) === PROTOCOL_PROBE_TIMEOUT_MS) {
1035
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe call failed:', e);
1036
+ }
1037
+ else {
1038
+ Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
1039
+ }
708
1040
  throw e;
709
1041
  }
710
1042
  finally {
711
- this.runPromise = null;
1043
+ if (timeout)
1044
+ clearTimeout(timeout);
1045
+ if (this.runPromise === runPromise) {
1046
+ this.runPromise = null;
1047
+ }
712
1048
  }
713
1049
  });
714
1050
  }
@@ -716,7 +1052,7 @@ class ReactNativeBleTransport {
716
1052
  this.stopped = true;
717
1053
  }
718
1054
  disconnect(session) {
719
- var _a, _b, _c, _d, _e;
1055
+ var _a, _b, _c, _d, _e, _f;
720
1056
  return __awaiter(this, void 0, void 0, function* () {
721
1057
  Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport resetSession: ', session);
722
1058
  const transport = transportCache[session];
@@ -765,9 +1101,16 @@ class ReactNativeBleTransport {
765
1101
  if (transportCache[session]) {
766
1102
  delete transportCache[session];
767
1103
  }
1104
+ this.deviceProtocol.delete(session);
1105
+ this.deviceProtocolHints.delete(session);
1106
+ this.protocolV2Assemblers.delete(session);
1107
+ this.resetProtocolV2Frames(session);
1108
+ if (((_d = this.activeProtocolV2Call) === null || _d === void 0 ? void 0 : _d.uuid) === session) {
1109
+ this.activeProtocolV2Call = null;
1110
+ }
768
1111
  try {
769
- (_d = this.emitter) === null || _d === void 0 ? void 0 : _d.emit('device-disconnect', {
770
- name: (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name,
1112
+ (_e = this.emitter) === null || _e === void 0 ? void 0 : _e.emit('device-disconnect', {
1113
+ name: (_f = transport === null || transport === void 0 ? void 0 : transport.device) === null || _f === void 0 ? void 0 : _f.name,
771
1114
  id: session,
772
1115
  connectId: session,
773
1116
  });
@@ -783,6 +1126,367 @@ class ReactNativeBleTransport {
783
1126
  if (this.runPromise) ;
784
1127
  this.runPromise = null;
785
1128
  }
1129
+ getCachedTransport(uuid) {
1130
+ const transport = transportCache[uuid];
1131
+ if (!transport) {
1132
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
1133
+ }
1134
+ return transport;
1135
+ }
1136
+ createProtocolMismatchError(expected) {
1137
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Device protocol mismatch: expected ${expected}, but device did not respond to expected protocol`);
1138
+ }
1139
+ createProtocolDetectionError() {
1140
+ return hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, 'Unable to detect BLE protocol: device did not respond to Protocol V1 Initialize or Protocol V2 Ping');
1141
+ }
1142
+ clearProbeProtocol(uuid, protocol) {
1143
+ if (this.deviceProtocol.get(uuid) === protocol) {
1144
+ this.deviceProtocol.delete(uuid);
1145
+ }
1146
+ }
1147
+ detectProtocol(uuid, expectedProtocol, protocolHint) {
1148
+ return __awaiter(this, void 0, void 0, function* () {
1149
+ if (expectedProtocol === 'V1') {
1150
+ if (yield this.probeProtocolV1(uuid)) {
1151
+ this.deviceProtocol.set(uuid, 'V1');
1152
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V1 (expected)`);
1153
+ return 'V1';
1154
+ }
1155
+ throw this.createProtocolMismatchError(expectedProtocol);
1156
+ }
1157
+ if (expectedProtocol === 'V2') {
1158
+ this.deviceProtocol.set(uuid, 'V2');
1159
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (expected)`);
1160
+ return 'V2';
1161
+ }
1162
+ if (protocolHint === 'V2') {
1163
+ this.deviceProtocol.set(uuid, 'V2');
1164
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
1165
+ return 'V2';
1166
+ }
1167
+ if (this.deviceProtocol.get(uuid) === 'V2') {
1168
+ this.deviceProtocol.set(uuid, 'V2');
1169
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (cached)`);
1170
+ return 'V2';
1171
+ }
1172
+ const protocolV1Detected = yield this.probeProtocolV1(uuid);
1173
+ if (protocolV1Detected) {
1174
+ this.deviceProtocol.set(uuid, 'V1');
1175
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V1`);
1176
+ return 'V1';
1177
+ }
1178
+ yield this.resetProbeStateAfterProtocolProbe(uuid, 'V1');
1179
+ if (yield this.probeProtocolV2(uuid)) {
1180
+ this.deviceProtocol.set(uuid, 'V2');
1181
+ Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2`);
1182
+ return 'V2';
1183
+ }
1184
+ this.deviceProtocol.delete(uuid);
1185
+ throw this.createProtocolDetectionError();
1186
+ });
1187
+ }
1188
+ resetProbeStateAfterProtocolProbe(uuid, protocol) {
1189
+ var _a, _b, _c, _d;
1190
+ return __awaiter(this, void 0, void 0, function* () {
1191
+ const transport = transportCache[uuid];
1192
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1193
+ this.resetProtocolV2Frames(uuid);
1194
+ if (((_b = this.activeProtocolV2Call) === null || _b === void 0 ? void 0 : _b.uuid) === uuid) {
1195
+ this.activeProtocolV2Call = null;
1196
+ }
1197
+ if (this.runPromise) {
1198
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1199
+ this.runPromise.reject(error);
1200
+ this.runPromise = null;
1201
+ }
1202
+ if (!transport)
1203
+ return;
1204
+ const previousNotifyTransactionId = transport.notifyTransactionId;
1205
+ if (this.monitorTokens.get(uuid) === transport.monitorToken) {
1206
+ this.monitorTokens.delete(uuid);
1207
+ }
1208
+ (_c = transport.notifySubscription) === null || _c === void 0 ? void 0 : _c.remove();
1209
+ transport.notifySubscription = undefined;
1210
+ if (previousNotifyTransactionId) {
1211
+ try {
1212
+ yield ((_d = this.blePlxManager) === null || _d === void 0 ? void 0 : _d.cancelTransaction(previousNotifyTransactionId));
1213
+ }
1214
+ catch (error) {
1215
+ 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);
1216
+ }
1217
+ }
1218
+ const monitorToken = this.nextMonitorToken;
1219
+ this.nextMonitorToken += 1;
1220
+ const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
1221
+ transport.monitorToken = monitorToken;
1222
+ transport.notifyTransactionId = notifyTransactionId;
1223
+ this.monitorTokens.set(uuid, monitorToken);
1224
+ transport.notifySubscription = this._monitorCharacteristic(transport.notifyCharacteristic, uuid, monitorToken, notifyTransactionId);
1225
+ if (reactNative.Platform.OS === 'ios') {
1226
+ yield new Promise(resolve => {
1227
+ setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
1228
+ });
1229
+ }
1230
+ });
1231
+ }
1232
+ probeProtocolV1(uuid) {
1233
+ return __awaiter(this, void 0, void 0, function* () {
1234
+ if (!this._messages) {
1235
+ return false;
1236
+ }
1237
+ try {
1238
+ this.deviceProtocol.set(uuid, 'V1');
1239
+ yield this.callProtocolV1(uuid, 'Initialize', {}, { timeoutMs: PROTOCOL_PROBE_TIMEOUT_MS });
1240
+ return true;
1241
+ }
1242
+ catch (error) {
1243
+ this.clearProbeProtocol(uuid, 'V1');
1244
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V1 Initialize probe failed:', error);
1245
+ return false;
1246
+ }
1247
+ });
1248
+ }
1249
+ probeProtocolV2(uuid) {
1250
+ var _a;
1251
+ return __awaiter(this, void 0, void 0, function* () {
1252
+ if (!this._messages || !this._messagesV2) {
1253
+ return false;
1254
+ }
1255
+ this.deviceProtocol.set(uuid, 'V2');
1256
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1257
+ const detected = yield transport.probeProtocolV2({
1258
+ call: (name, data, options) => this.callProtocolV2(uuid, name, data, options),
1259
+ timeoutMs: PROTOCOL_V2_PROBE_TIMEOUT_MS,
1260
+ logger: Log,
1261
+ logPrefix: 'ProtocolV2 RN-BLE',
1262
+ onProbeFailed: () => {
1263
+ var _a;
1264
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1265
+ this.resetProtocolV2Frames(uuid);
1266
+ },
1267
+ });
1268
+ if (!detected) {
1269
+ this.clearProbeProtocol(uuid, 'V2');
1270
+ }
1271
+ return detected;
1272
+ });
1273
+ }
1274
+ handleProtocolV2Notification(uuid, data) {
1275
+ var _a, _b, _c;
1276
+ try {
1277
+ if (!this.runPromise || ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) !== uuid) {
1278
+ (_b = this.protocolV2Assemblers.get(uuid)) === null || _b === void 0 ? void 0 : _b.reset();
1279
+ this.resetProtocolV2Frames(uuid);
1280
+ return;
1281
+ }
1282
+ if (data.length === 0)
1283
+ return;
1284
+ const assembler = this.protocolV2Assemblers.get(uuid);
1285
+ if (!assembler)
1286
+ return;
1287
+ let frameData = assembler.push(data);
1288
+ while (frameData) {
1289
+ this.resolveProtocolV2Frame(uuid, frameData);
1290
+ frameData = assembler.push(new Uint8Array(0));
1291
+ }
1292
+ }
1293
+ catch (error) {
1294
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 notification error:', error);
1295
+ const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
1296
+ (_c = this.runPromise) === null || _c === void 0 ? void 0 : _c.reject(notifyError);
1297
+ this.rejectAllProtocolV2Frames(notifyError);
1298
+ }
1299
+ }
1300
+ getProtocolV2FrameQueue(uuid) {
1301
+ let queue = this.protocolV2FrameQueues.get(uuid);
1302
+ if (!queue) {
1303
+ queue = [];
1304
+ this.protocolV2FrameQueues.set(uuid, queue);
1305
+ }
1306
+ return queue;
1307
+ }
1308
+ resolveProtocolV2Frame(uuid, frame) {
1309
+ const framePromise = this.protocolV2FramePromises.get(uuid);
1310
+ if (framePromise) {
1311
+ framePromise.resolve(frame);
1312
+ this.protocolV2FramePromises.delete(uuid);
1313
+ return;
1314
+ }
1315
+ this.getProtocolV2FrameQueue(uuid).push(frame);
1316
+ }
1317
+ rejectAllProtocolV2Frames(error) {
1318
+ this.protocolV2FrameQueues.clear();
1319
+ for (const framePromise of this.protocolV2FramePromises.values()) {
1320
+ framePromise.reject(error);
1321
+ }
1322
+ this.protocolV2FramePromises.clear();
1323
+ }
1324
+ resetProtocolV2Frames(uuid) {
1325
+ this.protocolV2FrameQueues.delete(uuid);
1326
+ this.protocolV2FramePromises.delete(uuid);
1327
+ }
1328
+ isActiveProtocolV2Call(uuid, token) {
1329
+ var _a;
1330
+ return ((_a = this.activeProtocolV2Call) === null || _a === void 0 ? void 0 : _a.uuid) === uuid && this.activeProtocolV2Call.token === token;
1331
+ }
1332
+ readProtocolV2Frame(uuid) {
1333
+ return __awaiter(this, void 0, void 0, function* () {
1334
+ const queuedFrame = this.getProtocolV2FrameQueue(uuid).shift();
1335
+ if (queuedFrame) {
1336
+ return queuedFrame;
1337
+ }
1338
+ const framePromise = hdShared.createDeferred();
1339
+ this.protocolV2FramePromises.set(uuid, framePromise);
1340
+ try {
1341
+ return yield framePromise.promise;
1342
+ }
1343
+ finally {
1344
+ if (this.protocolV2FramePromises.get(uuid) === framePromise) {
1345
+ this.protocolV2FramePromises.delete(uuid);
1346
+ }
1347
+ }
1348
+ });
1349
+ }
1350
+ writeProtocolV2Frame(transport, frame, options) {
1351
+ return __awaiter(this, void 0, void 0, function* () {
1352
+ const tuning = getProtocolV2BleTuning();
1353
+ const packetCapacity = resolveProtocolV2PacketCapacity({
1354
+ platform: reactNative.Platform.OS,
1355
+ iosPacketLength: tuning.iosPacketLength,
1356
+ androidPacketLength: tuning.androidPacketLength,
1357
+ mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
1358
+ });
1359
+ const writeWithResponse = !!(options === null || options === void 0 ? void 0 : options.writeWithResponse) || (!!(options === null || options === void 0 ? void 0 : options.highVolume) && tuning.highVolumeWriteWithResponse);
1360
+ const writeMode = resolveBleWriteMode(transport.writeCharacteristic, writeWithResponse ? 'withResponse' : 'withoutResponse');
1361
+ const shouldThrottle = !!(options === null || options === void 0 ? void 0 : options.highVolume) && writeMode === 'withoutResponse';
1362
+ let packetsWritten = 0;
1363
+ try {
1364
+ for (let offset = 0; offset < frame.length; offset += packetCapacity) {
1365
+ const chunk = frame.slice(offset, offset + packetCapacity);
1366
+ const base64 = buffer.Buffer.from(chunk).toString('base64');
1367
+ if (writeMode === 'withResponse') {
1368
+ yield transport.writeCharacteristic.writeWithResponse(base64);
1369
+ }
1370
+ else {
1371
+ yield transport.writeCharacteristic.writeWithoutResponse(base64);
1372
+ }
1373
+ packetsWritten += 1;
1374
+ if (shouldThrottle &&
1375
+ packetsWritten % tuning.highVolumeWriteBurstSize === 0 &&
1376
+ offset + packetCapacity < frame.length) {
1377
+ yield delay(tuning.highVolumeWritePauseMs);
1378
+ }
1379
+ }
1380
+ if (shouldThrottle) {
1381
+ yield delay(tuning.highVolumeWriteFlushDelayMs);
1382
+ }
1383
+ }
1384
+ catch (error) {
1385
+ if ((options === null || options === void 0 ? void 0 : options.highVolume) && !writeWithResponse && packetsWritten === 0) {
1386
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume writeWithoutResponse failed before data was sent, fallback to writeWithResponse:', error);
1387
+ yield this.writeProtocolV2Frame(transport, frame, {
1388
+ highVolume: true,
1389
+ writeWithResponse: true,
1390
+ });
1391
+ return;
1392
+ }
1393
+ throw error;
1394
+ }
1395
+ });
1396
+ }
1397
+ callProtocolV2(uuid, name, data, options) {
1398
+ var _a, _b, _c, _d;
1399
+ return __awaiter(this, void 0, void 0, function* () {
1400
+ if (!this._messages || !this._messagesV2) {
1401
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1402
+ }
1403
+ const forceRun = name === 'Initialize' || name === 'Cancel' || name === 'GetProtoVersion';
1404
+ if (this.runPromise) {
1405
+ if (!forceRun) {
1406
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
1407
+ }
1408
+ const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise);
1409
+ this.runPromise.reject(error);
1410
+ this.rejectAllProtocolV2Frames(error);
1411
+ this.runPromise = null;
1412
+ this.activeProtocolV2Call = null;
1413
+ }
1414
+ const transport$1 = this.getCachedTransport(uuid);
1415
+ const runPromise = hdShared.createDeferred();
1416
+ runPromise.promise.catch(() => undefined);
1417
+ this.runPromise = runPromise;
1418
+ const callToken = this.nextProtocolV2CallToken++;
1419
+ this.activeProtocolV2Call = { uuid, token: callToken };
1420
+ (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1421
+ this.resetProtocolV2Frames(uuid);
1422
+ let completed = false;
1423
+ 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 });
1424
+ const highVolumeWrite = transport.LogBlockCommand.has(name);
1425
+ if (highVolumeWrite) {
1426
+ const tuning = getProtocolV2BleTuning();
1427
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 high-volume write uses throttled writeWithoutResponse:', name, {
1428
+ packetCapacity: reactNative.Platform.OS === 'ios' ? tuning.iosPacketLength : tuning.androidPacketLength,
1429
+ burstSize: tuning.highVolumeWriteBurstSize,
1430
+ pauseMs: tuning.highVolumeWritePauseMs,
1431
+ flushDelayMs: tuning.highVolumeWriteFlushDelayMs,
1432
+ writeWithResponse: tuning.highVolumeWriteWithResponse,
1433
+ });
1434
+ }
1435
+ try {
1436
+ const session = new transport.ProtocolV2Session({
1437
+ schemas: {
1438
+ protocolV1: this._messages,
1439
+ protocolV2: this._messagesV2,
1440
+ },
1441
+ router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
1442
+ writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
1443
+ yield this.writeProtocolV2Frame(transport$1, frame, {
1444
+ highVolume: highVolumeWrite,
1445
+ });
1446
+ }),
1447
+ readFrame: () => __awaiter(this, void 0, void 0, function* () {
1448
+ const rxFrame = yield this.readProtocolV2Frame(uuid);
1449
+ if (!(rxFrame instanceof Uint8Array)) {
1450
+ throw new Error('Protocol V2 response is not Uint8Array');
1451
+ }
1452
+ return rxFrame;
1453
+ }),
1454
+ logger: Log,
1455
+ logPrefix: 'ProtocolV2 RN-BLE',
1456
+ createTimeoutError: (_messageName, timeout) => hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleTimeoutError, `BLE response timeout after ${timeout}ms for ${name}`),
1457
+ });
1458
+ const result = yield session.call(name, data, callOptions);
1459
+ completed = true;
1460
+ return result;
1461
+ }
1462
+ catch (e) {
1463
+ if (this.isActiveProtocolV2Call(uuid, callToken)) {
1464
+ (_c = this.protocolV2Assemblers.get(uuid)) === null || _c === void 0 ? void 0 : _c.reset();
1465
+ this.resetProtocolV2Frames(uuid);
1466
+ }
1467
+ Log === null || Log === void 0 ? void 0 : Log.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
1468
+ throw e;
1469
+ }
1470
+ finally {
1471
+ if (this.isActiveProtocolV2Call(uuid, callToken)) {
1472
+ if (!completed) {
1473
+ (_d = this.protocolV2Assemblers.get(uuid)) === null || _d === void 0 ? void 0 : _d.reset();
1474
+ }
1475
+ this.resetProtocolV2Frames(uuid);
1476
+ this.activeProtocolV2Call = null;
1477
+ }
1478
+ if (this.runPromise === runPromise) {
1479
+ this.runPromise = null;
1480
+ }
1481
+ }
1482
+ });
1483
+ }
1484
+ getProtocolType(path) {
1485
+ return this.deviceProtocol.get(path);
1486
+ }
786
1487
  }
787
1488
 
788
- module.exports = ReactNativeBleTransport;
1489
+ exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
1490
+ exports["default"] = ReactNativeBleTransport;
1491
+ exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
1492
+ exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;