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.
Files changed (101) hide show
  1. package/.readthedocs.yaml +35 -0
  2. package/LICENSE.md +21 -21
  3. package/README.md +163 -48
  4. package/docs/Makefile +20 -0
  5. package/docs/client/channel.rst +209 -0
  6. package/docs/client/nodbus_master_serial.rst +559 -0
  7. package/docs/client/nodbus_master_tcp.rst +573 -0
  8. package/docs/conf.py +41 -0
  9. package/docs/images/01-readcoils.png +0 -0
  10. package/docs/images/02-readinputs.png +0 -0
  11. package/docs/images/03-readholding.png +0 -0
  12. package/docs/images/04-readinputsreg.png +0 -0
  13. package/docs/images/05-writecoil.png +0 -0
  14. package/docs/images/06-writeregister.png +0 -0
  15. package/docs/images/15-writecoil.png +0 -0
  16. package/docs/images/16.png +0 -0
  17. package/docs/images/22-mask.png +0 -0
  18. package/docs/images/23.png +0 -0
  19. package/docs/images/7.png +0 -0
  20. package/docs/images/modbus_pdu.png +0 -0
  21. package/docs/images/serial_adu.png +0 -0
  22. package/docs/images/tcp_adu.png +0 -0
  23. package/docs/index.rst +30 -0
  24. package/docs/make.bat +35 -0
  25. package/docs/protocol/modbus_master.rst +276 -0
  26. package/docs/protocol/modbus_master_serial.rst +290 -0
  27. package/docs/protocol/modbus_master_tcp.rst +296 -0
  28. package/docs/protocol/modbus_server.rst +469 -0
  29. package/docs/protocol/modbus_server_serial.rst +543 -0
  30. package/docs/protocol/modbus_server_tcp.rst +365 -0
  31. package/docs/requirements.txt +4 -0
  32. package/docs/server/net_server.rst +242 -0
  33. package/docs/server/nodbus_serial_server.rst +652 -0
  34. package/docs/server/nodbus_tcp_server.rst +505 -0
  35. package/docs/starting.rst +192 -0
  36. package/docs/static/simple logo.jpg +0 -0
  37. package/package.json +39 -30
  38. package/samples/mb_serial_server.js +77 -0
  39. package/samples/mb_tcp_client.js +114 -0
  40. package/samples/mb_tcp_server.js +58 -0
  41. package/src/client/net/serialchannel.js +195 -0
  42. package/src/client/net/tcpchannel.js +233 -0
  43. package/src/client/net/udpchannel.js +243 -0
  44. package/src/client/nodbus_serial_client.js +577 -0
  45. package/src/client/nodbus_tcp_client.js +542 -0
  46. package/src/nodbus-plus.js +157 -110
  47. package/src/protocol/modbus_master.js +298 -961
  48. package/src/protocol/modbus_master_serial.js +247 -0
  49. package/src/protocol/modbus_master_tcp.js +219 -0
  50. package/src/protocol/modbus_server.js +936 -0
  51. package/src/protocol/modbus_server_serial.js +368 -0
  52. package/src/protocol/modbus_server_tcp.js +129 -0
  53. package/src/protocol/utils.js +296 -0
  54. package/src/server/net/serialserver.js +184 -0
  55. package/src/server/net/tcpserver.js +290 -0
  56. package/src/server/net/udpserver.js +242 -0
  57. package/src/server/nodbus_serial_server.js +238 -0
  58. package/src/server/nodbus_tcp_server.js +249 -0
  59. package/test/modbus_master.test.js +279 -0
  60. package/test/modbus_master_serial.test.js +124 -0
  61. package/test/modbus_master_tcp.test.js +178 -0
  62. package/test/modbus_server.test.js +506 -0
  63. package/test/modbus_server_serial.test.js +328 -0
  64. package/test/modbus_server_tcp.test.js +91 -0
  65. package/test/nodbus_client_serial.test.js +307 -0
  66. package/test/nodbus_client_tcp.test.js +334 -0
  67. package/test/nodbus_server_serial.test.js +255 -0
  68. package/test/nodbus_server_tcp.test.js +216 -0
  69. package/CHANGELOG.md +0 -27
  70. package/src/client/m_stcp_client.js +0 -214
  71. package/src/client/m_tcp_client.js +0 -234
  72. package/src/net/tcpclient.js +0 -173
  73. package/src/net/tcpserver.js +0 -329
  74. package/src/protocol/adu.js +0 -40
  75. package/src/protocol/ascii_adu.js +0 -139
  76. package/src/protocol/boolean_register.js +0 -78
  77. package/src/protocol/functions/Force_Multiple_Coils.js +0 -76
  78. package/src/protocol/functions/Force_Single_Coil.js +0 -54
  79. package/src/protocol/functions/Mask_Holding_Register.js +0 -47
  80. package/src/protocol/functions/Preset_Multiple_Registers.js +0 -53
  81. package/src/protocol/functions/Preset_Single_Register.js +0 -39
  82. package/src/protocol/functions/Read_Coil_Status.js +0 -59
  83. package/src/protocol/functions/Read_Holding_Registers.js +0 -52
  84. package/src/protocol/functions/Read_Input_Registers.js +0 -52
  85. package/src/protocol/functions/Read_Input_Status.js +0 -58
  86. package/src/protocol/mbap.js +0 -60
  87. package/src/protocol/modbus_device.js +0 -35
  88. package/src/protocol/modbus_slave.js +0 -522
  89. package/src/protocol/pdu.js +0 -70
  90. package/src/protocol/rtu_adu.js +0 -122
  91. package/src/protocol/serial_adu.js +0 -29
  92. package/src/protocol/tcp_adu.js +0 -84
  93. package/src/protocol/word_register.js +0 -122
  94. package/src/server/m_stcp_server.js +0 -310
  95. package/src/server/m_tcp_server.js +0 -295
  96. package/test/modbus-stcp-server-test.js +0 -72
  97. package/test/modbus-stcp-server-test1.js +0 -72
  98. package/test/modbus-tcp-client-test.js +0 -159
  99. package/test/modbus-tcp-server-test.js +0 -75
  100. package/test/modbus-tcp-server-test2.js +0 -75
  101. package/test/modbus_stcp_client.js +0 -149
package/package.json CHANGED
@@ -1,30 +1,39 @@
1
- {
2
- "name": "nodbus-plus",
3
- "version": "0.8.2",
4
- "description": "A nodejs modbus library made in javascript",
5
- "keywords": [
6
- "node",
7
- "modbus",
8
- "library",
9
- "client",
10
- "master",
11
- "slave",
12
- "server"
13
- ],
14
- "main": "src/nodbus-plus.js",
15
- "author": {
16
- "name": "Héctor E. Socarrás Cabrera",
17
- "email": "hsocarras1987@gmail.com"
18
- },
19
- "repository": {
20
- "type": "git",
21
- "url": "https://github.com/hsocarras/nodbus-plus"
22
- },
23
- "bugs": {
24
- "url": "https://github.com/hsocarras/nodbus-plus/issues"
25
- },
26
- "engines": {
27
- "node": ">= 6.0.0"
28
- },
29
- "license": "MIT"
30
- }
1
+ {
2
+ "name": "nodbus-plus",
3
+ "version": "1.0.0",
4
+ "description": "A nodejs modbus library made in javascript",
5
+ "keywords": [
6
+ "node",
7
+ "modbus",
8
+ "library",
9
+ "client",
10
+ "master",
11
+ "slave",
12
+ "server"
13
+ ],
14
+ "main": "src/nodbus-plus.js",
15
+ "scripts": {
16
+ "test": "jest --detectOpenHandles"
17
+ },
18
+ "author": {
19
+ "name": "Héctor E. Socarrás Cabrera",
20
+ "email": "hsocarras1987@gmail.com"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/hsocarras/nodbus-plus"
25
+ },
26
+ "bugs": {
27
+ "url": "https://github.com/hsocarras/nodbus-plus/issues"
28
+ },
29
+ "engines": {
30
+ "node": ">= 10.0.0"
31
+ },
32
+ "license": "MIT",
33
+ "devDependencies": {
34
+ "jest": "^29.4.3"
35
+ },
36
+ "dependencies": {
37
+ "serialport": "^11.0.0"
38
+ }
39
+ }
@@ -0,0 +1,77 @@
1
+ const nodbus = require('../src/nodbus-plus');
2
+ const arg = process.argv.slice(2);
3
+
4
+ let cfg = {
5
+ address : 1,
6
+ transmitionMode: 0,
7
+ inputs : 2048,
8
+ coils : 2048,
9
+ holdingRegisters : 10000,
10
+ inputRegisters : 10000,
11
+ port : 502,
12
+ }
13
+
14
+ if (arg.length > 0){
15
+
16
+ let newAddress = Number(arg[0]);
17
+
18
+ if (typeof newAddress == 'number'){
19
+ cfg.address = newAddress;
20
+ }
21
+
22
+ if(arg[1] == '-ascii'){
23
+
24
+ cfg.transmitionMode = 1;
25
+
26
+ }
27
+
28
+
29
+ }
30
+
31
+ let server = nodbus.createSerialServer('tcp', cfg);
32
+
33
+ server.on('listening', function(port){
34
+ console.log('Server listening on: ' + port);
35
+ });
36
+
37
+ if (arg.length > 0){
38
+ if(arg[2] == 'req'){
39
+
40
+ server.on('request', function(sock, req){
41
+ console.log('Request received')
42
+ console.log(req)
43
+ });
44
+ }
45
+ else if(arg[2] == 'req-res'){
46
+
47
+ server.on('request', function(sock, req){
48
+ console.log('Request received')
49
+ console.log(req)
50
+ });
51
+
52
+ server.on('response', function(sock, res){
53
+ console.log('Responding')
54
+ console.log(res)
55
+ });
56
+
57
+ }
58
+ else if(arg[2] == 'raw'){
59
+
60
+ server.on('data', function(sock, data){
61
+ console.log('Data received')
62
+ console.log(data)
63
+ });
64
+ }
65
+ else{
66
+ console.log('Blind Mode selected')
67
+ }
68
+
69
+ }
70
+ else{
71
+ server.on('error', function(err){
72
+ console.log(err)
73
+ });
74
+ }
75
+
76
+
77
+ server.start()
@@ -0,0 +1,114 @@
1
+ const nodbus = require('../src/nodbus-plus');
2
+
3
+ channelCfg = {
4
+ ip:'127.0.0.1',
5
+ port:502,
6
+ timeout:250,
7
+ }
8
+
9
+ let client = nodbus.createTcpClient();
10
+ client.addChannel('device', 'tcp1', channelCfg);
11
+
12
+ client.on('connection', (id)=>{
13
+ console.log('connection stablish')
14
+ process.stdout.write("device >> ")
15
+ })
16
+
17
+ client.on('connection-closed', (id)=>{
18
+ console.log('client disconnected')
19
+ process.stdout.write(">>> ")
20
+ })
21
+
22
+ client.on('error', (e)=>{
23
+ console.log('Error')
24
+ console.log(e)
25
+ process.stdout.write("device >> ")
26
+ })
27
+
28
+ client.on('request', (id, req)=>{
29
+ console.log('request sended to device');
30
+ console.log('Awaiting for response ...');
31
+ })
32
+
33
+ client.on('req-timeout', (id, adu)=>{
34
+ console.log('timeout')
35
+ process.stdout.write("device >> ")
36
+ })
37
+
38
+ client.on('response', (id, res)=>{
39
+ console.log(res)
40
+ process.stdout.write("device >> ")
41
+ })
42
+
43
+ function repl(){
44
+
45
+ process.stdout.write(">>> ")
46
+ const stdin = process.openStdin();
47
+
48
+ stdin.addListener("data", (data) => {
49
+
50
+ let lineBuffer = data.subarray(0, data.length - 2); //removing 0d 0a characters
51
+ let input = lineBuffer.toString();
52
+
53
+
54
+ let comands = input.split(' ');
55
+
56
+ let success;
57
+ let start;
58
+ let cuantity;
59
+
60
+ switch(comands[0]){
61
+
62
+ case 'exit':
63
+ process.exit();
64
+ break;
65
+ case 'q':
66
+ process.exit();
67
+ break;
68
+ case 'connect':
69
+ client.connect('device')
70
+ break
71
+ case 'disconnect':
72
+ client.disconnect('device')
73
+ break
74
+ case 'readcoils':
75
+ start = comands[1];
76
+ cuantity = comands[2];
77
+ success = client.readCoils('device', 255, start, cuantity);
78
+ if(success == false){
79
+ console.log('the client must connect first')
80
+ process.stdout.write(">>> ")
81
+ }
82
+ break
83
+ case 'readholding':
84
+ start = comands[1];
85
+ cuantity = comands[2];
86
+ success = client.readHoldingRegisters('device', 255, start, cuantity);
87
+ if(success == false){
88
+ console.log('the client must connect first')
89
+ process.stdout.write(">>> ")
90
+ }
91
+ break
92
+ case 'preset':
93
+ let value = Buffer.alloc(2);
94
+ value.writeInt16BE(Number(comands[1]));
95
+ start= comands[2];
96
+ cuantity = comands[3];
97
+ success = client.presetSingleRegister(value, 'device', 255, start);
98
+ if(success == false){
99
+ console.log('the client must connect first')
100
+ process.stdout.write(">>> ")
101
+ }
102
+ break
103
+ default:
104
+ console.log('unknow comand')
105
+ process.stdout.write(">>> ")
106
+
107
+ }
108
+
109
+
110
+
111
+ })
112
+ }
113
+
114
+ repl()
@@ -0,0 +1,58 @@
1
+ const nodbus = require('../src/nodbus-plus');
2
+ const arg = process.argv.slice(2);
3
+
4
+ const cfg = {
5
+ inputs : 2048,
6
+ coils : 2048,
7
+ holdingRegisters : 10000,
8
+ inputRegisters : 10000,
9
+ port : 502,
10
+ }
11
+
12
+ let server = nodbus.createTcpServer('tcp', cfg);
13
+
14
+ server.on('listening', function(port){
15
+ console.log('Server listening on: ' + port);
16
+ });
17
+
18
+ if (arg.length > 0){
19
+ if(arg[0] == 'req'){
20
+
21
+ server.on('request', function(sock, req){
22
+ console.log('Request received')
23
+ console.log(req)
24
+ });
25
+ }
26
+ else if(arg[0] == 'req-res'){
27
+
28
+ server.on('request', function(sock, req){
29
+ console.log('Request received')
30
+ console.log(req)
31
+ });
32
+
33
+ server.on('response', function(sock, res){
34
+ console.log('Responding')
35
+ console.log(res)
36
+ });
37
+
38
+ }
39
+ else if(arg[0] == 'raw'){
40
+
41
+ server.on('data', function(sock, data){
42
+ console.log('Data received')
43
+ console.log(data)
44
+ });
45
+ }
46
+ else{
47
+ console.log('Blind Mode selected')
48
+ }
49
+
50
+ }
51
+ else{
52
+ server.on('error', function(err){
53
+ console.log(err)
54
+ });
55
+ }
56
+
57
+
58
+ server.start()
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Serial Channel module.
3
+ * @module net/serialchannel.
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
+ //No operation default function for listeners
13
+ const noop = () => {};
14
+
15
+ //default config
16
+ //Default Server's Configuration object
17
+ const defaultCfg = {
18
+
19
+ speed : 7, //Enum startin at 0
20
+ dataBits : 8,
21
+ stopBits : 1,
22
+ parity : 1,
23
+ timeBetweenFrame : 20,
24
+ }
25
+
26
+ //BaudRates Map
27
+ const allowedBaudRates = [110, 300, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200];
28
+ const allowedParity = ['none', 'even', 'odd'];
29
+
30
+ /**
31
+ * Class representing a serial channel.
32
+ */
33
+ class SerialChannel {
34
+ /**
35
+ * Create a serial channel.
36
+ */
37
+ constructor(channelCfg){
38
+
39
+ let self = this;
40
+
41
+ channelCfg.autoOpen = false;
42
+ channelCfg.path = channelCfg.port;
43
+ if(channelCfg.speed == undefined){ channelCfg.speed = defaultCfg.speed}
44
+ channelCfg.baudRate = allowedBaudRates[channelCfg.speed];
45
+ if(channelCfg.dataBits == undefined){ channelCfg.dataBits = defaultCfg.dataBits}
46
+ if(channelCfg.stopBits == undefined){ channelCfg.stopBits = defaultCfg.stopBits}
47
+ if(channelCfg.parity == undefined | channelCfg.parity < 0 | channelCfg.parity > 2){ channelCfg.parity = allowedParity[defaultCfg.parity]}
48
+ if(channelCfg.timeBetweenFrame == undefined){channelCfg.timeBetweenFrame = defaultCfg.timeBetweenFrame}
49
+
50
+
51
+
52
+ this.name = channelCfg.name;
53
+
54
+
55
+ this.port = channelCfg.port;
56
+
57
+
58
+
59
+ /**
60
+ *net.socket Object
61
+ * @type {object}
62
+ */
63
+ this.coreChannel = new SerialPort(netCfg);
64
+ this.parser = this.coreChannel.pipe(new InterByteTimeoutParser({ interval: netCfg.timeBetweenFrame }));
65
+
66
+ //Hooks functions *****************************************************************************************************************************
67
+
68
+ /**
69
+ * function to executed when modbus message is detected
70
+ * @param {Buffer} data
71
+ */
72
+ this.onMbAduHook = noop;
73
+ this.onDataHook = noop;
74
+ this.parser.on('data', (data)=>{
75
+
76
+ self.onDataHook(data);
77
+
78
+
79
+
80
+ if(self.validateFrame(data)){
81
+ self.onMbAduHook(data);
82
+ }
83
+
84
+
85
+ });
86
+
87
+ this.onConnectHook = noop;
88
+ this.coreChannel.on('open', ()=>{
89
+ self.onConnectHook();
90
+ })
91
+
92
+ this.onErrorHook = noop;
93
+ this.coreChannel.on('error', (e)=>{
94
+ this.onErrorHook(e);
95
+ })
96
+
97
+ /*
98
+ this.onEndHook = noop;
99
+ this.coreChannel.on('end', () =>{
100
+
101
+ })
102
+
103
+ this.onTimeOutHook = noop;
104
+ */
105
+ this.onCloseHook = noop;
106
+ this.coreChannel.on('close', (e) =>{
107
+ self.onCloseHook();
108
+ })
109
+
110
+ this.onWriteHook = noop;
111
+
112
+ this.validateFrame = noop;
113
+
114
+ }
115
+
116
+ isConnected(){
117
+
118
+ return this.coreChannel.isOpen;
119
+
120
+ }
121
+
122
+ /**
123
+ * Init a connection with a server
124
+ * @returns {Promise} A promise that will be resolve once the connection is stablished with the socket as argument, or will
125
+ * be rejected with ip and port as parameters.
126
+ */
127
+ connect(){
128
+
129
+ let self = this;
130
+ let promise = new Promise(function(resolve, reject){
131
+
132
+ try{
133
+
134
+ self.coreChannel.open((err)=>{
135
+
136
+ if(err){
137
+ self.onErrorHook(e);
138
+ reject('serial', self.port);
139
+ }
140
+ else{
141
+ resolve(self.coreChannel);
142
+ }
143
+
144
+ });
145
+
146
+
147
+ }
148
+ catch(e){
149
+ self.onErrorHook(e);
150
+ reject('serial', self.port);
151
+ }
152
+ })
153
+
154
+ return promise;
155
+ }
156
+
157
+
158
+ disconnect(){
159
+ let self = this;
160
+
161
+ this.coreChannel.close();
162
+
163
+ return Promise.resolve();
164
+
165
+ }
166
+
167
+ /**
168
+ * Write data to a server
169
+ * @param {Buffer} frame data to send to server.
170
+ * @returns {bool} True if success, otherwise false
171
+ * be rejected with ip and por as parameters.
172
+ */
173
+ write(frame){
174
+
175
+ let self = this;
176
+ if(self.isConnected() == false){
177
+ return false;
178
+ }
179
+ else{
180
+
181
+ this.coreChannel.write(frame, function(){
182
+
183
+ self.onWriteHook(frame);
184
+
185
+ });
186
+
187
+ return true;
188
+ }
189
+ }
190
+
191
+
192
+
193
+ }
194
+
195
+ module.exports = SerialChannel;