|
19 | 19 | namespace Modbus { |
20 | 20 | namespace TCP { |
21 | 21 |
|
| 22 | +//* maximum number of Modbus registers (per type) |
22 | 23 | static constexpr int MAX_REGS = 0x10000; |
23 | 24 |
|
| 25 | +//* value to increment error counter if semaphore could not be acquired |
| 26 | +static constexpr long SEMAPHORE_ERROR_INC = 10; |
| 27 | + |
| 28 | +//* value to decrement error counter if semaphore could be acquired |
| 29 | +static constexpr long SEMAPHORE_ERROR_DEC = 1; |
| 30 | + |
| 31 | +//* maximum value of semaphore error counter |
| 32 | +static constexpr long SEMAPHORE_ERROR_MAX = 1000; |
| 33 | + |
| 34 | +//* maximum time to wait for semaphore (100ms) |
| 35 | +static constexpr struct timespec SEMAPHORE_MAX_TIME = {0, 100'000}; |
| 36 | + |
24 | 37 | Client_Poll::Client_Poll(const std::string &host, |
25 | 38 | const std::string &service, |
26 | 39 | modbus_mapping_t *mapping, |
@@ -56,7 +69,7 @@ Client_Poll::Client_Poll(const std::string &host, |
56 | 69 |
|
57 | 70 | // use mapping for all client ids |
58 | 71 | for (std::size_t i = 0; i < MAX_CLIENT_IDS; ++i) { |
59 | | - this->mappings[i] = mapping; |
| 72 | + this->mappings[i] = mb_mapping; |
60 | 73 | } |
61 | 74 |
|
62 | 75 | listen(); |
@@ -174,6 +187,12 @@ void Client_Poll::set_tcp_timeout(std::size_t tcp_timeout) { |
174 | 187 | } |
175 | 188 | #endif |
176 | 189 |
|
| 190 | +void Client_Poll::enable_semaphore(const std::string &name, bool force) { |
| 191 | + if (semaphore) throw std::logic_error("semaphore already enabled"); |
| 192 | + |
| 193 | + semaphore = std::make_unique<cxxsemaphore::Semaphore>(name, 1, force); |
| 194 | +} |
| 195 | + |
177 | 196 | void Client_Poll::set_debug(bool debug) { |
178 | 197 | if (modbus_set_debug(modbus, debug)) { |
179 | 198 | const std::string error_msg = modbus_strerror(errno); |
@@ -369,7 +388,28 @@ Client_Poll::run_t Client_Poll::run(int signal_fd, bool reconnect, int timeout) |
369 | 388 | auto mapping = mappings[CLIENT_ID]; |
370 | 389 |
|
371 | 390 | // handle request |
| 391 | + if (semaphore) { |
| 392 | + if (!semaphore->wait(SEMAPHORE_MAX_TIME)) { |
| 393 | + std::cerr << Print_Time::iso << " WARNING: Failed to acquire semaphore '" |
| 394 | + << semaphore->get_name() << "' within 100ms." << std::endl; |
| 395 | + |
| 396 | + semaphore_error_counter += SEMAPHORE_ERROR_INC; |
| 397 | + |
| 398 | + if (semaphore_error_counter >= SEMAPHORE_ERROR_MAX) { |
| 399 | + std::cerr << Print_Time::iso << "ERROR: Repeatedly failed to acquire the semaphore" |
| 400 | + << std::endl; |
| 401 | + close_con(client_addrs); |
| 402 | + return run_t::semaphore; |
| 403 | + } |
| 404 | + } else { |
| 405 | + semaphore_error_counter -= SEMAPHORE_ERROR_DEC; |
| 406 | + if (semaphore_error_counter < 0) semaphore_error_counter = 0; |
| 407 | + } |
| 408 | + } |
| 409 | + |
372 | 410 | int ret = modbus_reply(modbus, query, rc, mapping); |
| 411 | + if (semaphore && semaphore->is_acquired()) semaphore->post(); |
| 412 | + |
373 | 413 | if (ret == -1) { |
374 | 414 | std::cerr << Print_Time::iso << " ERROR: modbus_reply failed: " << modbus_strerror(errno) |
375 | 415 | << std::endl; |
|
0 commit comments