From c4f7a2428521765dac88977eb726f544f2e3b040 Mon Sep 17 00:00:00 2001 From: Stéphane Raimbault Date: Thu, 14 Nov 2013 00:24:03 +0100 Subject: [PATCH] Change timeout to uint32 and add 3 byte timeout tests --- doc/modbus_get_byte_timeout.txt | 6 +++--- doc/modbus_get_response_timeout.txt | 6 +++--- doc/modbus_set_byte_timeout.txt | 17 +++++++++-------- doc/modbus_set_response_timeout.txt | 24 ++++++++++++------------ src/modbus.c | 15 ++++++++------- src/modbus.h | 8 ++++---- tests/unit-test-client.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- tests/unit-test-server.c | 17 +++++++++++++++++ tests/unit-test.h.in | 2 ++ 9 files changed, 123 insertions(+), 50 deletions(-) diff --git a/doc/modbus_get_byte_timeout.txt b/doc/modbus_get_byte_timeout.txt index 96e4310..8361dd4 100644 --- a/doc/modbus_get_byte_timeout.txt +++ b/doc/modbus_get_byte_timeout.txt @@ -9,7 +9,7 @@ modbus_get_byte_timeout - get timeout between bytes SYNOPSIS -------- -*int modbus_get_byte_timeout(modbus_t *'ctx', long *'to_sec', long *'to_usec');* +*int modbus_get_byte_timeout(modbus_t *'ctx', uint32_t *'to_sec', uint32_t *'to_usec');* DESCRIPTION @@ -29,8 +29,8 @@ EXAMPLE ------- [source,c] ------------------- -long to_sec; -long to_usec; +uint32_t to_sec; +uint32_t to_usec; /* Save original timeout */ modbus_get_byte_timeout(ctx, &to_sec, &to_usec); diff --git a/doc/modbus_get_response_timeout.txt b/doc/modbus_get_response_timeout.txt index 775b649..b5c74d7 100644 --- a/doc/modbus_get_response_timeout.txt +++ b/doc/modbus_get_response_timeout.txt @@ -9,7 +9,7 @@ modbus_get_response_timeout - get timeout for response SYNOPSIS -------- -*int modbus_get_response_timeout(modbus_t *'ctx', long *'to_sec', long *'to_usec');* +*int modbus_get_response_timeout(modbus_t *'ctx', uint32_t *'to_sec', uint32_t *'to_usec');* DESCRIPTION @@ -28,8 +28,8 @@ EXAMPLE ------- [source,c] ------------------- -long old_response_to_sec; -long old_response_to_usec; +uint32_t old_response_to_sec; +uint32_t old_response_to_usec; /* Save original timeout */ modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec); diff --git a/doc/modbus_set_byte_timeout.txt b/doc/modbus_set_byte_timeout.txt index 14cd03d..9df3588 100644 --- a/doc/modbus_set_byte_timeout.txt +++ b/doc/modbus_set_byte_timeout.txt @@ -9,23 +9,24 @@ modbus_set_byte_timeout - set timeout between bytes SYNOPSIS -------- -*void modbus_set_byte_timeout(modbus_t *'ctx', long 'to_sec', long 'to_usec');* +*void modbus_set_byte_timeout(modbus_t *'ctx', uint32_t 'to_sec', uint32_t 'to_usec');* DESCRIPTION ----------- The _modbus_set_byte_timeout()_ function shall set the timeout interval between -two consecutive bytes of the same message. If the delay between bytes is longer -than the given timeout, the 'ETIMEDOUT' error will be raised by the the function -waiting for a response. +two consecutive bytes of the same message. The timeout is an upper bound on the +amount of time elapsed before _select()_ returns, if the time elapsed is longer +than the defined timeout, an 'ETIMEDOUT' error will be raised by the +function waiting for a response. The value of _to_usec_ argument must be in the range 0 to 999999. -If _to_sec_ is set to -1 then this timeout will not be used at all. In this -case, _modbus_set_response_timeout()_ governs the entire handling of the +If both _to_sec_ and _to_usec_ are zero, this timeout will not be used at all. +In this case, _modbus_set_response_timeout()_ governs the entire handling of the response, the full confirmation response must be received before expiration of the response timeout. When a byte timeout is set, the response timeout is only -used to wait for the first byte of the response. +used to wait for until the first byte of the response. RETURN VALUE @@ -37,7 +38,7 @@ errno. ERRORS ------ *EINVAL*:: -The argument _ctx_ is NULL or _to_usec_ is not smaller than 1000000. +The argument _ctx_ is NULL or _to_usec_ is larger than 1000000. SEE ALSO diff --git a/doc/modbus_set_response_timeout.txt b/doc/modbus_set_response_timeout.txt index c5e21f1..a4e3424 100644 --- a/doc/modbus_set_response_timeout.txt +++ b/doc/modbus_set_response_timeout.txt @@ -9,18 +9,18 @@ modbus_set_response_timeout - set timeout for response SYNOPSIS -------- -*int modbus_set_response_timeout(modbus_t *'ctx', long 'to_sec', long 'to_usec');* +*int modbus_set_response_timeout(modbus_t *'ctx', uint32_t 'to_sec', uint32_t 'to_usec');* DESCRIPTION ----------- The _modbus_set_response_timeout()_ function shall set the timeout interval used -to wait for a response. When a byte timeout is set, if the waiting before -receiving the first byte of response is longer than the given timeout, the -'ETIMEDOUT' error will be raised by the function waiting for a response. When -byte timeout is disabled, the full confirmation response must be received before -expiration of the response timeout. +to wait for a response. When a byte timeout is set, if elapsed time for the +first byte of response is longer than the given timeout, an 'ETIMEDOUT' error +will be raised by the function waiting for a response. When byte timeout is +disabled, the full confirmation response must be received before expiration of +the response timeout. The value of to_usec argument must be in the range 0 to 999999. @@ -34,22 +34,22 @@ errno. ERRORS ------ *EINVAL*:: -The argument _ctx_ is NULL or _to_sec_/_to_usec_ aren't equal or greater than 0 or -_to_usec_ is not smaller than 1000000. +The argument _ctx_ is NULL, or both _to_sec_ and _to_usec_ are zero, or _to_usec_ +is larger than 1000000. EXAMPLE ------- [source,c] ------------------- -long old_response_to_sec; -long old_response_to_usec; +uint32_t old_response_to_sec; +uint32_t old_response_to_usec; /* Save original timeout */ modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec); -/* Define a new and too short timeout! */ -modbus_set_response_timeout(ctx, 0, 0); +/* Define a new timeout of 200ms */ +modbus_set_response_timeout(ctx, 0, 200000); ------------------- diff --git a/src/modbus.c b/src/modbus.c index 356d006..1b6f25c 100644 --- a/src/modbus.c +++ b/src/modbus.c @@ -462,7 +462,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) } } - if (length_to_read > 0 && ctx->byte_timeout.tv_sec >= 0 && ctx->byte_timeout.tv_usec >= 0) { + if (length_to_read > 0 && + (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) { /* If there is no character in the buffer, the allowed timeout interval between two consecutive bytes is defined by byte_timeout */ @@ -1644,7 +1645,7 @@ int modbus_get_socket(modbus_t *ctx) } /* Get the timeout interval used to wait for a response */ -int modbus_get_response_timeout(modbus_t *ctx, long *to_sec, long *to_usec) +int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec) { if (ctx == NULL) { errno = EINVAL; @@ -1656,10 +1657,10 @@ int modbus_get_response_timeout(modbus_t *ctx, long *to_sec, long *to_usec) return 0; } -int modbus_set_response_timeout(modbus_t *ctx, long to_sec, long to_usec) +int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec) { if (ctx == NULL || - to_sec < 0 || to_usec < 0 || to_usec > 999999) { + (to_sec == 0 && to_usec == 0) || to_usec > 999999) { errno = EINVAL; return -1; } @@ -1670,7 +1671,7 @@ int modbus_set_response_timeout(modbus_t *ctx, long to_sec, long to_usec) } /* Get the timeout interval between two consecutive bytes of a message */ -int modbus_get_byte_timeout(modbus_t *ctx, long *to_sec, long *to_usec) +int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec) { if (ctx == NULL) { errno = EINVAL; @@ -1682,9 +1683,9 @@ int modbus_get_byte_timeout(modbus_t *ctx, long *to_sec, long *to_usec) return 0; } -int modbus_set_byte_timeout(modbus_t *ctx, long to_sec, long to_usec) +int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec) { - /* Byte timeout can be disabled with negative values */ + /* Byte timeout can be disabled when both values are zero */ if (ctx == NULL || to_usec > 999999) { errno = EINVAL; return -1; diff --git a/src/modbus.h b/src/modbus.h index dbb0069..fd38f10 100644 --- a/src/modbus.h +++ b/src/modbus.h @@ -172,11 +172,11 @@ MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mo MODBUS_API int modbus_set_socket(modbus_t *ctx, int s); MODBUS_API int modbus_get_socket(modbus_t *ctx); -MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, long *to_sec, long *to_usec); -MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, long to_sec, long to_usec); +MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec); +MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec); -MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, long *to_sec, long *to_usec); -MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, long to_sec, long to_usec); +MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec); +MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec); MODBUS_API int modbus_get_header_length(modbus_t *ctx); diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index 9f5d902..18b43a5 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -44,8 +44,10 @@ int main(int argc, char *argv[]) int rc; float real; uint32_t ireal; - long old_response_timeout_sec; - long old_response_timeout_usec; + uint32_t old_response_to_sec; + uint32_t old_response_to_usec; + uint32_t old_byte_to_sec; + uint32_t old_byte_to_usec; int use_backend; if (argc > 1) { @@ -647,10 +649,11 @@ int main(int argc, char *argv[]) } /* Save original timeout */ - modbus_get_response_timeout(ctx, &old_response_timeout_sec, &old_response_timeout_usec); + modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec); + modbus_get_byte_timeout(ctx, &old_byte_to_sec, &old_byte_to_usec); - rc = modbus_set_response_timeout(ctx, -1, 0); - printf("1/6 Invalid response timeout (negative): "); + rc = modbus_set_response_timeout(ctx, 0, 0); + printf("1/6 Invalid response timeout (zero): "); if (rc == -1 && errno == EINVAL) { printf("OK\n"); } else { @@ -659,7 +662,7 @@ int main(int argc, char *argv[]) } rc = modbus_set_response_timeout(ctx, 0, 1000000); - printf("2/6 Invalid response timeout (too large): "); + printf("2/6 Invalid response timeout (too large us): "); if (rc == -1 && errno == EINVAL) { printf("OK\n"); } else { @@ -668,7 +671,7 @@ int main(int argc, char *argv[]) } rc = modbus_set_byte_timeout(ctx, 0, 1000000); - printf("3/6 Invalid byte timeout (too large): "); + printf("3/6 Invalid byte timeout (too large us): "); if (rc == -1 && errno == EINVAL) { printf("OK\n"); } else { @@ -676,21 +679,21 @@ int main(int argc, char *argv[]) goto close; } - modbus_set_response_timeout(ctx, 0, 0); + modbus_set_response_timeout(ctx, 0, 1); rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); - printf("4/6 Zero response timeout: "); + printf("4/6 1us response timeout: "); if (rc == -1 && errno == ETIMEDOUT) { printf("OK\n"); } else { - printf("FAILED (can fail on slow systems or Windows)\n"); + printf("FAILED (can fail on some platforms)\n"); } /* A wait and flush operation is done by the error recovery code of * libmodbus but after a sleep of current response timeout * so 0 can't be too short! */ - usleep(old_response_timeout_sec * 1000000 + old_response_timeout_usec); + usleep(old_response_to_sec * 1000000 + old_response_to_usec); modbus_flush(ctx); /* Trigger a special behaviour on server to wait for 0.5 second before @@ -721,8 +724,57 @@ int main(int argc, char *argv[]) goto close; } - /* Restore original timeout */ - modbus_set_response_timeout(ctx, old_response_timeout_sec, old_response_timeout_usec); + /* Disable the byte timeout. + The full response must be available in the 600ms interval */ + modbus_set_byte_timeout(ctx, 0, 0); + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS, + 1, tab_rp_registers); + printf("7/7 Disable byte timeout: "); + if (rc == 1) { + printf("OK\n"); + } else { + printf("FAILED\n"); + goto close; + } + + /* Restore original response timeout */ + modbus_set_response_timeout(ctx, old_response_to_sec, + old_response_to_usec); + + if (use_backend == TCP) { + /* Test server is only able to test byte timeout with the TCP backend */ + + /* Timeout of 3ms between bytes */ + modbus_set_byte_timeout(ctx, 0, 3000); + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS, + 1, tab_rp_registers); + printf("1/2 Too small byte timeout (3ms < 5ms): "); + if (rc == -1 && errno == ETIMEDOUT) { + printf("OK\n"); + } else { + printf("FAILED\n"); + goto close; + } + + /* Wait remaing bytes before flushing */ + usleep(11 * 5000); + modbus_flush(ctx); + + /* Timeout of 10ms between bytes */ + modbus_set_byte_timeout(ctx, 0, 7000); + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS, + 1, tab_rp_registers); + printf("2/2 Adapted byte timeout (7ms > 5ms): "); + if (rc == 1) { + printf("OK\n"); + } else { + printf("FAILED\n"); + goto close; + } + } + + /* Restore original byte timeout */ + modbus_set_byte_timeout(ctx, old_byte_to_sec, old_byte_to_usec); /** BAD RESPONSE **/ printf("\nTEST BAD RESPONSE ERROR:\n"); diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c index c122071..54f7d2d 100644 --- a/tests/unit-test-server.c +++ b/tests/unit-test-server.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "unit-test.h" @@ -179,6 +180,22 @@ int main(int argc, char*argv[]) == UT_REGISTERS_ADDRESS_SLEEP_500_MS) { printf("Sleep 0.5 s before replying\n"); usleep(500000); + } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) + == UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS) { + /* Test low level only available in TCP mode */ + /* Catch the reply and send reply byte a byte */ + uint8_t req[] = "\x00\x1C\x00\x00\x00\x05\xFF\x03\x02\x00\x00"; + int req_length = 11; + int w_s = modbus_get_socket(ctx); + + /* Copy TID */ + req[1] = query[1]; + for (i=0; i < req_length; i++) { + printf("(%.2X)", req[i]); + usleep(500); + send(w_s, req + i, 1, MSG_NOSIGNAL); + } + continue; } } diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in index cf78aae..b51b96d 100644 --- a/tests/unit-test.h.in +++ b/tests/unit-test.h.in @@ -52,6 +52,8 @@ const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0x6C; const uint16_t UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE = 0x6D; /* The server will wait for 1 second before replying to test timeout */ const uint16_t UT_REGISTERS_ADDRESS_SLEEP_500_MS = 0x6E; +/* The server will wait for 5 ms before sending each byte */ +const uint16_t UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS = 0x6F; const uint16_t UT_REGISTERS_NB = 0x3; const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0001, 0x0064 }; -- libgit2 0.21.4