@onekeyfe/hd-transport-react-native 1.1.27-alpha.41 → 1.1.27-alpha.6

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,13 +1,12 @@
1
1
  'use strict';
2
2
 
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
3
  var reactNative = require('react-native');
6
4
  var buffer = require('buffer');
7
5
  var reactNativeBlePlx = require('react-native-ble-plx');
8
6
  var ByteBuffer = require('bytebuffer');
9
7
  var transport = require('@onekeyfe/hd-transport');
10
8
  var hdShared = require('@onekeyfe/hd-shared');
9
+ var hdCore = require('@onekeyfe/hd-core');
11
10
  var BleUtils = require('@onekeyfe/react-native-ble-utils');
12
11
 
13
12
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
@@ -46,126 +45,44 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
46
45
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
47
46
  };
48
47
 
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;
48
+ const Logger = hdCore.getLogger(hdCore.LoggerNames.HdBleTransport);
60
49
  const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].getConnectedPeripherals(serviceUuids);
61
50
  const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
62
51
  const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
63
52
  let timeout;
64
- let cleanupListener;
65
- const cleanup = () => {
53
+ const cleanup = (cleanupListener) => {
66
54
  if (timeout) {
67
55
  clearTimeout(timeout);
68
56
  }
69
57
  if (cleanupListener)
70
58
  cleanupListener();
71
59
  };
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 => {
60
+ const cleanupListener = BleUtils__default["default"].onDeviceBondState(peripheral => {
77
61
  var _a;
78
62
  if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
79
63
  return;
80
64
  }
81
65
  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
+ }
82
72
  const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
83
73
  const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
84
74
  Logger.debug('onDeviceBondState bondState:', bondState);
85
75
  if (hasBonded) {
86
- cleanup();
76
+ cleanup(cleanupListener);
87
77
  resolve(peripheral);
88
78
  }
89
79
  else if (hasCanceled) {
90
- cleanup();
80
+ cleanup(cleanupListener);
91
81
  reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
92
82
  }
93
83
  });
94
84
  });
95
85
 
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
-
169
86
  const timer = process.env.NODE_ENV === 'development'
170
87
  ? {
171
88
  timeout: (fn, ms) => {
@@ -209,27 +126,58 @@ const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject)
209
126
  }, ms);
210
127
  });
211
128
 
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
+
212
159
  const isHeaderChunk = (chunk) => {
213
160
  if (chunk.length < 9)
214
161
  return false;
215
162
  const [MagicQuestionMark, sharp1, sharp2] = chunk;
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)) {
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)) {
219
166
  return true;
220
167
  }
221
168
  return false;
222
169
  };
223
170
 
224
- const Log$1 = bleLogger;
171
+ const Log$1 = hdCore.getLogger(hdCore.LoggerNames.HdBleTransport);
225
172
  class BleTransport {
226
173
  constructor(device, writeCharacteristic, notifyCharacteristic) {
227
174
  this.name = 'ReactNativeBleTransport';
228
- this.mtuSize = 23;
175
+ this.mtuSize = 20;
229
176
  this.id = device.id;
230
177
  this.device = device;
231
178
  this.writeCharacteristic = writeCharacteristic;
232
179
  this.notifyCharacteristic = notifyCharacteristic;
180
+ console.log(`BleTransport(${String(this.id)}) new instance`);
233
181
  }
234
182
  writeWithRetry(data, retryCount = BleTransport.MAX_RETRIES) {
235
183
  return __awaiter(this, void 0, void 0, function* () {
@@ -239,7 +187,7 @@ class BleTransport {
239
187
  catch (error) {
240
188
  Log$1 === null || Log$1 === void 0 ? void 0 : Log$1.debug(`Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`);
241
189
  if (retryCount > 0) {
242
- yield hdShared.wait(BleTransport.RETRY_DELAY);
190
+ yield hdCore.wait(BleTransport.RETRY_DELAY);
243
191
  if (error.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
244
192
  error.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
245
193
  try {
@@ -263,101 +211,52 @@ class BleTransport {
263
211
  BleTransport.MAX_RETRIES = 5;
264
212
  BleTransport.RETRY_DELAY = 2000;
265
213
 
266
- const { check, ProtocolV1, parseConfigure } = transport__default["default"];
267
- const Log = bleLogger;
214
+ const { check, buildBuffers, receiveOne, parseConfigure } = transport__default["default"];
215
+ const Log = hdCore.getLogger(hdCore.LoggerNames.HdBleTransport);
268
216
  const transportCache = {};
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;
217
+ const FIRMWARE_UPLOAD_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 5;
218
+ const FIRMWARE_UPLOAD_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 8 : 10;
219
+ const FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 24 : 30;
220
+ const FIRMWARE_UPLOAD_WRITE_MAX_RETRIES = 8;
221
+ const FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS = 2000;
222
+ const ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH = 192;
223
+ const FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_FIRMWARE_UPLOAD_PACKET_LENGTH;
224
+ const ANDROID_GATT_CONGESTED_STATUS = 143;
278
225
  const delay = (ms) => new Promise(resolve => {
279
226
  setTimeout(resolve, ms);
280
227
  });
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);
228
+ const getFirmwareUploadWriteRetryType = (error) => {
229
+ if (!error || typeof error !== 'object')
230
+ return null;
231
+ const bleWriteError = error;
232
+ if (bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.DeviceDisconnected ||
233
+ bleWriteError.errorCode === reactNativeBlePlx.BleErrorCode.CharacteristicNotFound) {
234
+ return 'reconnectable';
235
+ }
236
+ if (bleWriteError.androidErrorCode === ANDROID_GATT_CONGESTED_STATUS ||
237
+ bleWriteError.status === ANDROID_GATT_CONGESTED_STATUS) {
238
+ return 'congested';
239
+ }
240
+ const text = [bleWriteError.reason, bleWriteError.message, bleWriteError.name]
241
+ .filter(value => typeof value === 'string')
242
+ .join(' ');
243
+ return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
295
244
  };
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,
245
+ const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
246
+ let connectOptions = {
247
+ requestMTU: 256,
331
248
  timeout: 3000,
332
249
  refreshGatt: 'OnConnected',
333
250
  };
334
251
  const tryToGetConfiguration = (device) => {
335
252
  if (!device || !device.serviceUUIDs)
336
253
  return null;
337
- const serviceUUID = device.serviceUUIDs.find(uuid => getInfosForServiceUuid(uuid, 'classic'));
338
- if (!serviceUUID)
339
- return null;
254
+ const [serviceUUID] = device.serviceUUIDs;
340
255
  const infos = getInfosForServiceUuid(serviceUUID, 'classic');
341
256
  if (!infos)
342
257
  return null;
343
258
  return infos;
344
259
  };
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
- });
361
260
  function remapError(error) {
362
261
  var _a;
363
262
  if (error instanceof reactNativeBlePlx.BleError) {
@@ -382,21 +281,12 @@ class ReactNativeBleTransport {
382
281
  this.name = 'ReactNativeBleTransport';
383
282
  this.configured = false;
384
283
  this.stopped = false;
385
- this.scanTimeout = DEVICE_SCAN_TIMEOUT_MS;
284
+ this.scanTimeout = 3000;
386
285
  this.runPromise = null;
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;
286
+ this.firmwareUploadWriteRecoveryIds = new Set();
287
+ this.scanTimeout = (_a = options.scanTimeout) !== null && _a !== void 0 ? _a : 3000;
397
288
  }
398
- init(logger, emitter) {
399
- setBleLogger(logger);
289
+ init(_logger, emitter) {
400
290
  this.emitter = emitter;
401
291
  }
402
292
  configure(signedData) {
@@ -404,10 +294,6 @@ class ReactNativeBleTransport {
404
294
  this.configured = true;
405
295
  this._messages = messages;
406
296
  }
407
- configureProtocolV2(signedData) {
408
- this._messagesV2 = parseConfigure(signedData);
409
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 schema configured');
410
- }
411
297
  listen() {
412
298
  }
413
299
  getPlxManager() {
@@ -416,6 +302,134 @@ class ReactNativeBleTransport {
416
302
  this.blePlxManager = new reactNativeBlePlx.BleManager();
417
303
  return Promise.resolve(this.blePlxManager);
418
304
  }
305
+ resolveCharacteristics(device) {
306
+ return __awaiter(this, void 0, void 0, function* () {
307
+ yield device.discoverAllServicesAndCharacteristics();
308
+ let infos = tryToGetConfiguration(device);
309
+ let characteristics;
310
+ if (!infos) {
311
+ for (const serviceUuid of getBluetoothServiceUuids()) {
312
+ try {
313
+ characteristics = yield device.characteristicsForService(serviceUuid);
314
+ infos = getInfosForServiceUuid(serviceUuid, 'classic');
315
+ break;
316
+ }
317
+ catch (e) {
318
+ Log === null || Log === void 0 ? void 0 : Log.error(e);
319
+ }
320
+ }
321
+ }
322
+ if (!infos) {
323
+ try {
324
+ Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection when service not found');
325
+ yield device.cancelConnection();
326
+ }
327
+ catch (e) {
328
+ Log === null || Log === void 0 ? void 0 : Log.debug('cancel connection error when service not found: ', e.message || e.reason);
329
+ }
330
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
331
+ }
332
+ const { serviceUuid, writeUuid, notifyUuid } = infos;
333
+ if (!characteristics) {
334
+ characteristics = yield device.characteristicsForService(serviceUuid);
335
+ }
336
+ if (!characteristics) {
337
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound);
338
+ }
339
+ let writeCharacteristic;
340
+ let notifyCharacteristic;
341
+ for (const c of characteristics) {
342
+ if (c.uuid === writeUuid) {
343
+ writeCharacteristic = c;
344
+ }
345
+ else if (c.uuid === notifyUuid) {
346
+ notifyCharacteristic = c;
347
+ }
348
+ }
349
+ if (!writeCharacteristic) {
350
+ throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: write characteristic not found');
351
+ }
352
+ if (!notifyCharacteristic) {
353
+ throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
354
+ }
355
+ if (!writeCharacteristic.isWritableWithResponse) {
356
+ throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
357
+ }
358
+ if (!notifyCharacteristic.isNotifiable) {
359
+ throw hdShared.ERRORS.TypedError('BLECharacteristicNotNotifiable: notify characteristic not notifiable');
360
+ }
361
+ return {
362
+ writeCharacteristic,
363
+ notifyCharacteristic,
364
+ };
365
+ });
366
+ }
367
+ attachDisconnectSubscription(transport, device, uuid) {
368
+ var _a;
369
+ (_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
370
+ transport.disconnectSubscription = device.onDisconnected(() => {
371
+ var _a;
372
+ if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
373
+ Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect ignored during FirmwareUpload write recovery: ', uuid);
374
+ return;
375
+ }
376
+ try {
377
+ Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
378
+ (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
379
+ name: device === null || device === void 0 ? void 0 : device.name,
380
+ id: device === null || device === void 0 ? void 0 : device.id,
381
+ connectId: device === null || device === void 0 ? void 0 : device.id,
382
+ });
383
+ if (this.runPromise) {
384
+ this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError));
385
+ }
386
+ }
387
+ catch (e) {
388
+ Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
389
+ }
390
+ finally {
391
+ this.release(uuid);
392
+ }
393
+ });
394
+ }
395
+ reconnectFirmwareUploadTransport(uuid, transport) {
396
+ var _a, _b;
397
+ return __awaiter(this, void 0, void 0, function* () {
398
+ this.firmwareUploadWriteRecoveryIds.add(uuid);
399
+ try {
400
+ (_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
401
+ transport.disconnectSubscription = undefined;
402
+ (_b = transport.notifySubscription) === null || _b === void 0 ? void 0 : _b.remove();
403
+ transport.notifySubscription = undefined;
404
+ let { device } = transport;
405
+ const isConnected = yield device.isConnected().catch(() => false);
406
+ if (!isConnected) {
407
+ try {
408
+ device = yield device.connect(connectOptions);
409
+ }
410
+ catch (e) {
411
+ if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
412
+ e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
413
+ connectOptions = {};
414
+ device = yield device.connect();
415
+ }
416
+ else if (e.errorCode !== reactNativeBlePlx.BleErrorCode.DeviceAlreadyConnected) {
417
+ throw e;
418
+ }
419
+ }
420
+ }
421
+ const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(device);
422
+ transport.device = device;
423
+ transport.writeCharacteristic = writeCharacteristic;
424
+ transport.notifyCharacteristic = notifyCharacteristic;
425
+ transport.notifySubscription = this._monitorCharacteristic(notifyCharacteristic, uuid);
426
+ this.attachDisconnectSubscription(transport, device, uuid);
427
+ }
428
+ finally {
429
+ this.firmwareUploadWriteRecoveryIds.delete(uuid);
430
+ }
431
+ });
432
+ }
419
433
  enumerate() {
420
434
  return __awaiter(this, void 0, void 0, function* () {
421
435
  return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
@@ -443,10 +457,9 @@ class ReactNativeBleTransport {
443
457
  }
444
458
  }
445
459
  blePlxManager.startDeviceScan(null, {
446
- allowDuplicates: true,
447
460
  scanMode: reactNativeBlePlx.ScanMode.LowLatency,
448
461
  }, (error, device) => {
449
- var _a, _b, _c;
462
+ var _a, _b;
450
463
  if (error) {
451
464
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan manager: ', blePlxManager);
452
465
  Log === null || Log === void 0 ? void 0 : Log.debug('ble scan error: ', error);
@@ -467,35 +480,13 @@ class ReactNativeBleTransport {
467
480
  }
468
481
  return;
469
482
  }
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) {
483
+ 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)) {
485
484
  Log === null || Log === void 0 ? void 0 : Log.debug('search device start ======================');
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(',')}`);
485
+ const { name, localName, id } = device !== null && device !== void 0 ? device : {};
486
+ 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 : ''}`);
488
487
  addDevice(device);
489
488
  Log === null || Log === void 0 ? void 0 : Log.debug('search device end ======================\n');
490
489
  }
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
- }
499
490
  });
500
491
  getConnectedDeviceIds(getBluetoothServiceUuids()).then(devices => {
501
492
  for (const device of devices) {
@@ -504,14 +495,8 @@ class ReactNativeBleTransport {
504
495
  }
505
496
  });
506
497
  const addDevice = (device) => {
507
- var _a;
508
498
  if (deviceList.every(d => d.id !== device.id)) {
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' }));
499
+ deviceList.push(Object.assign(Object.assign({}, device), { commType: 'ble' }));
515
500
  }
516
501
  };
517
502
  timer.timeout(() => {
@@ -522,32 +507,19 @@ class ReactNativeBleTransport {
522
507
  });
523
508
  }
524
509
  acquire(input) {
525
- var _a, _b, _c, _d, _e, _f;
510
+ var _a;
526
511
  return __awaiter(this, void 0, void 0, function* () {
527
- const { uuid, forceCleanRunPromise, expectedProtocol } = input;
512
+ const { uuid, forceCleanRunPromise } = input;
528
513
  if (!uuid) {
529
514
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleRequiredUUID);
530
515
  }
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);
543
- }
544
516
  let device = null;
517
+ if (transportCache[uuid]) {
518
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport not be released, will release: ', uuid);
519
+ yield this.release(uuid);
520
+ }
545
521
  if (forceCleanRunPromise && this.runPromise) {
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;
522
+ this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleForceCleanRunPromise));
551
523
  Log === null || Log === void 0 ? void 0 : Log.debug('Force clean Bluetooth run promise, forceCleanRunPromise: ', forceCleanRunPromise);
552
524
  }
553
525
  const blePlxManager = yield this.getPlxManager();
@@ -563,9 +535,6 @@ class ReactNativeBleTransport {
563
535
  if (bondState.bonding) {
564
536
  yield onDeviceBondState(uuid);
565
537
  }
566
- else if (!bondState.bonded) {
567
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
568
- }
569
538
  }
570
539
  if (!device) {
571
540
  const devices = yield blePlxManager.devices([uuid]);
@@ -586,6 +555,7 @@ class ReactNativeBleTransport {
586
555
  Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
587
556
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
588
557
  e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
558
+ connectOptions = {};
589
559
  Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
590
560
  device = yield blePlxManager.connectToDevice(uuid);
591
561
  }
@@ -604,22 +574,23 @@ class ReactNativeBleTransport {
604
574
  if (!(yield device.isConnected())) {
605
575
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device: ', uuid);
606
576
  try {
607
- device = yield device.connect(connectOptions);
577
+ yield device.connect(connectOptions);
608
578
  }
609
579
  catch (e) {
610
580
  Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
611
581
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
612
582
  e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
583
+ connectOptions = {};
613
584
  Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
614
585
  try {
615
- device = yield device.connect();
586
+ yield device.connect();
616
587
  }
617
588
  catch (e) {
618
589
  Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect error: ', e);
619
590
  if (e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
620
591
  Log === null || Log === void 0 ? void 0 : Log.debug('last try to reconnect');
621
592
  yield device.cancelConnection();
622
- device = yield device.connect();
593
+ yield device.connect();
623
594
  }
624
595
  }
625
596
  }
@@ -628,153 +599,29 @@ class ReactNativeBleTransport {
628
599
  }
629
600
  }
630
601
  }
631
- device = yield requestAndroidMtu(device);
632
- yield device.discoverAllServicesAndCharacteristics();
633
- let infos = tryToGetConfiguration(device);
634
- let characteristics;
635
- let fallbackServiceUuid;
636
- if (!infos) {
637
- for (const serviceUuid of getBluetoothServiceUuids()) {
638
- try {
639
- characteristics = yield device.characteristicsForService(serviceUuid);
640
- infos = getInfosForServiceUuid(serviceUuid, 'classic');
641
- break;
642
- }
643
- catch (e) {
644
- Log === null || Log === void 0 ? void 0 : Log.error(e);
645
- }
646
- }
647
- }
648
- if (!infos) {
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);
657
- }
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);
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) {
675
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleServiceNotFound);
676
- }
677
- if (!characteristics) {
678
- characteristics = yield device.characteristicsForService(serviceUuid);
679
- }
680
- if (!characteristics) {
681
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotFound);
682
- }
683
- let writeCharacteristic;
684
- let notifyCharacteristic;
685
- for (const c of characteristics) {
686
- if (isSameBleUuid(c.uuid, writeUuid)) {
687
- writeCharacteristic = c;
688
- }
689
- else if (isSameBleUuid(c.uuid, notifyUuid)) {
690
- notifyCharacteristic = c;
691
- }
692
- }
693
- if (!writeCharacteristic) {
694
- throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: write characteristic not found');
695
- }
696
- if (!notifyCharacteristic) {
697
- throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
698
- }
699
- if (!hasWritableCapability(writeCharacteristic)) {
700
- throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
701
- }
702
- if (!notifyCharacteristic.isNotifiable) {
703
- throw hdShared.ERRORS.TypedError('BLECharacteristicNotNotifiable: notify characteristic not notifiable');
704
- }
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', {
602
+ const { writeCharacteristic, notifyCharacteristic } = yield this.resolveCharacteristics(device);
603
+ yield this.release(uuid);
604
+ const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
605
+ transport.notifySubscription = this._monitorCharacteristic(transport.notifyCharacteristic, uuid);
606
+ transportCache[uuid] = transport;
607
+ (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-connect', {
735
608
  name: device.name,
736
609
  id: device.id,
737
610
  connectId: device.id,
738
611
  });
739
- transport$1.disconnectSubscription = device.onDisconnected(() => {
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
- }
745
- try {
746
- Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect: ', device === null || device === void 0 ? void 0 : device.id);
747
- (_a = this.emitter) === null || _a === void 0 ? void 0 : _a.emit('device-disconnect', {
748
- name: device === null || device === void 0 ? void 0 : device.name,
749
- id: device === null || device === void 0 ? void 0 : device.id,
750
- connectId: device === null || device === void 0 ? void 0 : device.id,
751
- });
752
- if (this.runPromise) {
753
- const error = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError);
754
- this.runPromise.reject(error);
755
- this.rejectAllProtocolV2Frames(error);
756
- }
757
- }
758
- catch (e) {
759
- Log === null || Log === void 0 ? void 0 : Log.debug('device disconnect error: ', e);
760
- }
761
- finally {
762
- this.release(uuid, true);
763
- }
764
- });
765
- return { uuid, protocolType };
612
+ this.attachDisconnectSubscription(transport, device, uuid);
613
+ return { uuid };
766
614
  });
767
615
  }
768
- _monitorCharacteristic(characteristic, uuid, monitorToken, notifyTransactionId) {
616
+ _monitorCharacteristic(characteristic, uuid) {
769
617
  let bufferLength = 0;
770
618
  let buffer$1 = [];
771
619
  const subscription = characteristic.monitor((error, c) => {
772
620
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
773
- const isCurrentMonitor = this.monitorTokens.get(uuid) === monitorToken;
774
621
  if (error) {
775
622
  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);
623
+ if (this.firmwareUploadWriteRecoveryIds.has(uuid)) {
624
+ Log === null || Log === void 0 ? void 0 : Log.debug('notify error ignored during FirmwareUpload write recovery: ', uuid);
778
625
  return;
779
626
  }
780
627
  if (this.runPromise) {
@@ -790,37 +637,20 @@ class ReactNativeBleTransport {
790
637
  ((_e = error.reason) === null || _e === void 0 ? void 0 : _e.includes('The handle is invalid')) ||
791
638
  ((_f = error.reason) === null || _f === void 0 ? void 0 : _f.includes('Writing is not permitted')) ||
792
639
  ((_g = error.reason) === null || _g === void 0 ? void 0 : _g.includes('notify change failed for device'))) {
793
- const notifyError = hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure);
794
- this.runPromise.reject(notifyError);
795
- this.rejectAllProtocolV2Frames(notifyError);
640
+ this.runPromise.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure));
796
641
  Log === null || Log === void 0 ? void 0 : Log.debug(`${hdShared.HardwareErrorCode.BleCharacteristicNotifyChangeFailure} ${error.message} ${error.reason}`);
797
642
  return;
798
643
  }
799
- const notifyError = hdShared.ERRORS.TypedError(ERROR);
800
- this.runPromise.reject(notifyError);
801
- this.rejectAllProtocolV2Frames(notifyError);
644
+ this.runPromise.reject(hdShared.ERRORS.TypedError(ERROR));
802
645
  Log === null || Log === void 0 ? void 0 : Log.debug(': monitor notify error, and has unreleased Promise', Error);
803
646
  }
804
647
  return;
805
648
  }
806
- if (!isCurrentMonitor) {
807
- Log === null || Log === void 0 ? void 0 : Log.debug('monitor data ignored for stale transport: ', uuid, notifyTransactionId);
808
- return;
809
- }
810
649
  if (!c) {
811
650
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleMonitorError);
812
651
  }
813
652
  try {
814
653
  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
- }
824
654
  if (isHeaderChunk(data)) {
825
655
  bufferLength = data.readInt32BE(5);
826
656
  buffer$1 = [...data.subarray(3)];
@@ -828,7 +658,7 @@ class ReactNativeBleTransport {
828
658
  else {
829
659
  buffer$1 = buffer$1.concat([...data]);
830
660
  }
831
- if (buffer$1.length - transport.PROTOCOL_V1_MESSAGE_HEADER_SIZE >= bufferLength) {
661
+ if (buffer$1.length - transport.COMMON_HEADER_SIZE >= bufferLength) {
832
662
  const value = buffer.Buffer.from(buffer$1);
833
663
  bufferLength = 0;
834
664
  buffer$1 = [];
@@ -837,65 +667,24 @@ class ReactNativeBleTransport {
837
667
  }
838
668
  catch (error) {
839
669
  Log === null || Log === void 0 ? void 0 : Log.debug('monitor data error: ', error);
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);
670
+ (_j = this.runPromise) === null || _j === void 0 ? void 0 : _j.reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError));
843
671
  }
844
- }, notifyTransactionId);
672
+ }, uuid);
845
673
  return subscription;
846
674
  }
847
- release(uuid, onclose = false) {
848
- var _a, _b, _c, _d, _e, _f, _g, _h;
675
+ release(uuid) {
676
+ var _a, _b, _c;
849
677
  return __awaiter(this, void 0, void 0, function* () {
850
678
  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
- }
869
679
  if (transport) {
870
- if (this.monitorTokens.get(uuid) === transport.monitorToken) {
871
- this.monitorTokens.delete(uuid);
872
- }
873
680
  Log === null || Log === void 0 ? void 0 : Log.debug('release: removing disconnect subscription for device: ', uuid);
874
- (_c = transport.disconnectSubscription) === null || _c === void 0 ? void 0 : _c.remove();
681
+ (_a = transport.disconnectSubscription) === null || _a === void 0 ? void 0 : _a.remove();
875
682
  transport.disconnectSubscription = undefined;
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();
683
+ 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);
684
+ (_c = transport.notifySubscription) === null || _c === void 0 ? void 0 : _c.remove();
878
685
  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
- }
887
686
  delete transportCache[uuid];
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);
687
+ if (reactNative.Platform.OS === 'android') ;
899
688
  }
900
689
  return Promise.resolve(true);
901
690
  });
@@ -905,7 +694,7 @@ class ReactNativeBleTransport {
905
694
  yield this.call(session, name, data);
906
695
  });
907
696
  }
908
- call(uuid, name, data, options) {
697
+ call(uuid, name, data) {
909
698
  return __awaiter(this, void 0, void 0, function* () {
910
699
  if (this.stopped) {
911
700
  return Promise.reject(hdShared.ERRORS.TypedError('Transport stopped.'));
@@ -918,10 +707,12 @@ class ReactNativeBleTransport {
918
707
  if (this.runPromise && !forceRun) {
919
708
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportCallInProgress);
920
709
  }
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}`);
710
+ const transport$1 = transportCache[uuid];
711
+ if (!transport$1) {
712
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotFound);
924
713
  }
714
+ this.runPromise = hdShared.createDeferred();
715
+ const messages = this._messages;
925
716
  if (name === 'ResourceUpdate' || name === 'ResourceAck') {
926
717
  Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', {
927
718
  file_name: data === null || data === void 0 ? void 0 : data.file_name,
@@ -929,29 +720,12 @@ class ReactNativeBleTransport {
929
720
  });
930
721
  }
931
722
  else if (transport.LogBlockCommand.has(name)) {
932
- Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' protocol: ', protocol);
723
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name);
933
724
  }
934
725
  else {
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);
726
+ Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native', 'call-', ' name: ', name, ' data: ', data);
947
727
  }
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;
728
+ const buffers = buildBuffers(messages, name, data);
955
729
  function writeChunkedData(buffers, writeFunction, onError) {
956
730
  return __awaiter(this, void 0, void 0, function* () {
957
731
  const packetCapacity = reactNative.Platform.OS === 'ios' ? IOS_PACKET_LENGTH : ANDROID_PACKET_LENGTH;
@@ -975,15 +749,90 @@ class ReactNativeBleTransport {
975
749
  }
976
750
  });
977
751
  }
752
+ function writeFirmwareUploadChunkedData(buffers, writeFunction, onError) {
753
+ return __awaiter(this, void 0, void 0, function* () {
754
+ let index = 0;
755
+ let packetsWritten = 0;
756
+ let chunk = ByteBuffer__default["default"].allocate(FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY);
757
+ while (index < buffers.length) {
758
+ const buffer = buffers[index].toBuffer();
759
+ chunk.append(buffer);
760
+ index += 1;
761
+ if (chunk.offset === FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY || index >= buffers.length) {
762
+ chunk.reset();
763
+ try {
764
+ yield writeFunction(chunk.toString('base64'));
765
+ packetsWritten += 1;
766
+ chunk = ByteBuffer__default["default"].allocate(FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY);
767
+ if (packetsWritten % FIRMWARE_UPLOAD_WRITE_BURST_SIZE === 0 && index < buffers.length) {
768
+ yield delay(FIRMWARE_UPLOAD_WRITE_PAUSE_MS);
769
+ }
770
+ }
771
+ catch (e) {
772
+ onError(e);
773
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleWriteCharacteristicError);
774
+ }
775
+ }
776
+ }
777
+ if (packetsWritten > 0) {
778
+ yield delay(FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS);
779
+ }
780
+ });
781
+ }
978
782
  if (name === 'EmmcFileWrite') {
979
- yield writeChunkedData(buffers, data => transport.writeWithRetry(data), e => {
783
+ yield writeChunkedData(buffers, data => transport$1.writeWithRetry(data), e => {
980
784
  this.runPromise = null;
981
785
  Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
982
786
  });
983
787
  }
984
788
  else if (name === 'FirmwareUpload') {
985
- yield writeChunkedData(buffers, (data) => __awaiter(this, void 0, void 0, function* () {
986
- yield transport.writeCharacteristic.writeWithoutResponse(data);
789
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write uses throttled BLE packets:', {
790
+ packetCapacity: FIRMWARE_UPLOAD_WRITE_PACKET_CAPACITY,
791
+ burstSize: FIRMWARE_UPLOAD_WRITE_BURST_SIZE,
792
+ pauseMs: FIRMWARE_UPLOAD_WRITE_PAUSE_MS,
793
+ flushDelayMs: FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS,
794
+ maxRetries: FIRMWARE_UPLOAD_WRITE_MAX_RETRIES,
795
+ });
796
+ yield writeFirmwareUploadChunkedData(buffers, (data) => __awaiter(this, void 0, void 0, function* () {
797
+ let attempt = 0;
798
+ while (true) {
799
+ try {
800
+ yield transport$1.writeCharacteristic.writeWithoutResponse(data);
801
+ return;
802
+ }
803
+ catch (error) {
804
+ const retryType = getFirmwareUploadWriteRetryType(error);
805
+ if (!retryType || attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
806
+ throw error;
807
+ }
808
+ const shouldReconnect = retryType === 'reconnectable';
809
+ const delayMs = shouldReconnect
810
+ ? FIRMWARE_UPLOAD_RECONNECT_RETRY_DELAY_MS
811
+ : resolveFirmwareUploadRetryDelay(attempt);
812
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload write retry:', {
813
+ attempt: attempt + 1,
814
+ delayMs,
815
+ reconnect: shouldReconnect,
816
+ error,
817
+ });
818
+ if (shouldReconnect) {
819
+ this.firmwareUploadWriteRecoveryIds.add(uuid);
820
+ }
821
+ yield delay(delayMs);
822
+ attempt += 1;
823
+ if (shouldReconnect) {
824
+ try {
825
+ yield this.reconnectFirmwareUploadTransport(uuid, transport$1);
826
+ }
827
+ catch (e) {
828
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] FirmwareUpload reconnect error:', e);
829
+ if (attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
830
+ throw e;
831
+ }
832
+ }
833
+ }
834
+ }
835
+ }
987
836
  }), e => {
988
837
  this.runPromise = null;
989
838
  Log === null || Log === void 0 ? void 0 : Log.error('writeCharacteristic write error: ', e);
@@ -993,7 +842,7 @@ class ReactNativeBleTransport {
993
842
  for (const o of buffers) {
994
843
  const outData = o.toString('base64');
995
844
  try {
996
- yield transport.writeCharacteristic.writeWithoutResponse(outData);
845
+ yield transport$1.writeCharacteristic.writeWithoutResponse(outData);
997
846
  }
998
847
  catch (e) {
999
848
  Log === null || Log === void 0 ? void 0 : Log.debug('writeCharacteristic write error: ', e);
@@ -1011,40 +860,20 @@ class ReactNativeBleTransport {
1011
860
  }
1012
861
  }
1013
862
  try {
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
- ]);
863
+ const response = yield this.runPromise.promise;
1026
864
  if (typeof response !== 'string') {
1027
865
  throw new Error('Returning data is not string.');
1028
866
  }
1029
867
  Log === null || Log === void 0 ? void 0 : Log.debug('receive data: ', response);
1030
- const jsonData = ProtocolV1.decodeMessage(messages, response);
868
+ const jsonData = receiveOne(messages, response);
1031
869
  return check.call(jsonData);
1032
870
  }
1033
871
  catch (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
- }
872
+ Log === null || Log === void 0 ? void 0 : Log.error('call error: ', e);
1040
873
  throw e;
1041
874
  }
1042
875
  finally {
1043
- if (timeout)
1044
- clearTimeout(timeout);
1045
- if (this.runPromise === runPromise) {
1046
- this.runPromise = null;
1047
- }
876
+ this.runPromise = null;
1048
877
  }
1049
878
  });
1050
879
  }
@@ -1052,7 +881,7 @@ class ReactNativeBleTransport {
1052
881
  this.stopped = true;
1053
882
  }
1054
883
  disconnect(session) {
1055
- var _a, _b, _c, _d, _e, _f;
884
+ var _a, _b, _c, _d, _e;
1056
885
  return __awaiter(this, void 0, void 0, function* () {
1057
886
  Log === null || Log === void 0 ? void 0 : Log.debug('transport-react-native transport resetSession: ', session);
1058
887
  const transport = transportCache[session];
@@ -1101,16 +930,9 @@ class ReactNativeBleTransport {
1101
930
  if (transportCache[session]) {
1102
931
  delete transportCache[session];
1103
932
  }
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
- }
1111
933
  try {
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,
934
+ (_d = this.emitter) === null || _d === void 0 ? void 0 : _d.emit('device-disconnect', {
935
+ name: (_e = transport === null || transport === void 0 ? void 0 : transport.device) === null || _e === void 0 ? void 0 : _e.name,
1114
936
  id: session,
1115
937
  connectId: session,
1116
938
  });
@@ -1126,367 +948,6 @@ class ReactNativeBleTransport {
1126
948
  if (this.runPromise) ;
1127
949
  this.runPromise = null;
1128
950
  }
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
- }
1487
951
  }
1488
952
 
1489
- exports.configureProtocolV2BleTuning = configureProtocolV2BleTuning;
1490
- exports["default"] = ReactNativeBleTransport;
1491
- exports.getProtocolV2BleTuning = getProtocolV2BleTuning;
1492
- exports.resetProtocolV2BleTuning = resetProtocolV2BleTuning;
953
+ module.exports = ReactNativeBleTransport;