node-zserial 1.0.15 → 1.0.17

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 (2) hide show
  1. package/package.json +1 -1
  2. package/zserial.js +70 -84
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-zserial",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Node-RED nodes to talk to serial ports",
5
5
  "dependencies": {
6
6
  "serialport": "^12.0.0"
package/zserial.js CHANGED
@@ -640,14 +640,35 @@ module.exports = function (RED) {
640
640
  this.tout = null;
641
641
  var msgout = obj.dequeue() || {};
642
642
  msgout.port = id;
643
- // if we have some leftover stuff, just send it
644
- if (i !== 0) {
645
- var m = buf.slice(0, i);
646
- m = Buffer.from(m);
647
- i = 0;
643
+ // // if we have some leftover stuff, just send it
644
+ // if (i !== 0) {
645
+ // var m = buf.slice(0, i);
646
+ // m = Buffer.from(m);
647
+ // i = 0;
648
+ // if (binoutput !== "bin") { m = m.toString(); }
649
+ // msgout.payload = m;
650
+ // }
651
+ // Prefer flushing data depending on split mode
652
+ var m = null;
653
+ if (spliton === "frame") {
654
+ if (typeof assembleBuf !== "undefined" && assembleBuf && assembleBuf.length) {
655
+ m = Buffer.from(assembleBuf);
656
+ assembleBuf = Buffer.alloc(0); // 清掉残留
657
+ }
658
+ } else {
659
+ if (i !== 0) {
660
+ m = buf.slice(0, i);
661
+ i = 0;
662
+ }
663
+ }
664
+
665
+ if (m) {
648
666
  if (binoutput !== "bin") { m = m.toString(); }
649
667
  msgout.payload = m;
668
+ } else {
669
+ msgout.payload = (binoutput !== "bin") ? "" : Buffer.alloc(0);
650
670
  }
671
+ msgout.status = "ERR_TIMEOUT";
651
672
  /* Notify the sender that a timeout occurred */
652
673
  obj._emitter.emit('timeout', msgout, qobj.sender);
653
674
  }, timeout);
@@ -749,33 +770,32 @@ module.exports = function (RED) {
749
770
 
750
771
 
751
772
  /***** -------------------------------- Frame parsers for DL/T645 & DL/T698.45 (FULL) -------------------------------- *****/
752
- // FE 去前导(645
773
+ // FE 去前导(645/部分场景)
753
774
  function stripFE(buf) {
754
775
  let s = 0;
755
776
  while (s < buf.length && buf[s] === 0xFE) s++;
756
777
  return buf.slice(s);
757
778
  }
758
- // 计算 8bit 累加和([start,end))
779
+ // 8bit 累加和([start,end))
759
780
  function sum8(buf, start, end) {
760
781
  let sum = 0;
761
782
  for (let i = start; i < end; i++) sum = (sum + buf[i]) & 0xFF;
762
783
  return sum;
763
784
  }
764
- // CRC-16/X25(HDLC/LAPB 常用):init 0xFFFF, poly 0x1021, refin/refout=true(实现中按位),xorout 0xFFFF
785
+ // CRC-16/X25init 0xFFFF, poly 0x1021(反射实现:0x8408),xorout 0xFFFF,帧内低字节在前
765
786
  function crc16x25(buf, start, end) {
766
787
  let crc = 0xFFFF;
767
788
  for (let i = start; i < end; i++) {
768
789
  crc ^= buf[i];
769
790
  for (let b = 0; b < 8; b++) {
770
- if (crc & 1) crc = (crc >>> 1) ^ 0x8408; // 0x8408 = reflect(0x1021)
791
+ if (crc & 1) crc = (crc >>> 1) ^ 0x8408;
771
792
  else crc >>>= 1;
772
793
  }
773
794
  }
774
795
  crc ^= 0xFFFF;
775
- // 返回 16-bit,低字节在前(与帧内 FCS 字节序一致)
776
796
  return crc & 0xFFFF;
777
797
  }
778
- // HDLC 解转义:0x7D 0xXX -> 0xXX ^ 0x20
798
+ // HDLC 透明传输反转义:0x7D 0xXX -> 0xXX ^ 0x20
779
799
  function unescapeHDLC(src) {
780
800
  const out = [];
781
801
  for (let i = 0; i < src.length; i++) {
@@ -790,115 +810,79 @@ module.exports = function (RED) {
790
810
  return Buffer.from(out);
791
811
  }
792
812
 
793
- // 解析 645:FE* 68 + 6 addr + 68 + ctrl + len + data + cs + 16
813
+ // 645:FE* 68 + 6 addr + 68 + ctrl + len + data + cs + 16
794
814
  function tryParse645(input) {
795
815
  let b = stripFE(input);
796
816
  if (b.length < 12) return { ok: false };
797
817
  if (b[0] !== 0x68) return { ok: false };
798
- if (b.length >= 8 && b[7] !== 0x68) return { ok: false }; // 第二个 0x68 缺失
799
- if (b.length < 12) return { ok: false };
800
-
818
+ if (b.length >= 8 && b[7] !== 0x68) return { ok: false }; // 第二个 0x68
801
819
  const dataLen = b[9] >>> 0;
802
820
  const total = 12 + dataLen;
803
821
  if (b.length < total) return { ok: false }; // 半包
804
-
805
- const csIdx = total - 2;
806
- const endIdx = total - 1;
807
- const csExpect = sum8(b, 8, csIdx); // 从 ctrl(索引8) 到 data 末
822
+ const csIdx = total - 2, endIdx = total - 1;
823
+ const csExpect = sum8(b, 8, csIdx);
808
824
  const csGot = b[csIdx];
809
825
  const endFlag = b[endIdx];
810
826
  const frame = b.slice(0, total);
811
-
812
- if (endFlag !== 0x16) {
813
- return { ok: false, used: total, frame, err: "645_END_FLAG_16_MISSING" };
814
- }
815
- if (csGot !== csExpect) {
816
- return { ok: false, used: total, frame, err: "645_CHECKSUM_MISMATCH" };
817
- }
827
+ if (endFlag !== 0x16) return { ok: false, used: total, frame, err: "645_END_FLAG_16_MISSING" };
828
+ if (csGot !== csExpect) return { ok: false, used: total, frame, err: "645_CHECKSUM_MISMATCH" };
818
829
  return { ok: true, used: total, frame };
819
830
  }
820
831
 
821
- // 解析 698 “Len 变体”:68 LL LH C ... DATA ... CS 16
832
+ // 698(68-LEN 变体):68 LL LH C ... DATA ... CS 16 ;兼容 FE* 前导
822
833
  function tryParse698Len(input) {
823
- // 注意:不要 stripFE(698 不用 FE 前导);但现场可能混入 FE 噪声,外层会先剔除非 {FE,68,7E}
824
- const b = input;
834
+ const b = stripFE(input); // 关键:剥 FE 前导
825
835
  if (b.length < 5) return { ok: false };
826
836
  if (b[0] !== 0x68) return { ok: false };
827
- // 若字节7 68,多为 645,交给 645 解析器
828
- if (b.length >= 8 && b[7] === 0x68) return { ok: false };
829
-
837
+ if (b.length >= 8 && b[7] === 0x68) return { ok: false }; // 645 645 解析
830
838
  const len = (b[1] | (b[2] << 8)) >>> 0;
831
- if (len <= 0 || len > 4096) {
832
- return { ok: false, used: 1, frame: b.slice(0, 1), err: "698_BAD_LENGTH" };
833
- }
834
- const total = 1 + 2 + len + 2; // 68 + LL,LH + payload(len) + CS,16
835
- if (b.length < total) return { ok: false }; // 半包
836
-
837
- const csIdx = total - 2;
838
- const endIdx = total - 1;
839
+ if (len <= 0 || len > 4096) return { ok: false, used: 1, frame: b.slice(0, 1), err: "698_BAD_LENGTH" };
840
+ const total = 1 + 2 + len + 2; // 68 + len2 + payload(len) + CS,16
841
+ if (b.length < total) return { ok: false }; // 半包
842
+ const csIdx = total - 2, endIdx = total - 1;
839
843
  const endFlag = b[endIdx];
840
- const csExpect = sum8(b, 3, csIdx); // 从 control(索引3) 起,到 CS 前
844
+ const csExpect = sum8(b, 3, csIdx); // 从 control 起到 CS 前
841
845
  const csGot = b[csIdx];
842
846
  const frame = b.slice(0, total);
843
-
844
- if (endFlag !== 0x16) {
845
- return { ok: false, used: total, frame, err: "698_END_FLAG_16_MISSING" };
846
- }
847
- if (csGot !== csExpect) {
848
- return { ok: false, used: total, frame, err: "698_CHECKSUM_MISMATCH" };
849
- }
847
+ if (endFlag !== 0x16) return { ok: false, used: total, frame, err: "698_END_FLAG_16_MISSING" };
848
+ if (csGot !== csExpect) return { ok: false, used: total, frame, err: "698_CHECKSUM_MISMATCH" };
850
849
  return { ok: true, used: total, frame };
851
850
  }
852
851
 
853
- // 解析 698 标准 HDLC7E ... FCS(lo,hi) 7E,支持 0x7D 透明传输与 FCS 校验
852
+ // 698HDLC):7E ... [FCS(lo,hi)] 7E,支持 0x7D 转义与 X.25 FCS
854
853
  function tryParse698HDLC(input) {
855
854
  const b = input;
856
- if (b.length < 6) return { ok: false }; // 7E + 最小帧 + 7E
855
+ if (b.length < 6) return { ok: false };
857
856
  if (b[0] !== 0x7E) return { ok: false };
858
-
859
- // 找到下一枚结束 0x7E(允许中间出现其他 0x7E? 正常应视为下一帧结束)
860
857
  let endPos = -1;
861
- for (let i = 1; i < b.length; i++) {
862
- if (b[i] === 0x7E) { endPos = i; break; }
863
- }
864
- if (endPos === -1) return { ok: false }; // 半包
865
-
866
- const rawFrame = b.slice(0, endPos + 1); // [0 .. endPos]
867
- const payloadEscaped = b.slice(1, endPos); // 去掉前后 0x7E
868
- // HDLC 透明传输反转义
858
+ for (let i = 1; i < b.length; i++) { if (b[i] === 0x7E) { endPos = i; break; } }
859
+ if (endPos === -1) return { ok: false }; // 半包
860
+ const rawFrame = b.slice(0, endPos + 1);
861
+ const payloadEscaped = b.slice(1, endPos); // 去 7E
869
862
  const payload = unescapeHDLC(payloadEscaped);
870
- if (payload.length < 3) {
871
- // 至少 1 字节信息 + 2 字节 FCS
872
- return { ok: false, used: endPos + 1, frame: rawFrame, err: "698_HDLC_TOO_SHORT" };
873
- }
874
-
875
- // FCS:最后两字节,低字节在前
863
+ if (payload.length < 3) return { ok: false, used: endPos + 1, frame: rawFrame, err: "698_HDLC_TOO_SHORT" };
876
864
  const fcsLo = payload[payload.length - 2];
877
865
  const fcsHi = payload[payload.length - 1];
878
866
  const fcs = (fcsHi << 8) | fcsLo;
879
867
  const calc = crc16x25(payload, 0, payload.length - 2);
880
-
881
- if (calc !== fcs) {
882
- return { ok: false, used: endPos + 1, frame: rawFrame, err: "698_HDLC_CRC_FAIL" };
883
- }
884
- // 校验 OK,返回原始帧(包含 7E .. 7E),便于上层直接下发/记录
885
- return { ok: true, used: endPos + 1, frame: rawFrame };
868
+ if (calc !== fcs) return { ok: false, used: endPos + 1, frame: rawFrame, err: "698_HDLC_CRC_FAIL" };
869
+ return { ok: true, used: endPos + 1, frame: rawFrame }; // 原始含 7E
886
870
  }
887
871
 
888
- // 统一喂入器:抽取多帧、报告错误帧、剔除噪声
872
+ // 统一喂入器:抽帧、报错、剔噪
889
873
  let assembleBuf = Buffer.alloc(0);
890
874
  function feedAndExtract(d, emitOk, emitErr) {
891
875
  if (!Buffer.isBuffer(d)) d = Buffer.from(d);
892
876
  assembleBuf = Buffer.concat([assembleBuf, d]);
893
877
 
894
- // 防溢出保护
878
+ // 防溢出
895
879
  if (assembleBuf.length > bufMaxSize) {
896
880
  emitErr(Buffer.from(assembleBuf), "BUFFER_OVERFLOW_DROP_OLD");
897
881
  assembleBuf = Buffer.alloc(0);
898
882
  return;
899
883
  }
900
884
 
901
- // 剔除前导噪声:仅保留以 0xFE(645 前导)、0x68(645/698-Len)或 0x7E(698-HDLC)开头
885
+ // 前导剔噪:仅保留以 FE/68/7E 开头;若以 FE 开头,剥离所有 FE 前导
902
886
  let s = 0;
903
887
  while (s < assembleBuf.length) {
904
888
  const c = assembleBuf[s];
@@ -906,10 +890,14 @@ module.exports = function (RED) {
906
890
  s++;
907
891
  }
908
892
  if (s > 0) assembleBuf = assembleBuf.slice(s);
893
+ if (assembleBuf.length && assembleBuf[0] === 0xFE) {
894
+ let k = 0; while (k < assembleBuf.length && assembleBuf[k] === 0xFE) k++;
895
+ assembleBuf = assembleBuf.slice(k);
896
+ }
909
897
 
910
- // 抽帧循环
898
+ // 抽帧
911
899
  while (assembleBuf.length >= 5) {
912
- // 优先 HDLC(避免 7E 被误当噪声),其次 645,再次 698-Len
900
+ // 优先 HDLC,再 645,再 698-Len(避免误判)
913
901
  let r = tryParse698HDLC(assembleBuf);
914
902
  if (!r.ok) r = tryParse645(assembleBuf);
915
903
  if (!r.ok) r = tryParse698Len(assembleBuf);
@@ -920,17 +908,15 @@ module.exports = function (RED) {
920
908
  continue;
921
909
  }
922
910
  if (r.used) {
923
- // 有足够信息判断该段为坏帧:直接丢弃并上报错误
924
911
  emitErr(r.frame, r.err || "FRAME_INVALID");
925
912
  assembleBuf = assembleBuf.slice(r.used);
926
913
  continue;
927
914
  }
928
- // 需要更多数据
929
- break;
915
+ break; // 需要更多数据
930
916
  }
931
917
  }
932
918
 
933
- /***** -------------------------------- Frame parsers for DL/T645 & DL/T698.45 (FULL) End-------------------------------- *****/
919
+ /***** -------------------------------- Frame parsers for DL/T645 & DL/T698.45 (FULL) End -------------------------------- *****/
934
920
 
935
921
 
936
922
  obj.serial.on('data', function (d) {
@@ -959,7 +945,7 @@ module.exports = function (RED) {
959
945
  var last_sender = null;
960
946
  if (obj.queue.length) { last_sender = obj.queue[0].sender; }
961
947
  var msgout = obj.dequeue() || {};
962
- if (binoutput !== "bin") { m = m.toString(); } // 若需要字符串
948
+ if (binoutput !== "bin") { m = m.toString(); }
963
949
  msgout.payload = m;
964
950
  msgout.port = port;
965
951
  msgout.status = "OK";
@@ -972,7 +958,7 @@ module.exports = function (RED) {
972
958
  if (obj.queue.length) { last_sender = obj.queue[0].sender; }
973
959
  var msgout = obj.dequeue() || {};
974
960
  if (binoutput !== "bin") { m = m.toString(); }
975
- msgout.payload = m; // 原样数据(便于上层记录/重放)
961
+ msgout.payload = m;
976
962
  msgout.port = port;
977
963
  msgout.status = "ERR_FRAME";
978
964
  msgout.reason = reason || "FRAME_INVALID";
@@ -984,7 +970,7 @@ module.exports = function (RED) {
984
970
 
985
971
  // —— 其余兼容模式(time/interbyte/count/char)保持原逻辑 ——
986
972
  // -------- existing legacy split modes (time/interbyte/count/char) --------
987
-
973
+
988
974
  for (var z = 0; z < d.length; z++) {
989
975
  var c = d[z];
990
976
  if (c === waitfor) { active = true; }