libmodbus4r 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/modbus.h ADDED
@@ -0,0 +1,347 @@
1
+ /*
2
+ * Copyright © 2001-2009 Stéphane Raimbault <stephane.raimbault@gmail.com>
3
+ *
4
+ * This program is free software: you can redistribute it and/or modify
5
+ * it under the terms of the GNU Lesser Public License as published by
6
+ * the Free Software Foundation; either version 3 of the License, or
7
+ * (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU Lesser Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Lesser Public License
15
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ #ifndef _MODBUS_H_
19
+ #define _MODBUS_H_
20
+
21
+ #include <stdint.h>
22
+ #include <termios.h>
23
+ #include <arpa/inet.h>
24
+
25
+ #ifdef __cplusplus
26
+ extern "C" {
27
+ #endif
28
+
29
+ #define MODBUS_TCP_DEFAULT_PORT 502
30
+ #define MODBUS_BROADCAST_ADDRESS 255
31
+
32
+ /* Slave index */
33
+ #define HEADER_LENGTH_RTU 1
34
+ #define PRESET_QUERY_LENGTH_RTU 6
35
+ #define PRESET_RESPONSE_LENGTH_RTU 2
36
+
37
+ #define HEADER_LENGTH_TCP 7
38
+ #define PRESET_QUERY_LENGTH_TCP 12
39
+ #define PRESET_RESPONSE_LENGTH_TCP 8
40
+
41
+ #define CHECKSUM_LENGTH_RTU 2
42
+ #define CHECKSUM_LENGTH_TCP 0
43
+
44
+ /* It's not really the minimal length (the real one is report slave ID
45
+ * in RTU (4 bytes)) but it's a convenient size to use in RTU or TCP
46
+ * communications to read many values or write a single one.
47
+ * Maximum between :
48
+ * - HEADER_LENGTH_TCP (7) + function (1) + address (2) + number (2)
49
+ * - HEADER_LENGTH_RTU (1) + function (1) + address (2) + number (2) + CRC (2)
50
+ */
51
+ #define MIN_QUERY_LENGTH 12
52
+
53
+ /* Modbus_Application_Protocol_V1_1b.pdf Chapter 4 Section 1 Page 5:
54
+ * - RS232 / RS485 ADU = 253 bytes + slave (1 byte) + CRC (2 bytes) = 256 bytes
55
+ * - TCP MODBUS ADU = 253 bytes + MBAP (7 bytes) = 260 bytes
56
+ */
57
+ #define MAX_PDU_LENGTH 253
58
+ #define MAX_ADU_LENGTH_RTU 256
59
+ #define MAX_ADU_LENGTH_TCP 260
60
+
61
+ /* Kept for compatibility reasons (deprecated) */
62
+ #define MAX_MESSAGE_LENGTH 260
63
+
64
+ /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
65
+ * Quantity of Coils (2 bytes): 1 to 2000 (0x7D0)
66
+ */
67
+ #define MAX_STATUS 2000
68
+
69
+ /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 3 page 15)
70
+ * Quantity of Registers (2 bytes): 1 to 125 (0x7D)
71
+ */
72
+ #define MAX_REGISTERS 125
73
+
74
+ #define REPORT_SLAVE_ID_LENGTH 75
75
+
76
+ /* Time out between trames in microsecond */
77
+ #define TIME_OUT_BEGIN_OF_TRAME 500000
78
+ #define TIME_OUT_END_OF_TRAME 500000
79
+
80
+ #ifndef FALSE
81
+ #define FALSE 0
82
+ #endif
83
+
84
+ #ifndef TRUE
85
+ #define TRUE 1
86
+ #endif
87
+
88
+ #ifndef OFF
89
+ #define OFF 0
90
+ #endif
91
+
92
+ #ifndef ON
93
+ #define ON 1
94
+ #endif
95
+
96
+ /* Function codes */
97
+ #define FC_READ_COIL_STATUS 0x01 /* discretes inputs */
98
+ #define FC_READ_INPUT_STATUS 0x02 /* discretes outputs */
99
+ #define FC_READ_HOLDING_REGISTERS 0x03
100
+ #define FC_READ_INPUT_REGISTERS 0x04
101
+ #define FC_FORCE_SINGLE_COIL 0x05
102
+ #define FC_PRESET_SINGLE_REGISTER 0x06
103
+ #define FC_READ_EXCEPTION_STATUS 0x07
104
+ #define FC_FORCE_MULTIPLE_COILS 0x0F
105
+ #define FC_PRESET_MULTIPLE_REGISTERS 0x10
106
+ #define FC_REPORT_SLAVE_ID 0x11
107
+
108
+ /* Protocol exceptions */
109
+ #define ILLEGAL_FUNCTION -0x01
110
+ #define ILLEGAL_DATA_ADDRESS -0x02
111
+ #define ILLEGAL_DATA_VALUE -0x03
112
+ #define SLAVE_DEVICE_FAILURE -0x04
113
+ #define SERVER_FAILURE -0x04
114
+ #define ACKNOWLEDGE -0x05
115
+ #define SLAVE_DEVICE_BUSY -0x06
116
+ #define SERVER_BUSY -0x06
117
+ #define NEGATIVE_ACKNOWLEDGE -0x07
118
+ #define MEMORY_PARITY_ERROR -0x08
119
+ #define GATEWAY_PROBLEM_PATH -0x0A
120
+ #define GATEWAY_PROBLEM_TARGET -0x0B
121
+
122
+ /* Local */
123
+ #define INVALID_DATA -0x10
124
+ #define INVALID_CRC -0x11
125
+ #define INVALID_EXCEPTION_CODE -0x12
126
+
127
+ #define SELECT_TIMEOUT -0x13
128
+ #define SELECT_FAILURE -0x14
129
+ #define SOCKET_FAILURE -0x15
130
+ #define CONNECTION_CLOSED -0x16
131
+
132
+ /* Internal using */
133
+ #define MSG_LENGTH_UNDEFINED -1
134
+
135
+ typedef enum { RTU=0, TCP } type_com_t;
136
+ typedef enum { FLUSH_OR_CONNECT_ON_ERROR, NOP_ON_ERROR } error_handling_t;
137
+
138
+ /* This structure is byte-aligned */
139
+ typedef struct {
140
+ /* Slave address */
141
+ int slave;
142
+ /* Descriptor (tty or socket) */
143
+ int fd;
144
+ /* Communication mode: RTU or TCP */
145
+ type_com_t type_com;
146
+ /* Flag debug */
147
+ int debug;
148
+ /* TCP port */
149
+ int port;
150
+ /* Device: "/dev/ttyS0", "/dev/ttyUSB0" or "/dev/tty.USA19*"
151
+ on Mac OS X for KeySpan USB<->Serial adapters this string
152
+ had to be made bigger on OS X as the directory+file name
153
+ was bigger than 19 bytes. Making it 67 bytes for now, but
154
+ OS X does support 256 byte file names. May become a problem
155
+ in the future. */
156
+ #ifdef __APPLE_CC__
157
+ char device[64];
158
+ #else
159
+ char device[16];
160
+ #endif
161
+ /* Bauds: 9600, 19200, 57600, 115200, etc */
162
+ int baud;
163
+ /* Data bit */
164
+ uint8_t data_bit;
165
+ /* Stop bit */
166
+ uint8_t stop_bit;
167
+ /* Parity: "even", "odd", "none" */
168
+ char parity[5];
169
+ /* In error_treat with TCP, do a reconnect or just dump the error */
170
+ uint8_t error_handling;
171
+ /* IP address */
172
+ char ip[16];
173
+ /* Save old termios settings */
174
+ struct termios old_tios;
175
+ } modbus_param_t;
176
+
177
+ typedef struct {
178
+ int nb_coil_status;
179
+ int nb_input_status;
180
+ int nb_input_registers;
181
+ int nb_holding_registers;
182
+ uint8_t *tab_coil_status;
183
+ uint8_t *tab_input_status;
184
+ uint16_t *tab_input_registers;
185
+ uint16_t *tab_holding_registers;
186
+ } modbus_mapping_t;
187
+
188
+
189
+ /* All functions used for sending or receiving data return:
190
+ - the numbers of values (bits or word) if success (0 or more)
191
+ - less than 0 for exceptions errors
192
+ */
193
+
194
+ /* Reads the boolean status of coils and sets the array elements in
195
+ the destination to TRUE or FALSE */
196
+ int read_coil_status(modbus_param_t *mb_param, int start_addr, int nb,
197
+ uint8_t *dest);
198
+
199
+ /* Same as read_coil_status but reads the slaves input table */
200
+ int read_input_status(modbus_param_t *mb_param, int start_addr, int nb,
201
+ uint8_t *dest);
202
+
203
+ /* Reads the holding registers in a slave and put the data into an
204
+ array */
205
+ int read_holding_registers(modbus_param_t *mb_param, int start_addr, int nb,
206
+ uint16_t *dest);
207
+
208
+ /* Reads the input registers in a slave and put the data into an
209
+ array */
210
+ int read_input_registers(modbus_param_t *mb_param, int start_addr, int nb,
211
+ uint16_t *dest);
212
+
213
+ /* Turns ON or OFF a single coil in the slave device */
214
+ int force_single_coil(modbus_param_t *mb_param, int coil_addr, int state);
215
+
216
+ /* Sets a value in one holding register in the slave device */
217
+ int preset_single_register(modbus_param_t *mb_param, int reg_addr, int value);
218
+
219
+ /* Sets/resets the coils in the slave from an array in argument */
220
+ int force_multiple_coils(modbus_param_t *mb_param, int start_addr, int nb,
221
+ const uint8_t *data);
222
+
223
+ /* Copies the values in the slave from the array given in argument */
224
+ int preset_multiple_registers(modbus_param_t *mb_param, int start_addr, int nb,
225
+ const uint16_t *data);
226
+
227
+ /* Returns the slave id! */
228
+ int report_slave_id(modbus_param_t *mb_param, uint8_t *dest);
229
+
230
+ /* Initializes the modbus_param_t structure for RTU.
231
+ - device: "/dev/ttyS0"
232
+ - baud: 9600, 19200, 57600, 115200, etc
233
+ - parity: "even", "odd" or "none"
234
+ - data_bits: 5, 6, 7, 8
235
+ - stop_bits: 1, 2
236
+ */
237
+ void modbus_init_rtu(modbus_param_t *mb_param, const char *device,
238
+ int baud, const char *parity, int data_bit,
239
+ int stop_bit, int slave);
240
+
241
+ /* Initializes the modbus_param_t structure for TCP.
242
+ - ip: "192.168.0.5"
243
+ - port: 1099
244
+ - slave: 5
245
+
246
+ Set the port to MODBUS_TCP_DEFAULT_PORT to use the default one
247
+ (502). It's convenient to use a port number greater than or equal
248
+ to 1024 because it's not necessary to be root to use this port
249
+ number.
250
+ */
251
+ void modbus_init_tcp(modbus_param_t *mb_param, const char *ip_address, int port,
252
+ int slave);
253
+
254
+ /* By default, the error handling mode used is CONNECT_ON_ERROR.
255
+
256
+ With FLUSH_OR_CONNECT_ON_ERROR, the library will attempt an immediate
257
+ reconnection which may hang for several seconds if the network to
258
+ the remote target unit is down.
259
+
260
+ With NOP_ON_ERROR, it is expected that the application will
261
+ check for network error returns and deal with them as necessary.
262
+
263
+ This function is only useful in TCP mode.
264
+ */
265
+ void modbus_set_error_handling(modbus_param_t *mb_param, error_handling_t error_handling);
266
+
267
+ /* Establishes a modbus connexion.
268
+ Returns 0 on success or -1 on failure. */
269
+ int modbus_connect(modbus_param_t *mb_param);
270
+
271
+ /* Closes a modbus connection */
272
+ void modbus_close(modbus_param_t *mb_param);
273
+
274
+ /* Flush the pending request */
275
+ void modbus_flush(modbus_param_t *mb_param);
276
+
277
+ /* Activates the debug messages */
278
+ void modbus_set_debug(modbus_param_t *mb_param, int boolean);
279
+
280
+ /**
281
+ * SLAVE/CLIENT FUNCTIONS
282
+ **/
283
+
284
+ /* Allocates 4 arrays to store coils, input status, input registers and
285
+ holding registers. The pointers are stored in modbus_mapping structure.
286
+
287
+ Returns 0 on success and -1 on failure
288
+ */
289
+ int modbus_mapping_new(modbus_mapping_t *mb_mapping,
290
+ int nb_coil_status, int nb_input_status,
291
+ int nb_holding_registers, int nb_input_registers);
292
+
293
+ /* Frees the 4 arrays */
294
+ void modbus_mapping_free(modbus_mapping_t *mb_mapping);
295
+
296
+ /* Listens for any query from one or many modbus masters in TCP.
297
+
298
+ Returns: socket
299
+ */
300
+ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection);
301
+
302
+ /* Waits for a connection */
303
+ int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket);
304
+
305
+ /* Listens for any query from a modbus master in TCP, requires the socket file
306
+ descriptor etablished with the master device in argument.
307
+
308
+ Returns:
309
+ - 0 on success, or a negative error number if the request fails
310
+ - query, message received
311
+ - query_length, length in bytes of the message
312
+ */
313
+ int modbus_slave_receive(modbus_param_t *mb_param, int sockfd,
314
+ uint8_t *query, int *query_length);
315
+
316
+ /* Manages the received query.
317
+ Analyses the query and constructs a response.
318
+
319
+ If an error occurs, this function construct the response
320
+ accordingly.
321
+ */
322
+ void modbus_slave_manage(modbus_param_t *mb_param, const uint8_t *query,
323
+ int query_length, modbus_mapping_t *mb_mapping);
324
+
325
+
326
+ /**
327
+ * UTILS FUNCTIONS
328
+ **/
329
+
330
+ /* Sets many input/coil status from a single byte value (all 8 bits of
331
+ the byte value are set) */
332
+ void set_bits_from_byte(uint8_t *dest, int address, const uint8_t value);
333
+
334
+ /* Sets many input/coil status from a table of bytes (only the bits
335
+ between address and address + nb_bits are set) */
336
+ void set_bits_from_bytes(uint8_t *dest, int address, int nb_bits,
337
+ const uint8_t *tab_byte);
338
+
339
+ /* Gets the byte value from many input/coil status.
340
+ To obtain a full byte, set nb_bits to 8. */
341
+ uint8_t get_byte_from_bits(const uint8_t *src, int address, int nb_bits);
342
+
343
+ #ifdef __cplusplus
344
+ }
345
+ #endif
346
+
347
+ #endif /* _MODBUS_H_ */
data/ext/modbus4r.c CHANGED
@@ -14,10 +14,14 @@ GNU General Public License for more details. */
14
14
  #include "modbus4r.h"
15
15
  #include "errors.h"
16
16
  #include "master.h"
17
+ #include "slave.h"
17
18
  #include "tcp_master.h"
18
19
  #include "rtu_master.h"
20
+ #include "tcp_slave.h"
21
+ #include "rtu_slave.h"
19
22
 
20
- VALUE mModBus, cMaster, cTCPMaster, cRTUMaster;
23
+ VALUE mModBus, cMaster, cTCPMaster, cRTUMaster, cSlave,
24
+ cTCPSlave, cRTUSlave;
21
25
 
22
26
  void Init__modbus4r()
23
27
  {
@@ -28,29 +32,61 @@ void Init__modbus4r()
28
32
  rb_define_method(cMaster, "connect", mb_mstr_connect, 0);
29
33
  rb_define_method(cMaster, "close", mb_mstr_close, 0);
30
34
  rb_define_method(cMaster, "read_coil_status",
31
- mb_mstr_read_coil_status, 3);
35
+ mb_mstr_read_coil_status, 2);
32
36
  rb_define_method(cMaster, "read_input_status",
33
- mb_mstr_read_input_status, 3);
37
+ mb_mstr_read_input_status, 2);
34
38
  rb_define_method(cMaster, "read_holding_registers",
35
- mb_mstr_read_holding_registers, 3);
39
+ mb_mstr_read_holding_registers, 2);
36
40
  rb_define_method(cMaster, "read_input_registers",
37
- mb_mstr_read_input_registers, 3);
41
+ mb_mstr_read_input_registers, 2);
38
42
  rb_define_method(cMaster, "force_single_coil",
39
- mb_mstr_force_single_coil, 3);
43
+ mb_mstr_force_single_coil, 2);
40
44
  rb_define_method(cMaster, "preset_single_register",
41
- mb_mstr_preset_single_register, 3);
45
+ mb_mstr_preset_single_register, 2);
42
46
  rb_define_method(cMaster, "force_multiple_coils",
43
- mb_mstr_force_multiple_coils, 3);
47
+ mb_mstr_force_multiple_coils, 2);
44
48
  rb_define_method(cMaster, "preset_multiple_registers",
45
- mb_mstr_preset_multiple_registers, 3);
49
+ mb_mstr_preset_multiple_registers, 2);
46
50
 
47
51
  /* TCPMaster */
48
52
  cTCPMaster = rb_define_class_under(mModBus, "TCPMaster", cMaster);
49
- rb_define_singleton_method(cTCPMaster, "new", mb_tcp_mstr_new, 2);
53
+ rb_define_singleton_method(cTCPMaster, "new", mb_tcp_mstr_new, 3);
50
54
 
51
55
  /* RTUMaster */
52
56
  cRTUMaster = rb_define_class_under(mModBus, "RTUMaster", cMaster);
53
- rb_define_singleton_method(cRTUMaster, "new", mb_rtu_mstr_new, 5);
57
+ rb_define_singleton_method(cRTUMaster, "new", mb_rtu_mstr_new, 6);
58
+
59
+ /* Slave */
60
+ cSlave = rb_define_class_under(mModBus, "Slave", rb_cObject);
61
+ rb_define_method(cSlave, "stoped?", mb_sl_is_stoped, 0);
62
+ rb_define_method(cSlave, "coil_status",
63
+ mb_sl_get_coil_status, 0);
64
+ rb_define_method(cSlave, "coil_status=",
65
+ mb_sl_set_coil_status, 1);
66
+ rb_define_method(cSlave, "input_status",
67
+ mb_sl_get_input_status, 0);
68
+ rb_define_method(cSlave, "input_status=",
69
+ mb_sl_set_input_status, 1);
70
+ rb_define_method(cSlave, "holding_registers",
71
+ mb_sl_get_holding_registers, 0);
72
+ rb_define_method(cSlave, "holding_registers=",
73
+ mb_sl_set_holding_registers, 1);
74
+ rb_define_method(cSlave, "input_registers",
75
+ mb_sl_get_input_registers, 0);
76
+ rb_define_method(cSlave, "input_registers=",
77
+ mb_sl_set_input_registers, 1);
78
+ rb_define_method(cSlave, "join", mb_sl_join, 0);
79
+ /* TCPSlave */
80
+ cTCPSlave = rb_define_class_under(mModBus, "TCPSlave", cSlave);
81
+ rb_define_singleton_method(cTCPSlave, "new", mb_tcp_sl_new, 3);
82
+ rb_define_method(cTCPSlave, "start", mb_tcp_sl_start, 0);
83
+ rb_define_method(cTCPSlave, "stop", mb_tcp_sl_stop, 0);
84
+
85
+ /* RTUSlave */
86
+ cRTUSlave = rb_define_class_under(mModBus, "RTUSlave", cSlave);
87
+ rb_define_singleton_method(cRTUSlave, "new", mb_rtu_sl_new, 6);
88
+ rb_define_method(cRTUSlave, "start", mb_rtu_sl_start, 0);
89
+ rb_define_method(cRTUSlave, "stop", mb_rtu_sl_stop, 0);
54
90
 
55
91
  /* Errors */
56
92
  mErrors = rb_define_module_under(mModBus, "Errors");
data/ext/modbus4r.h CHANGED
@@ -14,8 +14,13 @@ GNU General Public License for more details. */
14
14
  #ifndef MODBUS_H
15
15
  #define MODBUS_H
16
16
 
17
+ #include "modbus.h"
18
+ #ifdef RUBY_1_8
19
+ #include <ruby.h>
20
+ #include <intern.h>
21
+ #else
17
22
  #include "ruby/ruby.h"
18
23
  #include "ruby/intern.h"
19
- #include "modbus/modbus.h"
24
+ #endif
20
25
 
21
26
  #endif
data/ext/rtu_master.c CHANGED
@@ -12,15 +12,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
12
  GNU General Public License for more details. */
13
13
 
14
14
  #include "modbus4r.h"
15
-
16
- void mb_rtu_mstr_free(modbus_param_t *mb_param )
17
- {
18
- modbus_close(mb_param);
19
- free(mb_param);
20
- }
15
+ #include "master.h"
21
16
 
22
17
  VALUE mb_rtu_mstr_new(VALUE self, VALUE device, VALUE baud,
23
- VALUE parity, VALUE data_bit, VALUE stop_bit)
18
+ VALUE parity, VALUE data_bit,
19
+ VALUE stop_bit, VALUE slave)
24
20
  {
25
21
  modbus_param_t *mb_param;
26
22
 
@@ -30,9 +26,11 @@ VALUE mb_rtu_mstr_new(VALUE self, VALUE device, VALUE baud,
30
26
  parity = rb_funcall(parity, rb_intern("to_s"), 0);
31
27
  data_bit = rb_funcall(data_bit, rb_intern("to_i"), 0);
32
28
  stop_bit = rb_funcall(stop_bit, rb_intern("to_i"), 0);
29
+ slave = rb_funcall(slave, rb_intern("to_i"), 0);
33
30
 
34
31
  modbus_init_rtu(mb_param, RSTRING_PTR(device), FIX2INT(baud),
35
- RSTRING_PTR(parity), FIX2INT(data_bit), FIX2INT(stop_bit));
32
+ RSTRING_PTR(parity), FIX2INT(data_bit),
33
+ FIX2INT(stop_bit), FIX2INT(slave));
36
34
 
37
- return Data_Wrap_Struct(self, 0, mb_rtu_mstr_free, mb_param);
35
+ return Data_Wrap_Struct(self, 0, mb_mstr_free, mb_param);
38
36
  }
data/ext/rtu_master.h CHANGED
@@ -15,6 +15,7 @@ GNU General Public License for more details. */
15
15
  #define RTU_MASTER_H
16
16
 
17
17
  extern VALUE mb_rtu_mstr_new(VALUE self, VALUE device, VALUE baud,
18
- VALUE parity, VALUE data_bit, VALUE stop_bit);
18
+ VALUE parity, VALUE data_bit,
19
+ VALUE stop_bit, VALUE slave);
19
20
 
20
21
  #endif
data/ext/rtu_slave.c ADDED
@@ -0,0 +1,131 @@
1
+ /* libmodbus4r - binding use libmodbus for Ruby.
2
+ Copyright (C) 2009 Timin Aleksey
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details. */
13
+
14
+ #include <pthread.h>
15
+ #include <unistd.h>
16
+ #include "modbus4r.h"
17
+ #include "slave.h"
18
+ #include "errors.h"
19
+
20
+ void mb_rtu_sl_free(modbus_slave_t *mb_slave)
21
+ {
22
+ pthread_cancel(mb_slave->tid);
23
+
24
+ modbus_close(mb_slave->mb_param);
25
+
26
+ modbus_mapping_free(mb_slave->mb_map);
27
+ #ifndef RUBY_1_8
28
+ rb_ary_free(mb_slave->coil_status);
29
+ rb_ary_free(mb_slave->input_status);
30
+ rb_ary_free(mb_slave->holding_registers);
31
+ rb_ary_free(mb_slave->input_registers);
32
+ #else
33
+ free(RARRAY_PTR(mb_slave->coil_status));
34
+ free(RARRAY_PTR(mb_slave->input_status));
35
+ free(RARRAY_PTR(mb_slave->holding_registers));
36
+ free(RARRAY_PTR(mb_slave->input_registers));
37
+ #endif
38
+
39
+ free(mb_slave);
40
+ }
41
+
42
+ void *mb_rtu_serv(void *arg)
43
+ {
44
+ modbus_slave_t *mb_slave = (modbus_slave_t *)arg;
45
+
46
+ uint8_t query[MAX_MESSAGE_LENGTH];
47
+ int query_size;
48
+ while (1) {
49
+ int ret = modbus_slave_receive(mb_slave->mb_param, -1,
50
+ query, &query_size);
51
+
52
+ if (ret == 0) {
53
+ mb_push_coil_status(mb_slave);
54
+ mb_push_input_status(mb_slave);
55
+ mb_push_holding_registers(mb_slave);
56
+ mb_push_input_registers(mb_slave);
57
+
58
+ modbus_slave_manage(mb_slave->mb_param, query,
59
+ query_size, mb_slave->mb_map);
60
+
61
+ mb_pull_coil_status(mb_slave);
62
+ mb_pull_holding_registers(mb_slave);
63
+ } else if (ret == CONNECTION_CLOSED) {
64
+ break;
65
+ } else {
66
+ continue;
67
+ }
68
+ }
69
+ }
70
+
71
+ VALUE mb_rtu_sl_new(VALUE self, VALUE device, VALUE baud,
72
+ VALUE parity, VALUE data_bit,
73
+ VALUE stop_bit, VALUE slave)
74
+ {
75
+ modbus_slave_t *mb_slave;
76
+
77
+ mb_slave = malloc(sizeof(modbus_slave_t));
78
+ mb_slave->mb_param = malloc(sizeof(modbus_param_t));
79
+ mb_slave->mb_map = malloc(sizeof(modbus_mapping_t));
80
+
81
+ device = rb_funcall(device, rb_intern("to_s"), 0);
82
+ baud = rb_funcall(baud, rb_intern("to_i"), 0);
83
+ parity = rb_funcall(parity, rb_intern("to_s"), 0);
84
+ data_bit = rb_funcall(data_bit, rb_intern("to_i"), 0);
85
+ stop_bit = rb_funcall(stop_bit, rb_intern("to_i"), 0);
86
+ slave = rb_funcall(slave, rb_intern("to_i"), 0);
87
+
88
+ modbus_init_rtu(mb_slave->mb_param, RSTRING_PTR(device), FIX2INT(baud),
89
+ RSTRING_PTR(parity), FIX2INT(data_bit),
90
+ FIX2INT(stop_bit), FIX2INT(slave));
91
+ int ret = modbus_mapping_new(mb_slave->mb_map, 0, 0, 0, 0);
92
+ if (ret < 0) {
93
+ rb_raise(rb_eStandardError, "Memory allocation failed");
94
+ }
95
+
96
+ mb_slave->coil_status = rb_ary_new();
97
+ mb_slave->input_status = rb_ary_new();
98
+ mb_slave->holding_registers = rb_ary_new();
99
+ mb_slave->input_registers = rb_ary_new();
100
+
101
+ return Data_Wrap_Struct(self, 0, mb_rtu_sl_free, mb_slave);
102
+ }
103
+
104
+ VALUE mb_rtu_sl_start(VALUE self)
105
+ {
106
+ modbus_slave_t *mb_slave;
107
+ Data_Get_Struct(self, modbus_slave_t, mb_slave);
108
+
109
+ int ret = pthread_create(&mb_slave->tid, NULL, mb_rtu_serv,
110
+ (void *)mb_slave);
111
+ if (ret != 0) {
112
+ rb_raise(rb_eStandardError, "Slave has not started");
113
+ }
114
+
115
+ return self;
116
+ }
117
+
118
+ VALUE mb_rtu_sl_stop(VALUE self)
119
+ {
120
+ modbus_slave_t *mb_slave;
121
+ Data_Get_Struct(self, modbus_slave_t, mb_slave);
122
+
123
+ int ret = pthread_cancel(mb_slave->tid);
124
+ if (ret != 0) {
125
+ rb_raise(rb_eStandardError, "Slave has not stoped");
126
+ }
127
+
128
+ close(mb_slave->listen_sock);
129
+
130
+ return self;
131
+ }
data/ext/rtu_slave.h ADDED
@@ -0,0 +1,23 @@
1
+ /* libmodbus4r - binding use libmodbus for Ruby.
2
+ Copyright (C) 2009 Timin Aleksey
3
+
4
+ This program is free software: you can redistribute it and/or modify
5
+ it under the terms of the GNU General Public License as published by
6
+ the Free Software Foundation, either version 3 of the License, or
7
+ (at your option) any later version.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details. */
13
+
14
+ #ifndef RTU_SLAVE_H
15
+ #define RTU_SLAVE_H
16
+
17
+ extern VALUE mb_rtu_sl_new(VALUE self, VALUE device, VALUE baud,
18
+ VALUE parity, VALUE data_bit,
19
+ VALUE stop_bit, VALUE slave);
20
+ extern VALUE mb_rtu_sl_start(VALUE self);
21
+ extern VALUE mb_rtu_sl_stop(VALUE self);
22
+
23
+ #endif