16
16
#include < system_error>
17
17
#include < unistd.h>
18
18
19
+ #include < iostream>
20
+
19
21
namespace Modbus {
20
22
namespace TCP {
21
23
@@ -29,21 +31,74 @@ Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t *mappi
29
31
throw std::runtime_error (" failed to create modbus instance: " + error_msg);
30
32
}
31
33
34
+ modbus_mapping_t *mb_mapping;
35
+
32
36
if (mapping == nullptr ) {
33
37
// create new mapping with the maximum number of registers
34
- this -> mapping = modbus_mapping_new (MAX_REGS, MAX_REGS, MAX_REGS, MAX_REGS);
35
- if (this -> mapping == nullptr ) {
38
+ mb_mapping = modbus_mapping_new (MAX_REGS, MAX_REGS, MAX_REGS, MAX_REGS);
39
+ if (mb_mapping == nullptr ) {
36
40
const std::string error_msg = modbus_strerror (errno);
37
41
modbus_free (modbus);
38
42
throw std::runtime_error (" failed to allocate memory: " + error_msg);
39
43
}
40
- delete_mapping = true ;
44
+ delete_mapping = mapping ;
41
45
} else {
42
46
// use the provided mapping object
43
- this ->mapping = mapping;
44
- delete_mapping = false ;
47
+ mb_mapping = mapping;
48
+ delete_mapping = nullptr ;
49
+ }
50
+
51
+ // use mapping for all client ids
52
+ for (std::size_t i = 0 ; i < MAX_CLIENT_IDS; ++i) {
53
+ this ->mappings [i] = mapping;
54
+ }
55
+
56
+ listen ();
57
+
58
+ #ifdef OS_LINUX
59
+ if (tcp_timeout) set_tcp_timeout (tcp_timeout);
60
+ #else
61
+ static_cast <void >(tcp_timeout);
62
+ #endif
63
+ }
64
+
65
+ Slave::Slave (const std::string &ip, unsigned short port, modbus_mapping_t **mappings, std::size_t tcp_timeout) {
66
+ // create modbus object
67
+ modbus = modbus_new_tcp (ip.c_str (), static_cast <int >(port));
68
+ if (modbus == nullptr ) {
69
+ const std::string error_msg = modbus_strerror (errno);
70
+ throw std::runtime_error (" failed to create modbus instance: " + error_msg);
45
71
}
46
72
73
+ delete_mapping = nullptr ;
74
+
75
+ for (std::size_t i = 0 ; i < MAX_CLIENT_IDS; ++i) {
76
+ if (mappings[i] == nullptr ) {
77
+ if (delete_mapping == nullptr ) {
78
+ delete_mapping = modbus_mapping_new (MAX_REGS, MAX_REGS, MAX_REGS, MAX_REGS);
79
+
80
+ if (delete_mapping == nullptr ) {
81
+ const std::string error_msg = modbus_strerror (errno);
82
+ modbus_free (modbus);
83
+ throw std::runtime_error (" failed to allocate memory: " + error_msg);
84
+ }
85
+ }
86
+ this ->mappings [i] = delete_mapping;
87
+ } else {
88
+ this ->mappings [i] = mappings[i];
89
+ }
90
+ }
91
+
92
+ listen ();
93
+
94
+ #ifdef OS_LINUX
95
+ if (tcp_timeout) set_tcp_timeout (tcp_timeout);
96
+ #else
97
+ static_cast <void >(tcp_timeout);
98
+ #endif
99
+ }
100
+
101
+ void Slave::listen () {
47
102
// create tcp socket
48
103
socket = modbus_tcp_listen (modbus, 1 );
49
104
if (socket == -1 ) {
@@ -58,48 +113,47 @@ Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t *mappi
58
113
if (tmp != 0 ) {
59
114
throw std::system_error (errno, std::generic_category (), " Failed to set socket option SO_KEEPALIVE" );
60
115
}
116
+ }
61
117
62
118
#ifdef OS_LINUX
63
- if ( tcp_timeout) {
64
- // set user timeout (~= timeout for tcp connection)
65
- unsigned user_timeout = static_cast <unsigned >(tcp_timeout) * 1000 ;
66
- tmp = setsockopt (socket, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout, sizeof (keepalive ));
67
- if (tmp != 0 ) {
68
- throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_USER_TIMEOUT" );
69
- }
119
+ void Slave::set_tcp_timeout (std:: size_t tcp_timeout) {
120
+ // set user timeout (~= timeout for tcp connection)
121
+ unsigned user_timeout = static_cast <unsigned >(tcp_timeout) * 1000 ;
122
+ int tmp = setsockopt (socket, IPPROTO_TCP, TCP_USER_TIMEOUT, &user_timeout, sizeof (tcp_timeout ));
123
+ if (tmp != 0 ) {
124
+ throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_USER_TIMEOUT" );
125
+ }
70
126
71
- // start sending keepalive request after one second without request
72
- unsigned keepidle = 1 ;
73
- tmp = setsockopt (socket, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof (keepidle));
74
- if (tmp != 0 ) {
75
- throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_KEEPIDLE" );
76
- }
127
+ // start sending keepalive request after one second without request
128
+ unsigned keepidle = 1 ;
129
+ tmp = setsockopt (socket, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, sizeof (keepidle));
130
+ if (tmp != 0 ) {
131
+ throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_KEEPIDLE" );
132
+ }
77
133
78
- // send up to 5 keepalive requests during the timeout time, but not more than one per second
79
- unsigned keepintvl = std::max (static_cast <unsigned >(tcp_timeout / 5 ), 1u );
80
- tmp = setsockopt (socket, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof (keepintvl));
81
- if (tmp != 0 ) {
82
- throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_KEEPINTVL" );
83
- }
134
+ // send up to 5 keepalive requests during the timeout time, but not more than one per second
135
+ unsigned keepintvl = std::max (static_cast <unsigned >(tcp_timeout / 5 ), 1u );
136
+ tmp = setsockopt (socket, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, sizeof (keepintvl));
137
+ if (tmp != 0 ) {
138
+ throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_KEEPINTVL" );
139
+ }
84
140
85
- // 5 keepalive requests if the timeout time is >= 5s; else send one request each second
86
- unsigned keepcnt = std::min (static_cast <unsigned >(tcp_timeout), 5u );
87
- tmp = setsockopt (socket, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof (keepcnt));
88
- if (tmp != 0 ) {
89
- throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_KEEPCNT" );
90
- }
141
+ // 5 keepalive requests if the timeout time is >= 5s; else send one request each second
142
+ unsigned keepcnt = std::min (static_cast <unsigned >(tcp_timeout), 5u );
143
+ tmp = setsockopt (socket, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, sizeof (keepcnt));
144
+ if (tmp != 0 ) {
145
+ throw std::system_error (errno, std::generic_category (), " Failed to set socket option TCP_KEEPCNT" );
91
146
}
92
- #else
93
- static_cast <void >(tcp_timeout);
94
- #endif
95
147
}
148
+ #endif
149
+
96
150
97
151
Slave::~Slave () {
98
152
if (modbus != nullptr ) {
99
153
modbus_close (modbus);
100
154
modbus_free (modbus);
101
155
}
102
- if (mapping != nullptr && delete_mapping) modbus_mapping_free (mapping );
156
+ if (delete_mapping) modbus_mapping_free (delete_mapping );
103
157
if (socket != -1 ) { close (socket); }
104
158
}
105
159
@@ -141,6 +195,11 @@ bool Slave::handle_request() {
141
195
int rc = modbus_receive (modbus, query);
142
196
143
197
if (rc > 0 ) {
198
+ const auto CLIENT_ID = query[6 ];
199
+
200
+ // get mapping
201
+ auto mapping = mappings[CLIENT_ID];
202
+
144
203
// handle request
145
204
int ret = modbus_reply (modbus, query, rc, mapping);
146
205
if (ret == -1 ) {
0 commit comments