@onekeyfe/hd-transport-react-native 1.2.0-alpha.71 → 1.2.0-alpha.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts +3 -2
- package/dist/bleStrategy.d.ts.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -20
- package/package.json +5 -5
- package/src/BleTransport.ts +9 -6
- package/src/__tests__/BleTransport.test.ts +24 -3
- package/src/__tests__/bleStrategy.test.ts +25 -7
- package/src/__tests__/protocolV2Link.test.ts +64 -5
- package/src/bleStrategy.ts +10 -8
- package/src/constants.ts +1 -1
- package/src/index.ts +29 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAE5B,mBAAmB,EAAE,cAAc,CAAC;IAEpC,oBAAoB,EAAE,cAAc,CAAC;IAErC,kBAAkB,CAAC,EAAE,YAAY,CAAC;IAElC,sBAAsB,CAAC,EAAE,YAAY,CAAC;IAEtC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,YAAY,CAAC,EAAE,MAAM,CAAC;gBAGpB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;IAiBhC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlD"}
|
package/dist/bleStrategy.d.ts
CHANGED
|
@@ -10,9 +10,10 @@ export declare function resolveProtocolV2PacketCapacity({ platform, iosPacketLen
|
|
|
10
10
|
androidPacketLength?: number;
|
|
11
11
|
mtu?: number | null;
|
|
12
12
|
}): number;
|
|
13
|
-
export declare function
|
|
13
|
+
export declare function shouldRefreshNegotiatedMtu(mtu?: number | null): boolean;
|
|
14
|
+
export declare function shouldWriteProtocolV2WithResponse({ platform, highThroughput, requestedWithResponse, characteristic, }: {
|
|
14
15
|
platform: BlePlatform;
|
|
15
|
-
|
|
16
|
+
highThroughput: boolean;
|
|
16
17
|
requestedWithResponse?: boolean;
|
|
17
18
|
characteristic: BleWriteCapability;
|
|
18
19
|
}): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bleStrategy.d.ts","sourceRoot":"","sources":["../src/bleStrategy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,WAEvE;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,QAAQ,EACR,eAA+C,EAC/C,mBAAuD,EACvD,GAAG,GACJ,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,
|
|
1
|
+
{"version":3,"file":"bleStrategy.d.ts","sourceRoot":"","sources":["../src/bleStrategy.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,sBAAsB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,yBAAyB,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC5C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,WAEvE;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,QAAQ,EACR,eAA+C,EAC/C,mBAAuD,EACvD,GAAG,GACJ,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB,UAMA;AAED,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,WAE7D;AAED,wBAAgB,iCAAiC,CAAC,EAChD,QAAQ,EACR,cAAc,EACd,qBAAqB,EACrB,cAAc,GACf,EAAE;IACD,QAAQ,EAAE,WAAW,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,cAAc,EAAE,kBAAkB,CAAC;CACpC,WAIA"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export declare const IOS_PACKET_LENGTH = 128;
|
|
2
2
|
export declare const ANDROID_PACKET_LENGTH = 192;
|
|
3
3
|
export declare const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
4
|
-
export declare const ANDROID_PROTOCOL_V2_PACKET_LENGTH =
|
|
4
|
+
export declare const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
5
5
|
export declare const getBluetoothServiceUuids: () => string[];
|
|
6
6
|
export declare const getInfosForServiceUuid: (serviceUuid: string, deviceType: 'classic') => {
|
|
7
7
|
serviceUuid: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,15 @@ declare class BleTransport {
|
|
|
16
16
|
notifyTransactionId?: string;
|
|
17
17
|
monitorToken?: number;
|
|
18
18
|
constructor(device: Device, writeCharacteristic: Characteristic, notifyCharacteristic: Characteristic);
|
|
19
|
+
/**
|
|
20
|
+
* Bulk-transfer write (Protocol V1 FirmwareUpload / EmmcFileWrite only).
|
|
21
|
+
*
|
|
22
|
+
* Must stay writeWithoutResponse on every platform. writeWithResponse serialises
|
|
23
|
+
* each packet into its own connection-interval round trip, which on iOS turned a
|
|
24
|
+
* 1.7MB firmware upload (~13.5k packets) into a >10 minute transfer that never
|
|
25
|
+
* finished before the app-level timeout. Protocol V2 and ordinary V1 control
|
|
26
|
+
* messages pick their write type separately and are unaffected by this method.
|
|
27
|
+
*/
|
|
19
28
|
writeWithRetry(data: string): Promise<void>;
|
|
20
29
|
}
|
|
21
30
|
|
|
@@ -197,6 +206,7 @@ declare class ReactNativeBleTransport {
|
|
|
197
206
|
private writeProtocolV2Packet;
|
|
198
207
|
private writeProtocolV2Frame;
|
|
199
208
|
private callProtocolV2;
|
|
209
|
+
private ensureProtocolV2HighThroughputMtu;
|
|
200
210
|
private clearAndroidPriorityResetTimer;
|
|
201
211
|
private enableAndroidHighConnectionPriority;
|
|
202
212
|
private scheduleAndroidBalancedConnectionPriority;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAIL,UAAU,IAAI,aAAa,EAG5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -94,7 +94,7 @@ const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
|
|
|
94
94
|
const IOS_PACKET_LENGTH = 128;
|
|
95
95
|
const ANDROID_PACKET_LENGTH = 192;
|
|
96
96
|
const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
97
|
-
const ANDROID_PROTOCOL_V2_PACKET_LENGTH =
|
|
97
|
+
const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
98
98
|
const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
|
|
99
99
|
const OneKeyServices = {
|
|
100
100
|
classic: {
|
|
@@ -136,19 +136,20 @@ function hasWritableCapability(characteristic) {
|
|
|
136
136
|
return !!(characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse);
|
|
137
137
|
}
|
|
138
138
|
function resolveProtocolV2PacketCapacity({ platform, iosPacketLength = IOS_PROTOCOL_V2_PACKET_LENGTH, androidPacketLength = ANDROID_PROTOCOL_V2_PACKET_LENGTH, mtu, }) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
}
|
|
142
|
-
const payloadLength = Math.floor(mtu) - 3;
|
|
139
|
+
const negotiatedMtu = typeof mtu === 'number' && Number.isFinite(mtu) && mtu > 3 ? Math.floor(mtu) : 23;
|
|
140
|
+
const payloadLength = negotiatedMtu - 3;
|
|
143
141
|
const configuredPacketLength = platform === 'ios' ? iosPacketLength : androidPacketLength;
|
|
144
142
|
return Math.min(configuredPacketLength, payloadLength);
|
|
145
143
|
}
|
|
146
|
-
function
|
|
144
|
+
function shouldRefreshNegotiatedMtu(mtu) {
|
|
145
|
+
return typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= 23;
|
|
146
|
+
}
|
|
147
|
+
function shouldWriteProtocolV2WithResponse({ platform, highThroughput, requestedWithResponse, characteristic, }) {
|
|
147
148
|
if (!characteristic.isWritableWithResponse)
|
|
148
149
|
return false;
|
|
149
150
|
if (!characteristic.isWritableWithoutResponse)
|
|
150
151
|
return true;
|
|
151
|
-
return requestedWithResponse === true || (platform === 'ios' && !
|
|
152
|
+
return requestedWithResponse === true || (platform === 'ios' && !highThroughput);
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
const timer = process.env.NODE_ENV === 'development'
|
|
@@ -215,10 +216,6 @@ class BleTransport {
|
|
|
215
216
|
}
|
|
216
217
|
writeWithRetry(data) {
|
|
217
218
|
return __awaiter(this, void 0, void 0, function* () {
|
|
218
|
-
if (reactNative.Platform.OS === 'ios' && this.writeCharacteristic.isWritableWithResponse) {
|
|
219
|
-
yield this.writeCharacteristic.writeWithResponse(data);
|
|
220
|
-
return;
|
|
221
|
-
}
|
|
222
219
|
yield this.writeCharacteristic.writeWithoutResponse(data);
|
|
223
220
|
});
|
|
224
221
|
}
|
|
@@ -321,7 +318,6 @@ function getDeviceDisplayName(device) {
|
|
|
321
318
|
}
|
|
322
319
|
const IOS_REQUEST_MTU = 247;
|
|
323
320
|
const ANDROID_REQUEST_MTU = 517;
|
|
324
|
-
const BLE_MTU_REFRESH_THRESHOLD = 247;
|
|
325
321
|
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
326
322
|
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
327
323
|
const getRequestedBleMtu = () => reactNative.Platform.OS === 'android' ? ANDROID_REQUEST_MTU : IOS_REQUEST_MTU;
|
|
@@ -775,13 +771,13 @@ class ReactNativeBleTransport {
|
|
|
775
771
|
const initialMtu = transport$1.mtuSize;
|
|
776
772
|
let refreshAttempts = 0;
|
|
777
773
|
if ((reactNative.Platform.OS === 'ios' || reactNative.Platform.OS === 'android') &&
|
|
778
|
-
(
|
|
774
|
+
shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
779
775
|
refreshAttempts += 1;
|
|
780
776
|
let refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 1);
|
|
781
777
|
transport$1.device = refreshedDevice;
|
|
782
778
|
transport$1.mtuSize =
|
|
783
779
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport$1.mtuSize;
|
|
784
|
-
if (
|
|
780
|
+
if (shouldRefreshNegotiatedMtu(transport$1.mtuSize)) {
|
|
785
781
|
yield delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
786
782
|
refreshAttempts += 1;
|
|
787
783
|
refreshedDevice = yield requestNegotiatedMtu(transport$1.device, 'servicesAndNotifyReady', 2);
|
|
@@ -1842,7 +1838,7 @@ class ReactNativeBleTransport {
|
|
|
1842
1838
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1843
1839
|
const shouldUseWriteWithResponse = shouldWriteProtocolV2WithResponse({
|
|
1844
1840
|
platform: reactNative.Platform.OS,
|
|
1845
|
-
|
|
1841
|
+
highThroughput: context.highThroughput,
|
|
1846
1842
|
requestedWithResponse: context.writeWithResponse,
|
|
1847
1843
|
characteristic: transport.writeCharacteristic,
|
|
1848
1844
|
});
|
|
@@ -1911,13 +1907,14 @@ class ReactNativeBleTransport {
|
|
|
1911
1907
|
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.TransportNotConfigured);
|
|
1912
1908
|
}
|
|
1913
1909
|
const callOptions = options;
|
|
1914
|
-
const
|
|
1915
|
-
if (
|
|
1910
|
+
const highThroughputWrite = transport.isProtocolV2HighThroughputCall(name);
|
|
1911
|
+
if (highThroughputWrite) {
|
|
1912
|
+
yield this.ensureProtocolV2HighThroughputMtu(uuid);
|
|
1916
1913
|
const tuning = getProtocolV2BleTuning();
|
|
1917
1914
|
const currentTransport = this.getCachedTransport(uuid);
|
|
1918
1915
|
const writeWithResponse = shouldWriteProtocolV2WithResponse({
|
|
1919
1916
|
platform: reactNative.Platform.OS,
|
|
1920
|
-
|
|
1917
|
+
highThroughput: true,
|
|
1921
1918
|
requestedWithResponse: options === null || options === void 0 ? void 0 : options.writeWithResponse,
|
|
1922
1919
|
characteristic: currentTransport.writeCharacteristic,
|
|
1923
1920
|
});
|
|
@@ -1941,7 +1938,7 @@ class ReactNativeBleTransport {
|
|
|
1941
1938
|
});
|
|
1942
1939
|
}
|
|
1943
1940
|
}
|
|
1944
|
-
if (
|
|
1941
|
+
if (highThroughputWrite) {
|
|
1945
1942
|
yield this.enableAndroidHighConnectionPriority(uuid);
|
|
1946
1943
|
}
|
|
1947
1944
|
try {
|
|
@@ -1952,12 +1949,26 @@ class ReactNativeBleTransport {
|
|
|
1952
1949
|
throw e;
|
|
1953
1950
|
}
|
|
1954
1951
|
finally {
|
|
1955
|
-
if (
|
|
1952
|
+
if (highThroughputWrite) {
|
|
1956
1953
|
this.scheduleAndroidBalancedConnectionPriority(uuid);
|
|
1957
1954
|
}
|
|
1958
1955
|
}
|
|
1959
1956
|
});
|
|
1960
1957
|
}
|
|
1958
|
+
ensureProtocolV2HighThroughputMtu(uuid) {
|
|
1959
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1960
|
+
const transport = this.getCachedTransport(uuid);
|
|
1961
|
+
if (!shouldRefreshNegotiatedMtu(transport.mtuSize))
|
|
1962
|
+
return;
|
|
1963
|
+
const refreshedDevice = yield requestNegotiatedMtu(transport.device, 'highThroughput', 1);
|
|
1964
|
+
transport.device = refreshedDevice;
|
|
1965
|
+
transport.mtuSize =
|
|
1966
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
1967
|
+
if (shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
1968
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleConnectedError, `Protocol V2 high-throughput BLE MTU unavailable: ${String(transport.mtuSize)}`);
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
}
|
|
1961
1972
|
clearAndroidPriorityResetTimer(uuid) {
|
|
1962
1973
|
const timerId = this.androidPriorityResetTimers.get(uuid);
|
|
1963
1974
|
if (timerId !== undefined) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.73",
|
|
4
4
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
"lint:fix": "eslint . --fix"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@onekeyfe/hd-core": "1.2.0-alpha.
|
|
24
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
25
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
23
|
+
"@onekeyfe/hd-core": "1.2.0-alpha.73",
|
|
24
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.73",
|
|
25
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.73",
|
|
26
26
|
"@onekeyfe/react-native-ble-utils": "^0.1.6",
|
|
27
27
|
"react-native-ble-plx": "3.5.1"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "5fd2c617e179181cdb15243aec8bbbe28c77cd27"
|
|
30
30
|
}
|
package/src/BleTransport.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { Platform } from 'react-native';
|
|
2
|
-
|
|
3
1
|
import type { Characteristic, Device, Subscription } from 'react-native-ble-plx';
|
|
4
2
|
|
|
5
3
|
export default class BleTransport {
|
|
@@ -34,11 +32,16 @@ export default class BleTransport {
|
|
|
34
32
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
35
33
|
}
|
|
36
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Bulk-transfer write (Protocol V1 FirmwareUpload / EmmcFileWrite only).
|
|
37
|
+
*
|
|
38
|
+
* Must stay writeWithoutResponse on every platform. writeWithResponse serialises
|
|
39
|
+
* each packet into its own connection-interval round trip, which on iOS turned a
|
|
40
|
+
* 1.7MB firmware upload (~13.5k packets) into a >10 minute transfer that never
|
|
41
|
+
* finished before the app-level timeout. Protocol V2 and ordinary V1 control
|
|
42
|
+
* messages pick their write type separately and are unaffected by this method.
|
|
43
|
+
*/
|
|
37
44
|
async writeWithRetry(data: string): Promise<void> {
|
|
38
|
-
if (Platform.OS === 'ios' && this.writeCharacteristic.isWritableWithResponse) {
|
|
39
|
-
await this.writeCharacteristic.writeWithResponse(data);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
45
|
await this.writeCharacteristic.writeWithoutResponse(data);
|
|
43
46
|
}
|
|
44
47
|
}
|
|
@@ -38,8 +38,8 @@ describe('BleTransport side-effecting writes', () => {
|
|
|
38
38
|
});
|
|
39
39
|
const writeCharacteristic = {
|
|
40
40
|
isWritableWithResponse: true,
|
|
41
|
-
writeWithResponse: jest.fn(() => Promise.
|
|
42
|
-
writeWithoutResponse: jest.fn(() => Promise.
|
|
41
|
+
writeWithResponse: jest.fn(() => Promise.resolve()),
|
|
42
|
+
writeWithoutResponse: jest.fn(() => Promise.reject(error)),
|
|
43
43
|
};
|
|
44
44
|
const device = {
|
|
45
45
|
id: 'classic-id',
|
|
@@ -50,10 +50,31 @@ describe('BleTransport side-effecting writes', () => {
|
|
|
50
50
|
|
|
51
51
|
await expect(transport.writeWithRetry('payload')).rejects.toBe(error);
|
|
52
52
|
|
|
53
|
-
expect(writeCharacteristic.
|
|
53
|
+
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(1);
|
|
54
54
|
expect(device.connect).not.toHaveBeenCalled();
|
|
55
55
|
});
|
|
56
56
|
|
|
57
|
+
test('keeps iOS bulk transfer on writeWithoutResponse even when the characteristic supports responses', async () => {
|
|
58
|
+
// writeWithResponse serialises every packet into its own connection-interval
|
|
59
|
+
// round trip. On a ~1.7MB firmware (~13.5k packets) that stalled the upload past
|
|
60
|
+
// the 600s app-level timeout, so bulk transfer must never opt into it.
|
|
61
|
+
const writeCharacteristic = {
|
|
62
|
+
isWritableWithResponse: true,
|
|
63
|
+
writeWithResponse: jest.fn(() => Promise.resolve()),
|
|
64
|
+
writeWithoutResponse: jest.fn(() => Promise.resolve()),
|
|
65
|
+
};
|
|
66
|
+
const transport = new BleTransport(
|
|
67
|
+
{ id: 'classic-id' } as any,
|
|
68
|
+
writeCharacteristic as any,
|
|
69
|
+
{} as any
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
await transport.writeWithRetry('payload');
|
|
73
|
+
|
|
74
|
+
expect(writeCharacteristic.writeWithResponse).not.toHaveBeenCalled();
|
|
75
|
+
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledWith('payload');
|
|
76
|
+
});
|
|
77
|
+
|
|
57
78
|
test('keeps Android Protocol V1 writes on writeWithoutResponse', async () => {
|
|
58
79
|
Platform.OS = 'android';
|
|
59
80
|
const writeCharacteristic = {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hasWritableCapability,
|
|
3
3
|
resolveProtocolV2PacketCapacity,
|
|
4
|
+
shouldRefreshNegotiatedMtu,
|
|
4
5
|
shouldWriteProtocolV2WithResponse,
|
|
5
6
|
} from '../bleStrategy';
|
|
6
7
|
|
|
@@ -14,13 +15,20 @@ describe('React Native BLE strategy', () => {
|
|
|
14
15
|
expect(hasWritableCapability(characteristic)).toBe(true);
|
|
15
16
|
});
|
|
16
17
|
|
|
17
|
-
test('
|
|
18
|
-
expect(
|
|
18
|
+
test('uses the conservative ATT payload when MTU is unavailable', () => {
|
|
19
|
+
expect(
|
|
19
20
|
resolveProtocolV2PacketCapacity({
|
|
20
21
|
platform: 'android',
|
|
21
22
|
mtu: null,
|
|
22
23
|
})
|
|
23
|
-
).
|
|
24
|
+
).toBe(20);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('only refreshes an unavailable or default MTU snapshot', () => {
|
|
28
|
+
expect(shouldRefreshNegotiatedMtu(undefined)).toBe(true);
|
|
29
|
+
expect(shouldRefreshNegotiatedMtu(23)).toBe(true);
|
|
30
|
+
expect(shouldRefreshNegotiatedMtu(185)).toBe(false);
|
|
31
|
+
expect(shouldRefreshNegotiatedMtu(247)).toBe(false);
|
|
24
32
|
});
|
|
25
33
|
|
|
26
34
|
test('caps Android packet length by negotiated MTU payload', () => {
|
|
@@ -33,10 +41,20 @@ describe('React Native BLE strategy', () => {
|
|
|
33
41
|
).toBe(97);
|
|
34
42
|
});
|
|
35
43
|
|
|
36
|
-
test('
|
|
44
|
+
test('keeps the default Android packet length within the validated ceiling', () => {
|
|
45
|
+
expect(
|
|
46
|
+
resolveProtocolV2PacketCapacity({
|
|
47
|
+
platform: 'android',
|
|
48
|
+
mtu: 517,
|
|
49
|
+
})
|
|
50
|
+
).toBe(244);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('allows an explicit Android packet length override for validated experiments', () => {
|
|
37
54
|
expect(
|
|
38
55
|
resolveProtocolV2PacketCapacity({
|
|
39
56
|
platform: 'android',
|
|
57
|
+
androidPacketLength: 514,
|
|
40
58
|
mtu: 517,
|
|
41
59
|
})
|
|
42
60
|
).toBe(514);
|
|
@@ -81,7 +99,7 @@ describe('React Native BLE strategy', () => {
|
|
|
81
99
|
expect(
|
|
82
100
|
shouldWriteProtocolV2WithResponse({
|
|
83
101
|
platform: 'ios',
|
|
84
|
-
|
|
102
|
+
highThroughput: true,
|
|
85
103
|
requestedWithResponse: false,
|
|
86
104
|
characteristic,
|
|
87
105
|
})
|
|
@@ -89,7 +107,7 @@ describe('React Native BLE strategy', () => {
|
|
|
89
107
|
expect(
|
|
90
108
|
shouldWriteProtocolV2WithResponse({
|
|
91
109
|
platform: 'ios',
|
|
92
|
-
|
|
110
|
+
highThroughput: true,
|
|
93
111
|
requestedWithResponse: true,
|
|
94
112
|
characteristic,
|
|
95
113
|
})
|
|
@@ -100,7 +118,7 @@ describe('React Native BLE strategy', () => {
|
|
|
100
118
|
expect(
|
|
101
119
|
shouldWriteProtocolV2WithResponse({
|
|
102
120
|
platform: 'ios',
|
|
103
|
-
|
|
121
|
+
highThroughput: true,
|
|
104
122
|
requestedWithResponse: false,
|
|
105
123
|
characteristic: {
|
|
106
124
|
isWritableWithResponse: true,
|
|
@@ -491,6 +491,63 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
491
491
|
await transport.release(uuid, true);
|
|
492
492
|
});
|
|
493
493
|
|
|
494
|
+
test('accepts a stable low MTU without the delayed refresh loop', async () => {
|
|
495
|
+
const { transport, uuid, device } = createHarness();
|
|
496
|
+
device.mtu = 185;
|
|
497
|
+
|
|
498
|
+
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
499
|
+
uuid,
|
|
500
|
+
protocolType: 'V2',
|
|
501
|
+
});
|
|
502
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(1);
|
|
503
|
+
expect((transport as any).getCachedTransport(uuid).mtuSize).toBe(185);
|
|
504
|
+
await transport.release(uuid, true);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
test('continues Protocol V2 probing with a conservative packet size when MTU is unavailable', async () => {
|
|
508
|
+
const { transport, uuid, device, writeCharacteristic } = createHarness();
|
|
509
|
+
device.mtu = undefined;
|
|
510
|
+
|
|
511
|
+
await expect(transport.acquire({ uuid })).resolves.toEqual({
|
|
512
|
+
uuid,
|
|
513
|
+
protocolType: 'V2',
|
|
514
|
+
});
|
|
515
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(3);
|
|
516
|
+
expect((transport as any).getCachedTransport(uuid).mtuSize).toBeUndefined();
|
|
517
|
+
expect(writeCharacteristic.writeWithResponse).toHaveBeenCalled();
|
|
518
|
+
await transport.release(uuid, true);
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
test('refreshes an unavailable MTU before a Protocol V2 high-volume write', async () => {
|
|
522
|
+
const { transport, uuid, device, writeCharacteristic } = createHarness();
|
|
523
|
+
device.mtu = undefined;
|
|
524
|
+
|
|
525
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
526
|
+
device.requestMTU.mockImplementationOnce(() => {
|
|
527
|
+
device.mtu = 247;
|
|
528
|
+
return Promise.resolve(device);
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
await expect(transport.call(uuid, 'FileWrite', {})).resolves.toBeDefined();
|
|
532
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(4);
|
|
533
|
+
expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(1);
|
|
534
|
+
await transport.release(uuid, true);
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
test('rejects a Protocol V2 high-volume write when MTU remains unavailable', async () => {
|
|
538
|
+
const { transport, uuid, device, writeCharacteristic } = createHarness();
|
|
539
|
+
device.mtu = undefined;
|
|
540
|
+
|
|
541
|
+
await transport.acquire({ uuid, expectedProtocol: 'V2' });
|
|
542
|
+
|
|
543
|
+
await expect(transport.call(uuid, 'FileWrite', {})).rejects.toMatchObject({
|
|
544
|
+
errorCode: HardwareErrorCode.BleConnectedError,
|
|
545
|
+
});
|
|
546
|
+
expect(device.requestMTU).toHaveBeenCalledTimes(4);
|
|
547
|
+
expect(writeCharacteristic.writeWithoutResponse).not.toHaveBeenCalled();
|
|
548
|
+
await transport.release(uuid, true);
|
|
549
|
+
});
|
|
550
|
+
|
|
494
551
|
test('reconnects before falling back to Protocol V1 after a fatal V2 probe failure', async () => {
|
|
495
552
|
setPlatformOS('android');
|
|
496
553
|
const { transport, uuid, device, notifySubscriptionRemovers, disconnectSubscriptionRemovers } =
|
|
@@ -692,7 +749,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
692
749
|
const context = {
|
|
693
750
|
messageName: 'ProtocolInfoRequest',
|
|
694
751
|
timeoutMs: 1000,
|
|
695
|
-
|
|
752
|
+
highThroughput: false,
|
|
696
753
|
generation: 1,
|
|
697
754
|
signal: new AbortController().signal,
|
|
698
755
|
};
|
|
@@ -726,7 +783,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
726
783
|
const context = {
|
|
727
784
|
messageName: 'ProtocolInfoRequest',
|
|
728
785
|
timeoutMs: 1000,
|
|
729
|
-
|
|
786
|
+
highThroughput: false,
|
|
730
787
|
generation: 1,
|
|
731
788
|
signal: new AbortController().signal,
|
|
732
789
|
};
|
|
@@ -743,6 +800,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
743
800
|
);
|
|
744
801
|
|
|
745
802
|
await call;
|
|
803
|
+
// The only scheduled timer is the per-packet BLE write watchdog: no pacing delay.
|
|
746
804
|
expect(setTimeoutSpy.mock.calls.map(([, timeout]) => timeout)).toEqual([
|
|
747
805
|
BLE_WRITE_PACKET_TIMEOUT_MS,
|
|
748
806
|
]);
|
|
@@ -801,7 +859,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
801
859
|
const context = {
|
|
802
860
|
messageName: 'Ping',
|
|
803
861
|
timeoutMs: 1000,
|
|
804
|
-
|
|
862
|
+
highThroughput: false,
|
|
805
863
|
generation: 1,
|
|
806
864
|
signal: new AbortController().signal,
|
|
807
865
|
};
|
|
@@ -834,7 +892,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
834
892
|
const context = {
|
|
835
893
|
messageName: 'FileWrite',
|
|
836
894
|
timeoutMs: 1000,
|
|
837
|
-
|
|
895
|
+
highThroughput: true,
|
|
838
896
|
generation: 1,
|
|
839
897
|
signal: new AbortController().signal,
|
|
840
898
|
};
|
|
@@ -862,7 +920,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
862
920
|
const context = {
|
|
863
921
|
messageName: 'FileWrite',
|
|
864
922
|
timeoutMs: 1000,
|
|
865
|
-
|
|
923
|
+
highThroughput: true,
|
|
866
924
|
generation: 1,
|
|
867
925
|
signal: new AbortController().signal,
|
|
868
926
|
};
|
|
@@ -878,6 +936,7 @@ describe('ReactNativeBleTransport Protocol V2 link lifecycle', () => {
|
|
|
878
936
|
);
|
|
879
937
|
|
|
880
938
|
expect(writeWithoutResponse).toHaveBeenCalledTimes(3);
|
|
939
|
+
// One BLE write watchdog per packet and nothing else: no burst or flush pauses.
|
|
881
940
|
expect(setTimeoutSpy.mock.calls.map(([, timeout]) => timeout)).toEqual([
|
|
882
941
|
BLE_WRITE_PACKET_TIMEOUT_MS,
|
|
883
942
|
BLE_WRITE_PACKET_TIMEOUT_MS,
|
package/src/bleStrategy.ts
CHANGED
|
@@ -22,27 +22,29 @@ export function resolveProtocolV2PacketCapacity({
|
|
|
22
22
|
androidPacketLength?: number;
|
|
23
23
|
mtu?: number | null;
|
|
24
24
|
}) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const payloadLength = Math.floor(mtu) - 3;
|
|
25
|
+
const negotiatedMtu =
|
|
26
|
+
typeof mtu === 'number' && Number.isFinite(mtu) && mtu > 3 ? Math.floor(mtu) : 23;
|
|
27
|
+
const payloadLength = negotiatedMtu - 3;
|
|
30
28
|
const configuredPacketLength = platform === 'ios' ? iosPacketLength : androidPacketLength;
|
|
31
29
|
return Math.min(configuredPacketLength, payloadLength);
|
|
32
30
|
}
|
|
33
31
|
|
|
32
|
+
export function shouldRefreshNegotiatedMtu(mtu?: number | null) {
|
|
33
|
+
return typeof mtu !== 'number' || !Number.isFinite(mtu) || mtu <= 23;
|
|
34
|
+
}
|
|
35
|
+
|
|
34
36
|
export function shouldWriteProtocolV2WithResponse({
|
|
35
37
|
platform,
|
|
36
|
-
|
|
38
|
+
highThroughput,
|
|
37
39
|
requestedWithResponse,
|
|
38
40
|
characteristic,
|
|
39
41
|
}: {
|
|
40
42
|
platform: BlePlatform;
|
|
41
|
-
|
|
43
|
+
highThroughput: boolean;
|
|
42
44
|
requestedWithResponse?: boolean;
|
|
43
45
|
characteristic: BleWriteCapability;
|
|
44
46
|
}) {
|
|
45
47
|
if (!characteristic.isWritableWithResponse) return false;
|
|
46
48
|
if (!characteristic.isWritableWithoutResponse) return true;
|
|
47
|
-
return requestedWithResponse === true || (platform === 'ios' && !
|
|
49
|
+
return requestedWithResponse === true || (platform === 'ios' && !highThroughput);
|
|
48
50
|
}
|
package/src/constants.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { createKnownBleUuidAliases, matchesKnownBleUuid } from '@onekeyfe/hd-sha
|
|
|
3
3
|
export const IOS_PACKET_LENGTH = 128;
|
|
4
4
|
export const ANDROID_PACKET_LENGTH = 192;
|
|
5
5
|
export const IOS_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
6
|
-
export const ANDROID_PROTOCOL_V2_PACKET_LENGTH =
|
|
6
|
+
export const ANDROID_PROTOCOL_V2_PACKET_LENGTH = 244;
|
|
7
7
|
|
|
8
8
|
type BluetoothServices = Record<
|
|
9
9
|
string,
|
package/src/index.ts
CHANGED
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
} from 'react-native-ble-plx';
|
|
11
11
|
import ByteBuffer from 'bytebuffer';
|
|
12
12
|
import transport, {
|
|
13
|
-
LogBlockCommand,
|
|
14
13
|
type OneKeyDeviceInfoBase,
|
|
15
14
|
PROTOCOL_V1_MESSAGE_HEADER_SIZE,
|
|
16
15
|
PROTOCOL_V2_BLE_FRAME_MAX_BYTES,
|
|
@@ -21,6 +20,7 @@ import transport, {
|
|
|
21
20
|
ProtocolV2LinkManager,
|
|
22
21
|
TRANSPORT_EVENT,
|
|
23
22
|
type TransportCallOptions,
|
|
23
|
+
isProtocolV2HighThroughputCall,
|
|
24
24
|
probeProtocolV2 as probeProtocolV2Helper,
|
|
25
25
|
writeProtocolV2BleFrame,
|
|
26
26
|
} from '@onekeyfe/hd-transport';
|
|
@@ -36,6 +36,7 @@ import { getConnectedDeviceIds, onDeviceBondState, pairDevice } from './BleManag
|
|
|
36
36
|
import {
|
|
37
37
|
hasWritableCapability,
|
|
38
38
|
resolveProtocolV2PacketCapacity,
|
|
39
|
+
shouldRefreshNegotiatedMtu,
|
|
39
40
|
shouldWriteProtocolV2WithResponse,
|
|
40
41
|
} from './bleStrategy';
|
|
41
42
|
import { subscribeBleOn } from './subscribeBleOn';
|
|
@@ -213,7 +214,6 @@ function getDeviceDisplayName(device?: Device | null) {
|
|
|
213
214
|
|
|
214
215
|
const IOS_REQUEST_MTU = 247;
|
|
215
216
|
const ANDROID_REQUEST_MTU = 517;
|
|
216
|
-
const BLE_MTU_REFRESH_THRESHOLD = 247;
|
|
217
217
|
const BLE_MTU_REFRESH_RETRY_DELAY_MS = 200;
|
|
218
218
|
const ANDROID_HIGH_PRIORITY_IDLE_MS = 1000;
|
|
219
219
|
|
|
@@ -279,7 +279,7 @@ const tryToGetConfiguration = (device: Device) => {
|
|
|
279
279
|
|
|
280
280
|
const requestNegotiatedMtu = async (
|
|
281
281
|
device: Device,
|
|
282
|
-
stage: 'connected' | 'servicesAndNotifyReady',
|
|
282
|
+
stage: 'connected' | 'servicesAndNotifyReady' | 'highThroughput',
|
|
283
283
|
attempt: number
|
|
284
284
|
) => {
|
|
285
285
|
if (Platform.OS !== 'ios' && Platform.OS !== 'android') return device;
|
|
@@ -835,7 +835,7 @@ export default class ReactNativeBleTransport {
|
|
|
835
835
|
let refreshAttempts = 0;
|
|
836
836
|
if (
|
|
837
837
|
(Platform.OS === 'ios' || Platform.OS === 'android') &&
|
|
838
|
-
(
|
|
838
|
+
shouldRefreshNegotiatedMtu(transport.mtuSize)
|
|
839
839
|
) {
|
|
840
840
|
refreshAttempts += 1;
|
|
841
841
|
let refreshedDevice = await requestNegotiatedMtu(
|
|
@@ -847,7 +847,7 @@ export default class ReactNativeBleTransport {
|
|
|
847
847
|
transport.mtuSize =
|
|
848
848
|
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
849
849
|
|
|
850
|
-
if (
|
|
850
|
+
if (shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
851
851
|
await delay(BLE_MTU_REFRESH_RETRY_DELAY_MS);
|
|
852
852
|
refreshAttempts += 1;
|
|
853
853
|
refreshedDevice = await requestNegotiatedMtu(transport.device, 'servicesAndNotifyReady', 2);
|
|
@@ -2173,7 +2173,7 @@ export default class ReactNativeBleTransport {
|
|
|
2173
2173
|
) {
|
|
2174
2174
|
const shouldUseWriteWithResponse = shouldWriteProtocolV2WithResponse({
|
|
2175
2175
|
platform: Platform.OS,
|
|
2176
|
-
|
|
2176
|
+
highThroughput: context.highThroughput,
|
|
2177
2177
|
requestedWithResponse: context.writeWithResponse,
|
|
2178
2178
|
characteristic: transport.writeCharacteristic,
|
|
2179
2179
|
});
|
|
@@ -2266,14 +2266,15 @@ export default class ReactNativeBleTransport {
|
|
|
2266
2266
|
}
|
|
2267
2267
|
|
|
2268
2268
|
const callOptions = options;
|
|
2269
|
-
const
|
|
2269
|
+
const highThroughputWrite = isProtocolV2HighThroughputCall(name);
|
|
2270
2270
|
|
|
2271
|
-
if (
|
|
2271
|
+
if (highThroughputWrite) {
|
|
2272
|
+
await this.ensureProtocolV2HighThroughputMtu(uuid);
|
|
2272
2273
|
const tuning = getProtocolV2BleTuning();
|
|
2273
2274
|
const currentTransport = this.getCachedTransport(uuid);
|
|
2274
2275
|
const writeWithResponse = shouldWriteProtocolV2WithResponse({
|
|
2275
2276
|
platform: Platform.OS,
|
|
2276
|
-
|
|
2277
|
+
highThroughput: true,
|
|
2277
2278
|
requestedWithResponse: options?.writeWithResponse,
|
|
2278
2279
|
characteristic: currentTransport.writeCharacteristic,
|
|
2279
2280
|
});
|
|
@@ -2301,7 +2302,7 @@ export default class ReactNativeBleTransport {
|
|
|
2301
2302
|
}
|
|
2302
2303
|
}
|
|
2303
2304
|
|
|
2304
|
-
if (
|
|
2305
|
+
if (highThroughputWrite) {
|
|
2305
2306
|
await this.enableAndroidHighConnectionPriority(uuid);
|
|
2306
2307
|
}
|
|
2307
2308
|
|
|
@@ -2317,12 +2318,29 @@ export default class ReactNativeBleTransport {
|
|
|
2317
2318
|
Log?.error('[ReactNativeBleTransport] Protocol V2 call error:', e);
|
|
2318
2319
|
throw e;
|
|
2319
2320
|
} finally {
|
|
2320
|
-
if (
|
|
2321
|
+
if (highThroughputWrite) {
|
|
2321
2322
|
this.scheduleAndroidBalancedConnectionPriority(uuid);
|
|
2322
2323
|
}
|
|
2323
2324
|
}
|
|
2324
2325
|
}
|
|
2325
2326
|
|
|
2327
|
+
private async ensureProtocolV2HighThroughputMtu(uuid: string) {
|
|
2328
|
+
const transport = this.getCachedTransport(uuid);
|
|
2329
|
+
if (!shouldRefreshNegotiatedMtu(transport.mtuSize)) return;
|
|
2330
|
+
|
|
2331
|
+
const refreshedDevice = await requestNegotiatedMtu(transport.device, 'highThroughput', 1);
|
|
2332
|
+
transport.device = refreshedDevice;
|
|
2333
|
+
transport.mtuSize =
|
|
2334
|
+
typeof refreshedDevice.mtu === 'number' ? refreshedDevice.mtu : transport.mtuSize;
|
|
2335
|
+
|
|
2336
|
+
if (shouldRefreshNegotiatedMtu(transport.mtuSize)) {
|
|
2337
|
+
throw ERRORS.TypedError(
|
|
2338
|
+
HardwareErrorCode.BleConnectedError,
|
|
2339
|
+
`Protocol V2 high-throughput BLE MTU unavailable: ${String(transport.mtuSize)}`
|
|
2340
|
+
);
|
|
2341
|
+
}
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2326
2344
|
private clearAndroidPriorityResetTimer(uuid: string) {
|
|
2327
2345
|
const timerId = this.androidPriorityResetTimers.get(uuid);
|
|
2328
2346
|
if (timerId !== undefined) {
|