node-zserial 1.0.23 → 1.0.25
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/package.json +1 -1
- package/zserial.js +104 -43
package/package.json
CHANGED
package/zserial.js
CHANGED
|
@@ -24,7 +24,7 @@ module.exports = function (RED) {
|
|
|
24
24
|
node.send(msg);
|
|
25
25
|
done();
|
|
26
26
|
}, node);
|
|
27
|
-
}
|
|
27
|
+
}
|
|
28
28
|
else if (msg.serialConfigs) {
|
|
29
29
|
let allLen = msg.serialConfigs.length;
|
|
30
30
|
let total = msg.serialConfigs.length;
|
|
@@ -329,7 +329,7 @@ module.exports = function (RED) {
|
|
|
329
329
|
node.successMsg = {};
|
|
330
330
|
node.errorMsg = {};
|
|
331
331
|
node._msg = null
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
function initMsg(msg) {
|
|
334
334
|
node._msg = msg;
|
|
335
335
|
node.totallenth = msg.serialConfigs.length;
|
|
@@ -338,7 +338,7 @@ module.exports = function (RED) {
|
|
|
338
338
|
node.errorMsg = {};
|
|
339
339
|
}
|
|
340
340
|
function zsend(msg, err, alldone, port, done) {
|
|
341
|
-
|
|
341
|
+
|
|
342
342
|
let payload = msg || err;
|
|
343
343
|
node._msg.payload = payload;
|
|
344
344
|
node.totalMsg[port] = payload
|
|
@@ -358,7 +358,6 @@ module.exports = function (RED) {
|
|
|
358
358
|
sendAll(done);
|
|
359
359
|
}
|
|
360
360
|
function onMsg(msg, send, done) {
|
|
361
|
-
|
|
362
361
|
initMsg(msg);
|
|
363
362
|
if (!msg.serialConfigs) {
|
|
364
363
|
node.error("需要配置批量配置:msg.serialConfigs");
|
|
@@ -370,14 +369,14 @@ module.exports = function (RED) {
|
|
|
370
369
|
for (var i = 0; i < msg.serialConfigs.length; i++) {
|
|
371
370
|
var serialConfig = msg.serialConfigs[i];
|
|
372
371
|
serialConfig._msgid = msg._msgid + "_" + i;
|
|
373
|
-
getSerialServer(msg, serialConfig, done);
|
|
372
|
+
getSerialServer( msg, serialConfig, done);
|
|
374
373
|
}
|
|
375
374
|
}
|
|
376
375
|
|
|
377
376
|
function sendAll(done) {
|
|
377
|
+
|
|
378
378
|
try {
|
|
379
379
|
let len = Object.keys(node.totalMsg).length;
|
|
380
|
-
|
|
381
380
|
if (len == node.totallenth) {
|
|
382
381
|
let payload = {
|
|
383
382
|
totalMsg: node.totalMsg,
|
|
@@ -501,57 +500,69 @@ module.exports = function (RED) {
|
|
|
501
500
|
|
|
502
501
|
}
|
|
503
502
|
|
|
503
|
+
function isCurNode(msgout, curMsg, _ndoe, sender) {
|
|
504
|
+
// if (sender == node) { return true; }
|
|
505
|
+
if (msgout.request_msgid && msgout.request_msgid.startsWith(curMsg._msgid)) {
|
|
506
|
+
return true
|
|
507
|
+
}
|
|
508
|
+
return false
|
|
509
|
+
}
|
|
510
|
+
|
|
504
511
|
function setCallback(msg, serialConfig, done) {
|
|
505
512
|
let curPort = serialPool.get(serialConfig);
|
|
506
|
-
//
|
|
507
|
-
if (curPort._isBindEventInit) {
|
|
508
|
-
|
|
509
|
-
}
|
|
513
|
+
// 确保当前节点只绑定一次事件
|
|
514
|
+
// if (curPort._isBindEventInit) {
|
|
515
|
+
// return;
|
|
516
|
+
// }
|
|
510
517
|
// node.warn("setCallback called for " + curPort.serial.path);
|
|
511
|
-
curPort._isBindEventInit = true;
|
|
518
|
+
// curPort._isBindEventInit = true;
|
|
512
519
|
|
|
513
|
-
curPort.
|
|
520
|
+
if (node[`_dataHandler_${curPort.serial.path}`]) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
const dataHandler = function (msgout, sender) {
|
|
514
524
|
if (sender !== node) { return; }
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
525
|
+
try {
|
|
526
|
+
msgout.status = "OK";
|
|
527
|
+
zsend(msgout, null, null, curPort.serial.path, done);
|
|
528
|
+
} catch (error) {
|
|
529
|
+
node.error(error)
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const timeoutHandler = function (msgout, sender) {
|
|
519
535
|
if (sender !== node) { return; }
|
|
520
536
|
msgout.status = "ERR_TIMEOUT";
|
|
521
537
|
msgout.port = curPort.serial.path;
|
|
522
538
|
node.status({ fill: "red", shape: "ring", text: "timeout:::" + curPort.serial.path });
|
|
523
539
|
zsend(null, msgout, null, curPort.serial.path, done);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
curPort.on('initerror', function (port, retryNum, olderr) {
|
|
527
|
-
// zsend(null, {
|
|
528
|
-
// status: "ERR_INIT",
|
|
529
|
-
// text: `请检查端口是否打开,重试次数${retryNum}`,
|
|
530
|
-
// error: olderr,
|
|
531
|
-
// port: port
|
|
532
|
-
// }, null, curPort.serial.path, done);
|
|
533
|
-
});
|
|
540
|
+
}
|
|
534
541
|
|
|
542
|
+
node[`_dataHandler_${curPort.serial.path}`] = dataHandler
|
|
543
|
+
node[`_timeoutHandler_${curPort.serial.path}`] = timeoutHandler
|
|
544
|
+
curPort.on('data', dataHandler);
|
|
545
|
+
curPort.on('timeout', timeoutHandler);
|
|
546
|
+
|
|
547
|
+
node.on('close', function () {
|
|
548
|
+
node[`_dataHandler_${curPort.serial.path}`] = null
|
|
549
|
+
node[`_timeoutHandler_${curPort.serial.path}`] = null
|
|
550
|
+
curPort.off('data', dataHandler);
|
|
551
|
+
curPort.off('timeout', timeoutHandler);
|
|
552
|
+
})
|
|
553
|
+
}
|
|
535
554
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
// text: `重试${retryNum}失败`,
|
|
541
|
-
// port: port
|
|
542
|
-
// }, null, curPort.serial.path, done);
|
|
543
|
-
});
|
|
555
|
+
function afterClosed(port){
|
|
556
|
+
node[`_dataHandler_${port}`] = null
|
|
557
|
+
node[`_timeoutHandler_${port}`] = null
|
|
558
|
+
}
|
|
544
559
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
curPort.on('ready', function (port) {
|
|
549
|
-
// node.warn(`串口已准备好:${port}`);
|
|
550
|
-
});
|
|
560
|
+
if(!node._afterClosed){
|
|
561
|
+
node._afterClosed = afterClosed;
|
|
562
|
+
serialPool.on('afterClosed', node._afterClosed);
|
|
551
563
|
}
|
|
552
564
|
|
|
553
565
|
this.on("input", function (msg, send, done) {
|
|
554
|
-
|
|
555
566
|
onMsg(msg, send, done);
|
|
556
567
|
})
|
|
557
568
|
this.on("close", function (done) {
|
|
@@ -559,7 +570,9 @@ module.exports = function (RED) {
|
|
|
559
570
|
node.successMsg = null;
|
|
560
571
|
node.errorMsg = null;
|
|
561
572
|
try {
|
|
573
|
+
serialPool.off('afterClosed', node._afterClosed);
|
|
562
574
|
serialPool.closeAll(done, node);
|
|
575
|
+
node._afterClosed = null;
|
|
563
576
|
} catch (error) {
|
|
564
577
|
done();
|
|
565
578
|
}
|
|
@@ -876,6 +889,47 @@ module.exports = function (RED) {
|
|
|
876
889
|
return Buffer.from(out);
|
|
877
890
|
}
|
|
878
891
|
|
|
892
|
+
|
|
893
|
+
// GNW 蓝牙帧:7E 7E 7E 5A ... CS 7E A5
|
|
894
|
+
function tryParseBleGNW(input) {
|
|
895
|
+
const b = input;
|
|
896
|
+
if (b.length < 9) return { ok: false }; // 最短:4起始 + 1LEN + 1CMD + 0DATA + 1CS + 2结束
|
|
897
|
+
// 形态判定:必须以 7E 7E 7E 5A 开头
|
|
898
|
+
if (!(b[0] === 0x7E && b[1] === 0x7E && b[2] === 0x7E && b[3] === 0x5A)) {
|
|
899
|
+
// 若不是,看看后面是否有候选起点(容错脏字节)
|
|
900
|
+
const n = b.indexOf(0x7E);
|
|
901
|
+
if (n > 0) return { ok: false, used: n, frame: b.slice(0, n), err: "BLE_NO_7E7E7E5A_AT_START" };
|
|
902
|
+
return { ok: false };
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
// 向后找结束 A5,要求倒数第二个字节是 0x7E(结束符 7E A5)
|
|
906
|
+
let endPos = -1;
|
|
907
|
+
for (let i = 5; i < b.length; i++) {
|
|
908
|
+
if (b[i] === 0xA5 && b[i - 1] === 0x7E) { endPos = i; break; }
|
|
909
|
+
}
|
|
910
|
+
if (endPos === -1) return { ok: false }; // 半包,继续累计
|
|
911
|
+
|
|
912
|
+
const frame = b.slice(0, endPos + 1); // [0 .. A5]
|
|
913
|
+
// 基本字段位置:len 在 [4],cmd 在 [5],CS 在倒数第3个字节
|
|
914
|
+
const L = frame[4] >>> 0;
|
|
915
|
+
const cs = frame[frame.length - 3] >>> 0;
|
|
916
|
+
|
|
917
|
+
// (宽松)长度一致性:实测总长 T 与 L 的关系为 T = L + 3
|
|
918
|
+
const T = frame.length;
|
|
919
|
+
if ((T - 3) !== L) {
|
|
920
|
+
// 不强制失败,给出“长度不一致”的错误帧提示并丢掉该段,避免卡死
|
|
921
|
+
return { ok: false, used: frame.length, frame, err: "BLE_LEN_MISMATCH" };
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// 和校验:从起始 0x7E 到 CS 之前所有字节累加低8位
|
|
925
|
+
let sum = 0;
|
|
926
|
+
for (let i = 0; i < frame.length - 3; i++) sum = (sum + (frame[i] >>> 0)) & 0xFF;
|
|
927
|
+
if (sum !== cs) {
|
|
928
|
+
return { ok: false, used: frame.length, frame, err: "BLE_CS_FAIL" };
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
return { ok: true, used: frame.length, frame };
|
|
932
|
+
}
|
|
879
933
|
// 645:FE* 68 + 6 addr + 68 + ctrl + len + data + cs + 16
|
|
880
934
|
function tryParse645(input) {
|
|
881
935
|
// 统计 FE 前导(仅用于 used,不参与 CS 计算)
|
|
@@ -1026,8 +1080,14 @@ module.exports = function (RED) {
|
|
|
1026
1080
|
|
|
1027
1081
|
// 抽帧
|
|
1028
1082
|
while (assembleBuf.length >= 5) {
|
|
1029
|
-
// 优先 HDLC,再 645,再 698-Len(避免误判)
|
|
1030
|
-
let r = tryParse698HDLC(assembleBuf);
|
|
1083
|
+
// // 优先 HDLC,再 645,再 698-Len(避免误判)
|
|
1084
|
+
// let r = tryParse698HDLC(assembleBuf);
|
|
1085
|
+
// if (!r.ok) r = tryParse645(assembleBuf);
|
|
1086
|
+
// if (!r.ok) r = tryParse698Len(assembleBuf);
|
|
1087
|
+
|
|
1088
|
+
// --fix-20251108-先 BLE(7E7E7E5A…7EA5),再 698-HDLC,再 645,再 698-LEN
|
|
1089
|
+
let r = tryParseBleGNW(assembleBuf);
|
|
1090
|
+
if (!r.ok) r = tryParse698HDLC(assembleBuf);
|
|
1031
1091
|
if (!r.ok) r = tryParse645(assembleBuf);
|
|
1032
1092
|
if (!r.ok) r = tryParse698Len(assembleBuf);
|
|
1033
1093
|
|
|
@@ -1173,6 +1233,7 @@ module.exports = function (RED) {
|
|
|
1173
1233
|
try {
|
|
1174
1234
|
connections[port].close(function () {
|
|
1175
1235
|
serialPool.zlog(node, "关闭成功");
|
|
1236
|
+
_zemitter.emit('afterClosed', port);
|
|
1176
1237
|
RED.log.info(RED._("serial.errors.closed", { port: port }), {});
|
|
1177
1238
|
done();
|
|
1178
1239
|
});
|