node-zserial 1.0.33 → 1.0.34

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 +43 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-zserial",
3
- "version": "1.0.33",
3
+ "version": "1.0.34",
4
4
  "description": "Node-RED nodes to talk to serial ports",
5
5
  "dependencies": {
6
6
  "serialport": "^12.0.0"
package/zserial.js CHANGED
@@ -1,4 +1,8 @@
1
1
 
2
+ /**
3
+ *
4
+ * version: 1.0.34
5
+ */
2
6
  module.exports = function (RED) {
3
7
  /*jshint -W082 */
4
8
  "use strict";
@@ -655,6 +659,11 @@ module.exports = function (RED) {
655
659
  _retryNum: 0,
656
660
  tout: null,
657
661
  queue: [],
662
+ // ---- 防重复推进:同一次 serial 'data' 回调只允许 dequeue 一次 ----
663
+ _rxToken: 0,
664
+ _rxDequeuedToken: -1,
665
+ // ---- 发送序号:用于标记本次 writehead 的队首请求 ----
666
+ _txSeq: 0,
658
667
  on: function (a, b) { this._emitter.on(a, b); },
659
668
  once: function (a, b) { this._emitter.once(a, b); },
660
669
  close: function (cb) {
@@ -700,11 +709,23 @@ module.exports = function (RED) {
700
709
  writehead: function () {
701
710
  if (!this.queue.length) { return; }
702
711
  var qobj = this.queue[0];
712
+ // 标记本次发送的队首请求(用于防止 timeout 与接收回包边界竞态导致双推进)
713
+ qobj._done = false;
714
+ qobj._txId = (++obj._txSeq);
703
715
  this.write(qobj.payload, qobj.cb);
704
716
  var msg = qobj.msg;
705
717
  var timeout = msg.timeout || responsetimeout;
706
718
  this.tout = setTimeout(function () {
707
- this.tout = null;
719
+ // 注意:回调内 this 不是 obj,统一使用 obj.tout
720
+ obj.tout = null;
721
+
722
+ // 关键保护:timeout 触发时,只允许处理“仍然挂在队首的同一个 qobj”。
723
+ // 若队列已因正常回包 dequeue 推进,则该 timeout 已失效,直接忽略,避免连续发送/错位。
724
+ if (!obj.queue || !obj.queue.length) { return; }
725
+ if (obj.queue[0] !== qobj) { return; }
726
+ if (qobj._done) { return; }
727
+ qobj._done = true;
728
+
708
729
  var msgout = obj.dequeue() || {};
709
730
  msgout.port = id;
710
731
  // // if we have some leftover stuff, just send it
@@ -755,16 +776,33 @@ module.exports = function (RED) {
755
776
  // if we are trying to dequeue stuff from an
756
777
  // empty queue, that's an unsolicited message
757
778
  if (!this.queue.length) { return null; }
758
- var msg = Object.assign({}, this.queue[0].msg);
779
+
780
+ // 关键保护:同一次 serial 'data' 回调(同 _rxToken)内只允许 dequeue 一次。
781
+ // 防止 frame 自动解析在同一批输入字节上被多协议/多分支误判两次,导致队列被推进两次(连续发送)。
782
+ if (typeof this._rxToken === 'number' && this._rxDequeuedToken === this._rxToken) {
783
+ return null;
784
+ }
785
+ if (typeof this._rxToken === 'number') {
786
+ this._rxDequeuedToken = this._rxToken;
787
+ }
788
+
789
+ // 出队前标记 done:用于 timeout 回调校验
790
+ var qobj = this.queue[0];
791
+ if (qobj && qobj._done !== true) { qobj._done = true; }
792
+
793
+ var msg = Object.assign({}, qobj.msg);
759
794
  msg = Object.assign(msg, {
760
795
  request_payload: msg.payload,
761
796
  request_msgid: msg._msgid,
762
797
  });
763
798
  delete msg.payload;
764
- if (this.tout) {
799
+
800
+ // 取消当前请求的响应超时计时器
801
+ if (obj.tout) {
765
802
  clearTimeout(obj.tout);
766
803
  obj.tout = null;
767
804
  }
805
+
768
806
  this.queue.shift();
769
807
  this.writehead();
770
808
  return msg;
@@ -1280,6 +1318,8 @@ module.exports = function (RED) {
1280
1318
 
1281
1319
 
1282
1320
  obj.serial.on('data', function (d) {
1321
+ // 标记本次接收事件 token(用于防止同一次 data 回调内重复 dequeue 推进队列)
1322
+ obj._rxToken = (obj._rxToken || 0) + 1;
1283
1323
  // RED.log.info("data::::" + d);
1284
1324
  function emitData(data) {
1285
1325
  if (active === true) {