@onekeyfe/hd-transport-react-native 1.2.0-alpha.21 → 1.2.0-alpha.22

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.
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AA8BtC,eAAO,MAAM,wBAAwB,gBAA0B,CAAC;AAChE,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,cAAc,SAAS;iBA1BhE,MAAM;;;QAyCtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAAW,MAAM,GAAG,IAAI,WACP,CAAC;AAE/C,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,WAGjD,CAAC;AAEF,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,GAAG,IAAI,YAQxE,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,qBAAqB,MAAM,CAAC;AACzC,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAoCtC,eAAO,MAAM,wBAAwB,gBAA0B,CAAC;AAChE,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,cAAc,SAAS;iBAhChE,MAAM;;;QAiDtB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAAW,MAAM,GAAG,IAAI,WACP,CAAC;AAE/C,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,WAGjD,CAAC;AAEF,eAAO,MAAM,aAAa,UAAW,MAAM,GAAG,IAAI,UAAU,MAAM,GAAG,IAAI,YAQxE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -113,6 +113,7 @@ declare class ReactNativeBleTransport {
113
113
  private resetProtocolV2Frames;
114
114
  private rejectProtocolV2Frames;
115
115
  private readProtocolV2Frame;
116
+ private writeProtocolV2Packet;
116
117
  private writeProtocolV2Frame;
117
118
  private callProtocolV2;
118
119
  private createProtocolV2Adapter;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAEhB,KAAK,oBAAoB,EAIzB,KAAK,YAAY,EAGjB,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAC;AAehC,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAK1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,YAAY,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAkBjE,KAAK,0BAA0B,GAAG;IAChC,mBAAmB,EAAE,cAAc,CAAC;IACpC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AA8CF,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAiBF,wBAAgB,4BAA4B,CAAC,MAAM,GAAE,mBAAwB,QAY5E;AAED,wBAAgB,wBAAwB,SAGvC;AAED,wBAAgB,sBAAsB;;;EAErC;AA4BD,MAAM,MAAM,aAAa,GAAG,oBAAoB,GAAG,MAAM,CAAC;AA4D1D,MAAM,CAAC,OAAO,OAAO,uBAAuB;IAC1C,aAAa,EAAE,aAAa,GAAG,SAAS,CAAC;IAEzC,SAAS,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAEnE,WAAW,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,cAAc,CAAC,GAAG,SAAS,CAAC;IAErE,IAAI,SAA6B;IAEjC,UAAU,UAAS;IAEnB,OAAO,UAAS;IAEhB,WAAW,SAA0B;IAErC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAExC,OAAO,CAAC,EAAE,YAAY,CAAC;IAEvB,8BAA8B,cAAqB;IAGnD,OAAO,CAAC,cAAc,CAAwC;IAE9D,OAAO,CAAC,mBAAmB,CAAwC;IAEnE,OAAO,CAAC,oBAAoB,CAAoD;IAEhF,OAAO,CAAC,qBAAqB,CAAwC;IAErE,OAAO,CAAC,uBAAuB,CAAgD;IAE/E,OAAO,CAAC,eAAe,CAmBpB;IAEH,OAAO,CAAC,aAAa,CAAkC;IAEvD,OAAO,CAAC,gBAAgB,CAAK;gBAEjB,OAAO,EAAE,gBAAgB;IAIrC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY;IAKvC,SAAS,CAAC,UAAU,EAAE,GAAG;IAMzB,mBAAmB,CAAC,UAAU,EAAE,GAAG;IAOnC,MAAM;IAIN,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;IAMjC,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAmGjF,4BAA4B,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAgC5E,gCAAgC,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY;IAuDtE,SAAS;IAyHT,OAAO,CAAC,KAAK,EAAE,eAAe;;;;IAiLpC,sBAAsB,CACpB,cAAc,EAAE,cAAc,EAC9B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,mBAAmB,EAAE,MAAM,GAC1B,YAAY;IAsIT,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,UAAQ;IA8DrC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIjE,IAAI,CACR,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,oBAAoB;YA+BlB,cAAc;IA4M5B,IAAI;IAIE,UAAU,CAAC,OAAO,EAAE,MAAM;IA8EhC,MAAM;IAQN,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,2BAA2B;IAOnC,OAAO,CAAC,4BAA4B;IAOpC,OAAO,CAAC,kBAAkB;YAMZ,cAAc;YA0Dd,iCAAiC;YAoDjC,eAAe;YAgBf,eAAe;IAwB7B,OAAO,CAAC,4BAA4B;IA2BpC,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,qBAAqB;IAK7B,OAAO,CAAC,sBAAsB;YAShB,mBAAmB;YAiBnB,oBAAoB;YAepB,cAAc;IAuC5B,OAAO,CAAC,uBAAuB;IA4C/B,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -95,6 +95,7 @@ const IOS_PACKET_LENGTH = 128;
95
95
  const ANDROID_PACKET_LENGTH = 192;
96
96
  const ANDROID_DEFAULT_MTU = 23;
97
97
  const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
98
+ const Pro2ServiceUUID = 'fffd';
98
99
  const OneKeyServices = {
99
100
  classic: {
100
101
  [ClassicServiceUUID]: {
@@ -102,6 +103,11 @@ const OneKeyServices = {
102
103
  writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
103
104
  notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
104
105
  },
106
+ [Pro2ServiceUUID]: {
107
+ serviceUuid: Pro2ServiceUUID,
108
+ writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
109
+ notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
110
+ },
105
111
  },
106
112
  };
107
113
  const bluetoothServices = [];
@@ -117,7 +123,8 @@ const getInfosForServiceUuid = (serviceUuid, deviceType) => {
117
123
  return null;
118
124
  }
119
125
  const normalizedServiceUuid = normalizeBleUuid(serviceUuid);
120
- const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid);
126
+ const service = (_a = services[serviceUuid]) !== null && _a !== void 0 ? _a : Object.values(services).find(item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid ||
127
+ getBleUuidKey(item.serviceUuid) === getBleUuidKey(serviceUuid));
121
128
  if (!service) {
122
129
  return null;
123
130
  }
@@ -289,7 +296,6 @@ const getFirmwareUploadWriteRetryType = (error) => {
289
296
  return /GATT_CONGESTED|status\s*[:=]?\s*143/.test(text) ? 'congested' : null;
290
297
  };
291
298
  const resolveFirmwareUploadRetryDelay = (attempt, baseDelayMs = 200, maxDelayMs = 1200) => Math.min(baseDelayMs * Math.pow(2, attempt), maxDelayMs);
292
- const BLE_RESPONSE_TIMEOUT_MS = 30000;
293
299
  const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
294
300
  const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
295
301
  const DEVICE_SCAN_TIMEOUT_MS = 8000;
@@ -1326,13 +1332,16 @@ class ReactNativeBleTransport {
1326
1332
  throw this.createProtocolMismatchError(expectedProtocol);
1327
1333
  }
1328
1334
  if (expectedProtocol === 'V2') {
1329
- this.deviceProtocol.set(uuid, 'V2');
1330
- Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1331
- deviceId: uuid,
1332
- protocol: 'V2',
1333
- source: 'expected',
1334
- });
1335
- return 'V2';
1335
+ if (yield this.probeProtocolV2(uuid)) {
1336
+ this.deviceProtocol.set(uuid, 'V2');
1337
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] protocol detected', {
1338
+ deviceId: uuid,
1339
+ protocol: 'V2',
1340
+ source: 'expected',
1341
+ });
1342
+ return 'V2';
1343
+ }
1344
+ throw this.createProtocolMismatchError(expectedProtocol);
1336
1345
  }
1337
1346
  const probeOrder = protocolHint === 'V2' || this.deviceProtocol.get(uuid) === 'V2' ? ['V2', 'V1'] : ['V1', 'V2'];
1338
1347
  for (let i = 0; i < probeOrder.length; i += 1) {
@@ -1515,7 +1524,37 @@ class ReactNativeBleTransport {
1515
1524
  }
1516
1525
  });
1517
1526
  }
1518
- writeProtocolV2Frame(transport, frame) {
1527
+ writeProtocolV2Packet(transport, base64, context, assertCurrentGeneration) {
1528
+ return __awaiter(this, void 0, void 0, function* () {
1529
+ let attempt = 0;
1530
+ for (;;) {
1531
+ assertCurrentGeneration();
1532
+ if (context.signal.aborted) {
1533
+ throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
1534
+ }
1535
+ try {
1536
+ yield transport.writeCharacteristic.writeWithoutResponse(base64);
1537
+ assertCurrentGeneration();
1538
+ return;
1539
+ }
1540
+ catch (error) {
1541
+ if (getFirmwareUploadWriteRetryType(error) !== 'congested' ||
1542
+ attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES) {
1543
+ throw error;
1544
+ }
1545
+ const delayMs = resolveFirmwareUploadRetryDelay(attempt);
1546
+ attempt += 1;
1547
+ Log === null || Log === void 0 ? void 0 : Log.debug('[ReactNativeBleTransport] Protocol V2 congested write retry:', {
1548
+ name: context.messageName,
1549
+ attempt,
1550
+ delayMs,
1551
+ });
1552
+ yield delay(delayMs);
1553
+ }
1554
+ }
1555
+ });
1556
+ }
1557
+ writeProtocolV2Frame(transport, frame, context, assertCurrentGeneration) {
1519
1558
  return __awaiter(this, void 0, void 0, function* () {
1520
1559
  const tuning = getProtocolV2BleTuning();
1521
1560
  const packetCapacity = resolveProtocolV2PacketCapacity({
@@ -1524,20 +1563,28 @@ class ReactNativeBleTransport {
1524
1563
  androidPacketLength: tuning.androidPacketLength,
1525
1564
  mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
1526
1565
  });
1566
+ let packetsWritten = 0;
1527
1567
  for (let offset = 0; offset < frame.length; offset += packetCapacity) {
1528
1568
  const chunk = frame.slice(offset, offset + packetCapacity);
1529
1569
  const base64 = buffer.Buffer.from(chunk).toString('base64');
1530
- yield transport.writeCharacteristic.writeWithoutResponse(base64);
1570
+ yield this.writeProtocolV2Packet(transport, base64, context, assertCurrentGeneration);
1571
+ packetsWritten += 1;
1572
+ if (offset + packetCapacity < frame.length &&
1573
+ packetsWritten % FIRMWARE_UPLOAD_WRITE_BURST_SIZE === 0) {
1574
+ yield delay(FIRMWARE_UPLOAD_WRITE_PAUSE_MS);
1575
+ }
1576
+ }
1577
+ if (packetsWritten > FIRMWARE_UPLOAD_WRITE_BURST_SIZE) {
1578
+ yield delay(FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS);
1531
1579
  }
1532
1580
  });
1533
1581
  }
1534
1582
  callProtocolV2(uuid, name, data, options) {
1535
- var _a;
1536
1583
  return __awaiter(this, void 0, void 0, function* () {
1537
1584
  if (!this._messages || !this._messagesV2) {
1538
1585
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
1539
1586
  }
1540
- const callOptions = Object.assign(Object.assign({}, options), { timeoutMs: (_a = options === null || options === void 0 ? void 0 : options.timeoutMs) !== null && _a !== void 0 ? _a : BLE_RESPONSE_TIMEOUT_MS });
1587
+ const callOptions = options;
1541
1588
  const highVolumeWrite = transport.LogBlockCommand.has(name);
1542
1589
  if (highVolumeWrite) {
1543
1590
  const tuning = getProtocolV2BleTuning();
@@ -1574,10 +1621,10 @@ class ReactNativeBleTransport {
1574
1621
  (_a = this.protocolV2Assemblers.get(uuid)) === null || _a === void 0 ? void 0 : _a.reset();
1575
1622
  this.resetProtocolV2Frames(uuid);
1576
1623
  },
1577
- writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
1624
+ writeFrame: (frame, context) => __awaiter(this, void 0, void 0, function* () {
1578
1625
  assertCurrentGeneration();
1579
1626
  const currentTransport = this.getCachedTransport(uuid);
1580
- yield this.writeProtocolV2Frame(currentTransport, frame);
1627
+ yield this.writeProtocolV2Frame(currentTransport, frame, context, assertCurrentGeneration);
1581
1628
  }),
1582
1629
  readFrame: () => __awaiter(this, void 0, void 0, function* () {
1583
1630
  assertCurrentGeneration();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.0-alpha.21",
3
+ "version": "1.2.0-alpha.22",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -19,11 +19,11 @@
19
19
  "lint:fix": "eslint . --fix"
20
20
  },
21
21
  "dependencies": {
22
- "@onekeyfe/hd-core": "1.2.0-alpha.21",
23
- "@onekeyfe/hd-shared": "1.2.0-alpha.21",
24
- "@onekeyfe/hd-transport": "1.2.0-alpha.21",
22
+ "@onekeyfe/hd-core": "1.2.0-alpha.22",
23
+ "@onekeyfe/hd-shared": "1.2.0-alpha.22",
24
+ "@onekeyfe/hd-transport": "1.2.0-alpha.22",
25
25
  "@onekeyfe/react-native-ble-utils": "^0.1.6",
26
26
  "react-native-ble-plx": "3.5.1"
27
27
  },
28
- "gitHead": "efe594367fb3b196a5126baee7e2aba3e94986cd"
28
+ "gitHead": "ce94a5ebbe141b0c15db7c68d08085ca1ddb0166"
29
29
  }
@@ -6,7 +6,10 @@ import transportPackage, {
6
6
  } from '@onekeyfe/hd-transport';
7
7
  import { HardwareErrorCode } from '@onekeyfe/hd-shared';
8
8
 
9
- import ReactNativeBleTransport from '../index';
9
+ import ReactNativeBleTransport, {
10
+ configureProtocolV2BleTuning,
11
+ resetProtocolV2BleTuning,
12
+ } from '../index';
10
13
 
11
14
  jest.mock(
12
15
  'react-native',
@@ -91,6 +94,7 @@ const schemas = {
91
94
  const createHarness = () => {
92
95
  const uuid = 'rn-pro2-id';
93
96
  const sentSeqs: number[] = [];
97
+ let responseSeq = 0;
94
98
  let shouldRespond = true;
95
99
  let notifyCallback:
96
100
  | ((
@@ -111,11 +115,12 @@ const createHarness = () => {
111
115
  const frame = Buffer.from(base64, 'base64');
112
116
  sentSeqs.push(frame[6]);
113
117
  if (shouldRespond) {
118
+ responseSeq += 1;
114
119
  const response = ProtocolV2.encodeFrame(
115
120
  schemas,
116
121
  'Success',
117
122
  { message: 'ok' },
118
- { router: PROTOCOL_V2_CHANNEL_BLE_UART }
123
+ { router: PROTOCOL_V2_CHANNEL_BLE_UART, seq: responseSeq }
119
124
  );
120
125
  notifyCallback?.(null, { value: Buffer.from(response).toString('base64') });
121
126
  }
@@ -166,6 +171,10 @@ const createHarness = () => {
166
171
  };
167
172
 
168
173
  describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
174
+ afterEach(() => {
175
+ resetProtocolV2BleTuning();
176
+ });
177
+
169
178
  test('keeps the Protocol V2 sequence across probe and the next call', async () => {
170
179
  const { transport, uuid, sentSeqs } = createHarness();
171
180
 
@@ -240,4 +249,62 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
240
249
  await transport.disconnect(uuid);
241
250
  await rejection;
242
251
  });
252
+
253
+ test('chunks large frames and retries only transient GATT congestion', async () => {
254
+ const transport = new ReactNativeBleTransport({ scanTimeout: 1 }) as any;
255
+ const congested = { status: 143, message: 'GATT_CONGESTED' };
256
+ const writeWithoutResponse = jest
257
+ .fn()
258
+ .mockRejectedValueOnce(congested)
259
+ .mockResolvedValue(undefined);
260
+ const bleTransport = {
261
+ mtuSize: 23,
262
+ writeCharacteristic: { writeWithoutResponse },
263
+ };
264
+ const context = {
265
+ messageName: 'Ping',
266
+ timeoutMs: 1000,
267
+ highVolume: false,
268
+ generation: 1,
269
+ signal: new AbortController().signal,
270
+ };
271
+ const assertCurrentGeneration = jest.fn();
272
+ configureProtocolV2BleTuning({ iosPacketLength: 20 });
273
+
274
+ await transport.writeProtocolV2Frame(
275
+ bleTransport,
276
+ new Uint8Array(30),
277
+ context,
278
+ assertCurrentGeneration
279
+ );
280
+
281
+ expect(writeWithoutResponse).toHaveBeenCalledTimes(3);
282
+ expect(writeWithoutResponse.mock.calls[0][0]).toBe(writeWithoutResponse.mock.calls[1][0]);
283
+ expect(Buffer.from(writeWithoutResponse.mock.calls[2][0], 'base64')).toHaveLength(10);
284
+ expect(assertCurrentGeneration).toHaveBeenCalled();
285
+ });
286
+
287
+ test('does not retry a disconnected Protocol V2 write inside a partial frame', async () => {
288
+ const transport = new ReactNativeBleTransport({ scanTimeout: 1 }) as any;
289
+ const writeWithoutResponse = jest
290
+ .fn()
291
+ .mockRejectedValue({ errorCode: 205, message: 'Device disconnected' });
292
+ const bleTransport = {
293
+ mtuSize: 23,
294
+ writeCharacteristic: { writeWithoutResponse },
295
+ };
296
+ const context = {
297
+ messageName: 'FileWrite',
298
+ timeoutMs: 1000,
299
+ highVolume: true,
300
+ generation: 1,
301
+ signal: new AbortController().signal,
302
+ };
303
+ configureProtocolV2BleTuning({ iosPacketLength: 20 });
304
+
305
+ await expect(
306
+ transport.writeProtocolV2Frame(bleTransport, new Uint8Array(30), context, jest.fn())
307
+ ).rejects.toMatchObject({ errorCode: 205 });
308
+ expect(writeWithoutResponse).toHaveBeenCalledTimes(1);
309
+ });
243
310
  });
package/src/constants.ts CHANGED
@@ -12,6 +12,7 @@ type BluetoothServices = Record<
12
12
  >;
13
13
 
14
14
  const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
15
+ const Pro2ServiceUUID = 'fffd';
15
16
 
16
17
  const OneKeyServices: Record<string, BluetoothServices> = {
17
18
  classic: {
@@ -20,6 +21,11 @@ const OneKeyServices: Record<string, BluetoothServices> = {
20
21
  writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
21
22
  notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
22
23
  },
24
+ [Pro2ServiceUUID]: {
25
+ serviceUuid: Pro2ServiceUUID,
26
+ writeUuid: '00000002-0000-1000-8000-00805f9b34fb',
27
+ notifyUuid: '00000003-0000-1000-8000-00805f9b34fb',
28
+ },
23
29
  },
24
30
  };
25
31
 
@@ -40,7 +46,9 @@ export const getInfosForServiceUuid = (serviceUuid: string, deviceType: 'classic
40
46
  const service =
41
47
  services[serviceUuid] ??
42
48
  Object.values(services).find(
43
- item => normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid
49
+ item =>
50
+ normalizeBleUuid(item.serviceUuid) === normalizedServiceUuid ||
51
+ getBleUuidKey(item.serviceUuid) === getBleUuidKey(serviceUuid)
44
52
  );
45
53
  if (!service) {
46
54
  return null;
package/src/index.ts CHANGED
@@ -15,6 +15,7 @@ import transport, {
15
15
  PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
16
16
  PROTOCOL_V2_CHANNEL_BLE_UART,
17
17
  type ProtocolType,
18
+ type ProtocolV2CallContext,
18
19
  ProtocolV2FrameAssembler,
19
20
  ProtocolV2LinkManager,
20
21
  type TransportCallOptions,
@@ -103,7 +104,6 @@ const getFirmwareUploadWriteRetryType = (error: unknown): FirmwareUploadWriteRet
103
104
 
104
105
  const resolveFirmwareUploadRetryDelay = (attempt: number, baseDelayMs = 200, maxDelayMs = 1200) =>
105
106
  Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
106
- const BLE_RESPONSE_TIMEOUT_MS = 30_000;
107
107
  const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
108
108
  const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10_000;
109
109
  const DEVICE_SCAN_TIMEOUT_MS = 8000;
@@ -1392,15 +1392,16 @@ export default class ReactNativeBleTransport {
1392
1392
  }
1393
1393
 
1394
1394
  if (expectedProtocol === 'V2') {
1395
- // Skip probing when the caller explicitly confirms V2, such as reconnect after a
1396
- // firmware reboot where expectedProtocol carries the previously probed result.
1397
- this.deviceProtocol.set(uuid, 'V2');
1398
- Log?.debug('[ReactNativeBleTransport] protocol detected', {
1399
- deviceId: uuid,
1400
- protocol: 'V2',
1401
- source: 'expected',
1402
- });
1403
- return 'V2';
1395
+ if (await this.probeProtocolV2(uuid)) {
1396
+ this.deviceProtocol.set(uuid, 'V2');
1397
+ Log?.debug('[ReactNativeBleTransport] protocol detected', {
1398
+ deviceId: uuid,
1399
+ protocol: 'V2',
1400
+ source: 'expected',
1401
+ });
1402
+ return 'V2';
1403
+ }
1404
+ throw this.createProtocolMismatchError(expectedProtocol);
1404
1405
  }
1405
1406
 
1406
1407
  // Protocol must be actively probed after connection. Name, PID, and descriptors only
@@ -1608,7 +1609,47 @@ export default class ReactNativeBleTransport {
1608
1609
  }
1609
1610
  }
1610
1611
 
1611
- private async writeProtocolV2Frame(transport: BleTransport, frame: Uint8Array) {
1612
+ private async writeProtocolV2Packet(
1613
+ transport: BleTransport,
1614
+ base64: string,
1615
+ context: ProtocolV2CallContext,
1616
+ assertCurrentGeneration: () => void
1617
+ ) {
1618
+ let attempt = 0;
1619
+ for (;;) {
1620
+ assertCurrentGeneration();
1621
+ if (context.signal.aborted) {
1622
+ throw new Error(`Protocol V2 BLE write aborted for ${context.messageName}`);
1623
+ }
1624
+ try {
1625
+ await transport.writeCharacteristic.writeWithoutResponse(base64);
1626
+ assertCurrentGeneration();
1627
+ return;
1628
+ } catch (error) {
1629
+ if (
1630
+ getFirmwareUploadWriteRetryType(error) !== 'congested' ||
1631
+ attempt >= FIRMWARE_UPLOAD_WRITE_MAX_RETRIES
1632
+ ) {
1633
+ throw error;
1634
+ }
1635
+ const delayMs = resolveFirmwareUploadRetryDelay(attempt);
1636
+ attempt += 1;
1637
+ Log?.debug('[ReactNativeBleTransport] Protocol V2 congested write retry:', {
1638
+ name: context.messageName,
1639
+ attempt,
1640
+ delayMs,
1641
+ });
1642
+ await delay(delayMs);
1643
+ }
1644
+ }
1645
+ }
1646
+
1647
+ private async writeProtocolV2Frame(
1648
+ transport: BleTransport,
1649
+ frame: Uint8Array,
1650
+ context: ProtocolV2CallContext,
1651
+ assertCurrentGeneration: () => void
1652
+ ) {
1612
1653
  const tuning = getProtocolV2BleTuning();
1613
1654
  const packetCapacity = resolveProtocolV2PacketCapacity({
1614
1655
  platform: Platform.OS,
@@ -1616,10 +1657,21 @@ export default class ReactNativeBleTransport {
1616
1657
  androidPacketLength: tuning.androidPacketLength,
1617
1658
  mtu: Platform.OS === 'android' ? transport.mtuSize : undefined,
1618
1659
  });
1660
+ let packetsWritten = 0;
1619
1661
  for (let offset = 0; offset < frame.length; offset += packetCapacity) {
1620
1662
  const chunk = frame.slice(offset, offset + packetCapacity);
1621
1663
  const base64 = Buffer.from(chunk).toString('base64');
1622
- await transport.writeCharacteristic.writeWithoutResponse(base64);
1664
+ await this.writeProtocolV2Packet(transport, base64, context, assertCurrentGeneration);
1665
+ packetsWritten += 1;
1666
+ if (
1667
+ offset + packetCapacity < frame.length &&
1668
+ packetsWritten % FIRMWARE_UPLOAD_WRITE_BURST_SIZE === 0
1669
+ ) {
1670
+ await delay(FIRMWARE_UPLOAD_WRITE_PAUSE_MS);
1671
+ }
1672
+ }
1673
+ if (packetsWritten > FIRMWARE_UPLOAD_WRITE_BURST_SIZE) {
1674
+ await delay(FIRMWARE_UPLOAD_WRITE_FLUSH_DELAY_MS);
1623
1675
  }
1624
1676
  }
1625
1677
 
@@ -1633,10 +1685,7 @@ export default class ReactNativeBleTransport {
1633
1685
  throw ERRORS.TypedError(HardwareErrorCode.TransportNotConfigured);
1634
1686
  }
1635
1687
 
1636
- const callOptions = {
1637
- ...options,
1638
- timeoutMs: options?.timeoutMs ?? BLE_RESPONSE_TIMEOUT_MS,
1639
- };
1688
+ const callOptions = options;
1640
1689
  const highVolumeWrite = LogBlockCommand.has(name);
1641
1690
 
1642
1691
  if (highVolumeWrite) {
@@ -1679,10 +1728,10 @@ export default class ReactNativeBleTransport {
1679
1728
  this.protocolV2Assemblers.get(uuid)?.reset();
1680
1729
  this.resetProtocolV2Frames(uuid);
1681
1730
  },
1682
- writeFrame: async (frame: Uint8Array) => {
1731
+ writeFrame: async (frame: Uint8Array, context: ProtocolV2CallContext) => {
1683
1732
  assertCurrentGeneration();
1684
1733
  const currentTransport = this.getCachedTransport(uuid);
1685
- await this.writeProtocolV2Frame(currentTransport, frame);
1734
+ await this.writeProtocolV2Frame(currentTransport, frame, context, assertCurrentGeneration);
1686
1735
  },
1687
1736
  readFrame: async () => {
1688
1737
  assertCurrentGeneration();