Commit c4f7a2428521765dac88977eb726f544f2e3b040

Authored by Stéphane Raimbault
1 parent 8dc4e2e5

Change timeout to uint32 and add 3 byte timeout tests

- add byte timeout tests (TCP backend only)
- update and improve documentation
- long timeout values are now uint32_t so it changes the API
  to disable byte timeout
doc/modbus_get_byte_timeout.txt
... ... @@ -9,7 +9,7 @@ modbus_get_byte_timeout - get timeout between bytes
9 9  
10 10 SYNOPSIS
11 11 --------
12   -*int modbus_get_byte_timeout(modbus_t *'ctx', long *'to_sec', long *'to_usec');*
  12 +*int modbus_get_byte_timeout(modbus_t *'ctx', uint32_t *'to_sec', uint32_t *'to_usec');*
13 13  
14 14  
15 15 DESCRIPTION
... ... @@ -29,8 +29,8 @@ EXAMPLE
29 29 -------
30 30 [source,c]
31 31 -------------------
32   -long to_sec;
33   -long to_usec;
  32 +uint32_t to_sec;
  33 +uint32_t to_usec;
34 34  
35 35 /* Save original timeout */
36 36 modbus_get_byte_timeout(ctx, &to_sec, &to_usec);
... ...
doc/modbus_get_response_timeout.txt
... ... @@ -9,7 +9,7 @@ modbus_get_response_timeout - get timeout for response
9 9  
10 10 SYNOPSIS
11 11 --------
12   -*int modbus_get_response_timeout(modbus_t *'ctx', long *'to_sec', long *'to_usec');*
  12 +*int modbus_get_response_timeout(modbus_t *'ctx', uint32_t *'to_sec', uint32_t *'to_usec');*
13 13  
14 14  
15 15 DESCRIPTION
... ... @@ -28,8 +28,8 @@ EXAMPLE
28 28 -------
29 29 [source,c]
30 30 -------------------
31   -long old_response_to_sec;
32   -long old_response_to_usec;
  31 +uint32_t old_response_to_sec;
  32 +uint32_t old_response_to_usec;
33 33  
34 34 /* Save original timeout */
35 35 modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);
... ...
doc/modbus_set_byte_timeout.txt
... ... @@ -9,23 +9,24 @@ modbus_set_byte_timeout - set timeout between bytes
9 9  
10 10 SYNOPSIS
11 11 --------
12   -*void modbus_set_byte_timeout(modbus_t *'ctx', long 'to_sec', long 'to_usec');*
  12 +*void modbus_set_byte_timeout(modbus_t *'ctx', uint32_t 'to_sec', uint32_t 'to_usec');*
13 13  
14 14  
15 15 DESCRIPTION
16 16 -----------
17 17 The _modbus_set_byte_timeout()_ function shall set the timeout interval between
18   -two consecutive bytes of the same message. If the delay between bytes is longer
19   -than the given timeout, the 'ETIMEDOUT' error will be raised by the the function
20   -waiting for a response.
  18 +two consecutive bytes of the same message. The timeout is an upper bound on the
  19 +amount of time elapsed before _select()_ returns, if the time elapsed is longer
  20 +than the defined timeout, an 'ETIMEDOUT' error will be raised by the
  21 +function waiting for a response.
21 22  
22 23 The value of _to_usec_ argument must be in the range 0 to 999999.
23 24  
24   -If _to_sec_ is set to -1 then this timeout will not be used at all. In this
25   -case, _modbus_set_response_timeout()_ governs the entire handling of the
  25 +If both _to_sec_ and _to_usec_ are zero, this timeout will not be used at all.
  26 +In this case, _modbus_set_response_timeout()_ governs the entire handling of the
26 27 response, the full confirmation response must be received before expiration of
27 28 the response timeout. When a byte timeout is set, the response timeout is only
28   -used to wait for the first byte of the response.
  29 +used to wait for until the first byte of the response.
29 30  
30 31  
31 32 RETURN VALUE
... ... @@ -37,7 +38,7 @@ errno.
37 38 ERRORS
38 39 ------
39 40 *EINVAL*::
40   -The argument _ctx_ is NULL or _to_usec_ is not smaller than 1000000.
  41 +The argument _ctx_ is NULL or _to_usec_ is larger than 1000000.
41 42  
42 43  
43 44 SEE ALSO
... ...
doc/modbus_set_response_timeout.txt
... ... @@ -9,18 +9,18 @@ modbus_set_response_timeout - set timeout for response
9 9  
10 10 SYNOPSIS
11 11 --------
12   -*int modbus_set_response_timeout(modbus_t *'ctx', long 'to_sec', long 'to_usec');*
  12 +*int modbus_set_response_timeout(modbus_t *'ctx', uint32_t 'to_sec', uint32_t 'to_usec');*
13 13  
14 14  
15 15 DESCRIPTION
16 16 -----------
17 17  
18 18 The _modbus_set_response_timeout()_ function shall set the timeout interval used
19   -to wait for a response. When a byte timeout is set, if the waiting before
20   -receiving the first byte of response is longer than the given timeout, the
21   -'ETIMEDOUT' error will be raised by the function waiting for a response. When
22   -byte timeout is disabled, the full confirmation response must be received before
23   -expiration of the response timeout.
  19 +to wait for a response. When a byte timeout is set, if elapsed time for the
  20 +first byte of response is longer than the given timeout, an 'ETIMEDOUT' error
  21 +will be raised by the function waiting for a response. When byte timeout is
  22 +disabled, the full confirmation response must be received before expiration of
  23 +the response timeout.
24 24  
25 25 The value of to_usec argument must be in the range 0 to 999999.
26 26  
... ... @@ -34,22 +34,22 @@ errno.
34 34 ERRORS
35 35 ------
36 36 *EINVAL*::
37   -The argument _ctx_ is NULL or _to_sec_/_to_usec_ aren't equal or greater than 0 or
38   -_to_usec_ is not smaller than 1000000.
  37 +The argument _ctx_ is NULL, or both _to_sec_ and _to_usec_ are zero, or _to_usec_
  38 +is larger than 1000000.
39 39  
40 40  
41 41 EXAMPLE
42 42 -------
43 43 [source,c]
44 44 -------------------
45   -long old_response_to_sec;
46   -long old_response_to_usec;
  45 +uint32_t old_response_to_sec;
  46 +uint32_t old_response_to_usec;
47 47  
48 48 /* Save original timeout */
49 49 modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);
50 50  
51   -/* Define a new and too short timeout! */
52   -modbus_set_response_timeout(ctx, 0, 0);
  51 +/* Define a new timeout of 200ms */
  52 +modbus_set_response_timeout(ctx, 0, 200000);
53 53 -------------------
54 54  
55 55  
... ...
src/modbus.c
... ... @@ -462,7 +462,8 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
462 462 }
463 463 }
464 464  
465   - if (length_to_read > 0 && ctx->byte_timeout.tv_sec >= 0 && ctx->byte_timeout.tv_usec >= 0) {
  465 + if (length_to_read > 0 &&
  466 + (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0)) {
466 467 /* If there is no character in the buffer, the allowed timeout
467 468 interval between two consecutive bytes is defined by
468 469 byte_timeout */
... ... @@ -1644,7 +1645,7 @@ int modbus_get_socket(modbus_t *ctx)
1644 1645 }
1645 1646  
1646 1647 /* Get the timeout interval used to wait for a response */
1647   -int modbus_get_response_timeout(modbus_t *ctx, long *to_sec, long *to_usec)
  1648 +int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
1648 1649 {
1649 1650 if (ctx == NULL) {
1650 1651 errno = EINVAL;
... ... @@ -1656,10 +1657,10 @@ int modbus_get_response_timeout(modbus_t *ctx, long *to_sec, long *to_usec)
1656 1657 return 0;
1657 1658 }
1658 1659  
1659   -int modbus_set_response_timeout(modbus_t *ctx, long to_sec, long to_usec)
  1660 +int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
1660 1661 {
1661 1662 if (ctx == NULL ||
1662   - to_sec < 0 || to_usec < 0 || to_usec > 999999) {
  1663 + (to_sec == 0 && to_usec == 0) || to_usec > 999999) {
1663 1664 errno = EINVAL;
1664 1665 return -1;
1665 1666 }
... ... @@ -1670,7 +1671,7 @@ int modbus_set_response_timeout(modbus_t *ctx, long to_sec, long to_usec)
1670 1671 }
1671 1672  
1672 1673 /* Get the timeout interval between two consecutive bytes of a message */
1673   -int modbus_get_byte_timeout(modbus_t *ctx, long *to_sec, long *to_usec)
  1674 +int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
1674 1675 {
1675 1676 if (ctx == NULL) {
1676 1677 errno = EINVAL;
... ... @@ -1682,9 +1683,9 @@ int modbus_get_byte_timeout(modbus_t *ctx, long *to_sec, long *to_usec)
1682 1683 return 0;
1683 1684 }
1684 1685  
1685   -int modbus_set_byte_timeout(modbus_t *ctx, long to_sec, long to_usec)
  1686 +int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
1686 1687 {
1687   - /* Byte timeout can be disabled with negative values */
  1688 + /* Byte timeout can be disabled when both values are zero */
1688 1689 if (ctx == NULL || to_usec > 999999) {
1689 1690 errno = EINVAL;
1690 1691 return -1;
... ...
src/modbus.h
... ... @@ -172,11 +172,11 @@ MODBUS_API int modbus_set_error_recovery(modbus_t *ctx, modbus_error_recovery_mo
172 172 MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
173 173 MODBUS_API int modbus_get_socket(modbus_t *ctx);
174 174  
175   -MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, long *to_sec, long *to_usec);
176   -MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, long to_sec, long to_usec);
  175 +MODBUS_API int modbus_get_response_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
  176 +MODBUS_API int modbus_set_response_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
177 177  
178   -MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, long *to_sec, long *to_usec);
179   -MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, long to_sec, long to_usec);
  178 +MODBUS_API int modbus_get_byte_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec);
  179 +MODBUS_API int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec);
180 180  
181 181 MODBUS_API int modbus_get_header_length(modbus_t *ctx);
182 182  
... ...
tests/unit-test-client.c
... ... @@ -44,8 +44,10 @@ int main(int argc, char *argv[])
44 44 int rc;
45 45 float real;
46 46 uint32_t ireal;
47   - long old_response_timeout_sec;
48   - long old_response_timeout_usec;
  47 + uint32_t old_response_to_sec;
  48 + uint32_t old_response_to_usec;
  49 + uint32_t old_byte_to_sec;
  50 + uint32_t old_byte_to_usec;
49 51 int use_backend;
50 52  
51 53 if (argc > 1) {
... ... @@ -647,10 +649,11 @@ int main(int argc, char *argv[])
647 649 }
648 650  
649 651 /* Save original timeout */
650   - modbus_get_response_timeout(ctx, &old_response_timeout_sec, &old_response_timeout_usec);
  652 + modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec);
  653 + modbus_get_byte_timeout(ctx, &old_byte_to_sec, &old_byte_to_usec);
651 654  
652   - rc = modbus_set_response_timeout(ctx, -1, 0);
653   - printf("1/6 Invalid response timeout (negative): ");
  655 + rc = modbus_set_response_timeout(ctx, 0, 0);
  656 + printf("1/6 Invalid response timeout (zero): ");
654 657 if (rc == -1 && errno == EINVAL) {
655 658 printf("OK\n");
656 659 } else {
... ... @@ -659,7 +662,7 @@ int main(int argc, char *argv[])
659 662 }
660 663  
661 664 rc = modbus_set_response_timeout(ctx, 0, 1000000);
662   - printf("2/6 Invalid response timeout (too large): ");
  665 + printf("2/6 Invalid response timeout (too large us): ");
663 666 if (rc == -1 && errno == EINVAL) {
664 667 printf("OK\n");
665 668 } else {
... ... @@ -668,7 +671,7 @@ int main(int argc, char *argv[])
668 671 }
669 672  
670 673 rc = modbus_set_byte_timeout(ctx, 0, 1000000);
671   - printf("3/6 Invalid byte timeout (too large): ");
  674 + printf("3/6 Invalid byte timeout (too large us): ");
672 675 if (rc == -1 && errno == EINVAL) {
673 676 printf("OK\n");
674 677 } else {
... ... @@ -676,21 +679,21 @@ int main(int argc, char *argv[])
676 679 goto close;
677 680 }
678 681  
679   - modbus_set_response_timeout(ctx, 0, 0);
  682 + modbus_set_response_timeout(ctx, 0, 1);
680 683 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
681 684 UT_REGISTERS_NB, tab_rp_registers);
682   - printf("4/6 Zero response timeout: ");
  685 + printf("4/6 1us response timeout: ");
683 686 if (rc == -1 && errno == ETIMEDOUT) {
684 687 printf("OK\n");
685 688 } else {
686   - printf("FAILED (can fail on slow systems or Windows)\n");
  689 + printf("FAILED (can fail on some platforms)\n");
687 690 }
688 691  
689 692 /* A wait and flush operation is done by the error recovery code of
690 693 * libmodbus but after a sleep of current response timeout
691 694 * so 0 can't be too short!
692 695 */
693   - usleep(old_response_timeout_sec * 1000000 + old_response_timeout_usec);
  696 + usleep(old_response_to_sec * 1000000 + old_response_to_usec);
694 697 modbus_flush(ctx);
695 698  
696 699 /* Trigger a special behaviour on server to wait for 0.5 second before
... ... @@ -721,8 +724,57 @@ int main(int argc, char *argv[])
721 724 goto close;
722 725 }
723 726  
724   - /* Restore original timeout */
725   - modbus_set_response_timeout(ctx, old_response_timeout_sec, old_response_timeout_usec);
  727 + /* Disable the byte timeout.
  728 + The full response must be available in the 600ms interval */
  729 + modbus_set_byte_timeout(ctx, 0, 0);
  730 + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS,
  731 + 1, tab_rp_registers);
  732 + printf("7/7 Disable byte timeout: ");
  733 + if (rc == 1) {
  734 + printf("OK\n");
  735 + } else {
  736 + printf("FAILED\n");
  737 + goto close;
  738 + }
  739 +
  740 + /* Restore original response timeout */
  741 + modbus_set_response_timeout(ctx, old_response_to_sec,
  742 + old_response_to_usec);
  743 +
  744 + if (use_backend == TCP) {
  745 + /* Test server is only able to test byte timeout with the TCP backend */
  746 +
  747 + /* Timeout of 3ms between bytes */
  748 + modbus_set_byte_timeout(ctx, 0, 3000);
  749 + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS,
  750 + 1, tab_rp_registers);
  751 + printf("1/2 Too small byte timeout (3ms < 5ms): ");
  752 + if (rc == -1 && errno == ETIMEDOUT) {
  753 + printf("OK\n");
  754 + } else {
  755 + printf("FAILED\n");
  756 + goto close;
  757 + }
  758 +
  759 + /* Wait remaing bytes before flushing */
  760 + usleep(11 * 5000);
  761 + modbus_flush(ctx);
  762 +
  763 + /* Timeout of 10ms between bytes */
  764 + modbus_set_byte_timeout(ctx, 0, 7000);
  765 + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS,
  766 + 1, tab_rp_registers);
  767 + printf("2/2 Adapted byte timeout (7ms > 5ms): ");
  768 + if (rc == 1) {
  769 + printf("OK\n");
  770 + } else {
  771 + printf("FAILED\n");
  772 + goto close;
  773 + }
  774 + }
  775 +
  776 + /* Restore original byte timeout */
  777 + modbus_set_byte_timeout(ctx, old_byte_to_sec, old_byte_to_usec);
726 778  
727 779 /** BAD RESPONSE **/
728 780 printf("\nTEST BAD RESPONSE ERROR:\n");
... ...
tests/unit-test-server.c
... ... @@ -21,6 +21,7 @@
21 21 #include <stdlib.h>
22 22 #include <errno.h>
23 23 #include <modbus.h>
  24 +#include <sys/socket.h>
24 25  
25 26 #include "unit-test.h"
26 27  
... ... @@ -179,6 +180,22 @@ int main(int argc, char*argv[])
179 180 == UT_REGISTERS_ADDRESS_SLEEP_500_MS) {
180 181 printf("Sleep 0.5 s before replying\n");
181 182 usleep(500000);
  183 + } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1)
  184 + == UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS) {
  185 + /* Test low level only available in TCP mode */
  186 + /* Catch the reply and send reply byte a byte */
  187 + uint8_t req[] = "\x00\x1C\x00\x00\x00\x05\xFF\x03\x02\x00\x00";
  188 + int req_length = 11;
  189 + int w_s = modbus_get_socket(ctx);
  190 +
  191 + /* Copy TID */
  192 + req[1] = query[1];
  193 + for (i=0; i < req_length; i++) {
  194 + printf("(%.2X)", req[i]);
  195 + usleep(500);
  196 + send(w_s, req + i, 1, MSG_NOSIGNAL);
  197 + }
  198 + continue;
182 199 }
183 200 }
184 201  
... ...
tests/unit-test.h.in
... ... @@ -52,6 +52,8 @@ const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0x6C;
52 52 const uint16_t UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE = 0x6D;
53 53 /* The server will wait for 1 second before replying to test timeout */
54 54 const uint16_t UT_REGISTERS_ADDRESS_SLEEP_500_MS = 0x6E;
  55 +/* The server will wait for 5 ms before sending each byte */
  56 +const uint16_t UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS = 0x6F;
55 57  
56 58 const uint16_t UT_REGISTERS_NB = 0x3;
57 59 const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0001, 0x0064 };
... ...