libmodbus4r 0.2.2 → 0.3.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.
- data/NEWS +12 -3
- data/README +29 -24
- data/examples/use_rtu_master.rb +10 -17
- data/examples/use_rtu_slave.rb +24 -0
- data/examples/use_tcp_master.rb +11 -17
- data/examples/use_tcp_slave.rb +21 -0
- data/ext/errors.c +11 -11
- data/ext/extconf.rb +6 -1
- data/ext/master.c +30 -40
- data/ext/master.h +9 -8
- data/ext/modbus.c +1959 -0
- data/ext/modbus.h +347 -0
- data/ext/modbus4r.c +47 -11
- data/ext/modbus4r.h +6 -1
- data/ext/rtu_master.c +7 -9
- data/ext/rtu_master.h +2 -1
- data/ext/rtu_slave.c +131 -0
- data/ext/rtu_slave.h +23 -0
- data/ext/slave.c +215 -0
- data/ext/slave.h +44 -0
- data/ext/tcp_master.c +5 -9
- data/ext/tcp_master.h +2 -1
- data/ext/tcp_slave.c +134 -0
- data/ext/tcp_slave.h +21 -0
- data/lib/modbus4r.rb +12 -11
- data/spec/rtu_master_spec.rb +1 -1
- data/spec/rtu_slave_spec.rb +16 -0
- data/spec/tcp_master_spec.rb +36 -26
- data/spec/tcp_slave_spec.rb +95 -0
- metadata +21 -11
- data/TODO +0 -5
data/ext/slave.c
ADDED
@@ -0,0 +1,215 @@
|
|
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 <unistd.h>
|
15
|
+
#include <pthread.h>
|
16
|
+
#include "modbus4r.h"
|
17
|
+
#include "slave.h"
|
18
|
+
|
19
|
+
void mb_push_coil_status(modbus_slave_t *mb_slave)
|
20
|
+
{
|
21
|
+
int len = RARRAY_LEN(mb_slave->coil_status);
|
22
|
+
VALUE *ptr_coil = RARRAY_PTR(mb_slave->coil_status);
|
23
|
+
mb_slave->mb_map->nb_coil_status = len;
|
24
|
+
mb_slave->mb_map->tab_coil_status = malloc(sizeof(uint8_t) * len);
|
25
|
+
uint8_t *ptr_map = mb_slave->mb_map->tab_coil_status;
|
26
|
+
|
27
|
+
int i;
|
28
|
+
for (i = 0; i < len; i++) {
|
29
|
+
*ptr_map = (*ptr_coil == Qtrue ? 1 : 0);
|
30
|
+
ptr_coil++;
|
31
|
+
ptr_map++;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
void mb_pull_coil_status(modbus_slave_t *mb_slave)
|
36
|
+
{
|
37
|
+
uint8_t *ptr_map = mb_slave->mb_map->tab_coil_status;
|
38
|
+
VALUE *ptr_coil = RARRAY_PTR(mb_slave->coil_status);
|
39
|
+
int i;
|
40
|
+
for(i = 0; i < mb_slave->mb_map->nb_coil_status; i++) {
|
41
|
+
*ptr_coil = (*ptr_map == 0 ? Qfalse : Qtrue);
|
42
|
+
ptr_coil++;
|
43
|
+
ptr_map++;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
void mb_push_input_status(modbus_slave_t *mb_slave)
|
48
|
+
{
|
49
|
+
int len = RARRAY_LEN(mb_slave->input_status);
|
50
|
+
VALUE *ptr_input = RARRAY_PTR(mb_slave->input_status);
|
51
|
+
mb_slave->mb_map->nb_input_status = len;
|
52
|
+
mb_slave->mb_map->tab_input_status = malloc(sizeof(uint8_t) * len);
|
53
|
+
uint8_t *ptr_map = mb_slave->mb_map->tab_input_status;
|
54
|
+
|
55
|
+
int i;
|
56
|
+
for (i = 0; i < len; i++) {
|
57
|
+
*ptr_map = (*ptr_input == Qtrue ? 1 : 0);
|
58
|
+
ptr_input++;
|
59
|
+
ptr_map++;
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
void mb_push_holding_registers(modbus_slave_t *mb_slave)
|
64
|
+
{
|
65
|
+
int len = RARRAY_LEN(mb_slave->holding_registers);
|
66
|
+
VALUE *ptr_reg = RARRAY_PTR(mb_slave->holding_registers);
|
67
|
+
mb_slave->mb_map->nb_holding_registers = len;
|
68
|
+
mb_slave->mb_map->tab_holding_registers = malloc(sizeof(uint16_t) * len);
|
69
|
+
uint16_t *ptr_map = mb_slave->mb_map->tab_holding_registers;
|
70
|
+
|
71
|
+
int i;
|
72
|
+
for (i = 0; i < len; i++) {
|
73
|
+
*ptr_map = FIX2INT(*ptr_reg);
|
74
|
+
ptr_reg++;
|
75
|
+
ptr_map++;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
void mb_pull_holding_registers(modbus_slave_t *mb_slave)
|
80
|
+
{
|
81
|
+
uint16_t *ptr_map = mb_slave->mb_map->tab_holding_registers;
|
82
|
+
VALUE *ptr_reg = RARRAY_PTR(mb_slave->holding_registers);
|
83
|
+
int i;
|
84
|
+
for(i = 0; i < mb_slave->mb_map->nb_holding_registers; i++) {
|
85
|
+
*ptr_reg = INT2FIX(*ptr_map);
|
86
|
+
ptr_reg++;
|
87
|
+
ptr_map++;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
void mb_push_input_registers(modbus_slave_t *mb_slave)
|
92
|
+
{
|
93
|
+
int len = RARRAY_LEN(mb_slave->input_registers);
|
94
|
+
VALUE *ptr_reg = RARRAY_PTR(mb_slave->input_registers);
|
95
|
+
mb_slave->mb_map->nb_input_registers = len;
|
96
|
+
mb_slave->mb_map->tab_input_registers = malloc(sizeof(uint16_t) * len);
|
97
|
+
uint16_t *ptr_map = mb_slave->mb_map->tab_input_registers;
|
98
|
+
|
99
|
+
int i;
|
100
|
+
for (i = 0; i < len; i++) {
|
101
|
+
*ptr_map = FIX2INT(*ptr_reg);
|
102
|
+
ptr_reg++;
|
103
|
+
ptr_map++;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
VALUE mb_sl_is_stoped(VALUE self)
|
108
|
+
{
|
109
|
+
modbus_slave_t *mb_slave;
|
110
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
111
|
+
|
112
|
+
if (read(mb_slave->listen_sock, NULL, 0)
|
113
|
+
|| mb_slave->listen_sock == 0) {
|
114
|
+
return Qtrue;
|
115
|
+
}
|
116
|
+
return Qfalse;
|
117
|
+
}
|
118
|
+
|
119
|
+
VALUE mb_sl_get_coil_status(VALUE self)
|
120
|
+
{
|
121
|
+
modbus_slave_t *mb_slave;
|
122
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
123
|
+
|
124
|
+
return mb_slave->coil_status;
|
125
|
+
}
|
126
|
+
|
127
|
+
VALUE mb_sl_set_coil_status(VALUE self, VALUE value)
|
128
|
+
{
|
129
|
+
modbus_slave_t *mb_slave;
|
130
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
131
|
+
|
132
|
+
value = rb_funcall(value, rb_intern("to_a"), 0);
|
133
|
+
mb_slave->coil_status = rb_ary_dup(value);
|
134
|
+
|
135
|
+
return mb_slave->coil_status;
|
136
|
+
}
|
137
|
+
|
138
|
+
VALUE mb_sl_get_input_status(VALUE self)
|
139
|
+
{
|
140
|
+
modbus_slave_t *mb_slave;
|
141
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
142
|
+
|
143
|
+
return mb_slave->input_status;
|
144
|
+
}
|
145
|
+
|
146
|
+
VALUE mb_sl_set_input_status(VALUE self, VALUE value)
|
147
|
+
{
|
148
|
+
modbus_slave_t *mb_slave;
|
149
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
150
|
+
|
151
|
+
value = rb_funcall(value, rb_intern("to_a"), 0);
|
152
|
+
mb_slave->input_status = rb_ary_dup(value);
|
153
|
+
|
154
|
+
return mb_slave->input_status;
|
155
|
+
}
|
156
|
+
|
157
|
+
VALUE mb_sl_get_holding_registers(VALUE self)
|
158
|
+
{
|
159
|
+
modbus_slave_t *mb_slave;
|
160
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
161
|
+
|
162
|
+
return mb_slave->holding_registers;
|
163
|
+
}
|
164
|
+
|
165
|
+
VALUE mb_sl_set_holding_registers(VALUE self, VALUE value)
|
166
|
+
{
|
167
|
+
modbus_slave_t *mb_slave;
|
168
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
169
|
+
|
170
|
+
value = rb_funcall(value, rb_intern("to_a"), 0);
|
171
|
+
mb_slave->holding_registers = rb_ary_dup(value);
|
172
|
+
VALUE *reg = RARRAY_PTR(mb_slave->holding_registers);
|
173
|
+
|
174
|
+
int i;
|
175
|
+
for (i = 0; i < RARRAY_LEN(mb_slave->holding_registers); i++) {
|
176
|
+
*reg = rb_funcall(*reg, rb_intern("to_i"), 0);
|
177
|
+
}
|
178
|
+
|
179
|
+
return mb_slave->holding_registers;
|
180
|
+
}
|
181
|
+
|
182
|
+
VALUE mb_sl_get_input_registers(VALUE self)
|
183
|
+
{
|
184
|
+
modbus_slave_t *mb_slave;
|
185
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
186
|
+
|
187
|
+
return mb_slave->input_registers;
|
188
|
+
}
|
189
|
+
|
190
|
+
VALUE mb_sl_set_input_registers(VALUE self, VALUE value)
|
191
|
+
{
|
192
|
+
modbus_slave_t *mb_slave;
|
193
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
194
|
+
|
195
|
+
value = rb_funcall(value, rb_intern("to_a"), 0);
|
196
|
+
mb_slave->input_registers = rb_ary_dup(value);
|
197
|
+
VALUE *reg = RARRAY_PTR(mb_slave->input_registers);
|
198
|
+
|
199
|
+
int i;
|
200
|
+
for (i = 0; i < RARRAY_LEN(mb_slave->input_registers); i++) {
|
201
|
+
*reg = rb_funcall(*reg, rb_intern("to_i"), 0);
|
202
|
+
}
|
203
|
+
|
204
|
+
return mb_slave->input_registers;
|
205
|
+
}
|
206
|
+
|
207
|
+
VALUE mb_sl_join(VALUE self)
|
208
|
+
{
|
209
|
+
modbus_slave_t *mb_slave;
|
210
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
211
|
+
|
212
|
+
pthread_join(mb_slave->tid, NULL);
|
213
|
+
|
214
|
+
return self;
|
215
|
+
}
|
data/ext/slave.h
ADDED
@@ -0,0 +1,44 @@
|
|
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 SLAVE_H
|
15
|
+
#define SLAVE_H
|
16
|
+
|
17
|
+
typedef struct {
|
18
|
+
pthread_t tid;
|
19
|
+
int listen_sock;
|
20
|
+
modbus_param_t *mb_param;
|
21
|
+
modbus_mapping_t *mb_map;
|
22
|
+
VALUE coil_status;
|
23
|
+
VALUE input_status;
|
24
|
+
VALUE holding_registers;
|
25
|
+
VALUE input_registers;
|
26
|
+
} modbus_slave_t;
|
27
|
+
|
28
|
+
extern void mb_push_coil_status(modbus_slave_t *mb_slave);
|
29
|
+
extern void mb_pull_coil_status(modbus_slave_t *mb_slave);
|
30
|
+
extern void mb_push_input_status(modbus_slave_t *mb_slave);
|
31
|
+
extern void mb_push_holding_registers(modbus_slave_t *mb_slave);
|
32
|
+
extern void mb_pull_holding_registers(modbus_slave_t *mb_slave);
|
33
|
+
extern void mb_push_input_registers(modbus_slave_t *mb_slave);
|
34
|
+
extern VALUE mb_sl_is_stoped(VALUE self);
|
35
|
+
extern VALUE mb_sl_get_coil_status(VALUE self);
|
36
|
+
extern VALUE mb_sl_set_coil_status(VALUE self, VALUE value);
|
37
|
+
extern VALUE mb_sl_get_input_status(VALUE self);
|
38
|
+
extern VALUE mb_sl_set_input_status(VALUE self, VALUE value);
|
39
|
+
extern VALUE mb_sl_get_holding_registers(VALUE self);
|
40
|
+
extern VALUE mb_sl_set_holding_registers(VALUE self, VALUE value);
|
41
|
+
extern VALUE mb_sl_get_input_registers(VALUE self);
|
42
|
+
extern VALUE mb_sl_set_input_registers(VALUE self, VALUE value);
|
43
|
+
extern VALUE mb_sl_join(VALUE self);
|
44
|
+
#endif
|
data/ext/tcp_master.c
CHANGED
@@ -12,22 +12,18 @@ 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
|
+
#include "master.h"
|
15
16
|
|
16
|
-
|
17
|
-
{
|
18
|
-
modbus_close(mb_param);
|
19
|
-
free(mb_param);
|
20
|
-
}
|
21
|
-
|
22
|
-
VALUE mb_tcp_mstr_new(VALUE self, VALUE ip_address, VALUE port)
|
17
|
+
VALUE mb_tcp_mstr_new(VALUE self, VALUE ip_address, VALUE port, VALUE slave)
|
23
18
|
{
|
24
19
|
modbus_param_t *mb_param;
|
25
20
|
|
26
21
|
mb_param = malloc(sizeof(modbus_param_t));
|
27
22
|
ip_address = rb_funcall(ip_address, rb_intern("to_s"), 0);
|
28
23
|
port = rb_funcall(port, rb_intern("to_i"), 0);
|
24
|
+
slave = rb_funcall(slave, rb_intern("to_i"), 0);
|
29
25
|
|
30
|
-
modbus_init_tcp(mb_param, RSTRING_PTR(ip_address), FIX2INT(port));
|
26
|
+
modbus_init_tcp(mb_param, RSTRING_PTR(ip_address), FIX2INT(port), FIX2INT(slave));
|
31
27
|
|
32
|
-
return Data_Wrap_Struct(self, 0,
|
28
|
+
return Data_Wrap_Struct(self, 0, mb_mstr_free, mb_param);
|
33
29
|
}
|
data/ext/tcp_master.h
CHANGED
@@ -14,6 +14,7 @@ GNU General Public License for more details. */
|
|
14
14
|
#ifndef TCP_MASTER_H
|
15
15
|
#define TCP_MASTER_H
|
16
16
|
|
17
|
-
extern VALUE mb_tcp_mstr_new(VALUE self,
|
17
|
+
extern VALUE mb_tcp_mstr_new(VALUE self,
|
18
|
+
VALUE ip_address, VALUE port, VALUE slave);
|
18
19
|
|
19
20
|
#endif
|
data/ext/tcp_slave.c
ADDED
@@ -0,0 +1,134 @@
|
|
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_tcp_sl_free(modbus_slave_t *mb_slave)
|
21
|
+
{
|
22
|
+
close(mb_slave->listen_sock);
|
23
|
+
pthread_cancel(mb_slave->tid);
|
24
|
+
|
25
|
+
modbus_close(mb_slave->mb_param);
|
26
|
+
|
27
|
+
modbus_mapping_free(mb_slave->mb_map);
|
28
|
+
|
29
|
+
#ifndef RUBY_1_8
|
30
|
+
rb_ary_free(mb_slave->coil_status);
|
31
|
+
rb_ary_free(mb_slave->input_status);
|
32
|
+
rb_ary_free(mb_slave->holding_registers);
|
33
|
+
rb_ary_free(mb_slave->input_registers);
|
34
|
+
#else
|
35
|
+
free(RARRAY_PTR(mb_slave->coil_status));
|
36
|
+
free(RARRAY_PTR(mb_slave->input_status));
|
37
|
+
free(RARRAY_PTR(mb_slave->holding_registers));
|
38
|
+
free(RARRAY_PTR(mb_slave->input_registers));
|
39
|
+
#endif
|
40
|
+
|
41
|
+
free(mb_slave);
|
42
|
+
}
|
43
|
+
|
44
|
+
void *mb_tcp_serv(void *arg)
|
45
|
+
{
|
46
|
+
modbus_slave_t *mb_slave = (modbus_slave_t *)arg;
|
47
|
+
|
48
|
+
mb_slave->listen_sock = modbus_slave_listen_tcp(mb_slave->mb_param, 1);
|
49
|
+
|
50
|
+
while (1) {
|
51
|
+
modbus_slave_accept_tcp(mb_slave->mb_param,
|
52
|
+
&mb_slave->listen_sock);
|
53
|
+
uint8_t query[MAX_MESSAGE_LENGTH];
|
54
|
+
int query_size;
|
55
|
+
while(1) {
|
56
|
+
int ret = modbus_slave_receive(mb_slave->mb_param, -1,
|
57
|
+
query, &query_size);
|
58
|
+
|
59
|
+
if (ret == 0) {
|
60
|
+
mb_push_coil_status(mb_slave);
|
61
|
+
mb_push_input_status(mb_slave);
|
62
|
+
mb_push_holding_registers(mb_slave);
|
63
|
+
mb_push_input_registers(mb_slave);
|
64
|
+
|
65
|
+
modbus_slave_manage(mb_slave->mb_param, query,
|
66
|
+
query_size, mb_slave->mb_map);
|
67
|
+
|
68
|
+
mb_pull_coil_status(mb_slave);
|
69
|
+
mb_pull_holding_registers(mb_slave);
|
70
|
+
} else if (ret == CONNECTION_CLOSED) {
|
71
|
+
modbus_close(mb_slave->mb_param);
|
72
|
+
break;
|
73
|
+
} else {
|
74
|
+
continue;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
VALUE mb_tcp_sl_new(VALUE self, VALUE ip_address, VALUE port, VALUE slave)
|
81
|
+
{
|
82
|
+
modbus_slave_t *mb_slave;
|
83
|
+
mb_slave = malloc(sizeof(modbus_slave_t));
|
84
|
+
mb_slave->mb_param = malloc(sizeof(modbus_param_t));
|
85
|
+
mb_slave->mb_map = malloc(sizeof(modbus_mapping_t));
|
86
|
+
|
87
|
+
ip_address = rb_funcall(ip_address, rb_intern("to_s"), 0);
|
88
|
+
port = rb_funcall(port, rb_intern("to_i"), 0);
|
89
|
+
slave = rb_funcall(slave, rb_intern("to_i"), 0);
|
90
|
+
|
91
|
+
modbus_init_tcp(mb_slave->mb_param, RSTRING_PTR(ip_address), FIX2INT(port), FIX2INT(slave));
|
92
|
+
|
93
|
+
int ret = modbus_mapping_new(mb_slave->mb_map, 0, 0, 0, 0);
|
94
|
+
if (ret < 0) {
|
95
|
+
rb_raise(rb_eStandardError, "Memory allocation failed");
|
96
|
+
}
|
97
|
+
|
98
|
+
mb_slave->coil_status = rb_ary_new();
|
99
|
+
mb_slave->input_status = rb_ary_new();
|
100
|
+
mb_slave->holding_registers = rb_ary_new();
|
101
|
+
mb_slave->input_registers = rb_ary_new();
|
102
|
+
|
103
|
+
return Data_Wrap_Struct(self, 0, mb_tcp_sl_free, mb_slave);
|
104
|
+
}
|
105
|
+
|
106
|
+
VALUE mb_tcp_sl_start(VALUE self)
|
107
|
+
{
|
108
|
+
modbus_slave_t *mb_slave;
|
109
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
110
|
+
|
111
|
+
int ret = pthread_create(&mb_slave->tid, NULL, mb_tcp_serv,
|
112
|
+
(void *)mb_slave);
|
113
|
+
if (ret != 0) {
|
114
|
+
rb_raise(rb_eStandardError, "Slave has not started");
|
115
|
+
}
|
116
|
+
|
117
|
+
return self;
|
118
|
+
}
|
119
|
+
|
120
|
+
VALUE mb_tcp_sl_stop(VALUE self)
|
121
|
+
{
|
122
|
+
modbus_slave_t *mb_slave;
|
123
|
+
Data_Get_Struct(self, modbus_slave_t, mb_slave);
|
124
|
+
|
125
|
+
int ret = pthread_cancel(mb_slave->tid);
|
126
|
+
if (ret != 0) {
|
127
|
+
rb_raise(rb_eStandardError, "Slave has not stoped");
|
128
|
+
}
|
129
|
+
|
130
|
+
close(mb_slave->listen_sock);
|
131
|
+
modbus_close(mb_slave->mb_param);
|
132
|
+
|
133
|
+
return self;
|
134
|
+
}
|
data/ext/tcp_slave.h
ADDED
@@ -0,0 +1,21 @@
|
|
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 TCP_SLAVE_H
|
15
|
+
#define TCP_SLAVE_H
|
16
|
+
|
17
|
+
extern VALUE mb_tcp_sl_new(VALUE self, VALUE ip_address, VALUE port, VALUE id);
|
18
|
+
extern VALUE mb_tcp_sl_start(VALUE self);
|
19
|
+
extern VALUE mb_tcp_sl_stop(VALUE self);
|
20
|
+
|
21
|
+
#endif
|
data/lib/modbus4r.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
#libmodbus4r - binding use libmodbus for Ruby.
|
2
|
-
#Copyright (C) 2009 Timin Aleksey
|
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.
|
3
8
|
|
4
|
-
#This program is
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
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. */
|
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
13
|
|
14
14
|
require '_modbus4r'
|
15
|
+
|
data/spec/rtu_master_spec.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'modbus4r'
|
2
|
+
|
3
|
+
describe ModBus::RTUSlave do
|
4
|
+
before(:all) do
|
5
|
+
@sl = ModBus::RTUSlave.new('/dev/ttyS3', 9600, 'none', 8, 1, 1)
|
6
|
+
@sl.start
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be start" do
|
10
|
+
@sl.stoped?.should == false
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) do
|
14
|
+
@sl.stop unless @sl.stoped?
|
15
|
+
end
|
16
|
+
end
|
data/spec/tcp_master_spec.rb
CHANGED
@@ -3,12 +3,21 @@ require 'modbus4r'
|
|
3
3
|
describe ModBus::TCPMaster do
|
4
4
|
|
5
5
|
before(:all) do
|
6
|
-
@
|
6
|
+
@sl = ModBus::TCPSlave.new('127.0.0.1', 1502, 1)
|
7
|
+
@sl.coil_status = [false, false, false, false,
|
8
|
+
false, false, false, false]
|
9
|
+
@sl.input_status = [false, false, false, false,
|
10
|
+
false, false, false, false]
|
11
|
+
@sl.holding_registers = [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
12
|
+
@sl.input_registers = [0, 0, 0, 0, 0, 0, 0, 0, 0]
|
13
|
+
@sl.start
|
14
|
+
|
15
|
+
@mstr = ModBus::TCPMaster.new('127.0.0.1', 1502, 1)
|
7
16
|
@mstr.connect
|
8
17
|
end
|
9
18
|
|
10
19
|
it "should raise exception if have'n connected with slave" do
|
11
|
-
mstr = ModBus::TCPMaster.new('127.0.0.1', 1503)
|
20
|
+
mstr = ModBus::TCPMaster.new('127.0.0.1', 1503, 1)
|
12
21
|
mstr.closed?.should == true
|
13
22
|
lambda { mstr.connect }.should raise_error(ModBus::Errors::ModBusError, "Connection refused")
|
14
23
|
end
|
@@ -19,101 +28,102 @@ describe ModBus::TCPMaster do
|
|
19
28
|
|
20
29
|
# Read coil status
|
21
30
|
it "should read coil status" do
|
22
|
-
@mstr.read_coil_status(
|
31
|
+
@mstr.read_coil_status(0, 4).should == [false, false, false, false]
|
23
32
|
end
|
24
33
|
|
25
34
|
it "should raise exception if illegal data address" do
|
26
|
-
lambda { @mstr.read_coil_status(
|
35
|
+
lambda { @mstr.read_coil_status(0, 501) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
27
36
|
end
|
28
37
|
|
29
38
|
|
30
39
|
it "should raise exception if too many data" do
|
31
|
-
lambda { @mstr.read_coil_status(
|
40
|
+
lambda { @mstr.read_coil_status(0, 0x07D1) }.should raise_error(ModBus::Errors::ModBusError, "Invalid data (-16)")
|
32
41
|
end
|
33
42
|
|
34
43
|
# Read input status
|
35
44
|
it "should read discrete inputs" do
|
36
|
-
@mstr.read_input_status(
|
45
|
+
@mstr.read_input_status(0, 4).should == [false, false, false, false]
|
37
46
|
end
|
38
47
|
|
39
48
|
it "should raise exception if illegal data address" do
|
40
|
-
lambda { @mstr.read_input_status(
|
49
|
+
lambda { @mstr.read_input_status(0, 501) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
41
50
|
end
|
42
51
|
|
43
52
|
|
44
53
|
it "should raise exception if too many data" do
|
45
|
-
lambda { @mstr.read_input_status(
|
54
|
+
lambda { @mstr.read_input_status(0, 0x07D1) }.should raise_error(ModBus::Errors::ModBusError, "Invalid data (-16)")
|
46
55
|
end
|
47
56
|
|
48
57
|
# Read holding registers
|
49
58
|
it "should read discrete inputs" do
|
50
|
-
@mstr.read_holding_registers(
|
59
|
+
@mstr.read_holding_registers(0, 4).should == [0, 0, 0, 0]
|
51
60
|
end
|
52
61
|
|
53
62
|
it "should raise exception if illegal data address" do
|
54
|
-
lambda { @mstr.read_holding_registers(
|
63
|
+
lambda { @mstr.read_holding_registers(402, 99) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
55
64
|
end
|
56
65
|
|
57
66
|
|
58
67
|
it "should raise exception if too many data" do
|
59
|
-
lambda { @mstr.read_holding_registers(
|
68
|
+
lambda { @mstr.read_holding_registers(0, 0x007E) }.should raise_error(ModBus::Errors::ModBusError, "Invalid data (-16)")
|
60
69
|
end
|
61
70
|
|
62
71
|
# Read input registers
|
63
72
|
it "should read discrete inputs" do
|
64
|
-
@mstr.read_input_registers(
|
73
|
+
@mstr.read_input_registers(0, 4).should == [0, 0, 0, 0]
|
65
74
|
end
|
66
75
|
|
67
76
|
it "should raise exception if illegal data address" do
|
68
|
-
lambda { @mstr.read_input_registers(
|
77
|
+
lambda { @mstr.read_input_registers(402, 99) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
69
78
|
end
|
70
79
|
|
71
80
|
it "should raise exception if too many data" do
|
72
|
-
lambda { @mstr.read_input_registers(
|
81
|
+
lambda { @mstr.read_input_registers(0, 0x007E) }.should raise_error(ModBus::Errors::ModBusError, "Invalid data (-16)")
|
73
82
|
end
|
74
83
|
|
75
84
|
# Force single coil
|
76
85
|
it "should force single coil" do
|
77
|
-
@mstr.force_single_coil(
|
78
|
-
@mstr.read_coil_status(
|
86
|
+
@mstr.force_single_coil(4, true).should == @mstr
|
87
|
+
@mstr.read_coil_status(4, 4).should == [true, false, false, false]
|
79
88
|
end
|
80
89
|
|
81
90
|
it "should raise exception if illegal data address" do
|
82
|
-
lambda { @mstr.force_single_coil(
|
91
|
+
lambda { @mstr.force_single_coil(501, true) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
83
92
|
end
|
84
93
|
|
85
94
|
# Preset single register
|
86
95
|
it "should preset single register" do
|
87
|
-
@mstr.preset_single_register(
|
88
|
-
@mstr.read_holding_registers(
|
96
|
+
@mstr.preset_single_register(4, 0x0AA0).should == @mstr
|
97
|
+
@mstr.read_holding_registers(4, 1).should == [0x0AA0]
|
89
98
|
end
|
90
99
|
|
91
100
|
it "should raise exception if illegal data address" do
|
92
|
-
lambda { @mstr.preset_single_register(
|
101
|
+
lambda { @mstr.preset_single_register(501, 0x0AA0) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
93
102
|
end
|
94
103
|
|
95
104
|
# Force multiple coils
|
96
105
|
it "should force multiple coils" do
|
97
|
-
@mstr.force_multiple_coils(
|
98
|
-
@mstr.read_coil_status(
|
106
|
+
@mstr.force_multiple_coils(4, [false, true, false, true]).should == @mstr
|
107
|
+
@mstr.read_coil_status(3, 5).should == [false, false, true, false, true]
|
99
108
|
end
|
100
109
|
|
101
110
|
it "should raise exception if illegal data address" do
|
102
|
-
lambda { @mstr.force_multiple_coils(
|
111
|
+
lambda { @mstr.force_multiple_coils(501, [true, false]) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
103
112
|
end
|
104
113
|
|
105
114
|
# Preset multiple registers
|
106
115
|
it "should preset multiple registers" do
|
107
|
-
@mstr.preset_multiple_registers(
|
108
|
-
@mstr.read_holding_registers(
|
116
|
+
@mstr.preset_multiple_registers(4, [1, 2, 3, 0xAACC]).should == @mstr
|
117
|
+
@mstr.read_holding_registers(3, 5).should == [0, 1, 2, 3, 0xAACC]
|
109
118
|
end
|
110
119
|
|
111
120
|
it "should raise exception if illegal data address" do
|
112
|
-
lambda { @mstr.preset_multiple_registers(
|
121
|
+
lambda { @mstr.preset_multiple_registers(501, [1, 2]) }.should raise_error(ModBus::Errors::IllegalDataAddress, "Illegal data address (-2)")
|
113
122
|
end
|
114
123
|
|
115
124
|
after(:all) do
|
116
125
|
@mstr.close unless @mstr.closed?
|
126
|
+
@sl.stop unless @sl.stoped?
|
117
127
|
end
|
118
128
|
|
119
129
|
end
|