@jiabaida/tools 1.0.0 → 1.0.1
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/cjs/core/BleApiManager.js +1 -1
- package/dist/cjs/core/BleCmdAnalysis/BaseParamProtocol.js +1 -0
- package/dist/cjs/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -0
- package/dist/cjs/core/BleCmdAnalysis/BleCmdDD.js +1 -0
- package/dist/cjs/core/BleCmdAnalysis/BleCmdFFAA.js +1 -0
- package/dist/cjs/core/BleCmdAnalysis/BleCmdHVES.js +1 -0
- package/dist/cjs/core/BleCmdAnalysis/ESHostProtocol.js +1 -0
- package/dist/cjs/core/BleCmdAnalysis/readAndSetParam.js +1 -0
- package/dist/cjs/core/BleCmdAnalysis.js +1 -0
- package/dist/cjs/core/BleDataProcess.js +1 -0
- package/dist/cjs/core/OtaUpgrade.js +1 -0
- package/dist/cjs/core/TelinkApi.js +1 -0
- package/dist/cjs/core/Transfer.js +1 -0
- package/dist/cjs/core/commonfun.js +1 -1
- package/dist/cjs/core/dataJson/baseParamsJson.js +1 -0
- package/dist/cjs/core/keyAndPwdManager.js +1 -0
- package/dist/cjs/index.js +1 -1
- package/dist/esm/core/BleApiManager.js +1 -1
- package/dist/esm/core/BleCmdAnalysis/BaseParamProtocol.js +1 -0
- package/dist/esm/core/BleCmdAnalysis/BleCmdAnalysis.js +1 -0
- package/dist/esm/core/BleCmdAnalysis/BleCmdDD.js +1 -0
- package/dist/esm/core/BleCmdAnalysis/BleCmdFFAA.js +1 -0
- package/dist/esm/core/BleCmdAnalysis/BleCmdHVES.js +1 -0
- package/dist/esm/core/BleCmdAnalysis/ESHostProtocol.js +1 -0
- package/dist/esm/core/BleCmdAnalysis/readAndSetParam.js +1 -0
- package/dist/esm/core/BleCmdAnalysis.js +1 -0
- package/dist/esm/core/BleDataProcess.js +1 -0
- package/dist/esm/core/OtaUpgrade.js +1 -0
- package/dist/esm/core/TelinkApi.js +1 -0
- package/dist/esm/core/Transfer.js +1 -0
- package/dist/esm/core/commonfun.js +1 -1
- package/dist/esm/core/dataJson/baseParamsJson.js +1 -0
- package/dist/esm/core/keyAndPwdManager.js +1 -0
- package/dist/esm/index.js +1 -1
- package/package.json +13 -3
- package/src/core/BleApiManager.js +487 -0
- package/src/core/BleCmdAnalysis/BaseParamProtocol.js +651 -0
- package/src/core/BleCmdAnalysis/BleCmdAnalysis.js +220 -0
- package/src/core/BleCmdAnalysis/BleCmdDD.js +1214 -0
- package/src/core/BleCmdAnalysis/BleCmdDDA4.js +762 -0
- package/src/core/BleCmdAnalysis/BleCmdFFAA.js +407 -0
- package/src/core/BleCmdAnalysis/BleCmdHVES.js +1222 -0
- package/src/core/BleCmdAnalysis/ESHostProtocol.js +829 -0
- package/src/core/BleCmdAnalysis/index.js +7 -0
- package/src/core/BleCmdAnalysis/readAndSetParam.js +288 -0
- package/src/core/BleDataProcess.js +355 -0
- package/src/core/OtaUpgrade.js +338 -0
- package/src/core/TelinkApi.js +73 -0
- package/src/core/Transfer.js +516 -0
- package/src/core/array.js +10 -0
- package/src/core/commonfun.js +84 -0
- package/src/core/dataJson/baseParamsJson.js +754 -0
- package/src/core/dataJson/index.js +1 -0
- package/src/core/keyAndPwdManager.js +346 -0
- package/src/core/mqttServer.js +296 -0
- package/src/core/rsaEncrypt.js +45 -0
- package/src/index.js +11 -0
|
@@ -0,0 +1,338 @@
|
|
|
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(macAddr) : false;
|
|
44
|
+
this.onProgress = onProgress;
|
|
45
|
+
this.onSuccess = onSuccess;
|
|
46
|
+
this.onError = onError;
|
|
47
|
+
this.delay = delay || delayDefault;
|
|
48
|
+
this.fileHexArray = [];
|
|
49
|
+
this.totalTimes = 1;
|
|
50
|
+
this.finishedTimes = 0;
|
|
51
|
+
this.succeed = false;
|
|
52
|
+
this.ready = true;
|
|
53
|
+
this.timer = null;
|
|
54
|
+
this.s_progress = 0;
|
|
55
|
+
this.progressType = 'download'; // 当前进度类型: 'download' | 'upgrade'
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async start() {
|
|
59
|
+
this.progressType = 'download';
|
|
60
|
+
try {
|
|
61
|
+
await this.download();
|
|
62
|
+
} catch (e) {
|
|
63
|
+
this.fail('下载失败: ' + e.message);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async download() {
|
|
68
|
+
const that = this;
|
|
69
|
+
return new Promise((resolve, reject) => {
|
|
70
|
+
const downloadTask = uni.downloadFile({
|
|
71
|
+
url: that.filePath,
|
|
72
|
+
success: ({ tempFilePath }) => {
|
|
73
|
+
that.resolve(tempFilePath).then(resolve).catch(reject);
|
|
74
|
+
},
|
|
75
|
+
fail: (res) => {
|
|
76
|
+
that.fail('固件下载失败');
|
|
77
|
+
reject(res);
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
downloadTask.onProgressUpdate &&
|
|
81
|
+
downloadTask.onProgressUpdate(({ progress }) => {
|
|
82
|
+
that.onProgress && that.onProgress({ type: 'download', percent: progress });
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async resolve(tempFilePath) {
|
|
88
|
+
const that = this;
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
uni.saveFile({
|
|
91
|
+
tempFilePath,
|
|
92
|
+
success: ({ savedFilePath }) => {
|
|
93
|
+
if (this.platform === 'APP') {
|
|
94
|
+
plus.io.resolveLocalFileSystemURL(
|
|
95
|
+
savedFilePath,
|
|
96
|
+
(entry) => {
|
|
97
|
+
entry.file((file) => {
|
|
98
|
+
var fileReader = new plus.io.FileReader();
|
|
99
|
+
fileReader.readAsDataURL(file);
|
|
100
|
+
fileReader.onloadend = (e) => {
|
|
101
|
+
let base64 = e.target.result.split(',')[1];
|
|
102
|
+
const hexArray = Transfer.base64ToHexArray(base64);
|
|
103
|
+
const times = Math.ceil(hexArray.length / (that.isTeLink ? 16 : max));
|
|
104
|
+
that.fileHexArray = hexArray;
|
|
105
|
+
that.totalTimes = times;
|
|
106
|
+
that.finishedTimes = 0;
|
|
107
|
+
// 切换进度类型为升级
|
|
108
|
+
that.progressType = 'upgrade';
|
|
109
|
+
that.isTeLink ? that.telinkUpgrade() : that.normalUpgrade();
|
|
110
|
+
resolve();
|
|
111
|
+
};
|
|
112
|
+
fileReader.onerror = (e) => {
|
|
113
|
+
that.fail('固件解析失败');
|
|
114
|
+
reject(e);
|
|
115
|
+
};
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
(err) => {
|
|
119
|
+
that.fail('固件保存失败');
|
|
120
|
+
reject(err);
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
} else if (this.platform === 'MP') {
|
|
124
|
+
// 微信小程序读取本地文件为base64
|
|
125
|
+
const fs = wx.getFileSystemManager();
|
|
126
|
+
fs.readFile({
|
|
127
|
+
filePath: savedFilePath,
|
|
128
|
+
encoding: 'base64',
|
|
129
|
+
success: (res) => {
|
|
130
|
+
// res.data 为 base64 字符串
|
|
131
|
+
let base64 = res.data;
|
|
132
|
+
const hexArray = Transfer.base64ToHexArray(base64);
|
|
133
|
+
const times = Math.ceil(hexArray.length / (that.isTeLink ? 16 : max));
|
|
134
|
+
that.fileHexArray = hexArray;
|
|
135
|
+
that.totalTimes = times;
|
|
136
|
+
that.finishedTimes = 0;
|
|
137
|
+
// 切换进度类型为升级
|
|
138
|
+
that.progressType = 'upgrade';
|
|
139
|
+
that.isTeLink ? that.telinkUpgrade() : that.normalUpgrade();
|
|
140
|
+
resolve();
|
|
141
|
+
},
|
|
142
|
+
fail: (err) => {
|
|
143
|
+
console.error('[OTA] resolve failed:', JSON.stringify(err));
|
|
144
|
+
that.failed('文件解析失败');
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
fail: (res) => {
|
|
150
|
+
that.fail('固件保存失败');
|
|
151
|
+
reject(res);
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// 普通升级流程
|
|
158
|
+
normalUpgrade() {
|
|
159
|
+
setTimeout(() => {
|
|
160
|
+
BLE.writeATCmd(this.otaInfo, this.deviceId, this.fail.bind(this));
|
|
161
|
+
this.addBLECharValueChangeListener();
|
|
162
|
+
}, 2600);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Telink 升级流程
|
|
166
|
+
telinkUpgrade() {
|
|
167
|
+
this.write(['0x00', '0xff'], 0);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
write(pkg, type) {
|
|
171
|
+
const value = getBuffer(pkg.map((o) => parseInt(o, 16)));
|
|
172
|
+
const opt = {
|
|
173
|
+
deviceId: this.deviceId,
|
|
174
|
+
serviceId: '00010203-0405-0607-0809-0a0b0c0d1912',
|
|
175
|
+
characteristicId: '00010203-0405-0607-0809-0a0b0c0d2b12',
|
|
176
|
+
value,
|
|
177
|
+
success: () => this.onSucceed(type),
|
|
178
|
+
fail: async () => {
|
|
179
|
+
await this.sleep(this.delay * 2);
|
|
180
|
+
uni.writeBLECharacteristicValue({
|
|
181
|
+
...opt,
|
|
182
|
+
fail: async () => {
|
|
183
|
+
await this.sleep(this.delay * 2);
|
|
184
|
+
uni.writeBLECharacteristicValue({ ...opt, fail: this.fail.bind(this) });
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
uni.writeBLECharacteristicValue(opt);
|
|
190
|
+
if (isIOS) setTimeout(() => this.onSucceed(type), 5);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
onSucceed(type) {
|
|
194
|
+
if (type == 0) {
|
|
195
|
+
this.write(['0x01', '0xff'], 1);
|
|
196
|
+
} else if (type == 1) {
|
|
197
|
+
this.sendNextOtaPacketCommand();
|
|
198
|
+
} else if (type == 2) {
|
|
199
|
+
this.finishedTimes++;
|
|
200
|
+
this.sendNextOtaPacketCommand();
|
|
201
|
+
} else if (type == 3) {
|
|
202
|
+
this.sendNextOtaPacketCommand();
|
|
203
|
+
} else if (type == 4) {
|
|
204
|
+
this.sendOtaEndCommand();
|
|
205
|
+
} else if (type == 5) {
|
|
206
|
+
this.finishedTimes++;
|
|
207
|
+
this.succeed = true;
|
|
208
|
+
this.onSuccess && this.onSuccess();
|
|
209
|
+
}
|
|
210
|
+
this.onProgress && this.onProgress({ type: 'upgrade', percent: Math.floor((this.finishedTimes * 100) / this.totalTimes) });
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async sendNextOtaPacketCommand() {
|
|
214
|
+
const i = this.finishedTimes;
|
|
215
|
+
const maxLen = 16;
|
|
216
|
+
const index = TelinkApi.getIndexHexArr(i);
|
|
217
|
+
let pkgValue = this.fileHexArray.slice(i * maxLen, (i + 1) * maxLen);
|
|
218
|
+
if (pkgValue.length < maxLen) {
|
|
219
|
+
pkgValue = pkgValue.concat([...Array(maxLen - pkgValue.length)].map(() => '0xFF'));
|
|
220
|
+
}
|
|
221
|
+
const crc = TelinkApi.genCheck([...index, ...pkgValue]);
|
|
222
|
+
const pkg = [...index, ...pkgValue, ...crc];
|
|
223
|
+
const type = i >= this.totalTimes - 1 ? 4 : 2;
|
|
224
|
+
await this.sleep(this.delay);
|
|
225
|
+
this.write(pkg, type);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
sendOtaEndCommand() {
|
|
229
|
+
function genEnd(i, c = 0xff02) {
|
|
230
|
+
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());
|
|
231
|
+
}
|
|
232
|
+
const pkgValue = genEnd(this.totalTimes - 1);
|
|
233
|
+
const crc = TelinkApi.genCheck([...pkgValue]);
|
|
234
|
+
const pkg = [...pkgValue, ...crc];
|
|
235
|
+
this.write(pkg, 5);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
addBLECharValueChangeListener() {
|
|
239
|
+
const that = this;
|
|
240
|
+
uni.notifyBLECharacteristicValueChange({
|
|
241
|
+
deviceId: that.deviceId,
|
|
242
|
+
serviceId: BLE.serviceId,
|
|
243
|
+
characteristicId: BLE.readUUID,
|
|
244
|
+
state: true,
|
|
245
|
+
success: () => {},
|
|
246
|
+
fail: () => {},
|
|
247
|
+
});
|
|
248
|
+
that.ready = true;
|
|
249
|
+
that.readValue = [];
|
|
250
|
+
that.receiveLength = null;
|
|
251
|
+
uni.onBLECharacteristicValueChange(({ deviceId, serviceId, characteristicId, value }) => {
|
|
252
|
+
if (!that.ready) return;
|
|
253
|
+
if (deviceId == that.deviceId && serviceId == BLE.serviceId) {
|
|
254
|
+
const intArr = Array.prototype.map.call(new Uint8Array(value), (x) => x);
|
|
255
|
+
if (intArr.length > 0) {
|
|
256
|
+
if (that.receiveLength == null && intArr[0] == 0xff && intArr[1] == 0xaa) {
|
|
257
|
+
that.receiveLength = intArr[3] + 5;
|
|
258
|
+
}
|
|
259
|
+
if (that.receiveLength) {
|
|
260
|
+
that.readValue = that.readValue.concat(intArr);
|
|
261
|
+
if (that.readValue.length == that.receiveLength) {
|
|
262
|
+
that.doWithResponse([...that.readValue]);
|
|
263
|
+
that.readValue = [];
|
|
264
|
+
that.receiveLength = null;
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
that.readValue = [];
|
|
268
|
+
that.receiveLength = null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async doWithResponse(intArr) {
|
|
276
|
+
if (intArr[2] == 0x80) {
|
|
277
|
+
let str = String.fromCharCode(...intArr.slice(4, -1));
|
|
278
|
+
if (str.indexOf(this.otaInfo) > -1) {
|
|
279
|
+
this.finishedTimes = 0;
|
|
280
|
+
this.transferFirmwareFile();
|
|
281
|
+
}
|
|
282
|
+
if (str.indexOf(this.otaStart) > -1) {
|
|
283
|
+
if (str.toUpperCase().includes('ERROR')) {
|
|
284
|
+
this.fail(str);
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
if (str.toUpperCase().indexOf('S100') > -1) {
|
|
288
|
+
this.succeed = true;
|
|
289
|
+
this.onSuccess && this.onSuccess();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
if (intArr[2] == 0x50) {
|
|
294
|
+
if (intArr[4] == 0) {
|
|
295
|
+
this.finishedTimes++;
|
|
296
|
+
this.transferFirmwareFile();
|
|
297
|
+
} else {
|
|
298
|
+
this.transferFirmwareFile();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (intArr[2] == 0x51) {
|
|
302
|
+
if (intArr[4] == 0) {
|
|
303
|
+
this.startOTA();
|
|
304
|
+
} else {
|
|
305
|
+
this.fail('升级失败');
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
transferFirmwareFile() {
|
|
311
|
+
let nextTime = this.finishedTimes + 1;
|
|
312
|
+
const timeFor51 = nextTime > this.totalTimes;
|
|
313
|
+
if (timeFor51) {
|
|
314
|
+
const pkg = [0x00];
|
|
315
|
+
BLE.transferFirmwareFileCmd(this.deviceId, pkg, true, this.fail.bind(this));
|
|
316
|
+
} else {
|
|
317
|
+
const pkg = this.fileHexArray.slice(this.finishedTimes * max, nextTime * max);
|
|
318
|
+
const index = Transfer.decimalToTwoByteHexArray(nextTime);
|
|
319
|
+
BLE.transferFirmwareFileCmd(this.deviceId, index.concat(pkg), false, this.fail.bind(this));
|
|
320
|
+
}
|
|
321
|
+
this.onProgress && this.onProgress({ type: 'upgrade', percent: Math.floor((this.finishedTimes * 100) / this.totalTimes) });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async startOTA() {
|
|
325
|
+
BLE.writeATCmd(this.otaStart, this.deviceId, this.fail.bind(this));
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
fail(msg) {
|
|
329
|
+
this.succeed = false;
|
|
330
|
+
this.onError && this.onError(msg);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
sleep(n = 50) {
|
|
334
|
+
return new Promise((r) => setTimeout(() => r(true), n));
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export default OTAUpgrade;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { getChipTypeAsync, getDDA503Async, resolveDDA500, resolveDDA503 } from './BleCmdAnalysis/BleCmdDD';
|
|
2
|
+
const serviceId = '00010203-0405-0607-0809-0a0b0c0d1912';
|
|
3
|
+
const characteristicId = '00010203-0405-0607-0809-0a0b0c0d2b12';
|
|
4
|
+
export class TelinkApi {
|
|
5
|
+
static async checkOTAAvailable({ deviceId, macAddr }) {
|
|
6
|
+
const prefix = macAddr.slice(0, 8).toUpperCase();
|
|
7
|
+
try {
|
|
8
|
+
if (prefix == 'A5:C2:37') {
|
|
9
|
+
const socRes = await getChipTypeAsync(deviceId);
|
|
10
|
+
console.warn('芯片类型', socRes);
|
|
11
|
+
if (socRes && socRes?.type == 5) {
|
|
12
|
+
const versionHex = await getDDA503Async(deviceId);
|
|
13
|
+
const versionRes = resolveDDA503(versionHex);
|
|
14
|
+
console.warn('版本信息', versionRes);
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
} catch (error) {}
|
|
19
|
+
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
static isTeLink({ macAddr = '' } = { macAddr: '' }) {
|
|
23
|
+
const prefix1 = macAddr.slice(0, 2).toUpperCase();
|
|
24
|
+
const prefix = macAddr.slice(0, 8).toUpperCase();
|
|
25
|
+
// 内置板
|
|
26
|
+
return (prefix1 == 'A5' || prefix == 'A4:C1:38');
|
|
27
|
+
}
|
|
28
|
+
static getIndexHexArr(i) {
|
|
29
|
+
return i
|
|
30
|
+
.toString(16)
|
|
31
|
+
.padStart(4, '0')
|
|
32
|
+
.match(/(.{2})/g)
|
|
33
|
+
?.reverse()
|
|
34
|
+
.map((o) => `0x${o.toUpperCase()}`);
|
|
35
|
+
}
|
|
36
|
+
static crc16modbus(data, swapNeed = false) {
|
|
37
|
+
let crc = 0xffff;
|
|
38
|
+
for (let i = 0; i < data.length; i++) {
|
|
39
|
+
crc ^= data[i];
|
|
40
|
+
for (let j = 0; j < 8; j++) {
|
|
41
|
+
if (crc & 0x0001) {
|
|
42
|
+
crc = (crc >> 1) ^ 0xa001;
|
|
43
|
+
} else {
|
|
44
|
+
crc = crc >> 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// swap crc
|
|
49
|
+
if (swapNeed) crc = ((crc & 0xff) << 8) | ((crc >> 8) & 0xff);
|
|
50
|
+
return crc & 0xffff;
|
|
51
|
+
}
|
|
52
|
+
static decimalToHex(decimal, padding = 4) {
|
|
53
|
+
const hexDigits = [];
|
|
54
|
+
const hexMap = { 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F' };
|
|
55
|
+
|
|
56
|
+
while (decimal > 0) {
|
|
57
|
+
const remainder = decimal % 16;
|
|
58
|
+
if (remainder >= 10) {
|
|
59
|
+
// @ts-ignore
|
|
60
|
+
hexDigits.unshift(hexMap[remainder]);
|
|
61
|
+
} else {
|
|
62
|
+
hexDigits.unshift(`${remainder}`);
|
|
63
|
+
}
|
|
64
|
+
decimal = Math.floor(decimal / 16);
|
|
65
|
+
}
|
|
66
|
+
return hexDigits.join('').padStart(padding, '0');
|
|
67
|
+
}
|
|
68
|
+
static genCheck(data) {
|
|
69
|
+
const hex = this.crc16modbus(data, true);
|
|
70
|
+
const hexStr = this.decimalToHex(hex);
|
|
71
|
+
return [`0x${hexStr.slice(0, 2)}`, `0x${hexStr.slice(2, 4)}`];
|
|
72
|
+
}
|
|
73
|
+
}
|