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