nodbus-plus 0.8.2 → 1.0.0
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/.readthedocs.yaml +35 -0
- package/LICENSE.md +21 -21
- package/README.md +163 -48
- package/docs/Makefile +20 -0
- package/docs/client/channel.rst +209 -0
- package/docs/client/nodbus_master_serial.rst +559 -0
- package/docs/client/nodbus_master_tcp.rst +573 -0
- package/docs/conf.py +41 -0
- package/docs/images/01-readcoils.png +0 -0
- package/docs/images/02-readinputs.png +0 -0
- package/docs/images/03-readholding.png +0 -0
- package/docs/images/04-readinputsreg.png +0 -0
- package/docs/images/05-writecoil.png +0 -0
- package/docs/images/06-writeregister.png +0 -0
- package/docs/images/15-writecoil.png +0 -0
- package/docs/images/16.png +0 -0
- package/docs/images/22-mask.png +0 -0
- package/docs/images/23.png +0 -0
- package/docs/images/7.png +0 -0
- package/docs/images/modbus_pdu.png +0 -0
- package/docs/images/serial_adu.png +0 -0
- package/docs/images/tcp_adu.png +0 -0
- package/docs/index.rst +30 -0
- package/docs/make.bat +35 -0
- package/docs/protocol/modbus_master.rst +276 -0
- package/docs/protocol/modbus_master_serial.rst +290 -0
- package/docs/protocol/modbus_master_tcp.rst +296 -0
- package/docs/protocol/modbus_server.rst +469 -0
- package/docs/protocol/modbus_server_serial.rst +543 -0
- package/docs/protocol/modbus_server_tcp.rst +365 -0
- package/docs/requirements.txt +4 -0
- package/docs/server/net_server.rst +242 -0
- package/docs/server/nodbus_serial_server.rst +652 -0
- package/docs/server/nodbus_tcp_server.rst +505 -0
- package/docs/starting.rst +192 -0
- package/docs/static/simple logo.jpg +0 -0
- package/package.json +39 -30
- package/samples/mb_serial_server.js +77 -0
- package/samples/mb_tcp_client.js +114 -0
- package/samples/mb_tcp_server.js +58 -0
- package/src/client/net/serialchannel.js +195 -0
- package/src/client/net/tcpchannel.js +233 -0
- package/src/client/net/udpchannel.js +243 -0
- package/src/client/nodbus_serial_client.js +577 -0
- package/src/client/nodbus_tcp_client.js +542 -0
- package/src/nodbus-plus.js +157 -110
- package/src/protocol/modbus_master.js +298 -961
- package/src/protocol/modbus_master_serial.js +247 -0
- package/src/protocol/modbus_master_tcp.js +219 -0
- package/src/protocol/modbus_server.js +936 -0
- package/src/protocol/modbus_server_serial.js +368 -0
- package/src/protocol/modbus_server_tcp.js +129 -0
- package/src/protocol/utils.js +296 -0
- package/src/server/net/serialserver.js +184 -0
- package/src/server/net/tcpserver.js +290 -0
- package/src/server/net/udpserver.js +242 -0
- package/src/server/nodbus_serial_server.js +238 -0
- package/src/server/nodbus_tcp_server.js +249 -0
- package/test/modbus_master.test.js +279 -0
- package/test/modbus_master_serial.test.js +124 -0
- package/test/modbus_master_tcp.test.js +178 -0
- package/test/modbus_server.test.js +506 -0
- package/test/modbus_server_serial.test.js +328 -0
- package/test/modbus_server_tcp.test.js +91 -0
- package/test/nodbus_client_serial.test.js +307 -0
- package/test/nodbus_client_tcp.test.js +334 -0
- package/test/nodbus_server_serial.test.js +255 -0
- package/test/nodbus_server_tcp.test.js +216 -0
- package/CHANGELOG.md +0 -27
- package/src/client/m_stcp_client.js +0 -214
- package/src/client/m_tcp_client.js +0 -234
- package/src/net/tcpclient.js +0 -173
- package/src/net/tcpserver.js +0 -329
- package/src/protocol/adu.js +0 -40
- package/src/protocol/ascii_adu.js +0 -139
- package/src/protocol/boolean_register.js +0 -78
- package/src/protocol/functions/Force_Multiple_Coils.js +0 -76
- package/src/protocol/functions/Force_Single_Coil.js +0 -54
- package/src/protocol/functions/Mask_Holding_Register.js +0 -47
- package/src/protocol/functions/Preset_Multiple_Registers.js +0 -53
- package/src/protocol/functions/Preset_Single_Register.js +0 -39
- package/src/protocol/functions/Read_Coil_Status.js +0 -59
- package/src/protocol/functions/Read_Holding_Registers.js +0 -52
- package/src/protocol/functions/Read_Input_Registers.js +0 -52
- package/src/protocol/functions/Read_Input_Status.js +0 -58
- package/src/protocol/mbap.js +0 -60
- package/src/protocol/modbus_device.js +0 -35
- package/src/protocol/modbus_slave.js +0 -522
- package/src/protocol/pdu.js +0 -70
- package/src/protocol/rtu_adu.js +0 -122
- package/src/protocol/serial_adu.js +0 -29
- package/src/protocol/tcp_adu.js +0 -84
- package/src/protocol/word_register.js +0 -122
- package/src/server/m_stcp_server.js +0 -310
- package/src/server/m_tcp_server.js +0 -295
- package/test/modbus-stcp-server-test.js +0 -72
- package/test/modbus-stcp-server-test1.js +0 -72
- package/test/modbus-tcp-client-test.js +0 -159
- package/test/modbus-tcp-server-test.js +0 -75
- package/test/modbus-tcp-server-test2.js +0 -75
- package/test/modbus_stcp_client.js +0 -149
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate the crc from a modbus rtu's frame.
|
|
3
|
+
* @param {Buffer} frame The complete modbus rtu frame.
|
|
4
|
+
* @return {number} The CRC.
|
|
5
|
+
*/
|
|
6
|
+
function calcCRC(frame){
|
|
7
|
+
|
|
8
|
+
var crc_hi = 0xFF;
|
|
9
|
+
var crc_lo = 0xFF;
|
|
10
|
+
var index;
|
|
11
|
+
|
|
12
|
+
var auxcrc_hi = [0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
|
13
|
+
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
|
14
|
+
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
|
|
15
|
+
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
|
|
16
|
+
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
|
|
17
|
+
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
|
|
18
|
+
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
|
|
19
|
+
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
|
|
20
|
+
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
|
21
|
+
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
|
22
|
+
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
|
|
23
|
+
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
|
24
|
+
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
|
25
|
+
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
|
|
26
|
+
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
|
|
27
|
+
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
|
|
28
|
+
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
|
|
29
|
+
0x40];
|
|
30
|
+
|
|
31
|
+
var auxcrc_lo = [0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
|
|
32
|
+
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
|
|
33
|
+
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
|
|
34
|
+
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
|
|
35
|
+
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
|
|
36
|
+
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
|
|
37
|
+
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
|
|
38
|
+
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
|
|
39
|
+
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
|
|
40
|
+
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
|
|
41
|
+
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
|
|
42
|
+
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
|
|
43
|
+
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
|
|
44
|
+
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
|
|
45
|
+
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
|
|
46
|
+
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
|
|
47
|
+
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
|
|
48
|
+
0x40];
|
|
49
|
+
|
|
50
|
+
for(var i = 0; i< frame.length-2; i++) {
|
|
51
|
+
index = crc_hi ^ frame[i];
|
|
52
|
+
crc_hi = crc_lo ^ auxcrc_hi[index];
|
|
53
|
+
crc_lo = auxcrc_lo[index];
|
|
54
|
+
}
|
|
55
|
+
return (crc_hi << 8 | crc_lo);
|
|
56
|
+
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Calculate de LRC from a modbus ascii's frame.
|
|
61
|
+
* @param {Buffer} frame The complete modbus ascii frame.
|
|
62
|
+
* @return {number} The LRC.
|
|
63
|
+
*/
|
|
64
|
+
function calcLRC(frame){
|
|
65
|
+
|
|
66
|
+
var bufferBytes = Buffer.alloc(Math.floor((frame.length-5)/2));
|
|
67
|
+
var byteLRC = Buffer.alloc(1);
|
|
68
|
+
|
|
69
|
+
for(var i = 0; i < bufferBytes.length; i++){
|
|
70
|
+
bufferBytes[i]=Number('0x'+ frame.toString('ascii',2*i+1 ,2*i+3));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for(var i = 0; i < bufferBytes.length;i++){
|
|
74
|
+
byteLRC[0] = byteLRC[0] + bufferBytes[i];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var lrc_temp = Buffer.alloc(1);
|
|
78
|
+
lrc_temp[0] = -byteLRC[0];
|
|
79
|
+
var lrc = lrc_temp.readUInt8(0)
|
|
80
|
+
return lrc;
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
*function to convert a uint8 in 2 chars lenght buffer
|
|
86
|
+
*@param {number} uint8Val;
|
|
87
|
+
*@return {Buffer}
|
|
88
|
+
*/
|
|
89
|
+
function valByte2Chars (uint8Val){
|
|
90
|
+
|
|
91
|
+
let temp = Buffer.alloc(2);
|
|
92
|
+
|
|
93
|
+
//get LSB part
|
|
94
|
+
temp.write((uint8Val & 0x0F).toString(16).toUpperCase(), 1);
|
|
95
|
+
//get msb
|
|
96
|
+
temp.write((uint8Val >> 4).toString(16).toUpperCase());
|
|
97
|
+
|
|
98
|
+
return temp;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* This function calculate the necesary buffer to realize the desired mask function
|
|
103
|
+
* @param {Array} valueArray Array of numbers, values 1 on position that want to be true, 0 on position that
|
|
104
|
+
* want to be false and -1 in position that must be unchanged.
|
|
105
|
+
* example register value: [0 1 1 0 1 1 0 0 0 1 1 1 1 0 0 1] 0x9E36
|
|
106
|
+
* set register value: [1 0 0 1 -1 0 1 -1 -1 -1 0 0 1 1 -1 0]
|
|
107
|
+
* final register value: [1 0 0 1 1 0 1 0 0 1 0 0 1 1 0 0] 0x3259
|
|
108
|
+
* @returns {Buffer} Buffer value with AND MASK and OR MASK for modbus 0x16 function.
|
|
109
|
+
*/
|
|
110
|
+
function getMaskRegisterBuffer(valueArray){
|
|
111
|
+
|
|
112
|
+
let value = Buffer.alloc(4);
|
|
113
|
+
let AND_Mask = 0;
|
|
114
|
+
let OR_Mask = 0xFFFF;
|
|
115
|
+
let tempMask = 1;
|
|
116
|
+
let iteratorLimit = 16;
|
|
117
|
+
|
|
118
|
+
if(valueArray.length < 16){
|
|
119
|
+
iteratorLimit = valueArray.length;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
for (let i = 0; i < iteratorLimit; i++){
|
|
124
|
+
|
|
125
|
+
if(valueArray[i] == 1){
|
|
126
|
+
//AND_MASK = 0;
|
|
127
|
+
//OR_Mask = 1;
|
|
128
|
+
}
|
|
129
|
+
else if(valueArray[i] == 0){
|
|
130
|
+
//AND_MASK = 0;
|
|
131
|
+
//OR_MASK = 0
|
|
132
|
+
OR_Mask = OR_Mask & (~tempMask); //temp mask negated is 1111 1110 for i = 0
|
|
133
|
+
|
|
134
|
+
}
|
|
135
|
+
else{
|
|
136
|
+
//AND_MASK = 1;
|
|
137
|
+
//OR_MASK = 1
|
|
138
|
+
AND_Mask = AND_Mask | tempMask;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
tempMask = tempMask << 1;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
value.writeUInt16BE(AND_Mask);
|
|
145
|
+
value.writeUInt16BE(OR_Mask, 2);
|
|
146
|
+
|
|
147
|
+
return value;
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Function to get a Buffer from an Array of boolean
|
|
153
|
+
* @param {Array} boolArray Boolena Array to encoded to a buffer
|
|
154
|
+
* @return {Buffer}
|
|
155
|
+
*/
|
|
156
|
+
function boolsToBuffer(boolArray){
|
|
157
|
+
|
|
158
|
+
let bufValue = Buffer.alloc(Math.ceil(boolArray.length/8)); //Example 10 bools arrays need two bytes length buffer
|
|
159
|
+
let index = 0;
|
|
160
|
+
let byteOffset = 0;
|
|
161
|
+
let orMask = 0x01;
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
for(i = 0; i < boolArray.length; i++){
|
|
165
|
+
index = Math.floor((i)/8); //get the index in the buffer. example 0 for values between 0 -7;
|
|
166
|
+
byteOffset = i % 8;
|
|
167
|
+
orMask = 0x01;
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if(boolArray[i]){
|
|
171
|
+
bufValue[index] = bufValue[index] | (orMask << byteOffset);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return bufValue;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Function to convert a asccii frame to rtu to be processed
|
|
182
|
+
* @param {Buffer} asciiFrame
|
|
183
|
+
* @returns {Buffer} a equivalent rtu buffer
|
|
184
|
+
*/
|
|
185
|
+
function aduAsciiToRtu(asciiFrame){
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
//creating rtu frame. content frame + 2 bytes for crc
|
|
189
|
+
let rtuFrame = Buffer.alloc((asciiFrame.length-1)/2);
|
|
190
|
+
|
|
191
|
+
//droping first character (:), lrc and ending character(CR, LF) see Mover over serial line 1.02 b
|
|
192
|
+
for(let i = 0; i < asciiFrame.length - 4; i++){
|
|
193
|
+
rtuFrame[i] = Number('0x'+ asciiFrame.toString('ascii', 2*i + 1 , 2*i + 3));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
let crc = calcCRC(rtuFrame);
|
|
197
|
+
rtuFrame.writeUInt16BE(crc,rtuFrame.length - 2);
|
|
198
|
+
|
|
199
|
+
return rtuFrame;
|
|
200
|
+
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Function to convert a rtu frame to ascii to be responsed
|
|
205
|
+
* @param {Buffre} rtuFrame
|
|
206
|
+
* @returns {Buffer} a equivalent ascii buffer
|
|
207
|
+
*/
|
|
208
|
+
function aduRtuToAscii(rtuFrame){
|
|
209
|
+
|
|
210
|
+
//creating ascii frame. rtu frame * 2 + 1bytes for ':'
|
|
211
|
+
let asciiFrame = Buffer.alloc(rtuFrame.length * 2 + 1);
|
|
212
|
+
asciiFrame[0] = 0x3A;
|
|
213
|
+
asciiFrame[asciiFrame.length - 2] = 0x0D;
|
|
214
|
+
asciiFrame[asciiFrame.length - 1] = 0x0A;
|
|
215
|
+
|
|
216
|
+
//LRC calculation
|
|
217
|
+
let byteLRC = Buffer.alloc(1);
|
|
218
|
+
|
|
219
|
+
//chars value
|
|
220
|
+
let charsBuffer = Buffer.alloc(2);
|
|
221
|
+
|
|
222
|
+
for(let i = 0; i < rtuFrame.length - 2; i++){
|
|
223
|
+
byteLRC[0] = byteLRC[0] + rtuFrame[i];
|
|
224
|
+
charsBuffer = valByte2Chars(rtuFrame[i])
|
|
225
|
+
charsBuffer.copy(asciiFrame, 2*i + 1)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
byteLRC[0] = -byteLRC[0]
|
|
229
|
+
//get lrc chars
|
|
230
|
+
charsBuffer = valByte2Chars(byteLRC[0]);
|
|
231
|
+
charsBuffer.copy(asciiFrame, asciiFrame.length - 4);
|
|
232
|
+
|
|
233
|
+
return asciiFrame;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Low level api function to get a 2 bytes word value from buffer.
|
|
238
|
+
* @param {Buffer} targetBuffer buffer object to read
|
|
239
|
+
* @param {number} offset integer value with bit address.
|
|
240
|
+
* @return {Buffer} 2 bytes length buffer
|
|
241
|
+
* @throws {RangeError} if offset is out of buffer's bound.
|
|
242
|
+
*/
|
|
243
|
+
function getWordFromBuffer(targetBuffer, offset = 0){
|
|
244
|
+
|
|
245
|
+
if(offset < targetBuffer.length / 2){
|
|
246
|
+
|
|
247
|
+
let value = Buffer.alloc(2);
|
|
248
|
+
value[0] = targetBuffer[offset * 2];
|
|
249
|
+
value[1] = targetBuffer[offset*2 + 1];
|
|
250
|
+
|
|
251
|
+
return value;
|
|
252
|
+
|
|
253
|
+
}
|
|
254
|
+
else{
|
|
255
|
+
throw new RangeError("offset is out of buffer bounds");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Low level api function to set a 2 bytes word value into buffer.
|
|
261
|
+
* @param {Buffer} value 2 bytes long buffer object to write
|
|
262
|
+
* @param {Buffer} targetBuffer buffer object to write
|
|
263
|
+
* @param {number} offset integer value with offset in the buffer.
|
|
264
|
+
* @throws {RangeError} if offset is out of buffer's bound.
|
|
265
|
+
*/
|
|
266
|
+
function setWordToBuffer(value, targetBuffer, offset = 0){
|
|
267
|
+
|
|
268
|
+
if(offset < targetBuffer.length / 2){
|
|
269
|
+
|
|
270
|
+
targetBuffer[offset * 2] = value[0];
|
|
271
|
+
targetBuffer[offset*2 + 1] = value[1];
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
}
|
|
275
|
+
else{
|
|
276
|
+
throw new RangeError("offset is out of buffer bounds");
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
module.exports.calcCRC = calcCRC;
|
|
281
|
+
|
|
282
|
+
module.exports.calcLRC = calcLRC;
|
|
283
|
+
|
|
284
|
+
module.exports.valByteToChars = valByte2Chars;
|
|
285
|
+
|
|
286
|
+
module.exports.getMaskRegisterBuffer = getMaskRegisterBuffer;
|
|
287
|
+
|
|
288
|
+
module.exports.boolsToBuffer = boolsToBuffer;
|
|
289
|
+
|
|
290
|
+
module.exports.aduAsciiToRtu = aduAsciiToRtu;
|
|
291
|
+
|
|
292
|
+
module.exports.aduRtuToAscii = aduRtuToAscii;
|
|
293
|
+
|
|
294
|
+
module.exports.getWordFromBuffer = getWordFromBuffer;
|
|
295
|
+
|
|
296
|
+
module.exports.setWordToBuffer = setWordToBuffer
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
** Serial server module.
|
|
3
|
+
* @module net/tcpserver.
|
|
4
|
+
* @author Hector E. Socarras.
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { SerialPort } = require('serialport');
|
|
9
|
+
const { InterByteTimeoutParser } = require('@serialport/parser-inter-byte-timeout')
|
|
10
|
+
const { ReadlineParser } = require('@serialport/parser-readline')
|
|
11
|
+
|
|
12
|
+
//Default Server's Configuration object
|
|
13
|
+
const defaultCfg = {
|
|
14
|
+
|
|
15
|
+
speed : 7, //Enum startin at 0
|
|
16
|
+
dataBits : 8,
|
|
17
|
+
stopBits : 1,
|
|
18
|
+
parity : 1,
|
|
19
|
+
timeBetweenFrame : 20,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//No operation default function for listeners
|
|
23
|
+
const noop = () => {};
|
|
24
|
+
|
|
25
|
+
//BaudRates Map
|
|
26
|
+
const allowedBaudRates = [110, 300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200];
|
|
27
|
+
const allowedParity = ['none', 'even', 'odd'];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Class to wrap a serial port.
|
|
31
|
+
*/
|
|
32
|
+
class SerialServer {
|
|
33
|
+
/**
|
|
34
|
+
* Create a Serial Server.
|
|
35
|
+
* @param {object} netCfg configuration object.
|
|
36
|
+
*/
|
|
37
|
+
constructor(netCfg = defaultCfg){
|
|
38
|
+
|
|
39
|
+
netCfg.autoOpen = false;
|
|
40
|
+
netCfg.path = netCfg.port;
|
|
41
|
+
if(netCfg.speed == undefined){ netCfg.speed = defaultCfg.speed}
|
|
42
|
+
netCfg.baudRate = allowedBaudRates[netCfg.speed];
|
|
43
|
+
if(netCfg.dataBits == undefined){ netCfg.dataBits = defaultCfg.dataBits}
|
|
44
|
+
if(netCfg.stopBits == undefined){ netCfg.stopBits = defaultCfg.stopBits}
|
|
45
|
+
if(netCfg.parity == undefined | netCfg.parity < 0 | netCfg.parity > 2){ netCfg.parity = allowedParity[defaultCfg.parity]}
|
|
46
|
+
if(netCfg.timeBetweenFrame == undefined){netCfg.timeBetweenFrame = defaultCfg.timeBetweenFrame}
|
|
47
|
+
|
|
48
|
+
let self = this;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* tcp server
|
|
52
|
+
* @type {Object}
|
|
53
|
+
*/
|
|
54
|
+
this.coreServer = new SerialPort(netCfg);
|
|
55
|
+
|
|
56
|
+
this.parser = this.coreServer.pipe(new InterByteTimeoutParser({ interval: netCfg.timeBetweenFrame }));
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* port
|
|
62
|
+
* @type {number}
|
|
63
|
+
*/
|
|
64
|
+
this.port = netCfg.port;
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
//API Callback interfaces****************************************************************************************************************************************
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* function to executed when event data is emited
|
|
72
|
+
* @param {Buffer} data
|
|
73
|
+
*/
|
|
74
|
+
this.onDataHook = noop;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* function to executed when modbus message is detected
|
|
78
|
+
* @param {Buffer} data
|
|
79
|
+
*/
|
|
80
|
+
this.onMbAduHook = noop;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* function to executed when event listening is emited
|
|
84
|
+
*/
|
|
85
|
+
this.onListeningHook = noop;
|
|
86
|
+
this.coreServer.on('open', () => {
|
|
87
|
+
self.onListeningHook();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* function to executed when event error is emited
|
|
93
|
+
* @param {Object} error
|
|
94
|
+
*/
|
|
95
|
+
this.onErrorHook = noop;
|
|
96
|
+
this.coreServer.on('error', (e) => {
|
|
97
|
+
self.onErrorHook(e);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* function to executed when event close is emited
|
|
102
|
+
*/
|
|
103
|
+
this.onServerCloseHook = noop;
|
|
104
|
+
this.coreServer.on('close', function(){
|
|
105
|
+
|
|
106
|
+
self.onServerCloseHook();
|
|
107
|
+
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* function to executed when event write is emited
|
|
113
|
+
* @param {Buffer} buff
|
|
114
|
+
*/
|
|
115
|
+
this.onWriteHook = noop;
|
|
116
|
+
//******************************************************************************************************************************************************
|
|
117
|
+
|
|
118
|
+
//function for validating data****************************************************************
|
|
119
|
+
this.validateFrame = ()=>{
|
|
120
|
+
return false
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
this.parser.on('data',function(data){
|
|
124
|
+
|
|
125
|
+
if(self.onDataHook instanceof Function){
|
|
126
|
+
self.onDataHook(self, data);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
if(self.onMbAduHook instanceof Function & self.validateFrame(data)){
|
|
131
|
+
self.onMbAduHook(self, data);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* listening status
|
|
140
|
+
* @type {boolean}
|
|
141
|
+
*/
|
|
142
|
+
get isListening(){
|
|
143
|
+
return this.coreServer.isOpen;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Start the tcp server
|
|
149
|
+
*/
|
|
150
|
+
start (){
|
|
151
|
+
|
|
152
|
+
this.coreServer.open(function (err) {
|
|
153
|
+
if (err) {
|
|
154
|
+
self.onErrorHook(e);
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Stop the tcp server
|
|
162
|
+
*/
|
|
163
|
+
stop (){
|
|
164
|
+
//cerrando el server
|
|
165
|
+
this.coreServer.close();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* function to write in a conection. Callback to onWriteHook hook function.
|
|
170
|
+
* @param {number} socketIndex. Index to socket in connections array
|
|
171
|
+
* @param {buffer} data
|
|
172
|
+
*/
|
|
173
|
+
write (socket, frame){
|
|
174
|
+
let self = this;
|
|
175
|
+
|
|
176
|
+
this.coreServer.write(frame, function(){
|
|
177
|
+
self.onWriteHook(socket, frame);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = SerialServer;
|