njs-modbus 1.3.0 → 1.3.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/index.cjs +485 -273
- package/dist/index.d.ts +39 -13
- package/dist/index.mjs +485 -273
- package/dist/src/layers/application/abstract-application-layer.d.ts +6 -0
- package/dist/src/layers/application/ascii-application-layer.d.ts +7 -0
- package/dist/src/layers/application/rtu-application-layer.d.ts +7 -0
- package/dist/src/layers/application/tcp-application-layer.d.ts +7 -0
- package/dist/src/master/master.d.ts +12 -13
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -554,6 +554,12 @@ class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
554
554
|
*/
|
|
555
555
|
intervalBetweenFrames) {
|
|
556
556
|
super();
|
|
557
|
+
Object.defineProperty(this, "_waitingResponse", {
|
|
558
|
+
enumerable: true,
|
|
559
|
+
configurable: true,
|
|
560
|
+
writable: true,
|
|
561
|
+
value: void 0
|
|
562
|
+
});
|
|
557
563
|
Object.defineProperty(this, "_timerThreePointFive", {
|
|
558
564
|
enumerable: true,
|
|
559
565
|
configurable: true,
|
|
@@ -585,19 +591,31 @@ class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
585
591
|
}
|
|
586
592
|
const handleData = (data, response) => {
|
|
587
593
|
this._bufferRx = Buffer.concat([this._bufferRx, data]);
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
if (threePointFiveT) {
|
|
597
|
-
this._timerThreePointFive = setTimeout(handleData, threePointFiveT);
|
|
594
|
+
if (this._waitingResponse) {
|
|
595
|
+
this.framing(this._bufferRx, (error, frame) => {
|
|
596
|
+
if (error && error.message === 'Insufficient data length') {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
this._waitingResponse.callback(error, frame);
|
|
600
|
+
this._bufferRx = Buffer.alloc(0);
|
|
601
|
+
});
|
|
598
602
|
}
|
|
599
603
|
else {
|
|
600
|
-
|
|
604
|
+
clearTimeout(this._timerThreePointFive);
|
|
605
|
+
const handleData = () => {
|
|
606
|
+
this.framing(this._bufferRx, (error, frame) => {
|
|
607
|
+
if (!error) {
|
|
608
|
+
this.emit('framing', frame, response);
|
|
609
|
+
}
|
|
610
|
+
this._bufferRx = Buffer.alloc(0);
|
|
611
|
+
});
|
|
612
|
+
};
|
|
613
|
+
if (threePointFiveT) {
|
|
614
|
+
this._timerThreePointFive = setTimeout(handleData, threePointFiveT);
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
handleData();
|
|
618
|
+
}
|
|
601
619
|
}
|
|
602
620
|
};
|
|
603
621
|
physicalLayer.on('data', handleData);
|
|
@@ -613,18 +631,56 @@ class RtuApplicationLayer extends AbstractApplicationLayer {
|
|
|
613
631
|
physicalLayer.removeListener('close', handleClose);
|
|
614
632
|
});
|
|
615
633
|
}
|
|
616
|
-
framing(buffer) {
|
|
634
|
+
framing(buffer, callback) {
|
|
617
635
|
if (buffer.length >= 4) {
|
|
636
|
+
const frame = {
|
|
637
|
+
unit: buffer[0],
|
|
638
|
+
fc: buffer[1],
|
|
639
|
+
data: Array.from(buffer.subarray(2, buffer.length - 2)),
|
|
640
|
+
buffer,
|
|
641
|
+
};
|
|
642
|
+
if (this._waitingResponse) {
|
|
643
|
+
for (const check of this._waitingResponse.preCheck) {
|
|
644
|
+
const res = check(frame);
|
|
645
|
+
if (typeof res === 'undefined') {
|
|
646
|
+
callback(new Error('Insufficient data length'));
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
if (typeof res === 'number') {
|
|
650
|
+
if (res < frame.data.length) {
|
|
651
|
+
callback(new Error('Insufficient data length'));
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
if (res !== frame.data.length) {
|
|
655
|
+
callback(new Error('Invalid response'));
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (!res) {
|
|
660
|
+
callback(new Error('Invalid response'));
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
618
665
|
const crcPassed = buffer.readUInt16LE(buffer.length - 2) === crc(buffer.subarray(0, buffer.length - 2));
|
|
619
666
|
if (crcPassed) {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
buffer,
|
|
625
|
-
};
|
|
667
|
+
callback(null, frame);
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
callback(new Error('CRC check failed'));
|
|
626
671
|
}
|
|
627
672
|
}
|
|
673
|
+
else {
|
|
674
|
+
callback(new Error('Insufficient data length'));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
startWaitingResponse(preCheck, callback) {
|
|
678
|
+
this._waitingResponse = { preCheck, callback };
|
|
679
|
+
clearTimeout(this._timerThreePointFive);
|
|
680
|
+
this._bufferRx = Buffer.alloc(0);
|
|
681
|
+
}
|
|
682
|
+
stopWaitingResponse() {
|
|
683
|
+
this._waitingResponse = undefined;
|
|
628
684
|
}
|
|
629
685
|
encode(data) {
|
|
630
686
|
const buffer = Buffer.alloc(data.data.length + 4);
|
|
@@ -653,6 +709,12 @@ const CHAR_CODE = {
|
|
|
653
709
|
class AsciiApplicationLayer extends AbstractApplicationLayer {
|
|
654
710
|
constructor(physicalLayer) {
|
|
655
711
|
super();
|
|
712
|
+
Object.defineProperty(this, "_waitingResponse", {
|
|
713
|
+
enumerable: true,
|
|
714
|
+
configurable: true,
|
|
715
|
+
writable: true,
|
|
716
|
+
value: void 0
|
|
717
|
+
});
|
|
656
718
|
Object.defineProperty(this, "_status", {
|
|
657
719
|
enumerable: true,
|
|
658
720
|
configurable: true,
|
|
@@ -701,10 +763,14 @@ class AsciiApplicationLayer extends AbstractApplicationLayer {
|
|
|
701
763
|
else {
|
|
702
764
|
this._status = 'idle';
|
|
703
765
|
if (value === CHAR_CODE.LF) {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
766
|
+
this.framing(Buffer.from(this._frame), (error, frame) => {
|
|
767
|
+
if (this._waitingResponse) {
|
|
768
|
+
this._waitingResponse.callback(error, frame);
|
|
769
|
+
}
|
|
770
|
+
else if (!error) {
|
|
771
|
+
this.emit('framing', frame, response);
|
|
772
|
+
}
|
|
773
|
+
});
|
|
708
774
|
}
|
|
709
775
|
}
|
|
710
776
|
break;
|
|
@@ -717,7 +783,7 @@ class AsciiApplicationLayer extends AbstractApplicationLayer {
|
|
|
717
783
|
physicalLayer.removeListener('data', handleData);
|
|
718
784
|
});
|
|
719
785
|
const handleClose = () => {
|
|
720
|
-
this._status = '
|
|
786
|
+
this._status = 'idle';
|
|
721
787
|
this._frame = [];
|
|
722
788
|
};
|
|
723
789
|
physicalLayer.on('close', handleClose);
|
|
@@ -725,28 +791,71 @@ class AsciiApplicationLayer extends AbstractApplicationLayer {
|
|
|
725
791
|
physicalLayer.removeListener('close', handleClose);
|
|
726
792
|
});
|
|
727
793
|
}
|
|
728
|
-
framing(_buffer) {
|
|
729
|
-
if (_buffer.length >= 6
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
794
|
+
framing(_buffer, callback) {
|
|
795
|
+
if (_buffer.length >= 6) {
|
|
796
|
+
if (_buffer.length % 2 === 0) {
|
|
797
|
+
const ascii = [];
|
|
798
|
+
let num = '';
|
|
799
|
+
for (const value of _buffer) {
|
|
800
|
+
num += String.fromCharCode(value);
|
|
801
|
+
if (num.length === 2) {
|
|
802
|
+
ascii.push(Number('0x' + num));
|
|
803
|
+
num = '';
|
|
804
|
+
}
|
|
737
805
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
const lrcPassed = buffer[buffer.length - 1] === lrc(buffer.subarray(0, buffer.length - 1));
|
|
741
|
-
if (lrcPassed) {
|
|
742
|
-
return {
|
|
806
|
+
const buffer = Buffer.from(ascii);
|
|
807
|
+
const frame = {
|
|
743
808
|
unit: buffer[0],
|
|
744
809
|
fc: buffer[1],
|
|
745
810
|
data: Array.from(buffer.subarray(2, buffer.length - 1)),
|
|
746
811
|
buffer: _buffer,
|
|
747
812
|
};
|
|
813
|
+
if (this._waitingResponse) {
|
|
814
|
+
for (const check of this._waitingResponse.preCheck) {
|
|
815
|
+
const res = check(frame);
|
|
816
|
+
if (typeof res === 'undefined') {
|
|
817
|
+
callback(new Error('Insufficient data length'));
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
if (typeof res === 'number') {
|
|
821
|
+
if (res < frame.data.length) {
|
|
822
|
+
callback(new Error('Insufficient data length'));
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
if (res !== frame.data.length) {
|
|
826
|
+
callback(new Error('Invalid response'));
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
if (!res) {
|
|
831
|
+
callback(new Error('Invalid response'));
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
const lrcPassed = buffer[buffer.length - 1] === lrc(buffer.subarray(0, buffer.length - 1));
|
|
837
|
+
if (lrcPassed) {
|
|
838
|
+
callback(null, frame);
|
|
839
|
+
}
|
|
840
|
+
else {
|
|
841
|
+
callback(new Error('LRC check failed'));
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
callback(new Error('Invalid data'));
|
|
748
846
|
}
|
|
749
847
|
}
|
|
848
|
+
else {
|
|
849
|
+
callback(new Error('Insufficient data length'));
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
startWaitingResponse(preCheck, callback) {
|
|
853
|
+
this._waitingResponse = { preCheck, callback };
|
|
854
|
+
this._status = 'idle';
|
|
855
|
+
this._frame = [];
|
|
856
|
+
}
|
|
857
|
+
stopWaitingResponse() {
|
|
858
|
+
this._waitingResponse = undefined;
|
|
750
859
|
}
|
|
751
860
|
encode(data) {
|
|
752
861
|
const buffer = Buffer.alloc(data.data.length + 3);
|
|
@@ -774,6 +883,12 @@ class AsciiApplicationLayer extends AbstractApplicationLayer {
|
|
|
774
883
|
class TcpApplicationLayer extends AbstractApplicationLayer {
|
|
775
884
|
constructor(physicalLayer) {
|
|
776
885
|
super();
|
|
886
|
+
Object.defineProperty(this, "_waitingResponse", {
|
|
887
|
+
enumerable: true,
|
|
888
|
+
configurable: true,
|
|
889
|
+
writable: true,
|
|
890
|
+
value: void 0
|
|
891
|
+
});
|
|
777
892
|
Object.defineProperty(this, "_transactionId", {
|
|
778
893
|
enumerable: true,
|
|
779
894
|
configurable: true,
|
|
@@ -787,28 +902,68 @@ class TcpApplicationLayer extends AbstractApplicationLayer {
|
|
|
787
902
|
value: []
|
|
788
903
|
});
|
|
789
904
|
const handleData = (data, response) => {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
905
|
+
this.framing(data, (error, frame) => {
|
|
906
|
+
if (this._waitingResponse) {
|
|
907
|
+
this._waitingResponse.callback(error, frame);
|
|
908
|
+
}
|
|
909
|
+
else if (!error) {
|
|
910
|
+
this.emit('framing', frame, response);
|
|
911
|
+
}
|
|
912
|
+
});
|
|
794
913
|
};
|
|
795
914
|
physicalLayer.on('data', handleData);
|
|
796
915
|
this._removeAllListeners.push(() => {
|
|
797
916
|
physicalLayer.removeListener('data', handleData);
|
|
798
917
|
});
|
|
799
918
|
}
|
|
800
|
-
framing(buffer) {
|
|
919
|
+
framing(buffer, callback) {
|
|
801
920
|
if (buffer.length >= 8) {
|
|
802
921
|
if (buffer[2] === 0 && buffer[3] === 0 && buffer.readUInt16BE(4) === buffer.length - 6) {
|
|
803
|
-
|
|
922
|
+
const frame = {
|
|
804
923
|
transaction: buffer.readUInt16BE(0),
|
|
805
924
|
unit: buffer[6],
|
|
806
925
|
fc: buffer[7],
|
|
807
926
|
data: Array.from(buffer.subarray(8)),
|
|
808
927
|
buffer,
|
|
809
928
|
};
|
|
929
|
+
if (this._waitingResponse) {
|
|
930
|
+
for (const check of this._waitingResponse.preCheck) {
|
|
931
|
+
const res = check(frame);
|
|
932
|
+
if (typeof res === 'undefined') {
|
|
933
|
+
callback(new Error('Insufficient data length'));
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if (typeof res === 'number') {
|
|
937
|
+
if (res < frame.data.length) {
|
|
938
|
+
callback(new Error('Insufficient data length'));
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (res !== frame.data.length) {
|
|
942
|
+
callback(new Error('Invalid response'));
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (!res) {
|
|
947
|
+
callback(new Error('Invalid response'));
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
callback(null, frame);
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
callback(new Error('Invalid data'));
|
|
810
956
|
}
|
|
811
957
|
}
|
|
958
|
+
else {
|
|
959
|
+
callback(new Error('Insufficient data length'));
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
startWaitingResponse(preCheck, callback) {
|
|
963
|
+
this._waitingResponse = { preCheck, callback };
|
|
964
|
+
}
|
|
965
|
+
stopWaitingResponse() {
|
|
966
|
+
this._waitingResponse = undefined;
|
|
812
967
|
}
|
|
813
968
|
encode(data) {
|
|
814
969
|
var _a;
|
|
@@ -832,38 +987,6 @@ class TcpApplicationLayer extends AbstractApplicationLayer {
|
|
|
832
987
|
}
|
|
833
988
|
}
|
|
834
989
|
|
|
835
|
-
/******************************************************************************
|
|
836
|
-
Copyright (c) Microsoft Corporation.
|
|
837
|
-
|
|
838
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
839
|
-
purpose with or without fee is hereby granted.
|
|
840
|
-
|
|
841
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
842
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
843
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
844
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
845
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
846
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
847
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
848
|
-
***************************************************************************** */
|
|
849
|
-
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
853
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
854
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
855
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
856
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
857
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
858
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
859
|
-
});
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
863
|
-
var e = new Error(message);
|
|
864
|
-
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
865
|
-
};
|
|
866
|
-
|
|
867
990
|
class ModbusMaster extends EventEmitter {
|
|
868
991
|
get isOpen() {
|
|
869
992
|
return this.physicalLayer.isOpen;
|
|
@@ -891,12 +1014,6 @@ class ModbusMaster extends EventEmitter {
|
|
|
891
1014
|
writable: true,
|
|
892
1015
|
value: timeout
|
|
893
1016
|
});
|
|
894
|
-
Object.defineProperty(this, "_responses", {
|
|
895
|
-
enumerable: true,
|
|
896
|
-
configurable: true,
|
|
897
|
-
writable: true,
|
|
898
|
-
value: new Set()
|
|
899
|
-
});
|
|
900
1017
|
Object.defineProperty(this, "writeFC1", {
|
|
901
1018
|
enumerable: true,
|
|
902
1019
|
configurable: true,
|
|
@@ -981,11 +1098,6 @@ class ModbusMaster extends EventEmitter {
|
|
|
981
1098
|
this.handleFC22 = this.maskWriteRegister;
|
|
982
1099
|
this.handleFC23 = this.readAndWriteMultipleRegisters;
|
|
983
1100
|
this.handleFC43_14 = this.readDeviceIdentification;
|
|
984
|
-
applicationLayer.on('framing', (frame) => __awaiter(this, void 0, void 0, function* () {
|
|
985
|
-
for (const response of this._responses) {
|
|
986
|
-
response(frame);
|
|
987
|
-
}
|
|
988
|
-
}));
|
|
989
1101
|
physicalLayer.on('error', (error) => {
|
|
990
1102
|
this.emit('error', error);
|
|
991
1103
|
});
|
|
@@ -993,46 +1105,55 @@ class ModbusMaster extends EventEmitter {
|
|
|
993
1105
|
this.emit('close');
|
|
994
1106
|
});
|
|
995
1107
|
}
|
|
996
|
-
waitResponse(
|
|
1108
|
+
waitResponse(request, response, timeout) {
|
|
997
1109
|
return new Promise((resolve, reject) => {
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1110
|
+
this.physicalLayer
|
|
1111
|
+
.write(request.data)
|
|
1112
|
+
.then(() => {
|
|
1113
|
+
if (request.broadcast) {
|
|
1114
|
+
resolve();
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
const tid = setTimeout(() => {
|
|
1118
|
+
this.applicationLayer.stopWaitingResponse();
|
|
1119
|
+
reject(new Error('Timeout'));
|
|
1120
|
+
}, timeout);
|
|
1121
|
+
this.applicationLayer.startWaitingResponse(response.preCheck, (error, frame) => {
|
|
1122
|
+
clearTimeout(tid);
|
|
1123
|
+
this.applicationLayer.stopWaitingResponse();
|
|
1124
|
+
if (error) {
|
|
1125
|
+
reject(error);
|
|
1126
|
+
}
|
|
1127
|
+
else {
|
|
1128
|
+
resolve(frame);
|
|
1129
|
+
}
|
|
1013
1130
|
});
|
|
1014
1131
|
}
|
|
1015
|
-
}
|
|
1016
|
-
|
|
1132
|
+
})
|
|
1133
|
+
.catch((error) => {
|
|
1134
|
+
reject(error);
|
|
1135
|
+
});
|
|
1017
1136
|
});
|
|
1018
1137
|
}
|
|
1019
1138
|
writeFC1Or2(unit, fc, address, length, timeout) {
|
|
1139
|
+
const byteCount = Math.ceil(length / 8);
|
|
1020
1140
|
const bufferTx = Buffer.alloc(4);
|
|
1021
1141
|
bufferTx.writeUInt16BE(address, 0);
|
|
1022
1142
|
bufferTx.writeUInt16BE(length, 2);
|
|
1023
|
-
this.
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1143
|
+
return this.waitResponse({
|
|
1144
|
+
data: this.applicationLayer.encode({
|
|
1145
|
+
unit,
|
|
1146
|
+
fc,
|
|
1147
|
+
data: Array.from(bufferTx),
|
|
1148
|
+
}),
|
|
1149
|
+
broadcast: unit === 0,
|
|
1150
|
+
}, {
|
|
1151
|
+
preCheck: [(frame) => frame.unit === unit && frame.fc === fc, () => 1 + byteCount, (frame) => frame.data[0] === byteCount],
|
|
1152
|
+
}, timeout).then((frame) => {
|
|
1153
|
+
if (frame) {
|
|
1154
|
+
return Object.assign(Object.assign({}, frame), { data: Array.from({ length }).map((_, index) => (frame.data[1 + ~~(index / 8)] & (1 << index % 8)) > 0) });
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1036
1157
|
}
|
|
1037
1158
|
readCoils(unit, address, length, timeout = this.timeout) {
|
|
1038
1159
|
return this.writeFC1Or2(unit, 0x01, address, length, timeout);
|
|
@@ -1041,23 +1162,25 @@ class ModbusMaster extends EventEmitter {
|
|
|
1041
1162
|
return this.writeFC1Or2(unit, 0x02, address, length, timeout);
|
|
1042
1163
|
}
|
|
1043
1164
|
writeFC3Or4(unit, fc, address, length, timeout) {
|
|
1165
|
+
const byteCount = length * 2;
|
|
1044
1166
|
const bufferTx = Buffer.alloc(4);
|
|
1045
1167
|
bufferTx.writeUInt16BE(address, 0);
|
|
1046
1168
|
bufferTx.writeUInt16BE(length, 2);
|
|
1047
|
-
this.
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1169
|
+
return this.waitResponse({
|
|
1170
|
+
data: this.applicationLayer.encode({
|
|
1171
|
+
unit,
|
|
1172
|
+
fc,
|
|
1173
|
+
data: Array.from(bufferTx),
|
|
1174
|
+
}),
|
|
1175
|
+
broadcast: unit === 0,
|
|
1176
|
+
}, {
|
|
1177
|
+
preCheck: [(frame) => frame.unit === unit && frame.fc === fc, () => 1 + byteCount, (frame) => frame.data[0] === byteCount],
|
|
1178
|
+
}, timeout).then((frame) => {
|
|
1179
|
+
if (frame) {
|
|
1180
|
+
const bufferRx = Buffer.from(frame.data.slice(1));
|
|
1181
|
+
return Object.assign(Object.assign({}, frame), { data: Array.from({ length }).map((_, index) => bufferRx.readUInt16BE(index * 2)) });
|
|
1182
|
+
}
|
|
1183
|
+
});
|
|
1061
1184
|
}
|
|
1062
1185
|
readHoldingRegisters(unit, address, length, timeout = this.timeout) {
|
|
1063
1186
|
return this.writeFC3Or4(unit, 0x03, address, length, timeout);
|
|
@@ -1070,42 +1193,48 @@ class ModbusMaster extends EventEmitter {
|
|
|
1070
1193
|
const bufferTx = Buffer.alloc(4);
|
|
1071
1194
|
bufferTx.writeUInt16BE(address, 0);
|
|
1072
1195
|
bufferTx.writeUInt16BE(value ? 0xff00 : 0x0000, 2);
|
|
1073
|
-
this.
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1196
|
+
return this.waitResponse({
|
|
1197
|
+
data: this.applicationLayer.encode({
|
|
1198
|
+
unit,
|
|
1199
|
+
fc,
|
|
1200
|
+
data: Array.from(bufferTx),
|
|
1201
|
+
}),
|
|
1202
|
+
broadcast: unit === 0,
|
|
1203
|
+
}, {
|
|
1204
|
+
preCheck: [
|
|
1205
|
+
(frame) => frame.unit === unit && frame.fc === fc,
|
|
1206
|
+
() => bufferTx.length,
|
|
1207
|
+
(frame) => frame.data.every((v, i) => v === bufferTx[i]),
|
|
1208
|
+
],
|
|
1209
|
+
}, timeout).then((frame) => {
|
|
1210
|
+
if (frame) {
|
|
1211
|
+
return Object.assign(Object.assign({}, frame), { data: value });
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1088
1214
|
}
|
|
1089
1215
|
writeSingleRegister(unit, address, value, timeout = this.timeout) {
|
|
1090
1216
|
const fc = 0x06;
|
|
1091
1217
|
const bufferTx = Buffer.alloc(4);
|
|
1092
1218
|
bufferTx.writeUInt16BE(address, 0);
|
|
1093
1219
|
bufferTx.writeUInt16BE(value, 2);
|
|
1094
|
-
this.
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1220
|
+
return this.waitResponse({
|
|
1221
|
+
data: this.applicationLayer.encode({
|
|
1222
|
+
unit,
|
|
1223
|
+
fc,
|
|
1224
|
+
data: Array.from(bufferTx),
|
|
1225
|
+
}),
|
|
1226
|
+
broadcast: unit === 0,
|
|
1227
|
+
}, {
|
|
1228
|
+
preCheck: [
|
|
1229
|
+
(frame) => frame.unit === unit && frame.fc === fc,
|
|
1230
|
+
() => bufferTx.length,
|
|
1231
|
+
(frame) => frame.data.every((v, i) => v === bufferTx[i]),
|
|
1232
|
+
],
|
|
1233
|
+
}, timeout).then((frame) => {
|
|
1234
|
+
if (frame) {
|
|
1235
|
+
return Object.assign(Object.assign({}, frame), { data: value });
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1109
1238
|
}
|
|
1110
1239
|
writeMultipleCoils(unit, address, value, timeout = this.timeout) {
|
|
1111
1240
|
const fc = 0x0f;
|
|
@@ -1119,18 +1248,20 @@ class ModbusMaster extends EventEmitter {
|
|
|
1119
1248
|
bufferTx[5 + ~~(i / 8)] |= 1 << i % 8;
|
|
1120
1249
|
}
|
|
1121
1250
|
});
|
|
1122
|
-
this.
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1251
|
+
return this.waitResponse({
|
|
1252
|
+
data: this.applicationLayer.encode({
|
|
1253
|
+
unit,
|
|
1254
|
+
fc,
|
|
1255
|
+
data: Array.from(bufferTx),
|
|
1256
|
+
}),
|
|
1257
|
+
broadcast: unit === 0,
|
|
1258
|
+
}, {
|
|
1259
|
+
preCheck: [(frame) => frame.unit === unit && frame.fc === fc, () => 4, (frame) => frame.data.every((v, i) => v === bufferTx[i])],
|
|
1260
|
+
}, timeout).then((frame) => {
|
|
1261
|
+
if (frame) {
|
|
1262
|
+
return Object.assign(Object.assign({}, frame), { data: value });
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1134
1265
|
}
|
|
1135
1266
|
writeMultipleRegisters(unit, address, value, timeout = this.timeout) {
|
|
1136
1267
|
const fc = 0x10;
|
|
@@ -1142,40 +1273,48 @@ class ModbusMaster extends EventEmitter {
|
|
|
1142
1273
|
value.forEach((v, i) => {
|
|
1143
1274
|
bufferTx.writeUInt16BE(v, 5 + i * 2);
|
|
1144
1275
|
});
|
|
1145
|
-
this.
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1276
|
+
return this.waitResponse({
|
|
1277
|
+
data: this.applicationLayer.encode({
|
|
1278
|
+
unit,
|
|
1279
|
+
fc,
|
|
1280
|
+
data: Array.from(bufferTx),
|
|
1281
|
+
}),
|
|
1282
|
+
broadcast: unit === 0,
|
|
1283
|
+
}, {
|
|
1284
|
+
preCheck: [(frame) => frame.unit === unit && frame.fc === fc, () => 4, (frame) => frame.data.every((v, i) => v === bufferTx[i])],
|
|
1285
|
+
}, timeout).then((frame) => {
|
|
1286
|
+
if (frame) {
|
|
1287
|
+
return Object.assign(Object.assign({}, frame), { data: value });
|
|
1288
|
+
}
|
|
1289
|
+
});
|
|
1157
1290
|
}
|
|
1158
1291
|
reportServerId(unit, timeout = this.timeout) {
|
|
1159
1292
|
const fc = 0x11;
|
|
1160
|
-
this.
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
additionalData: frame.data.slice(3),
|
|
1174
|
-
};
|
|
1293
|
+
return this.waitResponse({
|
|
1294
|
+
data: this.applicationLayer.encode({
|
|
1295
|
+
unit,
|
|
1296
|
+
fc,
|
|
1297
|
+
data: [],
|
|
1298
|
+
}),
|
|
1299
|
+
broadcast: unit === 0,
|
|
1300
|
+
}, {
|
|
1301
|
+
preCheck: [
|
|
1302
|
+
(frame) => frame.unit === unit && frame.fc === fc,
|
|
1303
|
+
(frame) => {
|
|
1304
|
+
if (frame.data.length >= 3) {
|
|
1305
|
+
return 1 + frame.data[0];
|
|
1175
1306
|
}
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1307
|
+
},
|
|
1308
|
+
],
|
|
1309
|
+
}, timeout).then((frame) => {
|
|
1310
|
+
if (frame) {
|
|
1311
|
+
return Object.assign(Object.assign({}, frame), { data: {
|
|
1312
|
+
serverId: frame.data[1],
|
|
1313
|
+
runIndicatorStatus: frame.data[2] === 0xff,
|
|
1314
|
+
additionalData: frame.data.slice(3),
|
|
1315
|
+
} });
|
|
1316
|
+
}
|
|
1317
|
+
});
|
|
1179
1318
|
}
|
|
1180
1319
|
maskWriteRegister(unit, address, andMask, orMask, timeout = this.timeout) {
|
|
1181
1320
|
const fc = 0x16;
|
|
@@ -1183,18 +1322,20 @@ class ModbusMaster extends EventEmitter {
|
|
|
1183
1322
|
bufferTx.writeUInt16BE(address, 0);
|
|
1184
1323
|
bufferTx.writeUInt16BE(andMask, 2);
|
|
1185
1324
|
bufferTx.writeUInt16BE(orMask, 4);
|
|
1186
|
-
this.
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1325
|
+
return this.waitResponse({
|
|
1326
|
+
data: this.applicationLayer.encode({
|
|
1327
|
+
unit,
|
|
1328
|
+
fc,
|
|
1329
|
+
data: Array.from(bufferTx),
|
|
1330
|
+
}),
|
|
1331
|
+
broadcast: unit === 0,
|
|
1332
|
+
}, {
|
|
1333
|
+
preCheck: [(frame) => frame.unit === unit && frame.fc === fc, () => 6, (frame) => frame.data.every((v, i) => v === bufferTx[i])],
|
|
1334
|
+
}, timeout).then((frame) => {
|
|
1335
|
+
if (frame) {
|
|
1336
|
+
return Object.assign(Object.assign({}, frame), { data: { andMask, orMask } });
|
|
1337
|
+
}
|
|
1338
|
+
});
|
|
1198
1339
|
}
|
|
1199
1340
|
readAndWriteMultipleRegisters(unit, read, write, timeout = this.timeout) {
|
|
1200
1341
|
const fc = 0x17;
|
|
@@ -1208,73 +1349,104 @@ class ModbusMaster extends EventEmitter {
|
|
|
1208
1349
|
write.value.forEach((v, i) => {
|
|
1209
1350
|
bufferTx.writeUInt16BE(v, 9 + i * 2);
|
|
1210
1351
|
});
|
|
1211
|
-
this.
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1352
|
+
return this.waitResponse({
|
|
1353
|
+
data: this.applicationLayer.encode({
|
|
1354
|
+
unit,
|
|
1355
|
+
fc,
|
|
1356
|
+
data: Array.from(bufferTx),
|
|
1357
|
+
}),
|
|
1358
|
+
broadcast: unit === 0,
|
|
1359
|
+
}, {
|
|
1360
|
+
preCheck: [(frame) => frame.unit === unit && frame.fc === fc, () => 1 + byteCount, (frame) => frame.data[0] === byteCount],
|
|
1361
|
+
}, timeout).then((frame) => {
|
|
1362
|
+
if (frame) {
|
|
1363
|
+
const bufferRx = Buffer.from(frame.data.slice(1));
|
|
1364
|
+
return Object.assign(Object.assign({}, frame), { data: Array.from({ length: read.length }).map((_, index) => bufferRx.readUInt16BE(index * 2)) });
|
|
1365
|
+
}
|
|
1366
|
+
});
|
|
1224
1367
|
}
|
|
1225
1368
|
readDeviceIdentification(unit, readDeviceIDCode, objectId, timeout = this.timeout) {
|
|
1226
1369
|
const fc = 0x2b;
|
|
1227
|
-
this.
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
frame.data
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1370
|
+
return this.waitResponse({
|
|
1371
|
+
data: this.applicationLayer.encode({
|
|
1372
|
+
unit,
|
|
1373
|
+
fc,
|
|
1374
|
+
data: [0x0e, readDeviceIDCode, objectId],
|
|
1375
|
+
}),
|
|
1376
|
+
broadcast: unit === 0,
|
|
1377
|
+
}, {
|
|
1378
|
+
preCheck: [
|
|
1379
|
+
(frame) => frame.unit === unit && frame.fc === fc,
|
|
1380
|
+
(frame) => {
|
|
1381
|
+
if (frame.data.length >= 6) {
|
|
1382
|
+
if (frame.data[0] === 0x0e && frame.data[1] === readDeviceIDCode) {
|
|
1383
|
+
const objects = [];
|
|
1384
|
+
let object = [];
|
|
1385
|
+
for (const v of frame.data.slice(6)) {
|
|
1386
|
+
switch (object.length) {
|
|
1387
|
+
case 0:
|
|
1388
|
+
case 1: {
|
|
1389
|
+
object.push(v);
|
|
1390
|
+
break;
|
|
1391
|
+
}
|
|
1392
|
+
case 2: {
|
|
1393
|
+
object.push([v]);
|
|
1394
|
+
break;
|
|
1395
|
+
}
|
|
1396
|
+
case 3: {
|
|
1397
|
+
object[2].push(v);
|
|
1398
|
+
if (object[1] === object[2].length) {
|
|
1399
|
+
objects.push(2 + object[1]);
|
|
1400
|
+
object = [];
|
|
1401
|
+
}
|
|
1402
|
+
break;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1255
1405
|
}
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
break;
|
|
1406
|
+
if (objects.length === frame.data[5]) {
|
|
1407
|
+
return 6 + objects.reduce((previous, current) => previous + current, 0);
|
|
1259
1408
|
}
|
|
1260
1409
|
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
object = [];
|
|
1410
|
+
else {
|
|
1411
|
+
return false;
|
|
1264
1412
|
}
|
|
1265
1413
|
}
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1414
|
+
},
|
|
1415
|
+
],
|
|
1416
|
+
}, timeout).then((frame) => {
|
|
1417
|
+
if (frame) {
|
|
1418
|
+
const objects = [];
|
|
1419
|
+
let object = [];
|
|
1420
|
+
for (const v of frame.data.slice(6)) {
|
|
1421
|
+
switch (object.length) {
|
|
1422
|
+
case 0:
|
|
1423
|
+
case 1: {
|
|
1424
|
+
object.push(v);
|
|
1425
|
+
break;
|
|
1426
|
+
}
|
|
1427
|
+
case 2: {
|
|
1428
|
+
object.push([v]);
|
|
1429
|
+
break;
|
|
1430
|
+
}
|
|
1431
|
+
case 3: {
|
|
1432
|
+
object[2].push(v);
|
|
1433
|
+
if (object[1] === object[2].length) {
|
|
1434
|
+
objects.push({ id: object[0], value: Buffer.from(object[2]).toString() });
|
|
1435
|
+
object = [];
|
|
1436
|
+
}
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1274
1439
|
}
|
|
1275
1440
|
}
|
|
1276
|
-
|
|
1277
|
-
|
|
1441
|
+
return Object.assign(Object.assign({}, frame), { data: {
|
|
1442
|
+
readDeviceIDCode,
|
|
1443
|
+
conformityLevel: frame.data[2],
|
|
1444
|
+
moreFollows: frame.data[3] === 0xff,
|
|
1445
|
+
nextObjectId: frame.data[4],
|
|
1446
|
+
objects,
|
|
1447
|
+
} });
|
|
1448
|
+
}
|
|
1449
|
+
});
|
|
1278
1450
|
}
|
|
1279
1451
|
open(...args) {
|
|
1280
1452
|
return this.physicalLayer.open(...args);
|
|
@@ -1289,6 +1461,38 @@ class ModbusMaster extends EventEmitter {
|
|
|
1289
1461
|
}
|
|
1290
1462
|
}
|
|
1291
1463
|
|
|
1464
|
+
/******************************************************************************
|
|
1465
|
+
Copyright (c) Microsoft Corporation.
|
|
1466
|
+
|
|
1467
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
1468
|
+
purpose with or without fee is hereby granted.
|
|
1469
|
+
|
|
1470
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
1471
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
1472
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
1473
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
1474
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
1475
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
1476
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
1477
|
+
***************************************************************************** */
|
|
1478
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
1479
|
+
|
|
1480
|
+
|
|
1481
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
1482
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
1483
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
1484
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
1485
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
1486
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
1487
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
1492
|
+
var e = new Error(message);
|
|
1493
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
1494
|
+
};
|
|
1495
|
+
|
|
1292
1496
|
class ModbusSlave extends EventEmitter {
|
|
1293
1497
|
get isOpen() {
|
|
1294
1498
|
return this.physicalLayer.isOpen;
|
|
@@ -1329,7 +1533,15 @@ class ModbusSlave extends EventEmitter {
|
|
|
1329
1533
|
if (!(frame.unit === 0x00 || frame.unit === this.unit)) {
|
|
1330
1534
|
return;
|
|
1331
1535
|
}
|
|
1332
|
-
const response =
|
|
1536
|
+
const response = (data) => __awaiter(this, void 0, void 0, function* () {
|
|
1537
|
+
if (frame.unit === 0x00) {
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
try {
|
|
1541
|
+
yield _response(data);
|
|
1542
|
+
}
|
|
1543
|
+
catch (error) { }
|
|
1544
|
+
});
|
|
1333
1545
|
if (model.interceptor) {
|
|
1334
1546
|
try {
|
|
1335
1547
|
const data = yield model.interceptor(frame.fc, frame.data);
|