@jiabaida/tools 1.0.7 → 1.0.10

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.
Files changed (41) hide show
  1. package/dist/cjs/core/BleApiManager.js +1 -1
  2. package/dist/cjs/core/BleCmdAnalysis/BaseParamProtocol.js +1 -1
  3. package/dist/cjs/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -1
  4. package/dist/cjs/core/BleCmdAnalysis/BleCmdDD.js +1 -1
  5. package/dist/cjs/core/BleCmdAnalysis/BleCmdDDA4.js +1 -1
  6. package/dist/cjs/core/BleCmdAnalysis/BleCmdFFAA.js +1 -1
  7. package/dist/cjs/core/BleCmdAnalysis/readAndSetParam.js +1 -1
  8. package/dist/cjs/core/BleDataProcess.js +1 -1
  9. package/dist/cjs/core/OtaUpgrade.js +1 -1
  10. package/dist/cjs/core/Queue.js +1 -0
  11. package/dist/cjs/core/mqttServer.js +1 -1
  12. package/dist/cjs/core/tcpServer.js +1 -0
  13. package/dist/cjs/index.js +1 -1
  14. package/dist/esm/core/BleApiManager.js +1 -1
  15. package/dist/esm/core/BleCmdAnalysis/BaseParamProtocol.js +1 -1
  16. package/dist/esm/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -1
  17. package/dist/esm/core/BleCmdAnalysis/BleCmdDD.js +1 -1
  18. package/dist/esm/core/BleCmdAnalysis/BleCmdDDA4.js +1 -1
  19. package/dist/esm/core/BleCmdAnalysis/BleCmdFFAA.js +1 -1
  20. package/dist/esm/core/BleCmdAnalysis/BleCmdHVES.js +1 -1
  21. package/dist/esm/core/BleCmdAnalysis/readAndSetParam.js +1 -1
  22. package/dist/esm/core/BleDataProcess.js +1 -1
  23. package/dist/esm/core/OtaUpgrade.js +1 -1
  24. package/dist/esm/core/Queue.js +1 -0
  25. package/dist/esm/core/mqttServer.js +1 -1
  26. package/dist/esm/core/tcpServer.js +1 -0
  27. package/dist/esm/index.js +1 -1
  28. package/package.json +1 -1
  29. package/src/core/BleApiManager.js +33 -15
  30. package/src/core/BleCmdAnalysis/BaseParamProtocol.js +116 -32
  31. package/src/core/BleCmdAnalysis/BleCmdAnalysis.js +58 -2
  32. package/src/core/BleCmdAnalysis/BleCmdDD.js +88 -19
  33. package/src/core/BleCmdAnalysis/BleCmdDDA4.js +154 -227
  34. package/src/core/BleCmdAnalysis/BleCmdFFAA.js +1 -0
  35. package/src/core/BleCmdAnalysis/readAndSetParam.js +133 -16
  36. package/src/core/BleDataProcess.js +15 -11
  37. package/src/core/OtaUpgrade.js +356 -350
  38. package/src/core/Queue.js +34 -0
  39. package/src/core/mqttServer.js +75 -5
  40. package/src/core/tcpServer.js +341 -0
  41. package/src/index.js +1 -0
@@ -1,350 +1,356 @@
1
- import { getOS } from './commonfun';
2
- import { TelinkApi } from './TelinkApi';
3
- import Transfer, { BLE } from './Transfer';
4
-
5
- const max = BLE.PACKAGE_MAX_LENGTH;
6
- const delayDefault = BLE.WRITE_DELAY;
7
- const { isIOS, isAndroid } = getOS();
8
-
9
- function getBuffer(hexArr) {
10
- const buffer = new ArrayBuffer(hexArr.length);
11
- const dataView = new DataView(buffer);
12
- hexArr.forEach((hex, i) => dataView.setUint8(i, hex));
13
- return buffer;
14
- }
15
-
16
- /**
17
- * const ota = new OTAUpgrade({
18
- * deviceId,
19
- * macAddr,
20
- * filePath,
21
- * otaInfo,
22
- * otaStart,
23
- * otaReStart,
24
- * isTeLink, // 是否 Telink 升级
25
- * onProgress, // 升级进度回调
26
- * onSuccess, // 升级成功回调
27
- * onError, // 升级失败回调
28
- * delay, // 写入延时,默认20ms,iOS可适当调大一些
29
- * });
30
- * ota.start();
31
- **/
32
-
33
- export class OTAUpgrade {
34
- constructor({ deviceId, filePath, otaInfo, otaStart, otaReStart, macAddr, onProgress, onSuccess, onError, delay, platform = 'APP' }) {
35
- this.deviceId = deviceId;
36
- this.filePath = filePath;
37
- this.otaInfo = otaInfo;
38
- this.otaStart = otaStart;
39
- this.otaReStart = otaReStart;
40
- this.macAddr = macAddr;
41
- this.platform = platform; // 'APP' | 'MP' | 'H5'
42
- // 自动判断是否Telink,入参为macAddr
43
- this.isTeLink = TelinkApi.isTeLink ? TelinkApi.isTeLink({
44
- macAddr
45
- }) : false;
46
- this.onProgress = onProgress;
47
- this.onSuccess = onSuccess;
48
- this.onError = onError;
49
- this.delay = delay || delayDefault;
50
- this.fileHexArray = [];
51
- this.totalTimes = 1;
52
- this.finishedTimes = 0;
53
- this.succeed = false;
54
- this.ready = true;
55
- this.timer = null;
56
- this.s_progress = 0;
57
- this.otaStarting = false;
58
- this.progressType = 'download'; // 当前进度类型: 'download' | 'upgrade'
59
- }
60
-
61
- async start() {
62
- this.progressType = 'download';
63
- try {
64
- await this.download();
65
- } catch (e) {
66
- this.fail('下载失败: ' + e.message);
67
- }
68
- }
69
-
70
- async download() {
71
- const that = this;
72
- return new Promise((resolve, reject) => {
73
- const downloadTask = uni.downloadFile({
74
- url: that.filePath,
75
- success: ({ tempFilePath }) => {
76
- this.addBLECharValueChangeListener();
77
- that.resolve(tempFilePath).then(resolve).catch(reject);
78
- },
79
- fail: (res) => {
80
- that.fail('固件下载失败');
81
- reject(res);
82
- },
83
- });
84
- downloadTask.onProgressUpdate &&
85
- downloadTask.onProgressUpdate(({ progress }) => {
86
- that.onProgress && that.onProgress({ type: 'download', percent: progress });
87
- });
88
- });
89
- }
90
-
91
- async resolve(tempFilePath) {
92
- const that = this;
93
- return new Promise((resolve, reject) => {
94
- uni.saveFile({
95
- tempFilePath,
96
- success: ({ savedFilePath }) => {
97
- if (this.platform === 'APP') {
98
- plus.io.resolveLocalFileSystemURL(
99
- savedFilePath,
100
- (entry) => {
101
- entry.file((file) => {
102
- var fileReader = new plus.io.FileReader();
103
- fileReader.readAsDataURL(file);
104
- fileReader.onloadend = (e) => {
105
- let base64 = e.target.result.split(',')[1];
106
- const hexArray = Transfer.base64ToHexArray(base64);
107
- const times = Math.ceil(hexArray.length / (that.isTeLink ? 16 : max));
108
- that.fileHexArray = hexArray;
109
- that.totalTimes = times;
110
- that.finishedTimes = 0;
111
- // 切换进度类型为升级
112
- that.progressType = 'upgrade';
113
- that.isTeLink ? that.telinkUpgrade() : that.normalUpgrade();
114
- resolve();
115
- };
116
- fileReader.onerror = (e) => {
117
- that.fail('固件解析失败');
118
- reject(e);
119
- };
120
- });
121
- },
122
- (err) => {
123
- that.fail('固件保存失败');
124
- reject(err);
125
- }
126
- );
127
- } else if (this.platform === 'MP') {
128
- // 微信小程序读取本地文件为base64
129
- const fs = wx.getFileSystemManager();
130
- fs.readFile({
131
- filePath: savedFilePath,
132
- encoding: 'base64',
133
- success: (res) => {
134
- // res.data 为 base64 字符串
135
- let base64 = res.data;
136
- const hexArray = Transfer.base64ToHexArray(base64);
137
- const times = Math.ceil(hexArray.length / (that.isTeLink ? 16 : max));
138
- that.fileHexArray = hexArray;
139
- that.totalTimes = times;
140
- that.finishedTimes = 0;
141
- // 切换进度类型为升级
142
- that.progressType = 'upgrade';
143
- that.isTeLink ? that.telinkUpgrade() : that.normalUpgrade();
144
- resolve();
145
- },
146
- fail: (err) => {
147
- console.error('[OTA] resolve failed:', JSON.stringify(err));
148
- that.failed('文件解析失败');
149
- },
150
- });
151
- }
152
- },
153
- fail: (res) => {
154
- that.fail('固件保存失败');
155
- reject(res);
156
- },
157
- });
158
- });
159
- }
160
-
161
- // 普通升级流程
162
- normalUpgrade() {
163
- setTimeout(() => {
164
- BLE.writeATCmd(this.otaInfo, this.deviceId, this.fail.bind(this));
165
- }, 2600);
166
- }
167
-
168
- // Telink 升级流程
169
- telinkUpgrade() {
170
- this.write(['0x00', '0xff'], 0);
171
- }
172
-
173
- write(pkg, type) {
174
- const value = getBuffer(pkg.map((o) => parseInt(o, 16)));
175
- const opt = {
176
- deviceId: this.deviceId,
177
- serviceId: '00010203-0405-0607-0809-0a0b0c0d1912',
178
- characteristicId: '00010203-0405-0607-0809-0a0b0c0d2b12',
179
- value,
180
- success: () => this.onSucceed(type),
181
- fail: async () => {
182
- await this.sleep(this.delay * 2);
183
- uni.writeBLECharacteristicValue({
184
- ...opt,
185
- fail: async () => {
186
- await this.sleep(this.delay * 2);
187
- uni.writeBLECharacteristicValue({ ...opt, fail: this.fail.bind(this) });
188
- },
189
- });
190
- },
191
- };
192
- uni.writeBLECharacteristicValue(opt);
193
- if (isIOS) setTimeout(() => this.onSucceed(type), 5);
194
- }
195
-
196
- onSucceed(type) {
197
- if (type == 0) {
198
- this.write(['0x01', '0xff'], 1);
199
- } else if (type == 1) {
200
- this.sendNextOtaPacketCommand();
201
- } else if (type == 2) {
202
- this.finishedTimes++;
203
- this.sendNextOtaPacketCommand();
204
- } else if (type == 3) {
205
- this.sendNextOtaPacketCommand();
206
- } else if (type == 4) {
207
- this.sendOtaEndCommand();
208
- } else if (type == 5) {
209
- this.finishedTimes++;
210
- this.succeed = true;
211
- this.onSuccess && this.onSuccess();
212
- }
213
- this.onProgress && this.onProgress({ type: 'upgrade', percent: Math.floor((this.finishedTimes * 100) / this.totalTimes) });
214
- }
215
-
216
- async sendNextOtaPacketCommand() {
217
- const i = this.finishedTimes;
218
- const maxLen = 16;
219
- const index = TelinkApi.getIndexHexArr(i);
220
- let pkgValue = this.fileHexArray.slice(i * maxLen, (i + 1) * maxLen);
221
- if (pkgValue.length < maxLen) {
222
- pkgValue = pkgValue.concat([...Array(maxLen - pkgValue.length)].map(() => '0xFF'));
223
- }
224
- const crc = TelinkApi.genCheck([...index, ...pkgValue]);
225
- const pkg = [...index, ...pkgValue, ...crc];
226
- const type = i >= this.totalTimes - 1 ? 4 : 2;
227
- await this.sleep(this.delay);
228
- this.write(pkg, type);
229
- }
230
-
231
- sendOtaEndCommand() {
232
- function genEnd(i, c = 0xff02) {
233
- return [c & 0xff, (c >> 8) & 0xff, i & 0xff, (i >> 8) & 0xff, ~i & 0xff, (~i >> 8) & 0xff].map((o) => `0x${`00${o.toString(16)}`.slice(-2)}`.toUpperCase());
234
- }
235
- const pkgValue = genEnd(this.totalTimes - 1);
236
- const crc = TelinkApi.genCheck([...pkgValue]);
237
- const pkg = [...pkgValue, ...crc];
238
- this.write(pkg, 5);
239
- }
240
-
241
- addBLECharValueChangeListener() {
242
- console.log('添加蓝牙特征值变化监听');
243
- const that = this;
244
- uni.notifyBLECharacteristicValueChange({
245
- deviceId: that.deviceId,
246
- serviceId: BLE.serviceId,
247
- characteristicId: BLE.readUUID,
248
- state: true,
249
- success: () => {},
250
- fail: () => {},
251
- });
252
- that.ready = true;
253
- that.readValue = [];
254
- that.receiveLength = null;
255
- uni.onBLECharacteristicValueChange(({ deviceId, serviceId, characteristicId, value }) => {
256
- if (!that.ready) return;
257
- if (deviceId == that.deviceId && serviceId == BLE.serviceId) {
258
- const intArr = Array.prototype.map.call(new Uint8Array(value), (x) => x);
259
- if (intArr.length > 0) {
260
- if (that.receiveLength == null && intArr[0] == 0xff && intArr[1] == 0xaa) {
261
- that.receiveLength = intArr[3] + 5;
262
- }
263
- if (that.receiveLength) {
264
- that.readValue = that.readValue.concat(intArr);
265
- if (that.readValue.length == that.receiveLength) {
266
- that.doWithResponse([...that.readValue]);
267
- that.readValue = [];
268
- that.receiveLength = null;
269
- }
270
- } else {
271
- that.readValue = [];
272
- that.receiveLength = null;
273
- }
274
- }
275
- }
276
- });
277
- }
278
-
279
- async doWithResponse(intArr) {
280
- console.log('收到设备响应: ', intArr[2]);
281
- if (intArr[2] == 0x80) {
282
- let str = String.fromCharCode(...intArr.slice(4, -1));
283
- console.log('doWithResponse otaStart1', str);
284
- if (str.indexOf(this.otaInfo) > -1) {
285
- this.finishedTimes = 0;
286
- this.transferFirmwareFile();
287
- }
288
- if (str.indexOf(this.otaStart) > -1 || this.otaStarting) {
289
- if (str.indexOf(this.otaStart) > -1) {
290
- this.otaStarting = true;
291
- }
292
- console.log('doWithResponse otaStart2', str);
293
- if (str.toUpperCase().includes('ERROR')) {
294
- this.fail(str);
295
- return;
296
- }
297
- if (str.toUpperCase().indexOf('S100') > -1) {
298
- this.succeed = true;
299
- this.onSuccess && this.onSuccess();
300
- }
301
- }
302
- }
303
- if (intArr[2] == 0x50) {
304
- if (intArr[4] == 0) {
305
- this.finishedTimes++;
306
- this.transferFirmwareFile();
307
- } else {
308
- this.transferFirmwareFile();
309
- }
310
- }
311
- if (intArr[2] == 0x51) {
312
- if (intArr[4] == 0) {
313
- this.startOTA();
314
- } else {
315
- this.fail('升级失败');
316
- }
317
- }
318
- }
319
-
320
- transferFirmwareFile() {
321
- let nextTime = this.finishedTimes + 1;
322
- const timeFor51 = nextTime > this.totalTimes;
323
- if (timeFor51) {
324
- const pkg = [0x00];
325
- BLE.transferFirmwareFileCmd(this.deviceId, pkg, true, this.fail.bind(this));
326
- console.log('[OTA]', '=== Send 51 ===', this.finishedTimes, this.totalTimes, pkg);
327
- } else {
328
- const pkg = this.fileHexArray.slice(this.finishedTimes * max, nextTime * max);
329
- const index = Transfer.decimalToTwoByteHexArray(this.finishedTimes);
330
- BLE.transferFirmwareFileCmd(this.deviceId, index.concat(pkg), false, this.fail.bind(this));
331
- console.log('[OTA]', `S50-${this.finishedTimes}/${this.totalTimes}`);
332
- }
333
- this.onProgress && this.onProgress({ type: 'upgrade', percent: Math.floor((this.finishedTimes * 100) / this.totalTimes) });
334
- }
335
-
336
- async startOTA() {
337
- BLE.writeATCmd(this.otaStart, this.deviceId, this.fail.bind(this));
338
- }
339
-
340
- fail(msg) {
341
- this.succeed = false;
342
- this.onError && this.onError(msg);
343
- }
344
-
345
- sleep(n = 50) {
346
- return new Promise((r) => setTimeout(() => r(true), n));
347
- }
348
- }
349
-
350
- export default OTAUpgrade;
1
+ import { getOS } from './commonfun';
2
+ import { TelinkApi } from './TelinkApi';
3
+ import Transfer, { BLE } from './Transfer';
4
+
5
+ const max = BLE.PACKAGE_MAX_LENGTH;
6
+ const delayDefault = BLE.WRITE_DELAY;
7
+ const { isIOS, isAndroid } = getOS();
8
+
9
+ function getBuffer(hexArr) {
10
+ const buffer = new ArrayBuffer(hexArr.length);
11
+ const dataView = new DataView(buffer);
12
+ hexArr.forEach((hex, i) => dataView.setUint8(i, hex));
13
+ return buffer;
14
+ }
15
+
16
+ /**
17
+ * const ota = new OTAUpgrade({
18
+ * deviceId,
19
+ * macAddr,
20
+ * filePath,
21
+ * otaInfo,
22
+ * otaStart,
23
+ * otaReStart,
24
+ * isTeLink, // 是否 Telink 升级
25
+ * onProgress, // 升级进度回调
26
+ * onSuccess, // 升级成功回调
27
+ * onError, // 升级失败回调
28
+ * delay, // 写入延时,默认20ms,iOS可适当调大一些
29
+ * });
30
+ * ota.start();
31
+ **/
32
+
33
+ export class OTAUpgrade {
34
+ constructor({ deviceId, filePath, otaInfo, otaStart, otaReStart, macAddr, onProgress, onSuccess, onError, delay, platform = 'APP' }) {
35
+ this.deviceId = deviceId;
36
+ this.filePath = filePath;
37
+ this.otaInfo = otaInfo;
38
+ this.otaStart = otaStart;
39
+ this.otaReStart = otaReStart;
40
+ this.macAddr = macAddr;
41
+ this.platform = platform; // 'APP' | 'MP' | 'H5'
42
+ // 自动判断是否Telink,入参为macAddr
43
+ this.isTeLink = TelinkApi.isTeLink ? TelinkApi.isTeLink({
44
+ macAddr
45
+ }) : false;
46
+ this.onProgress = onProgress;
47
+ this.onSuccess = onSuccess;
48
+ this.onError = onError;
49
+ this.delay = delay || delayDefault;
50
+ this.fileHexArray = [];
51
+ this.totalTimes = 1;
52
+ this.finishedTimes = 0;
53
+ this.succeed = false;
54
+ this.ready = true;
55
+ this.timer = null;
56
+ this.s_progress = 0;
57
+ this.otaStarting = false;
58
+ this.progressType = 'download'; // 当前进度类型: 'download' | 'upgrade'
59
+ }
60
+
61
+ async start() {
62
+ this.progressType = 'download';
63
+ try {
64
+ await this.download();
65
+ } catch (e) {
66
+ this.fail('下载失败: ' + e.message);
67
+ }
68
+ }
69
+
70
+ async download() {
71
+ const that = this;
72
+ return new Promise((resolve, reject) => {
73
+ const downloadTask = uni.downloadFile({
74
+ url: that.filePath,
75
+ success: ({ tempFilePath }) => {
76
+ this.addBLECharValueChangeListener();
77
+ that.resolve(tempFilePath).then(resolve).catch(reject);
78
+ },
79
+ fail: (res) => {
80
+ that.fail('固件下载失败');
81
+ reject(res);
82
+ },
83
+ });
84
+ downloadTask.onProgressUpdate &&
85
+ downloadTask.onProgressUpdate(({ progress }) => {
86
+ that.onProgress && that.onProgress({ type: 'download', percent: progress });
87
+ });
88
+ });
89
+ }
90
+
91
+ async resolve(tempFilePath) {
92
+ const that = this;
93
+ return new Promise((resolve, reject) => {
94
+ uni.saveFile({
95
+ tempFilePath,
96
+ success: ({ savedFilePath }) => {
97
+ if (this.platform === 'APP') {
98
+ plus.io.resolveLocalFileSystemURL(
99
+ savedFilePath,
100
+ (entry) => {
101
+ entry.file((file) => {
102
+ var fileReader = new plus.io.FileReader();
103
+ fileReader.readAsDataURL(file);
104
+ fileReader.onloadend = (e) => {
105
+ let base64 = e.target.result.split(',')[1];
106
+ const hexArray = Transfer.base64ToHexArray(base64);
107
+ const times = Math.ceil(hexArray.length / (that.isTeLink ? 16 : max));
108
+ that.fileHexArray = hexArray;
109
+ that.totalTimes = times;
110
+ that.finishedTimes = 0;
111
+ // 切换进度类型为升级
112
+ that.progressType = 'upgrade';
113
+ that.isTeLink ? that.telinkUpgrade() : that.normalUpgrade();
114
+ resolve();
115
+ };
116
+ fileReader.onerror = (e) => {
117
+ that.fail('固件解析失败');
118
+ reject(e);
119
+ };
120
+ });
121
+ },
122
+ (err) => {
123
+ that.fail('固件保存失败');
124
+ reject(err);
125
+ }
126
+ );
127
+ } else if (this.platform === 'MP') {
128
+ // 微信小程序读取本地文件为base64
129
+ const fs = wx.getFileSystemManager();
130
+ fs.readFile({
131
+ filePath: savedFilePath,
132
+ encoding: 'base64',
133
+ success: (res) => {
134
+ // res.data 为 base64 字符串
135
+ let base64 = res.data;
136
+ const hexArray = Transfer.base64ToHexArray(base64);
137
+ const times = Math.ceil(hexArray.length / (that.isTeLink ? 16 : max));
138
+ that.fileHexArray = hexArray;
139
+ that.totalTimes = times;
140
+ that.finishedTimes = 0;
141
+ // 切换进度类型为升级
142
+ that.progressType = 'upgrade';
143
+ that.isTeLink ? that.telinkUpgrade() : that.normalUpgrade();
144
+ resolve();
145
+ },
146
+ fail: (err) => {
147
+ console.error('[OTA] resolve failed:', JSON.stringify(err));
148
+ that.failed('文件解析失败');
149
+ },
150
+ });
151
+ }
152
+ },
153
+ fail: (res) => {
154
+ that.fail('固件保存失败');
155
+ reject(res);
156
+ },
157
+ });
158
+ });
159
+ }
160
+
161
+ // 普通升级流程
162
+ normalUpgrade() {
163
+ setTimeout(() => {
164
+ BLE.writeATCmd(this.otaInfo, this.deviceId, this.fail.bind(this));
165
+ }, 2600);
166
+ }
167
+
168
+ // Telink 升级流程
169
+ telinkUpgrade() {
170
+ this.write(['0x00', '0xff'], 0);
171
+ }
172
+
173
+ write(pkg, type) {
174
+ const value = getBuffer(pkg.map((o) => parseInt(o, 16)));
175
+ const opt = {
176
+ deviceId: this.deviceId,
177
+ serviceId: '00010203-0405-0607-0809-0a0b0c0d1912',
178
+ characteristicId: '00010203-0405-0607-0809-0a0b0c0d2b12',
179
+ value,
180
+ success: () => this.onSucceed(type),
181
+ fail: async () => {
182
+ await this.sleep(this.delay * 2);
183
+ uni.writeBLECharacteristicValue({
184
+ ...opt,
185
+ fail: async () => {
186
+ await this.sleep(this.delay * 2);
187
+ uni.writeBLECharacteristicValue({
188
+ ...opt, fail: () => {
189
+ console.error('写入失败: ', pkg);
190
+ this.fail('写入失败');
191
+ } });
192
+ },
193
+ });
194
+ },
195
+ };
196
+ uni.writeBLECharacteristicValue(opt);
197
+ if (isIOS) setTimeout(() => this.onSucceed(type), 5);
198
+ }
199
+
200
+ onSucceed(type) {
201
+ if (type == 0) {
202
+ this.write(['0x01', '0xff'], 1);
203
+ } else if (type == 1) {
204
+ this.sendNextOtaPacketCommand();
205
+ } else if (type == 2) {
206
+ this.finishedTimes++;
207
+ this.sendNextOtaPacketCommand();
208
+ } else if (type == 3) {
209
+ this.sendNextOtaPacketCommand();
210
+ } else if (type == 4) {
211
+ this.sendOtaEndCommand();
212
+ } else if (type == 5) {
213
+ this.finishedTimes++;
214
+ this.succeed = true;
215
+ this.onSuccess && this.onSuccess();
216
+ }
217
+ this.onProgress && this.onProgress({ type: 'upgrade', percent: Math.floor((this.finishedTimes * 100) / this.totalTimes) });
218
+ }
219
+
220
+ async sendNextOtaPacketCommand() {
221
+ const i = this.finishedTimes;
222
+ const maxLen = 16;
223
+ const index = TelinkApi.getIndexHexArr(i);
224
+ let pkgValue = this.fileHexArray.slice(i * maxLen, (i + 1) * maxLen);
225
+ if (pkgValue.length < maxLen) {
226
+ pkgValue = pkgValue.concat([...Array(maxLen - pkgValue.length)].map(() => '0xFF'));
227
+ }
228
+ const crc = TelinkApi.genCheck([...index, ...pkgValue]);
229
+ const pkg = [...index, ...pkgValue, ...crc];
230
+ const type = i >= this.totalTimes - 1 ? 4 : 2;
231
+ await this.sleep(this.delay);
232
+ this.write(pkg, type);
233
+ }
234
+
235
+ sendOtaEndCommand() {
236
+ function genEnd(i, c = 0xff02) {
237
+ return [c & 0xff, (c >> 8) & 0xff, i & 0xff, (i >> 8) & 0xff, ~i & 0xff, (~i >> 8) & 0xff].map((o) => `0x${`00${o.toString(16)}`.slice(-2)}`.toUpperCase());
238
+ }
239
+ const pkgValue = genEnd(this.totalTimes - 1);
240
+ const crc = TelinkApi.genCheck([...pkgValue]);
241
+ const pkg = [...pkgValue, ...crc];
242
+ this.write(pkg, 5);
243
+ }
244
+
245
+ addBLECharValueChangeListener() {
246
+ console.log('添加蓝牙特征值变化监听');
247
+ const that = this;
248
+ uni.notifyBLECharacteristicValueChange({
249
+ deviceId: that.deviceId,
250
+ serviceId: BLE.serviceId,
251
+ characteristicId: BLE.readUUID,
252
+ state: true,
253
+ success: () => {},
254
+ fail: () => {},
255
+ });
256
+ that.ready = true;
257
+ that.readValue = [];
258
+ that.receiveLength = null;
259
+ uni.onBLECharacteristicValueChange(({ deviceId, serviceId, characteristicId, value }) => {
260
+ if (!that.ready) return;
261
+ if (deviceId == that.deviceId && serviceId == BLE.serviceId) {
262
+ const intArr = Array.prototype.map.call(new Uint8Array(value), (x) => x);
263
+ if (intArr.length > 0) {
264
+ if (that.receiveLength == null && intArr[0] == 0xff && intArr[1] == 0xaa) {
265
+ that.receiveLength = intArr[3] + 5;
266
+ }
267
+ if (that.receiveLength) {
268
+ that.readValue = that.readValue.concat(intArr);
269
+ if (that.readValue.length == that.receiveLength) {
270
+ that.doWithResponse([...that.readValue]);
271
+ that.readValue = [];
272
+ that.receiveLength = null;
273
+ }
274
+ } else {
275
+ that.readValue = [];
276
+ that.receiveLength = null;
277
+ }
278
+ }
279
+ }
280
+ });
281
+ }
282
+
283
+ async doWithResponse(intArr) {
284
+ console.log('收到设备响应: ', intArr[2]);
285
+ if (intArr[2] == 0x80) {
286
+ let str = String.fromCharCode(...intArr.slice(4, -1));
287
+ console.log('doWithResponse otaStart1', str);
288
+ if (str.indexOf(this.otaInfo) > -1) {
289
+ this.finishedTimes = 0;
290
+ this.transferFirmwareFile();
291
+ }
292
+ if (str.indexOf(this.otaStart) > -1 || this.otaStarting) {
293
+ if (str.indexOf(this.otaStart) > -1) {
294
+ this.otaStarting = true;
295
+ }
296
+ console.log('doWithResponse otaStart2', str);
297
+ if (str.toUpperCase().includes('ERROR')) {
298
+ this.fail(str);
299
+ return;
300
+ }
301
+ if (str.toUpperCase().indexOf('S100') > -1) {
302
+ this.succeed = true;
303
+ this.onSuccess && this.onSuccess();
304
+ }
305
+ }
306
+ }
307
+ if (intArr[2] == 0x50) {
308
+ if (intArr[4] == 0) {
309
+ this.finishedTimes++;
310
+ this.transferFirmwareFile();
311
+ } else {
312
+ this.transferFirmwareFile();
313
+ }
314
+ }
315
+ if (intArr[2] == 0x51) {
316
+ if (intArr[4] == 0) {
317
+ this.startOTA();
318
+ } else {
319
+ this.fail('升级失败');
320
+ }
321
+ }
322
+ }
323
+
324
+ async transferFirmwareFile() {
325
+ let nextTime = this.finishedTimes + 1;
326
+ const timeFor51 = nextTime > this.totalTimes;
327
+ if (timeFor51) {
328
+ const pkg = [0x00];
329
+ await BLE.sendDelay(this.delay);
330
+ BLE.transferFirmwareFileCmd(this.deviceId, pkg, true, this.fail.bind(this));
331
+ console.log('[OTA]', '=== Send 51 ===', this.finishedTimes, this.totalTimes, pkg);
332
+ } else {
333
+ const pkg = this.fileHexArray.slice(this.finishedTimes * max, nextTime * max);
334
+ const index = Transfer.decimalToTwoByteHexArray(this.finishedTimes);
335
+ await BLE.sendDelay(this.delay);
336
+ BLE.transferFirmwareFileCmd(this.deviceId, index.concat(pkg), false, this.fail.bind(this));
337
+ console.log('[OTA]', `S50-${this.finishedTimes}/${this.totalTimes}`);
338
+ }
339
+ this.onProgress && this.onProgress({ type: 'upgrade', percent: Math.floor((this.finishedTimes * 100) / this.totalTimes) });
340
+ }
341
+
342
+ async startOTA() {
343
+ BLE.writeATCmd(this.otaStart, this.deviceId, this.fail.bind(this));
344
+ }
345
+
346
+ fail(msg) {
347
+ this.succeed = false;
348
+ this.onError && this.onError(msg);
349
+ }
350
+
351
+ sleep(n = 50) {
352
+ return new Promise((r) => setTimeout(() => r(true), n));
353
+ }
354
+ }
355
+
356
+ export default OTAUpgrade;