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,19 +23,20 @@ By default there is no error recovery ('MODBUS_ERROR_RECOVERY_NONE') so the | ||
| 23 | application is responsible for controlling the error values returned by | 23 | application is responsible for controlling the error values returned by |
| 24 | libmodbus functions and for handling them if necessary. | 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 | When 'MODBUS_ERROR_RECOVERY_PROTOCOL' is set, a sleep and flush sequence will be | 36 | When 'MODBUS_ERROR_RECOVERY_PROTOCOL' is set, a sleep and flush sequence will be |
| 36 | used to cleanup the ongoing communication, this can occurs when the message | 37 | used to cleanup the ongoing communication, this can occurs when the message |
| 37 | length is invalid, the TID is wrong or the received function code is not the | 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 | The modes are mask values and so they are complementary. | 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,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 | #ifdef _WIN32 | 107 | #ifdef _WIN32 |
| 108 | /* usleep doesn't exist on Windows */ | 108 | /* usleep doesn't exist on Windows */ |
| @@ -117,7 +117,6 @@ static int _sleep_and_flush(modbus_t *ctx) | @@ -117,7 +117,6 @@ static int _sleep_and_flush(modbus_t *ctx) | ||
| 117 | while (nanosleep(&request, &remaining) == -1 && errno == EINTR) | 117 | while (nanosleep(&request, &remaining) == -1 && errno == EINTR) |
| 118 | request = remaining; | 118 | request = remaining; |
| 119 | #endif | 119 | #endif |
| 120 | - return modbus_flush(ctx); | ||
| 121 | } | 120 | } |
| 122 | 121 | ||
| 123 | int modbus_flush(modbus_t *ctx) | 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,9 +191,11 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length) | ||
| 192 | 191 | ||
| 193 | if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) { | 192 | if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) { |
| 194 | modbus_close(ctx); | 193 | modbus_close(ctx); |
| 194 | + _sleep_response_timeout(ctx); | ||
| 195 | modbus_connect(ctx); | 195 | modbus_connect(ctx); |
| 196 | } else { | 196 | } else { |
| 197 | - _sleep_and_flush(ctx); | 197 | + _sleep_response_timeout(ctx); |
| 198 | + modbus_flush(ctx); | ||
| 198 | } | 199 | } |
| 199 | errno = saved_errno; | 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,7 +380,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) | ||
| 379 | int saved_errno = errno; | 380 | int saved_errno = errno; |
| 380 | 381 | ||
| 381 | if (errno == ETIMEDOUT) { | 382 | if (errno == ETIMEDOUT) { |
| 382 | - _sleep_and_flush(ctx); | 383 | + _sleep_response_timeout(ctx); |
| 384 | + modbus_flush(ctx); | ||
| 383 | } else if (errno == EBADF) { | 385 | } else if (errno == EBADF) { |
| 384 | modbus_close(ctx); | 386 | modbus_close(ctx); |
| 385 | modbus_connect(ctx); | 387 | modbus_connect(ctx); |
| @@ -494,7 +496,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | @@ -494,7 +496,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | ||
| 494 | rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length); | 496 | rc = ctx->backend->pre_check_confirmation(ctx, req, rsp, rsp_length); |
| 495 | if (rc == -1) { | 497 | if (rc == -1) { |
| 496 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { | 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 | return -1; | 502 | return -1; |
| 500 | } | 503 | } |
| @@ -538,7 +541,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | @@ -538,7 +541,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | ||
| 538 | function, req[offset]); | 541 | function, req[offset]); |
| 539 | } | 542 | } |
| 540 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { | 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 | errno = EMBBADDATA; | 547 | errno = EMBBADDATA; |
| 544 | return -1; | 548 | return -1; |
| @@ -587,7 +591,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | @@ -587,7 +591,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | ||
| 587 | } | 591 | } |
| 588 | 592 | ||
| 589 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { | 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 | errno = EMBBADDATA; | 598 | errno = EMBBADDATA; |
| @@ -600,7 +605,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | @@ -600,7 +605,8 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, | ||
| 600 | rsp_length, rsp_length_computed); | 605 | rsp_length, rsp_length_computed); |
| 601 | } | 606 | } |
| 602 | if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_PROTOCOL) { | 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 | errno = EMBBADDATA; | 611 | errno = EMBBADDATA; |
| 606 | rc = -1; | 612 | rc = -1; |