@onekeyfe/hd-transport-react-native 1.1.27-alpha.37 → 1.1.27-alpha.38
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/BleManager.d.ts.map +1 -1
- package/dist/BleTransport.d.ts.map +1 -1
- package/dist/bleStrategy.d.ts +15 -0
- package/dist/bleStrategy.d.ts.map +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +117 -68
- package/package.json +5 -5
- package/src/BleManager.ts +11 -12
- package/src/BleTransport.ts +1 -2
- package/src/__tests__/bleStrategy.test.ts +47 -0
- package/src/bleStrategy.ts +62 -0
- package/src/constants.ts +1 -0
- package/src/index.ts +40 -16
package/dist/BleManager.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BleManager.d.ts","sourceRoot":"","sources":["../src/BleManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAWnE,eAAO,MAAM,qBAAqB,iBAAkB,MAAM,EAAE,0BACZ,CAAC;AAEjD,eAAO,MAAM,gBAAgB,6BAAwC,CAAC;AAEtE,eAAO,MAAM,UAAU,eAAgB,MAAM;;;EAAoC,CAAC;AAElF,eAAO,MAAM,iBAAiB,kBAAmB,MAAM,KAAG,QAAQ,UAAU,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"BleManager.d.ts","sourceRoot":"","sources":["../src/BleManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAWnE,eAAO,MAAM,qBAAqB,iBAAkB,MAAM,EAAE,0BACZ,CAAC;AAEjD,eAAO,MAAM,gBAAgB,6BAAwC,CAAC;AAEtE,eAAO,MAAM,UAAU,eAAgB,MAAM;;;EAAoC,CAAC;AAElF,eAAO,MAAM,iBAAiB,kBAAmB,MAAM,KAAG,QAAQ,UAAU,GAAG,SAAS,CAkCpF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,SAAM;IAEb,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;IAEtB,MAAM,CAAC,WAAW,SAAK;IAEvB,MAAM,CAAC,WAAW,SAAQ;gBAGxB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;
|
|
1
|
+
{"version":3,"file":"BleTransport.d.ts","sourceRoot":"","sources":["../src/BleTransport.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAMjF,MAAM,CAAC,OAAO,OAAO,YAAY;IAC/B,EAAE,EAAE,MAAM,CAAC;IAEX,IAAI,SAA6B;IAEjC,MAAM,EAAE,MAAM,CAAC;IAEf,OAAO,SAAM;IAEb,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;IAEtB,MAAM,CAAC,WAAW,SAAK;IAEvB,MAAM,CAAC,WAAW,SAAQ;gBAGxB,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,cAAc,EACnC,oBAAoB,EAAE,cAAc;IAchC,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,SAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;CA2BzF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type BlePlatform = 'ios' | 'android' | string;
|
|
2
|
+
export type BleWriteCapability = {
|
|
3
|
+
isWritableWithResponse?: boolean | null;
|
|
4
|
+
isWritableWithoutResponse?: boolean | null;
|
|
5
|
+
};
|
|
6
|
+
export type BleWriteMode = 'withResponse' | 'withoutResponse';
|
|
7
|
+
export declare function hasWritableCapability(characteristic: BleWriteCapability): boolean;
|
|
8
|
+
export declare function resolveBleWriteMode(characteristic: BleWriteCapability, preferredMode?: BleWriteMode): BleWriteMode;
|
|
9
|
+
export declare function resolveProtocolV2PacketCapacity({ platform, iosPacketLength, androidPacketLength, mtu, }: {
|
|
10
|
+
platform: BlePlatform;
|
|
11
|
+
iosPacketLength?: number;
|
|
12
|
+
androidPacketLength?: number;
|
|
13
|
+
mtu?: number | null;
|
|
14
|
+
}): number;
|
|
15
|
+
//# sourceMappingURL=bleStrategy.d.ts.map
|
|
@@ -0,0 +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,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,iBAAiB,CAAC;AAE9D,wBAAgB,qBAAqB,CAAC,cAAc,EAAE,kBAAkB,WAIvE;AAED,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,kBAAkB,EAClC,aAAa,GAAE,YAAgC,GAC9C,YAAY,CAkBd;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,QAAQ,EACR,eAAmC,EACnC,mBAA2C,EAC3C,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,UAWA"}
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const IOS_PACKET_LENGTH = 128;
|
|
2
2
|
export declare const ANDROID_PACKET_LENGTH = 192;
|
|
3
|
+
export declare const ANDROID_DEFAULT_MTU = 23;
|
|
3
4
|
export declare const getBluetoothServiceUuids: () => string[];
|
|
4
5
|
export declare const getInfosForServiceUuid: (serviceUuid: string, deviceType: 'classic') => {
|
|
5
6
|
serviceUuid: string;
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
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,EAE5B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,SAAS,EAAE,EAEhB,KAAK,oBAAoB,EAGzB,KAAK,YAAY,EAGjB,KAAK,oBAAoB,EAE1B,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -61,84 +61,41 @@ const getConnectedDeviceIds = (serviceUuids) => BleUtils__default["default"].get
|
|
|
61
61
|
const pairDevice = (macAddress) => BleUtils__default["default"].pairDevice(macAddress);
|
|
62
62
|
const onDeviceBondState = (bleMacAddress) => new Promise((resolve, reject) => {
|
|
63
63
|
let timeout;
|
|
64
|
-
|
|
64
|
+
let cleanupListener;
|
|
65
|
+
const cleanup = () => {
|
|
65
66
|
if (timeout) {
|
|
66
67
|
clearTimeout(timeout);
|
|
67
68
|
}
|
|
68
69
|
if (cleanupListener)
|
|
69
70
|
cleanupListener();
|
|
70
71
|
};
|
|
71
|
-
|
|
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 => {
|
|
72
77
|
var _a;
|
|
73
78
|
if (((_a = peripheral.id) === null || _a === void 0 ? void 0 : _a.toLowerCase()) !== bleMacAddress.toLowerCase()) {
|
|
74
79
|
return;
|
|
75
80
|
}
|
|
76
81
|
const { bondState } = peripheral;
|
|
77
|
-
if (bondState.preState === 'BOND_NONE' && bondState.state === 'BOND_BONDING') {
|
|
78
|
-
timeout = setTimeout(() => {
|
|
79
|
-
cleanup(cleanupListener);
|
|
80
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
|
|
81
|
-
}, 60 * 1000);
|
|
82
|
-
}
|
|
83
82
|
const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
|
|
84
83
|
const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
|
|
85
84
|
Logger.debug('onDeviceBondState bondState:', bondState);
|
|
86
85
|
if (hasBonded) {
|
|
87
|
-
cleanup(
|
|
86
|
+
cleanup();
|
|
88
87
|
resolve(peripheral);
|
|
89
88
|
}
|
|
90
89
|
else if (hasCanceled) {
|
|
91
|
-
cleanup(
|
|
90
|
+
cleanup();
|
|
92
91
|
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
|
|
93
92
|
}
|
|
94
93
|
});
|
|
95
94
|
});
|
|
96
95
|
|
|
97
|
-
const timer = process.env.NODE_ENV === 'development'
|
|
98
|
-
? {
|
|
99
|
-
timeout: (fn, ms) => {
|
|
100
|
-
const startTime = Date.now();
|
|
101
|
-
const interval = setInterval(() => {
|
|
102
|
-
if (Date.now() - startTime >= ms) {
|
|
103
|
-
clearInterval(interval);
|
|
104
|
-
fn();
|
|
105
|
-
}
|
|
106
|
-
}, 100);
|
|
107
|
-
return () => {
|
|
108
|
-
clearInterval(interval);
|
|
109
|
-
};
|
|
110
|
-
},
|
|
111
|
-
}
|
|
112
|
-
: {
|
|
113
|
-
timeout: (fn, ms) => {
|
|
114
|
-
const timeout = setTimeout(fn, ms);
|
|
115
|
-
return () => clearTimeout(timeout);
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
|
|
120
|
-
let done = false;
|
|
121
|
-
const subscription = bleManager.onStateChange(state => {
|
|
122
|
-
console.log('ble state -> ', state);
|
|
123
|
-
if (state === 'PoweredOn') {
|
|
124
|
-
if (done)
|
|
125
|
-
return;
|
|
126
|
-
clearTimeout();
|
|
127
|
-
done = true;
|
|
128
|
-
subscription.remove();
|
|
129
|
-
resolve();
|
|
130
|
-
}
|
|
131
|
-
}, true);
|
|
132
|
-
const clearTimeout = timer.timeout(() => {
|
|
133
|
-
if (done)
|
|
134
|
-
return;
|
|
135
|
-
subscription.remove();
|
|
136
|
-
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
137
|
-
}, ms);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
96
|
const IOS_PACKET_LENGTH = 128;
|
|
141
97
|
const ANDROID_PACKET_LENGTH = 192;
|
|
98
|
+
const ANDROID_DEFAULT_MTU = 23;
|
|
142
99
|
const ClassicServiceUUID = '00000001-0000-1000-8000-00805f9b34fb';
|
|
143
100
|
const OneKeyServices = {
|
|
144
101
|
classic: {
|
|
@@ -180,6 +137,78 @@ const isSameBleUuid = (left, right) => {
|
|
|
180
137
|
(getBleUuidKey(left) !== '' && getBleUuidKey(left) === getBleUuidKey(right)));
|
|
181
138
|
};
|
|
182
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
|
+
const timer = process.env.NODE_ENV === 'development'
|
|
170
|
+
? {
|
|
171
|
+
timeout: (fn, ms) => {
|
|
172
|
+
const startTime = Date.now();
|
|
173
|
+
const interval = setInterval(() => {
|
|
174
|
+
if (Date.now() - startTime >= ms) {
|
|
175
|
+
clearInterval(interval);
|
|
176
|
+
fn();
|
|
177
|
+
}
|
|
178
|
+
}, 100);
|
|
179
|
+
return () => {
|
|
180
|
+
clearInterval(interval);
|
|
181
|
+
};
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
: {
|
|
185
|
+
timeout: (fn, ms) => {
|
|
186
|
+
const timeout = setTimeout(fn, ms);
|
|
187
|
+
return () => clearTimeout(timeout);
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const subscribeBleOn = (bleManager, ms = 1000) => new Promise((resolve, reject) => {
|
|
192
|
+
let done = false;
|
|
193
|
+
const subscription = bleManager.onStateChange(state => {
|
|
194
|
+
console.log('ble state -> ', state);
|
|
195
|
+
if (state === 'PoweredOn') {
|
|
196
|
+
if (done)
|
|
197
|
+
return;
|
|
198
|
+
clearTimeout();
|
|
199
|
+
done = true;
|
|
200
|
+
subscription.remove();
|
|
201
|
+
resolve();
|
|
202
|
+
}
|
|
203
|
+
}, true);
|
|
204
|
+
const clearTimeout = timer.timeout(() => {
|
|
205
|
+
if (done)
|
|
206
|
+
return;
|
|
207
|
+
subscription.remove();
|
|
208
|
+
reject(hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BlePermissionError));
|
|
209
|
+
}, ms);
|
|
210
|
+
});
|
|
211
|
+
|
|
183
212
|
const isHeaderChunk = (chunk) => {
|
|
184
213
|
if (chunk.length < 9)
|
|
185
214
|
return false;
|
|
@@ -196,12 +225,11 @@ const Log$1 = bleLogger;
|
|
|
196
225
|
class BleTransport {
|
|
197
226
|
constructor(device, writeCharacteristic, notifyCharacteristic) {
|
|
198
227
|
this.name = 'ReactNativeBleTransport';
|
|
199
|
-
this.mtuSize =
|
|
228
|
+
this.mtuSize = 23;
|
|
200
229
|
this.id = device.id;
|
|
201
230
|
this.device = device;
|
|
202
231
|
this.writeCharacteristic = writeCharacteristic;
|
|
203
232
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
204
|
-
console.log(`BleTransport(${String(this.id)}) new instance`);
|
|
205
233
|
}
|
|
206
234
|
writeWithRetry(data, retryCount = BleTransport.MAX_RETRIES) {
|
|
207
235
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -240,9 +268,10 @@ const Log = bleLogger;
|
|
|
240
268
|
const transportCache = {};
|
|
241
269
|
const BLE_RESPONSE_TIMEOUT_MS = 30000;
|
|
242
270
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
243
|
-
const PROTOCOL_V2_PROBE_TIMEOUT_MS =
|
|
271
|
+
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10000;
|
|
244
272
|
const DEVICE_SCAN_TIMEOUT_MS = 8000;
|
|
245
273
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
274
|
+
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
246
275
|
const HIGH_VOLUME_WRITE_BURST_SIZE = reactNative.Platform.OS === 'ios' ? 4 : 6;
|
|
247
276
|
const HIGH_VOLUME_WRITE_PAUSE_MS = reactNative.Platform.OS === 'ios' ? 6 : 2;
|
|
248
277
|
const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = reactNative.Platform.OS === 'ios' ? 20 : 8;
|
|
@@ -296,7 +325,7 @@ function hasKnownOneKeyService(device) {
|
|
|
296
325
|
var _a;
|
|
297
326
|
return ((_a = device === null || device === void 0 ? void 0 : device.serviceUUIDs) !== null && _a !== void 0 ? _a : []).some(serviceUuid => getInfosForServiceUuid(serviceUuid, 'classic'));
|
|
298
327
|
}
|
|
299
|
-
|
|
328
|
+
const connectOptions = {
|
|
300
329
|
requestMTU: 256,
|
|
301
330
|
timeout: 3000,
|
|
302
331
|
refreshGatt: 'OnConnected',
|
|
@@ -508,6 +537,9 @@ class ReactNativeBleTransport {
|
|
|
508
537
|
if (bondState.bonding) {
|
|
509
538
|
yield onDeviceBondState(uuid);
|
|
510
539
|
}
|
|
540
|
+
else if (!bondState.bonded) {
|
|
541
|
+
throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
|
|
542
|
+
}
|
|
511
543
|
}
|
|
512
544
|
if (!device) {
|
|
513
545
|
const devices = yield blePlxManager.devices([uuid]);
|
|
@@ -528,7 +560,6 @@ class ReactNativeBleTransport {
|
|
|
528
560
|
Log === null || Log === void 0 ? void 0 : Log.debug('try to connect to device has error: ', e);
|
|
529
561
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
530
562
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
531
|
-
connectOptions = {};
|
|
532
563
|
Log === null || Log === void 0 ? void 0 : Log.debug('first try to reconnect without params');
|
|
533
564
|
device = yield blePlxManager.connectToDevice(uuid);
|
|
534
565
|
}
|
|
@@ -553,7 +584,6 @@ class ReactNativeBleTransport {
|
|
|
553
584
|
Log === null || Log === void 0 ? void 0 : Log.debug('not connected, try to connect to device has error: ', e);
|
|
554
585
|
if (e.errorCode === reactNativeBlePlx.BleErrorCode.DeviceMTUChangeFailed ||
|
|
555
586
|
e.errorCode === reactNativeBlePlx.BleErrorCode.OperationCancelled) {
|
|
556
|
-
connectOptions = {};
|
|
557
587
|
Log === null || Log === void 0 ? void 0 : Log.debug('second try to reconnect without params');
|
|
558
588
|
try {
|
|
559
589
|
device = yield device.connect();
|
|
@@ -639,7 +669,7 @@ class ReactNativeBleTransport {
|
|
|
639
669
|
if (!notifyCharacteristic) {
|
|
640
670
|
throw hdShared.ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
641
671
|
}
|
|
642
|
-
if (!writeCharacteristic
|
|
672
|
+
if (!hasWritableCapability(writeCharacteristic)) {
|
|
643
673
|
throw hdShared.ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
644
674
|
}
|
|
645
675
|
if (!notifyCharacteristic.isNotifiable) {
|
|
@@ -653,6 +683,9 @@ class ReactNativeBleTransport {
|
|
|
653
683
|
this.deviceProtocolHints.set(uuid, protocolHint);
|
|
654
684
|
}
|
|
655
685
|
const transport$1 = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
686
|
+
if (reactNative.Platform.OS === 'android') {
|
|
687
|
+
transport$1.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport$1.mtuSize;
|
|
688
|
+
}
|
|
656
689
|
const monitorToken = this.nextMonitorToken;
|
|
657
690
|
this.nextMonitorToken += 1;
|
|
658
691
|
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
@@ -667,6 +700,9 @@ class ReactNativeBleTransport {
|
|
|
667
700
|
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
668
701
|
});
|
|
669
702
|
}
|
|
703
|
+
else if (reactNative.Platform.OS === 'android') {
|
|
704
|
+
yield delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
705
|
+
}
|
|
670
706
|
const protocolType = yield this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
671
707
|
(_f = this.emitter) === null || _f === void 0 ? void 0 : _f.emit('device-connect', {
|
|
672
708
|
name: device.name,
|
|
@@ -1091,10 +1127,13 @@ class ReactNativeBleTransport {
|
|
|
1091
1127
|
}
|
|
1092
1128
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1093
1129
|
}
|
|
1094
|
-
if (protocolHint === 'V2'
|
|
1095
|
-
this.
|
|
1096
|
-
|
|
1097
|
-
|
|
1130
|
+
if (protocolHint === 'V2') {
|
|
1131
|
+
if (yield this.probeProtocolV2(uuid)) {
|
|
1132
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1133
|
+
Log === null || Log === void 0 ? void 0 : Log.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
|
|
1134
|
+
return 'V2';
|
|
1135
|
+
}
|
|
1136
|
+
throw this.createProtocolMismatchError('V2');
|
|
1098
1137
|
}
|
|
1099
1138
|
if (this.deviceProtocol.get(uuid) === 'V2' && (yield this.probeProtocolV2(uuid))) {
|
|
1100
1139
|
this.deviceProtocol.set(uuid, 'V2');
|
|
@@ -1282,15 +1321,21 @@ class ReactNativeBleTransport {
|
|
|
1282
1321
|
writeProtocolV2Frame(transport, frame, options) {
|
|
1283
1322
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1284
1323
|
const tuning = getProtocolV2BleTuning();
|
|
1285
|
-
const packetCapacity =
|
|
1324
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1325
|
+
platform: reactNative.Platform.OS,
|
|
1326
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
1327
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
1328
|
+
mtu: reactNative.Platform.OS === 'android' ? transport.mtuSize : undefined,
|
|
1329
|
+
});
|
|
1286
1330
|
const writeWithResponse = !!(options === null || options === void 0 ? void 0 : options.writeWithResponse) || (!!(options === null || options === void 0 ? void 0 : options.highVolume) && tuning.highVolumeWriteWithResponse);
|
|
1287
|
-
const
|
|
1331
|
+
const writeMode = resolveBleWriteMode(transport.writeCharacteristic, writeWithResponse ? 'withResponse' : 'withoutResponse');
|
|
1332
|
+
const shouldThrottle = !!(options === null || options === void 0 ? void 0 : options.highVolume) && writeMode === 'withoutResponse';
|
|
1288
1333
|
let packetsWritten = 0;
|
|
1289
1334
|
try {
|
|
1290
1335
|
for (let offset = 0; offset < frame.length; offset += packetCapacity) {
|
|
1291
1336
|
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1292
1337
|
const base64 = buffer.Buffer.from(chunk).toString('base64');
|
|
1293
|
-
if (
|
|
1338
|
+
if (writeMode === 'withResponse') {
|
|
1294
1339
|
yield transport.writeCharacteristic.writeWithResponse(base64);
|
|
1295
1340
|
}
|
|
1296
1341
|
else {
|
|
@@ -1365,7 +1410,11 @@ class ReactNativeBleTransport {
|
|
|
1365
1410
|
protocolV2: this._messagesV2,
|
|
1366
1411
|
},
|
|
1367
1412
|
router: transport.PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1368
|
-
writeFrame: (frame) => this
|
|
1413
|
+
writeFrame: (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
1414
|
+
yield this.writeProtocolV2Frame(transport$1, frame, {
|
|
1415
|
+
highVolume: highVolumeWrite,
|
|
1416
|
+
});
|
|
1417
|
+
}),
|
|
1369
1418
|
readFrame: () => __awaiter(this, void 0, void 0, function* () {
|
|
1370
1419
|
const rxFrame = yield this.readProtocolV2Frame(uuid);
|
|
1371
1420
|
if (!(rxFrame instanceof Uint8Array)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-transport-react-native",
|
|
3
|
-
"version": "1.1.27-alpha.
|
|
3
|
+
"version": "1.1.27-alpha.38",
|
|
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.1.27-alpha.
|
|
23
|
-
"@onekeyfe/hd-shared": "1.1.27-alpha.
|
|
24
|
-
"@onekeyfe/hd-transport": "1.1.27-alpha.
|
|
22
|
+
"@onekeyfe/hd-core": "1.1.27-alpha.38",
|
|
23
|
+
"@onekeyfe/hd-shared": "1.1.27-alpha.38",
|
|
24
|
+
"@onekeyfe/hd-transport": "1.1.27-alpha.38",
|
|
25
25
|
"@onekeyfe/react-native-ble-utils": "^0.1.4",
|
|
26
26
|
"react-native-ble-plx": "3.5.1"
|
|
27
27
|
},
|
|
28
|
-
"gitHead": "
|
|
28
|
+
"gitHead": "71f3b20e3ec0d2c4b21b444501115dc8c0eba20b"
|
|
29
29
|
}
|
package/src/BleManager.ts
CHANGED
|
@@ -21,36 +21,35 @@ export const pairDevice = (macAddress: string) => BleUtils.pairDevice(macAddress
|
|
|
21
21
|
|
|
22
22
|
export const onDeviceBondState = (bleMacAddress: string): Promise<Peripheral | undefined> =>
|
|
23
23
|
new Promise((resolve, reject) => {
|
|
24
|
-
let timeout:
|
|
24
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
25
|
+
let cleanupListener: (() => void) | undefined;
|
|
25
26
|
|
|
26
|
-
const cleanup = (
|
|
27
|
+
const cleanup = () => {
|
|
27
28
|
if (timeout) {
|
|
28
29
|
clearTimeout(timeout);
|
|
29
30
|
}
|
|
30
31
|
if (cleanupListener) cleanupListener();
|
|
31
32
|
};
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
timeout = setTimeout(() => {
|
|
35
|
+
cleanup();
|
|
36
|
+
reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
|
|
37
|
+
}, 60 * 1000);
|
|
38
|
+
|
|
39
|
+
cleanupListener = BleUtils.onDeviceBondState(peripheral => {
|
|
34
40
|
if (peripheral.id?.toLowerCase() !== bleMacAddress.toLowerCase()) {
|
|
35
41
|
return;
|
|
36
42
|
}
|
|
37
43
|
const { bondState } = peripheral;
|
|
38
44
|
|
|
39
|
-
if (bondState.preState === 'BOND_NONE' && bondState.state === 'BOND_BONDING') {
|
|
40
|
-
timeout = setTimeout(() => {
|
|
41
|
-
cleanup(cleanupListener);
|
|
42
|
-
reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded'));
|
|
43
|
-
}, 60 * 1000);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
45
|
const hasBonded = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_BONDED';
|
|
47
46
|
const hasCanceled = bondState.preState === 'BOND_BONDING' && bondState.state === 'BOND_NONE';
|
|
48
47
|
Logger.debug('onDeviceBondState bondState:', bondState);
|
|
49
48
|
if (hasBonded) {
|
|
50
|
-
cleanup(
|
|
49
|
+
cleanup();
|
|
51
50
|
resolve(peripheral);
|
|
52
51
|
} else if (hasCanceled) {
|
|
53
|
-
cleanup(
|
|
52
|
+
cleanup();
|
|
54
53
|
reject(ERRORS.TypedError(HardwareErrorCode.BleDeviceBondedCanceled, 'bonding canceled'));
|
|
55
54
|
}
|
|
56
55
|
});
|
package/src/BleTransport.ts
CHANGED
|
@@ -14,7 +14,7 @@ export default class BleTransport {
|
|
|
14
14
|
|
|
15
15
|
device: Device;
|
|
16
16
|
|
|
17
|
-
mtuSize =
|
|
17
|
+
mtuSize = 23;
|
|
18
18
|
|
|
19
19
|
writeCharacteristic: Characteristic;
|
|
20
20
|
|
|
@@ -41,7 +41,6 @@ export default class BleTransport {
|
|
|
41
41
|
this.device = device;
|
|
42
42
|
this.writeCharacteristic = writeCharacteristic;
|
|
43
43
|
this.notifyCharacteristic = notifyCharacteristic;
|
|
44
|
-
console.log(`BleTransport(${String(this.id)}) new instance`);
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
/**
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
hasWritableCapability,
|
|
3
|
+
resolveBleWriteMode,
|
|
4
|
+
resolveProtocolV2PacketCapacity,
|
|
5
|
+
} from '../bleStrategy';
|
|
6
|
+
|
|
7
|
+
describe('React Native BLE strategy', () => {
|
|
8
|
+
test('accepts writeWithoutResponse-only characteristics', () => {
|
|
9
|
+
const characteristic = {
|
|
10
|
+
isWritableWithResponse: false,
|
|
11
|
+
isWritableWithoutResponse: true,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
expect(hasWritableCapability(characteristic)).toBe(true);
|
|
15
|
+
expect(resolveBleWriteMode(characteristic)).toBe('withoutResponse');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('falls back to Android default ATT payload when MTU is unavailable', () => {
|
|
19
|
+
expect(
|
|
20
|
+
resolveProtocolV2PacketCapacity({
|
|
21
|
+
platform: 'android',
|
|
22
|
+
androidPacketLength: 192,
|
|
23
|
+
mtu: null,
|
|
24
|
+
})
|
|
25
|
+
).toBe(20);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('caps Android packet length by negotiated MTU payload', () => {
|
|
29
|
+
expect(
|
|
30
|
+
resolveProtocolV2PacketCapacity({
|
|
31
|
+
platform: 'android',
|
|
32
|
+
androidPacketLength: 192,
|
|
33
|
+
mtu: 100,
|
|
34
|
+
})
|
|
35
|
+
).toBe(97);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('keeps iOS packet length controlled by tuning profile', () => {
|
|
39
|
+
expect(
|
|
40
|
+
resolveProtocolV2PacketCapacity({
|
|
41
|
+
platform: 'ios',
|
|
42
|
+
iosPacketLength: 244,
|
|
43
|
+
mtu: 256,
|
|
44
|
+
})
|
|
45
|
+
).toBe(244);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ANDROID_DEFAULT_MTU, ANDROID_PACKET_LENGTH, IOS_PACKET_LENGTH } from './constants';
|
|
2
|
+
|
|
3
|
+
export type BlePlatform = 'ios' | 'android' | string;
|
|
4
|
+
|
|
5
|
+
export type BleWriteCapability = {
|
|
6
|
+
isWritableWithResponse?: boolean | null;
|
|
7
|
+
isWritableWithoutResponse?: boolean | null;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type BleWriteMode = 'withResponse' | 'withoutResponse';
|
|
11
|
+
|
|
12
|
+
export function hasWritableCapability(characteristic: BleWriteCapability) {
|
|
13
|
+
return !!(
|
|
14
|
+
characteristic.isWritableWithResponse || characteristic.isWritableWithoutResponse
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function resolveBleWriteMode(
|
|
19
|
+
characteristic: BleWriteCapability,
|
|
20
|
+
preferredMode: BleWriteMode = 'withoutResponse'
|
|
21
|
+
): BleWriteMode {
|
|
22
|
+
if (preferredMode === 'withoutResponse' && characteristic.isWritableWithoutResponse) {
|
|
23
|
+
return 'withoutResponse';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (preferredMode === 'withResponse' && characteristic.isWritableWithResponse) {
|
|
27
|
+
return 'withResponse';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (characteristic.isWritableWithoutResponse) {
|
|
31
|
+
return 'withoutResponse';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (characteristic.isWritableWithResponse) {
|
|
35
|
+
return 'withResponse';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return preferredMode;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function resolveProtocolV2PacketCapacity({
|
|
42
|
+
platform,
|
|
43
|
+
iosPacketLength = IOS_PACKET_LENGTH,
|
|
44
|
+
androidPacketLength = ANDROID_PACKET_LENGTH,
|
|
45
|
+
mtu,
|
|
46
|
+
}: {
|
|
47
|
+
platform: BlePlatform;
|
|
48
|
+
iosPacketLength?: number;
|
|
49
|
+
androidPacketLength?: number;
|
|
50
|
+
mtu?: number | null;
|
|
51
|
+
}) {
|
|
52
|
+
if (platform === 'ios') {
|
|
53
|
+
return iosPacketLength;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (platform === 'android') {
|
|
57
|
+
const payloadLength = Math.max((mtu ?? ANDROID_DEFAULT_MTU) - 3, 1);
|
|
58
|
+
return Math.min(androidPacketLength, payloadLength);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return androidPacketLength;
|
|
62
|
+
}
|
package/src/constants.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -22,6 +22,11 @@ import transport, {
|
|
|
22
22
|
import { ERRORS, HardwareErrorCode, createDeferred, isOnekeyDevice } from '@onekeyfe/hd-shared';
|
|
23
23
|
|
|
24
24
|
import { getConnectedDeviceIds, onDeviceBondState, pairDevice } from './BleManager';
|
|
25
|
+
import {
|
|
26
|
+
hasWritableCapability,
|
|
27
|
+
resolveBleWriteMode,
|
|
28
|
+
resolveProtocolV2PacketCapacity,
|
|
29
|
+
} from './bleStrategy';
|
|
25
30
|
import { subscribeBleOn } from './subscribeBleOn';
|
|
26
31
|
import {
|
|
27
32
|
ANDROID_PACKET_LENGTH,
|
|
@@ -48,9 +53,10 @@ const Log = bleLogger;
|
|
|
48
53
|
const transportCache: Record<string, BleTransport> = {};
|
|
49
54
|
const BLE_RESPONSE_TIMEOUT_MS = 30_000;
|
|
50
55
|
const PROTOCOL_PROBE_TIMEOUT_MS = 1000;
|
|
51
|
-
const PROTOCOL_V2_PROBE_TIMEOUT_MS =
|
|
56
|
+
const PROTOCOL_V2_PROBE_TIMEOUT_MS = 10_000;
|
|
52
57
|
const DEVICE_SCAN_TIMEOUT_MS = 8000;
|
|
53
58
|
const IOS_NOTIFY_READY_DELAY_MS = 150;
|
|
59
|
+
const ANDROID_NOTIFY_READY_DELAY_MS = 300;
|
|
54
60
|
const HIGH_VOLUME_WRITE_BURST_SIZE = Platform.OS === 'ios' ? 4 : 6;
|
|
55
61
|
const HIGH_VOLUME_WRITE_PAUSE_MS = Platform.OS === 'ios' ? 6 : 2;
|
|
56
62
|
const HIGH_VOLUME_WRITE_FLUSH_DELAY_MS = Platform.OS === 'ios' ? 20 : 8;
|
|
@@ -143,7 +149,7 @@ function hasKnownOneKeyService(device?: Device | null) {
|
|
|
143
149
|
);
|
|
144
150
|
}
|
|
145
151
|
|
|
146
|
-
|
|
152
|
+
const connectOptions: Record<string, unknown> = {
|
|
147
153
|
requestMTU: 256,
|
|
148
154
|
timeout: 3000,
|
|
149
155
|
refreshGatt: 'OnConnected',
|
|
@@ -430,11 +436,12 @@ export default class ReactNativeBleTransport {
|
|
|
430
436
|
throw error;
|
|
431
437
|
}
|
|
432
438
|
|
|
433
|
-
// check device is bonded
|
|
434
439
|
if (Platform.OS === 'android') {
|
|
435
440
|
const bondState = await pairDevice(uuid);
|
|
436
441
|
if (bondState.bonding) {
|
|
437
442
|
await onDeviceBondState(uuid);
|
|
443
|
+
} else if (!bondState.bonded) {
|
|
444
|
+
throw ERRORS.TypedError(HardwareErrorCode.BleDeviceNotBonded, 'device is not bonded');
|
|
438
445
|
}
|
|
439
446
|
}
|
|
440
447
|
|
|
@@ -460,7 +467,6 @@ export default class ReactNativeBleTransport {
|
|
|
460
467
|
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
461
468
|
e.errorCode === BleErrorCode.OperationCancelled
|
|
462
469
|
) {
|
|
463
|
-
connectOptions = {};
|
|
464
470
|
Log?.debug('first try to reconnect without params');
|
|
465
471
|
device = await blePlxManager.connectToDevice(uuid);
|
|
466
472
|
} else if (e.errorCode === BleErrorCode.DeviceAlreadyConnected) {
|
|
@@ -487,7 +493,6 @@ export default class ReactNativeBleTransport {
|
|
|
487
493
|
e.errorCode === BleErrorCode.DeviceMTUChangeFailed ||
|
|
488
494
|
e.errorCode === BleErrorCode.OperationCancelled
|
|
489
495
|
) {
|
|
490
|
-
connectOptions = {};
|
|
491
496
|
Log?.debug('second try to reconnect without params');
|
|
492
497
|
try {
|
|
493
498
|
device = await device.connect();
|
|
@@ -590,7 +595,7 @@ export default class ReactNativeBleTransport {
|
|
|
590
595
|
throw ERRORS.TypedError('BLECharacteristicNotFound: notify characteristic not found');
|
|
591
596
|
}
|
|
592
597
|
|
|
593
|
-
if (!writeCharacteristic
|
|
598
|
+
if (!hasWritableCapability(writeCharacteristic)) {
|
|
594
599
|
throw ERRORS.TypedError('BLECharacteristicNotWritable: write characteristic not writable');
|
|
595
600
|
}
|
|
596
601
|
|
|
@@ -612,6 +617,9 @@ export default class ReactNativeBleTransport {
|
|
|
612
617
|
}
|
|
613
618
|
|
|
614
619
|
const transport = new BleTransport(device, writeCharacteristic, notifyCharacteristic);
|
|
620
|
+
if (Platform.OS === 'android') {
|
|
621
|
+
transport.mtuSize = typeof device.mtu === 'number' ? device.mtu : transport.mtuSize;
|
|
622
|
+
}
|
|
615
623
|
const monitorToken = this.nextMonitorToken;
|
|
616
624
|
this.nextMonitorToken += 1;
|
|
617
625
|
const notifyTransactionId = `${uuid}:notify:${monitorToken}`;
|
|
@@ -632,6 +640,8 @@ export default class ReactNativeBleTransport {
|
|
|
632
640
|
await new Promise<void>(resolve => {
|
|
633
641
|
setTimeout(resolve, IOS_NOTIFY_READY_DELAY_MS);
|
|
634
642
|
});
|
|
643
|
+
} else if (Platform.OS === 'android') {
|
|
644
|
+
await delay(ANDROID_NOTIFY_READY_DELAY_MS);
|
|
635
645
|
}
|
|
636
646
|
|
|
637
647
|
const protocolType = await this.detectProtocol(uuid, expectedProtocol, protocolHint);
|
|
@@ -1164,10 +1174,13 @@ export default class ReactNativeBleTransport {
|
|
|
1164
1174
|
throw this.createProtocolMismatchError(expectedProtocol);
|
|
1165
1175
|
}
|
|
1166
1176
|
|
|
1167
|
-
if (protocolHint === 'V2'
|
|
1168
|
-
this.
|
|
1169
|
-
|
|
1170
|
-
|
|
1177
|
+
if (protocolHint === 'V2') {
|
|
1178
|
+
if (await this.probeProtocolV2(uuid)) {
|
|
1179
|
+
this.deviceProtocol.set(uuid, 'V2');
|
|
1180
|
+
Log?.debug(`[ReactNativeBleTransport] detectProtocol: uuid=${uuid} -> V2 (hint)`);
|
|
1181
|
+
return 'V2';
|
|
1182
|
+
}
|
|
1183
|
+
throw this.createProtocolMismatchError('V2');
|
|
1171
1184
|
}
|
|
1172
1185
|
|
|
1173
1186
|
if (this.deviceProtocol.get(uuid) === 'V2' && (await this.probeProtocolV2(uuid))) {
|
|
@@ -1370,18 +1383,26 @@ export default class ReactNativeBleTransport {
|
|
|
1370
1383
|
options?: { highVolume?: boolean; writeWithResponse?: boolean }
|
|
1371
1384
|
) {
|
|
1372
1385
|
const tuning = getProtocolV2BleTuning();
|
|
1373
|
-
const packetCapacity =
|
|
1374
|
-
Platform.OS
|
|
1386
|
+
const packetCapacity = resolveProtocolV2PacketCapacity({
|
|
1387
|
+
platform: Platform.OS,
|
|
1388
|
+
iosPacketLength: tuning.iosPacketLength,
|
|
1389
|
+
androidPacketLength: tuning.androidPacketLength,
|
|
1390
|
+
mtu: Platform.OS === 'android' ? transport.mtuSize : undefined,
|
|
1391
|
+
});
|
|
1375
1392
|
const writeWithResponse =
|
|
1376
1393
|
!!options?.writeWithResponse || (!!options?.highVolume && tuning.highVolumeWriteWithResponse);
|
|
1377
|
-
const
|
|
1394
|
+
const writeMode = resolveBleWriteMode(
|
|
1395
|
+
transport.writeCharacteristic,
|
|
1396
|
+
writeWithResponse ? 'withResponse' : 'withoutResponse'
|
|
1397
|
+
);
|
|
1398
|
+
const shouldThrottle = !!options?.highVolume && writeMode === 'withoutResponse';
|
|
1378
1399
|
let packetsWritten = 0;
|
|
1379
1400
|
|
|
1380
1401
|
try {
|
|
1381
1402
|
for (let offset = 0; offset < frame.length; offset += packetCapacity) {
|
|
1382
1403
|
const chunk = frame.slice(offset, offset + packetCapacity);
|
|
1383
1404
|
const base64 = Buffer.from(chunk).toString('base64');
|
|
1384
|
-
if (
|
|
1405
|
+
if (writeMode === 'withResponse') {
|
|
1385
1406
|
await transport.writeCharacteristic.writeWithResponse(base64);
|
|
1386
1407
|
} else {
|
|
1387
1408
|
await transport.writeCharacteristic.writeWithoutResponse(base64);
|
|
@@ -1476,8 +1497,11 @@ export default class ReactNativeBleTransport {
|
|
|
1476
1497
|
protocolV2: this._messagesV2,
|
|
1477
1498
|
},
|
|
1478
1499
|
router: PROTOCOL_V2_CHANNEL_BLE_UART,
|
|
1479
|
-
writeFrame: (frame: Uint8Array) =>
|
|
1480
|
-
this.writeProtocolV2Frame(transport, frame, {
|
|
1500
|
+
writeFrame: async (frame: Uint8Array) => {
|
|
1501
|
+
await this.writeProtocolV2Frame(transport, frame, {
|
|
1502
|
+
highVolume: highVolumeWrite,
|
|
1503
|
+
});
|
|
1504
|
+
},
|
|
1481
1505
|
readFrame: async () => {
|
|
1482
1506
|
const rxFrame = await this.readProtocolV2Frame(uuid);
|
|
1483
1507
|
if (!(rxFrame instanceof Uint8Array)) {
|