1616#include < system_error>
1717#include < unistd.h>
1818
19+ #include < iostream>
20+
1921namespace Modbus {
2022namespace TCP {
2123
@@ -29,21 +31,74 @@ Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t *mappi
2931 throw std::runtime_error (" failed to create modbus instance: " + error_msg);
3032 }
3133
34+ modbus_mapping_t *mb_mapping;
35+
3236 if (mapping == nullptr ) {
3337 // 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 ) {
3640 const std::string error_msg = modbus_strerror (errno);
3741 modbus_free (modbus);
3842 throw std::runtime_error (" failed to allocate memory: " + error_msg);
3943 }
40- delete_mapping = true ;
44+ delete_mapping = mapping ;
4145 } else {
4246 // 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);
4571 }
4672
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 () {
47102 // create tcp socket
48103 socket = modbus_tcp_listen (modbus, 1 );
49104 if (socket == -1 ) {
@@ -58,48 +113,47 @@ Slave::Slave(const std::string &ip, unsigned short port, modbus_mapping_t *mappi
58113 if (tmp != 0 ) {
59114 throw std::system_error (errno, std::generic_category (), " Failed to set socket option SO_KEEPALIVE" );
60115 }
116+ }
61117
62118#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+ }
70126
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+ }
77133
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+ }
84140
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" );
91146 }
92- #else
93- static_cast <void >(tcp_timeout);
94- #endif
95147}
148+ #endif
149+
96150
97151Slave::~Slave () {
98152 if (modbus != nullptr ) {
99153 modbus_close (modbus);
100154 modbus_free (modbus);
101155 }
102- if (mapping != nullptr && delete_mapping) modbus_mapping_free (mapping );
156+ if (delete_mapping) modbus_mapping_free (delete_mapping );
103157 if (socket != -1 ) { close (socket); }
104158}
105159
@@ -141,6 +195,11 @@ bool Slave::handle_request() {
141195 int rc = modbus_receive (modbus, query);
142196
143197 if (rc > 0 ) {
198+ const auto CLIENT_ID = query[6 ];
199+
200+ // get mapping
201+ auto mapping = mappings[CLIENT_ID];
202+
144203 // handle request
145204 int ret = modbus_reply (modbus, query, rc, mapping);
146205 if (ret == -1 ) {
0 commit comments