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,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
** Tcp server module.
|
|
3
|
+
* @module net/tcpserver.
|
|
4
|
+
* @author Hector E. Socarras.
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const net = require('node:net');
|
|
9
|
+
|
|
10
|
+
//Default Server's Configuration object
|
|
11
|
+
const defaultCfg = {
|
|
12
|
+
port : 502,
|
|
13
|
+
maxConnections : 32,
|
|
14
|
+
accessControlEnable: false,
|
|
15
|
+
tcpCoalescingDetection : false
|
|
16
|
+
//connectionTimeout : 0
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//No operation default function for listeners
|
|
20
|
+
const noop = () => {};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Class to wrap a node net server.
|
|
24
|
+
*/
|
|
25
|
+
class TcpServer {
|
|
26
|
+
/**
|
|
27
|
+
* Create a Tcp Server.
|
|
28
|
+
* @param {object} netCfg configuration object.
|
|
29
|
+
*/
|
|
30
|
+
constructor(netCfg = defaultCfg){
|
|
31
|
+
|
|
32
|
+
if(netCfg.port == undefined){ netCfg.port = defaultCfg.port}
|
|
33
|
+
if(netCfg.maxConnections == undefined){ netCfg.maxConnections = defaultCfg.maxConnections}
|
|
34
|
+
if(netCfg.accessControlEnable == undefined){ netCfg.accessControlEnable = defaultCfg.accessControlEnable}
|
|
35
|
+
if(netCfg.tcpCoalescingDetection == undefined){ netCfg.tcpCoalescingDetection = defaultCfg.tcpCoalescingDetection}
|
|
36
|
+
|
|
37
|
+
let self = this;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* tcp server
|
|
41
|
+
* @type {Object}
|
|
42
|
+
*/
|
|
43
|
+
this.coreServer = net.createServer();
|
|
44
|
+
|
|
45
|
+
//array whit connections
|
|
46
|
+
this.activeConnections = [];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* port
|
|
50
|
+
* @type {number}
|
|
51
|
+
*/
|
|
52
|
+
this.port = netCfg.port;
|
|
53
|
+
|
|
54
|
+
this.maxConnections = netCfg.maxConnections;
|
|
55
|
+
|
|
56
|
+
this.accessControlEnable = true;
|
|
57
|
+
|
|
58
|
+
this.tcpCoalescingDetection = netCfg.tcpCoalescingDetection;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Inactivity time to close a connection
|
|
62
|
+
* @type {number}
|
|
63
|
+
*/
|
|
64
|
+
//this.connectionTimeout = netCfg.connectionTimeout;
|
|
65
|
+
|
|
66
|
+
//API Callback interfaces****************************************************************************************************************************************
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* function to executed when event data is emited
|
|
70
|
+
* @param {Buffer} data
|
|
71
|
+
*/
|
|
72
|
+
this.onDataHook = noop;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* function to executed when modbus message is detected
|
|
76
|
+
* @param {Buffer} data
|
|
77
|
+
*/
|
|
78
|
+
this.onMbAduHook = noop;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* function to executed when event listening is emited
|
|
82
|
+
*/
|
|
83
|
+
this.onListeningHook = noop;
|
|
84
|
+
this.coreServer.on('listening', () => {
|
|
85
|
+
self.onListeningHook();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* function to executed access control
|
|
90
|
+
* @param {Object} net.socket
|
|
91
|
+
*/
|
|
92
|
+
this.onConnectionRequestHook = noop;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* function to executed when event connection is emited
|
|
96
|
+
* @param {Object} net.socket
|
|
97
|
+
*/
|
|
98
|
+
this.onConnectionAcceptedHook = noop;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* function to executed when event error is emited
|
|
102
|
+
* @param {Object} error
|
|
103
|
+
*/
|
|
104
|
+
this.onErrorHook = noop;
|
|
105
|
+
this.coreServer.on('error', (e) => {
|
|
106
|
+
self.onErrorHook(e);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* function to executed when event close is emited
|
|
111
|
+
*/
|
|
112
|
+
this.onServerCloseHook = noop;
|
|
113
|
+
this.coreServer.on('close', function(){
|
|
114
|
+
|
|
115
|
+
self.activeConnections = [];
|
|
116
|
+
self.onServerCloseHook();
|
|
117
|
+
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* function to executed when event socket#close is emited
|
|
122
|
+
*/
|
|
123
|
+
this.onConnectionCloseHook = noop;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* function to executed when event write is emited
|
|
127
|
+
* @param {Buffer} buff
|
|
128
|
+
*/
|
|
129
|
+
this.onWriteHook = noop;
|
|
130
|
+
//******************************************************************************************************************************************************
|
|
131
|
+
|
|
132
|
+
//function for validating data****************************************************************
|
|
133
|
+
this.validateFrame = ()=>{ return false}
|
|
134
|
+
|
|
135
|
+
this.coreServer.on('connection', function(socket) {
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
//disabling nagle algorithm
|
|
139
|
+
socket.setNoDelay(true);
|
|
140
|
+
|
|
141
|
+
socket.on('data',function(data){
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
if(self.onDataHook instanceof Function){
|
|
145
|
+
self.onDataHook(socket, data);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
//Active tcp coalesing detection for modbus tcp
|
|
149
|
+
if(self.tcpCoalescingDetection){
|
|
150
|
+
//one tcp message can have more than one modbus indication.
|
|
151
|
+
//each modbus tcp message have a length field
|
|
152
|
+
let messages = self.resolveTcpCoalescing(data);
|
|
153
|
+
|
|
154
|
+
messages.forEach((message) => {
|
|
155
|
+
if(self.onMbAduHook instanceof Function & self.validateFrame(message)){
|
|
156
|
+
self.onMbAduHook(socket, message);
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
//Non active tcp coalesing detection for modbus serial
|
|
162
|
+
else{
|
|
163
|
+
|
|
164
|
+
if(self.onMbAduHook instanceof Function & self.validateFrame(data)){
|
|
165
|
+
self.onMbAduHook(socket, data);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
socket.on('error', (e) => {
|
|
174
|
+
if(self.onErrorHook instanceof Function){
|
|
175
|
+
self.onErrorHook(e);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
socket.on('close',function(had_error){
|
|
180
|
+
|
|
181
|
+
var index = self.activeConnections.indexOf(socket);
|
|
182
|
+
//deleting socket from pool
|
|
183
|
+
self.activeConnections.splice(index,1);
|
|
184
|
+
|
|
185
|
+
if(self.onConnectionCloseHook instanceof Function){
|
|
186
|
+
self.onConnectionCloseHook(had_error);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
//adding sockets to connections pool
|
|
192
|
+
self.activeConnections.push(socket)
|
|
193
|
+
|
|
194
|
+
if(self.onConnectionAcceptedHook instanceof Function){
|
|
195
|
+
self.onConnectionAcceptedHook(socket);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
get maxConnections(){
|
|
203
|
+
return this.coreServer.maxConnections;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
set maxConnections(max){
|
|
207
|
+
this.coreServer.maxConnections = max;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* listening status
|
|
212
|
+
* @type {boolean}
|
|
213
|
+
*/
|
|
214
|
+
get isListening(){
|
|
215
|
+
return this.coreServer.listening;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Start the tcp server
|
|
221
|
+
*/
|
|
222
|
+
start (){
|
|
223
|
+
try {
|
|
224
|
+
this.coreServer.listen(this.port)
|
|
225
|
+
}
|
|
226
|
+
catch(error){
|
|
227
|
+
this.onErrorHook(error);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Stop the tcp server
|
|
233
|
+
*/
|
|
234
|
+
stop (){
|
|
235
|
+
//cerrando el server
|
|
236
|
+
this.activeConnections.forEach(function(element){
|
|
237
|
+
element.destroy();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
this.coreServer.close();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* function to write in a conection. Callback to onWriteHook hook function.
|
|
245
|
+
* @param {number} socketIndex. Index to socket in connections array
|
|
246
|
+
* @param {buffer} data
|
|
247
|
+
*/
|
|
248
|
+
write (socket, frame){
|
|
249
|
+
let self = this;
|
|
250
|
+
|
|
251
|
+
socket.write(frame, 'utf8', function(){
|
|
252
|
+
self.onWriteHook(socket, frame);
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Split the input buffer in several indication buffer baset on length property
|
|
258
|
+
* of modbus tcp header. The goal of this funcion is suport several modbus indication
|
|
259
|
+
* on same tcp frame due to tcp coalesing.
|
|
260
|
+
* @param {Buffer Object} dataFrame
|
|
261
|
+
* @return {Buffer array}
|
|
262
|
+
*/
|
|
263
|
+
resolveTcpCoalescing(dataFrame){
|
|
264
|
+
//get de first tcp header length
|
|
265
|
+
let indicationsList = [];
|
|
266
|
+
|
|
267
|
+
if (dataFrame.length > 7){
|
|
268
|
+
let expectedlength = dataFrame.readUInt16BE(4);
|
|
269
|
+
let indication = Buffer.alloc(expectedlength + 6);
|
|
270
|
+
|
|
271
|
+
if(dataFrame.length == expectedlength + 6){
|
|
272
|
+
dataFrame.copy(indication);
|
|
273
|
+
indicationsList.push(indication);
|
|
274
|
+
}
|
|
275
|
+
else if (dataFrame.length > expectedlength + 6){
|
|
276
|
+
dataFrame.copy(indication, 0, 0, expectedlength + 6);
|
|
277
|
+
indicationsList.push(indication);
|
|
278
|
+
indicationsList = indicationsList.concat(this.resolveTcpCoalescing(dataFrame.slice(expectedlength + 6)));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return indicationsList;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
module.exports = TcpServer;
|
|
289
|
+
|
|
290
|
+
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
** UDP server module.
|
|
3
|
+
* @module net/udpnet.
|
|
4
|
+
* @author Hector E. Socarras.
|
|
5
|
+
* @version 1.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const dgram = require('node:dgram');
|
|
9
|
+
|
|
10
|
+
//Default Server's Configuration object
|
|
11
|
+
const defaultCfg = {
|
|
12
|
+
port : 502,
|
|
13
|
+
maxConnections : 32,
|
|
14
|
+
accessControlEnable: false,
|
|
15
|
+
//connectionTimeout : 0,
|
|
16
|
+
udpType: 'udp4'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
//No operation default function for listeners
|
|
20
|
+
const noop = () => {};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Class to wrap a node udp datagram socket.
|
|
24
|
+
*/
|
|
25
|
+
class UdpServer {
|
|
26
|
+
/**
|
|
27
|
+
* Create a UdpServer.
|
|
28
|
+
* @param {object} netCfg configuration object.
|
|
29
|
+
*/
|
|
30
|
+
constructor(netCfg = defaultCfg, type){
|
|
31
|
+
|
|
32
|
+
if(netCfg.port == undefined){ netCfg.port = defaultCfg.port}
|
|
33
|
+
if(netCfg.maxConnections == undefined){ netCfg.maxConnections = defaultCfg.maxConnections}
|
|
34
|
+
if(netCfg.accessControlEnable == undefined){ netCfg.accessControlEnable = defaultCfg.accessControlEnable}
|
|
35
|
+
if(netCfg.udpType != 'udp4' & netCfg.udpType != 'udp6'){ netCfg.udpType = defaultCfg.udpType}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
var self = this;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* udp server
|
|
42
|
+
* @type {Object}
|
|
43
|
+
*/
|
|
44
|
+
this.coreServer = dgram.createSocket(netCfg.udpType);
|
|
45
|
+
|
|
46
|
+
//array whit connections
|
|
47
|
+
this.activeConnections = [];
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* port
|
|
51
|
+
* @type {number}
|
|
52
|
+
*/
|
|
53
|
+
this.port = netCfg.port;
|
|
54
|
+
|
|
55
|
+
this.maxConnections = netCfg.maxConnections;
|
|
56
|
+
|
|
57
|
+
this.accessControlEnable = true;
|
|
58
|
+
|
|
59
|
+
this.tcpCoalescingDetection = netCfg.tcpCoalescingDetection;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* listening status
|
|
63
|
+
* @type {boolean}
|
|
64
|
+
*/
|
|
65
|
+
this.isListening = false;
|
|
66
|
+
|
|
67
|
+
//Hoocks functions***************************************************************************************************
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* function to executed when event data is emited
|
|
71
|
+
* @param {Buffer} data
|
|
72
|
+
*/
|
|
73
|
+
this.onDataHook = noop;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* function to executed when modbus message is detected
|
|
77
|
+
* @param {Buffer} data
|
|
78
|
+
*/
|
|
79
|
+
this.onMbAduHook = noop;
|
|
80
|
+
|
|
81
|
+
this.coreServer.on('message', function(msg, rinfo){
|
|
82
|
+
|
|
83
|
+
//udp is conexionless protocol.
|
|
84
|
+
|
|
85
|
+
rinfo.remoteAddress = rinfo.address;
|
|
86
|
+
rinfo.remotePort = rinfo.port;
|
|
87
|
+
|
|
88
|
+
self.onDataHook(rinfo, msg);
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
//Active tcp coalesing detection for modbus tcp
|
|
92
|
+
if(self.tcpCoalescingDetection){
|
|
93
|
+
//one tcp message can have more than one modbus indication.
|
|
94
|
+
//each modbus tcp message have a length field
|
|
95
|
+
let messages = self.resolveTcpCoalescing(msg);
|
|
96
|
+
|
|
97
|
+
messages.forEach((message) => {
|
|
98
|
+
if(self.onMbAduHook instanceof Function & self.validateFrame(message)){
|
|
99
|
+
self.onMbAduHook(rinfo, message);
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
//Non active tcp coalesing detection for modbus serial
|
|
105
|
+
else{
|
|
106
|
+
|
|
107
|
+
if(self.onMbAduHook instanceof Function & self.validateFrame(msg)){
|
|
108
|
+
self.onMbAduHook(rinfo, msg);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* function to executed when event listening is emited
|
|
117
|
+
*/
|
|
118
|
+
this.onListeningHook = noop;
|
|
119
|
+
this.coreServer.on('listening', () => {
|
|
120
|
+
self.isListening = true;
|
|
121
|
+
self.onListeningHook();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* function to executed access control
|
|
126
|
+
* @param {Object} net.socket
|
|
127
|
+
*/
|
|
128
|
+
this.onConnectionRequestHook = noop;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* function to executed when event connection is emited
|
|
132
|
+
* @param {Object} net.socket
|
|
133
|
+
*/
|
|
134
|
+
this.onConnectionAcceptedHook = noop;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* function to executed when event error is emited
|
|
138
|
+
* @param {Object} error
|
|
139
|
+
*/
|
|
140
|
+
this.onErrorHook = noop;
|
|
141
|
+
this.coreServer.on('error', (e) => {
|
|
142
|
+
self.onErrorHook(e);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* function to executed when event close is emited
|
|
147
|
+
*/
|
|
148
|
+
this.onServerCloseHook = noop;
|
|
149
|
+
this.coreServer.on('close', function(){
|
|
150
|
+
self.isListening = false;
|
|
151
|
+
self.onServerCloseHook();
|
|
152
|
+
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* function to executed when event socket#close is emited
|
|
157
|
+
*/
|
|
158
|
+
this.onConnectionCloseHook = noop;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* function to executed when event write is emited
|
|
162
|
+
* @param {Buffer} buff
|
|
163
|
+
*/
|
|
164
|
+
this.onWriteHook = noop;
|
|
165
|
+
|
|
166
|
+
//function for validating data****************************************************************
|
|
167
|
+
this.validateFrame = ()=>{ return false}
|
|
168
|
+
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Start the tcp server
|
|
173
|
+
*/
|
|
174
|
+
start (){
|
|
175
|
+
var self = this;
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
this.coreServer.bind(this.port)
|
|
179
|
+
}
|
|
180
|
+
catch(error){
|
|
181
|
+
this.onError(error);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Stop the tcp server
|
|
188
|
+
*/
|
|
189
|
+
stop (){
|
|
190
|
+
//cerrando el server
|
|
191
|
+
this.coreServer.close();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* function to write in a conection
|
|
196
|
+
* @param {number} socketIndex. Index to socket in connections array
|
|
197
|
+
* @param {buffer} data
|
|
198
|
+
*/
|
|
199
|
+
write (rinfo, frame){
|
|
200
|
+
let self = this;
|
|
201
|
+
|
|
202
|
+
self.coreServer.send(frame, 0, frame.length, rinfo.port, rinfo.address, function(){
|
|
203
|
+
if(self.onWrite){
|
|
204
|
+
self.onWrite(rinfo, frame);
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Split the input buffer in several indication buffer baset on length property
|
|
211
|
+
* of modbus tcp header. The goal of this funcion is suport several modbus indication
|
|
212
|
+
* on same tcp frame due to tcp coalesing.
|
|
213
|
+
* @param {Buffer Object} dataFrame
|
|
214
|
+
* @return {Buffer array}
|
|
215
|
+
*/
|
|
216
|
+
resolveTcpCoalescing(dataFrame){
|
|
217
|
+
//get de first tcp header length
|
|
218
|
+
let indicationsList = [];
|
|
219
|
+
|
|
220
|
+
if (dataFrame.length > 7){
|
|
221
|
+
let expectedlength = dataFrame.readUInt16BE(4);
|
|
222
|
+
let indication = Buffer.alloc(expectedlength + 6);
|
|
223
|
+
|
|
224
|
+
if(dataFrame.length == expectedlength + 6){
|
|
225
|
+
dataFrame.copy(indication);
|
|
226
|
+
indicationsList.push(indication);
|
|
227
|
+
}
|
|
228
|
+
else if (dataFrame.length > expectedlength + 6){
|
|
229
|
+
dataFrame.copy(indication, 0, 0, expectedlength + 6);
|
|
230
|
+
indicationsList.push(indication);
|
|
231
|
+
indicationsList = indicationsList.concat(this.resolveTcpCoalescing(dataFrame.slice(expectedlength + 6)));
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return indicationsList;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
//Old pattern for static members
|
|
240
|
+
UdpServer.prototype.validateFrame = require('./tcpserver').prototype.validateFrame;
|
|
241
|
+
|
|
242
|
+
module.exports = UdpServer;
|