Commit a06255be5ca65545221b099ee8607c8c1bbc800f
1 parent
ef81a69e
Sleep for delay of response timeout before reconnect (closes #77)
Thanks to Karl Palsson.
Showing
2 changed files
with
24 additions
and
17 deletions
doc/modbus_set_error_recovery.txt
| ... | ... | @@ -23,19 +23,20 @@ By default there is no error recovery ('MODBUS_ERROR_RECOVERY_NONE') so the |
| 23 | 23 | application is responsible for controlling the error values returned by |
| 24 | 24 | libmodbus functions and for handling them if necessary. |
| 25 | 25 | |
| 26 | -When 'MODBUS_ERROR_RECOVERY_LINK' is set, the library will attempt an immediate | |
| 27 | -reconnection (which may hang for several seconds if the network to the remote | |
| 28 | -target unit is down). This mode will try a infinite close/connect loop until | |
| 29 | -success on send call and will just try one time to retablish the connection on | |
| 30 | -select/read calls (if the connecton was down, the values to read are certainly | |
| 31 | -not available anymore after reconnection, except for slave/server). This mode | |
| 32 | -will also run flush requests after a delay based on the current response timeout | |
| 33 | -in some situations (eg. timeout of select call). | |
| 26 | +When 'MODBUS_ERROR_RECOVERY_LINK' is set, the library will attempt an | |
| 27 | +reconnection after a delay defined by response timeout of the libmodbus context. | |
| 28 | +This mode will try a infinite close/connect loop until success on send call and | |
| 29 | +will just try one time to retablish the connection on select/read calls (if the | |
| 30 | +connecton was down, the values to read are certainly not available anymore after | |
| 31 | +reconnection, except for slave/server). This mode will also run flush requests | |
| 32 | +after a delay based on the current response timeout in some situations (eg. | |
| 33 | +timeout of select call). The reconnection attempt can hang for several seconds | |
| 34 | +if the network to the remote target unit is down. | |
| 34 | 35 | |
| 35 | 36 | When 'MODBUS_ERROR_RECOVERY_PROTOCOL' is set, a sleep and flush sequence will be |
| 36 | 37 | used to cleanup the ongoing communication, this can occurs when the message |
| 37 | 38 | length is invalid, the TID is wrong or the received function code is not the |
| 38 | -expected one. | |
| 39 | +expected one. The response timeout delay will be used to sleep. | |
| 39 | 40 | |
| 40 | 41 | The modes are mask values and so they are complementary. |
| 41 | 42 | ... | ... |
src/modbus.c
| ... | ... | @@ -102,7 +102,7 @@ void _error_print(modbus_t *ctx, const char *context) |
| 102 | 102 | } |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | -static int _sleep_and_flush(modbus_t *ctx) | |
| 105 | +static void _sleep_response_timeout(modbus_t *ctx) | |
| 106 | 106 | { |
| 107 | 107 | #ifdef _WIN32 |
| 108 | 108 | /* usleep doesn't exist on Windows */ |
| ... | ... | @@ -117,7 +117,6 @@ static int _sleep_and_flush(modbus_t *ctx) |
| 117 | 117 | while (nanosleep(&request, &remaining) == -1 && errno == EINTR) |
| 118 | 118 | request = remaining; |
| 119 | 119 | #endif |
| 120 | - return modbus_flush(ctx); | |
| 121 | 120 | } |
| 122 | 121 | |
| 123 | 122 | int modbus_flush(modbus_t *ctx) |
| ... | ... | @@ -192,9 +191,11 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length) |
| 192 | 191 | |
| 193 | 192 | if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) { |
| 194 | 193 | modbus_close(ctx); |
| 194 | + _sleep_response_timeout(ctx); | |
| 195 | 195 | modbus_connect(ctx); |
| 196 | 196 | } else { |
| 197 | - _sleep_and_flush(ctx); | |
| 197 | + _sleep_response_timeout(ctx); | |
| 198 | + modbus_flush(ctx); | |
| 198 | 199 | } |
| 199 | 200 | errno = saved_errno; |
| 200 | 201 | } |
| ... | ... | @@ -379,7 +380,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) |
| 379 | 380 | int saved_errno = errno; |
| 380 | 381 | |
| 381 | 382 | if (errno == ETIMEDOUT) { |
| 382 | - _sleep_and_flush(ctx); | |
| 383 | + _sleep_response_timeout(ctx); | |
| 384 | + modbus_flush(ctx); | |
| 383 | 385 | } else if (errno == EBADF) { |
| 384 | 386 | modbus_close(ctx); |
| 385 | 387 | modbus_connect(ctx); |
| ... | ... | @@ -494,7 +496,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, |
| 494 | 496 | rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length); |
| 495 | 497 | if (rc == -1) { |
| 496 | 498 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { |
| 497 | - _sleep_and_flush(ctx); | |
| 499 | + _sleep_response_timeout(ctx); | |
| 500 | + modbus_flush(ctx); | |
| 498 | 501 | } |
| 499 | 502 | return -1; |
| 500 | 503 | } |
| ... | ... | @@ -538,7 +541,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, |
| 538 | 541 | function, req[offset]); |
| 539 | 542 | } |
| 540 | 543 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { |
| 541 | - _sleep_and_flush(ctx); | |
| 544 | + _sleep_response_timeout(ctx); | |
| 545 | + modbus_flush(ctx); | |
| 542 | 546 | } |
| 543 | 547 | errno = EMBBADDATA; |
| 544 | 548 | return -1; |
| ... | ... | @@ -587,7 +591,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, |
| 587 | 591 | } |
| 588 | 592 | |
| 589 | 593 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { |
| 590 | - _sleep_and_flush(ctx); | |
| 594 | + _sleep_response_timeout(ctx); | |
| 595 | + modbus_flush(ctx); | |
| 591 | 596 | } |
| 592 | 597 | |
| 593 | 598 | errno = EMBBADDATA; |
| ... | ... | @@ -600,7 +605,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, |
| 600 | 605 | rsp_length, rsp_length_computed); |
| 601 | 606 | } |
| 602 | 607 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { |
| 603 | - _sleep_and_flush(ctx); | |
| 608 | + _sleep_response_timeout(ctx); | |
| 609 | + modbus_flush(ctx); | |
| 604 | 610 | } |
| 605 | 611 | errno = EMBBADDATA; |
| 606 | 612 | rc = -1; | ... | ... |