From ee2af14da8bdaab0a1baf2c9cab59bd08076564d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Jan 2025 12:26:06 +0100 Subject: [PATCH 1/6] tests/unit-test-server.c: clarify failed TCP listener situations Signed-off-by: Jim Klimov --- tests/unit-test-server.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c index bb25ba43..ee844396 100644 --- a/tests/unit-test-server.c +++ b/tests/unit-test-server.c @@ -82,12 +82,24 @@ int main(int argc, char *argv[]) if (use_backend == TCP) { ctx = modbus_new_tcp(ip_or_device, 1502); + if (ctx == NULL) { + fprintf(stderr, "Failed to allocate the context for TCP: %s\n", modbus_strerror(errno)); + return -1; + } query = malloc(MODBUS_TCP_MAX_ADU_LENGTH); } else if (use_backend == TCP_PI) { ctx = modbus_new_tcp_pi(ip_or_device, "1502"); + if (ctx == NULL) { + fprintf(stderr, "Failed to allocate the context for TCP PI: %s\n", modbus_strerror(errno)); + return -1; + } query = malloc(MODBUS_TCP_MAX_ADU_LENGTH); } else { ctx = modbus_new_rtu(ip_or_device, 115200, 'N', 8, 1); + if (ctx == NULL) { + fprintf(stderr, "Failed to allocate the context for Serial: %s\n", modbus_strerror(errno)); + return -1; + } modbus_set_slave(ctx, SERVER_ID); query = malloc(MODBUS_RTU_MAX_ADU_LENGTH); } @@ -124,10 +136,28 @@ int main(int argc, char *argv[]) if (use_backend == TCP) { s = modbus_tcp_listen(ctx, 1); - modbus_tcp_accept(ctx, &s); + if (s == -1) { + fprintf(stderr, "Unable to modbus_tcp_listen(), got invalid socket: %s\n", modbus_strerror(errno)); + modbus_free(ctx); + return -1; + } + if (modbus_tcp_accept(ctx, &s) == -1) { + fprintf(stderr, "Unable to modbus_tcp_accept(): %s\n", modbus_strerror(errno)); + modbus_free(ctx); + return -1; + } } else if (use_backend == TCP_PI) { s = modbus_tcp_pi_listen(ctx, 1); - modbus_tcp_pi_accept(ctx, &s); + if (s == -1) { + fprintf(stderr, "Unable to modbus_tcp_pi_listen(), got invalid socket: %s\n", modbus_strerror(errno)); + modbus_free(ctx); + return -1; + } + if (modbus_tcp_pi_accept(ctx, &s) == -1) { + fprintf(stderr, "Unable to modbus_tcp_pi_accept(): %s\n", modbus_strerror(errno)); + modbus_free(ctx); + return -1; + } } else { rc = modbus_connect(ctx); if (rc == -1) { From d2019d2b6b97e3ec2c99ec382cbdafc4c36b19b8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Jan 2025 13:55:18 +0100 Subject: [PATCH 2/6] tests/unit-test-client.c: revise ASSERT_TRUE messages Signed-off-by: Jim Klimov --- tests/unit-test-client.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index a1813b1e..16e8a728 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -174,7 +174,7 @@ int main(int argc, char *argv[]) rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, 1, tab_rp_bits); printf("2/2 modbus_read_bits: "); - ASSERT_TRUE(rc == 1, "FAILED (nb points %d)\n", rc); + ASSERT_TRUE(rc == 1, "FAILED (nb points: %d)\n", rc); ASSERT_TRUE(tab_rp_bits[0] == ON, "FAILED (%0X != %0X)\n", tab_rp_bits[0], ON); /* End single */ @@ -191,7 +191,7 @@ int main(int argc, char *argv[]) rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB, tab_rp_bits); printf("2/2 modbus_read_bits: "); - ASSERT_TRUE(rc == UT_BITS_NB, "FAILED (nb points %d)\n", rc); + ASSERT_TRUE(rc == UT_BITS_NB, "FAILED (nb points: %d)\n", rc); i = 0; nb_points = UT_BITS_NB; @@ -212,7 +212,7 @@ int main(int argc, char *argv[]) rc = modbus_read_input_bits(ctx, UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB, tab_rp_bits); printf("1/1 modbus_read_input_bits: "); - ASSERT_TRUE(rc == UT_INPUT_BITS_NB, "FAILED (nb points %d)\n", rc); + ASSERT_TRUE(rc == UT_INPUT_BITS_NB, "FAILED (nb points: %d)\n", rc); i = 0; nb_points = UT_INPUT_BITS_NB; @@ -238,7 +238,7 @@ int main(int argc, char *argv[]) rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 1, tab_rp_registers); printf("2/2 modbus_read_registers: "); - ASSERT_TRUE(rc == 1, "FAILED (nb points %d)\n", rc); + ASSERT_TRUE(rc == 1, "FAILED (nb points: %d)\n", rc); ASSERT_TRUE(tab_rp_registers[0] == 0x1234, "FAILED (%0X != %0X)\n", tab_rp_registers[0], @@ -254,7 +254,7 @@ int main(int argc, char *argv[]) rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); printf("2/5 modbus_read_registers: "); - ASSERT_TRUE(rc == UT_REGISTERS_NB, "FAILED (nb points %d)\n", rc); + ASSERT_TRUE(rc == UT_REGISTERS_NB, "FAILED (nb points: %d)\n", rc); for (i = 0; i < UT_REGISTERS_NB; i++) { ASSERT_TRUE(tab_rp_registers[i] == UT_REGISTERS_TAB[i], @@ -265,7 +265,7 @@ int main(int argc, char *argv[]) rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 0, tab_rp_registers); printf("3/5 modbus_read_registers (0): "); - ASSERT_TRUE(rc == -1, "FAILED (nb_points %d)\n", rc); + ASSERT_TRUE(rc == -1, "FAILED (nb_points: %d)\n", rc); nb_points = (UT_REGISTERS_NB > UT_INPUT_REGISTERS_NB) ? UT_REGISTERS_NB : UT_INPUT_REGISTERS_NB; @@ -283,7 +283,7 @@ int main(int argc, char *argv[]) tab_rp_registers); printf("4/5 modbus_write_and_read_registers: "); ASSERT_TRUE( - rc == UT_REGISTERS_NB, "FAILED (nb points %d != %d)\n", rc, UT_REGISTERS_NB); + rc == UT_REGISTERS_NB, "FAILED (nb points: %d != %d)\n", rc, UT_REGISTERS_NB); ASSERT_TRUE(tab_rp_registers[0] == UT_REGISTERS_TAB[0], "FAILED (%0X != %0X)\n", @@ -301,7 +301,7 @@ int main(int argc, char *argv[]) rc = modbus_read_input_registers( ctx, UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB, tab_rp_registers); printf("1/1 modbus_read_input_registers: "); - ASSERT_TRUE(rc == UT_INPUT_REGISTERS_NB, "FAILED (nb points %d)\n", rc); + ASSERT_TRUE(rc == UT_INPUT_REGISTERS_NB, "FAILED (nb points: %d)\n", rc); for (i = 0; i < UT_INPUT_REGISTERS_NB; i++) { ASSERT_TRUE(tab_rp_registers[i] == UT_INPUT_REGISTERS_TAB[i], @@ -314,7 +314,7 @@ int main(int argc, char *argv[]) printf("1/1 Write mask: "); rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x12); rc = modbus_mask_write_register(ctx, UT_REGISTERS_ADDRESS, 0xF2, 0x25); - ASSERT_TRUE(rc != -1, "FAILED (%x == -1)\n", rc); + ASSERT_TRUE(rc != -1, "FAILED (rc: %x == -1)\n", rc); rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 1, tab_rp_registers); ASSERT_TRUE( tab_rp_registers[0] == 0x17, "FAILED (%0X != %0X)\n", tab_rp_registers[0], 0x17); @@ -702,7 +702,7 @@ int main(int argc, char *argv[]) rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS, 1, tab_rp_registers); printf("2/2 Adapted byte timeout (7ms > 5ms): "); - ASSERT_TRUE(rc == 1, ""); + ASSERT_TRUE(rc == 1, "FAILED (rc: %d != 1)", rc); } /* Restore original byte timeout */ @@ -858,7 +858,7 @@ int test_server(modbus_t *ctx, int use_backend) rc = modbus_receive(ctx, rsp); modbus_set_socket(ctx, old_s); printf("* modbus_receive with invalid socket: "); - ASSERT_TRUE(rc == -1, "FAILED (%d)\n", rc); + ASSERT_TRUE(rc == -1, "FAILED (rc: %d != -1)\n", rc); req_length = modbus_send_raw_request(ctx, read_raw_req, READ_RAW_REQ_LEN); printf("* modbus_send_raw_request: "); From bb648208af022b10fbfdaa6e6ddbf839a438916c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Jan 2025 17:49:20 +0100 Subject: [PATCH 3/6] tests/unit-test-client.c: introduce TEST_TITLE() to ease navigation in test log; move the message to before the tested library method Signed-off-by: Jim Klimov --- tests/unit-test-client.c | 206 +++++++++++++++++++++------------------ 1 file changed, 113 insertions(+), 93 deletions(-) diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index 16e8a728..b08f48ed 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -33,18 +33,29 @@ int send_crafted_request(modbus_t *ctx, int equal_dword(uint16_t *tab_reg, const uint32_t value); int is_memory_equal(const void *s1, const void *s2, size_t size); -#define BUG_REPORT(_cond, _format, _args...) \ - printf( \ - "\nLine %d: assertion error for '%s': " _format "\n", __LINE__, #_cond, ##_args) - -#define ASSERT_TRUE(_cond, _format, __args...) \ - { \ - if (_cond) { \ - printf("OK\n"); \ - } else { \ - BUG_REPORT(_cond, _format, ##__args); \ - goto close; \ - } \ +static char last_test_title[256]; +#define BUG_REPORT(_cond, _format, _args...) \ + printf( \ + "\nLine %d: assertion error for '%s': " \ + _format "\n", __LINE__, #_cond, ##_args) + +#define ASSERT_TRUE(_cond, _format, __args...) \ + { \ + if (_cond) { \ + printf("%s: OK\n", last_test_title); \ + } else { \ + printf("%s: FAILED\n", last_test_title); \ + BUG_REPORT(_cond, _format, ##__args); \ + goto close; \ + } \ + }; + +#define TEST_TITLE(_format, _args...) \ + { \ + snprintf(last_test_title, sizeof(last_test_title), \ + _format, ##_args); \ + printf("\n=== Test at line %4d: %s :\n", \ + __LINE__, last_test_title); \ }; int is_memory_equal(const void *s1, const void *s2, size_t size) @@ -157,7 +168,7 @@ int main(int argc, char *argv[]) printf("** UNIT TESTING **\n"); - printf("1/1 No response timeout modification on connect: "); + TEST_TITLE("1/1 No response timeout modification on connect"); modbus_get_response_timeout(ctx, &new_response_to_sec, &new_response_to_usec); ASSERT_TRUE(old_response_to_sec == new_response_to_sec && old_response_to_usec == new_response_to_usec, @@ -168,12 +179,12 @@ int main(int argc, char *argv[]) /** COIL BITS **/ /* Single */ + TEST_TITLE("1/2 modbus_write_bit"); rc = modbus_write_bit(ctx, UT_BITS_ADDRESS, ON); - printf("1/2 modbus_write_bit: "); ASSERT_TRUE(rc == 1, ""); + TEST_TITLE("2/2 modbus_read_bits"); rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, 1, tab_rp_bits); - printf("2/2 modbus_read_bits: "); ASSERT_TRUE(rc == 1, "FAILED (nb points: %d)\n", rc); ASSERT_TRUE(tab_rp_bits[0] == ON, "FAILED (%0X != %0X)\n", tab_rp_bits[0], ON); @@ -184,13 +195,13 @@ int main(int argc, char *argv[]) uint8_t tab_value[UT_BITS_NB]; modbus_set_bits_from_bytes(tab_value, 0, UT_BITS_NB, UT_BITS_TAB); + TEST_TITLE("1/2 modbus_write_bits"); rc = modbus_write_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB, tab_value); - printf("1/2 modbus_write_bits: "); ASSERT_TRUE(rc == UT_BITS_NB, ""); } + TEST_TITLE("2/2 modbus_read_bits"); rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB, tab_rp_bits); - printf("2/2 modbus_read_bits: "); ASSERT_TRUE(rc == UT_BITS_NB, "FAILED (nb points: %d)\n", rc); i = 0; @@ -209,9 +220,9 @@ int main(int argc, char *argv[]) /* End of multiple bits */ /** DISCRETE INPUTS **/ + TEST_TITLE("1/1 modbus_read_input_bits"); rc = modbus_read_input_bits(ctx, UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB, tab_rp_bits); - printf("1/1 modbus_read_input_bits: "); ASSERT_TRUE(rc == UT_INPUT_BITS_NB, "FAILED (nb points: %d)\n", rc); i = 0; @@ -232,12 +243,12 @@ int main(int argc, char *argv[]) /** HOLDING REGISTERS **/ /* Single register */ + TEST_TITLE("1/2 modbus_write_register"); rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x1234); - printf("1/2 modbus_write_register: "); ASSERT_TRUE(rc == 1, ""); + TEST_TITLE("2/2 modbus_read_registers"); rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 1, tab_rp_registers); - printf("2/2 modbus_read_registers: "); ASSERT_TRUE(rc == 1, "FAILED (nb points: %d)\n", rc); ASSERT_TRUE(tab_rp_registers[0] == 0x1234, "FAILED (%0X != %0X)\n", @@ -246,14 +257,14 @@ int main(int argc, char *argv[]) /* End of single register */ /* Many registers */ + TEST_TITLE("1/5 modbus_write_registers"); rc = modbus_write_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, UT_REGISTERS_TAB); - printf("1/5 modbus_write_registers: "); ASSERT_TRUE(rc == UT_REGISTERS_NB, ""); + TEST_TITLE("2/5 modbus_read_registers"); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); - printf("2/5 modbus_read_registers: "); ASSERT_TRUE(rc == UT_REGISTERS_NB, "FAILED (nb points: %d)\n", rc); for (i = 0; i < UT_REGISTERS_NB; i++) { @@ -263,14 +274,15 @@ int main(int argc, char *argv[]) UT_REGISTERS_TAB[i]); } + TEST_TITLE("3/5 modbus_read_registers (0)"); rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 0, tab_rp_registers); - printf("3/5 modbus_read_registers (0): "); ASSERT_TRUE(rc == -1, "FAILED (nb_points: %d)\n", rc); nb_points = (UT_REGISTERS_NB > UT_INPUT_REGISTERS_NB) ? UT_REGISTERS_NB : UT_INPUT_REGISTERS_NB; memset(tab_rp_registers, 0, nb_points * sizeof(uint16_t)); + TEST_TITLE("4/5 modbus_write_and_read_registers"); /* Write registers to zero from tab_rp_registers and store read registers into tab_rp_registers. So the read registers must set to 0, except the first one because there is an offset of 1 register on write. */ @@ -281,7 +293,6 @@ int main(int argc, char *argv[]) UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); - printf("4/5 modbus_write_and_read_registers: "); ASSERT_TRUE( rc == UT_REGISTERS_NB, "FAILED (nb points: %d != %d)\n", rc, UT_REGISTERS_NB); @@ -294,13 +305,14 @@ int main(int argc, char *argv[]) ASSERT_TRUE( tab_rp_registers[i] == 0, "FAILED (%0X != %0X)\n", tab_rp_registers[i], 0); } + /* FIXME: Who is 5/5 here? */ /* End of many registers */ /** INPUT REGISTERS **/ + TEST_TITLE("1/1 modbus_read_input_registers"); rc = modbus_read_input_registers( ctx, UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB, tab_rp_registers); - printf("1/1 modbus_read_input_registers: "); ASSERT_TRUE(rc == UT_INPUT_REGISTERS_NB, "FAILED (nb points: %d)\n", rc); for (i = 0; i < UT_INPUT_REGISTERS_NB; i++) { @@ -311,7 +323,7 @@ int main(int argc, char *argv[]) } /* MASKS */ - printf("1/1 Write mask: "); + TEST_TITLE("1/1 Write mask"); rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS, 0x12); rc = modbus_mask_write_register(ctx, UT_REGISTERS_ADDRESS, 0xF2, 0x25); ASSERT_TRUE(rc != -1, "FAILED (rc: %x == -1)\n", rc); @@ -321,35 +333,35 @@ int main(int argc, char *argv[]) printf("\nTEST FLOATS\n"); /** FLOAT **/ - printf("1/4 Set/get float ABCD: "); + TEST_TITLE("1/4 Set/get float ABCD"); modbus_set_float_abcd(UT_REAL, tab_rp_registers); ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_ABCD, 4), "FAILED Set float ABCD"); real = modbus_get_float_abcd(UT_IREAL_ABCD); ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); - printf("2/4 Set/get float DCBA: "); + TEST_TITLE("2/4 Set/get float DCBA"); modbus_set_float_dcba(UT_REAL, tab_rp_registers); ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_DCBA, 4), "FAILED Set float DCBA"); real = modbus_get_float_dcba(UT_IREAL_DCBA); ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); - printf("3/4 Set/get float BADC: "); + TEST_TITLE("3/4 Set/get float BADC"); modbus_set_float_badc(UT_REAL, tab_rp_registers); ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_BADC, 4), "FAILED Set float BADC"); real = modbus_get_float_badc(UT_IREAL_BADC); ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); - printf("4/4 Set/get float CDAB: "); + TEST_TITLE("4/4 Set/get float CDAB"); modbus_set_float_cdab(UT_REAL, tab_rp_registers); ASSERT_TRUE(is_memory_equal(tab_rp_registers, UT_IREAL_CDAB, 4), "FAILED Set float CDAB"); real = modbus_get_float_cdab(UT_IREAL_CDAB); ASSERT_TRUE(real == UT_REAL, "FAILED (%f != %f)\n", real, UT_REAL); - printf("\nAt this point, error messages doesn't mean the test has failed\n"); + printf("\nAt this point, error messages don't mean the test has failed\n"); /** ILLEGAL DATA ADDRESS **/ printf("\nTEST ILLEGAL DATA ADDRESS:\n"); @@ -357,91 +369,92 @@ int main(int argc, char *argv[]) /* The mapping begins at the defined addresses and ends at address + * nb_points so these addresses are not valid. */ + TEST_TITLE("* modbus_read_bits (0)"); rc = modbus_read_bits(ctx, 0, 1, tab_rp_bits); - printf("* modbus_read_bits (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_read_bits (max)"); rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, UT_BITS_NB + 1, tab_rp_bits); - printf("* modbus_read_bits (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_read_input_bits (0)"); rc = modbus_read_input_bits(ctx, 0, 1, tab_rp_bits); - printf("* modbus_read_input_bits (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_read_input_bits (max)"); rc = modbus_read_input_bits( ctx, UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB + 1, tab_rp_bits); - printf("* modbus_read_input_bits (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_read_registers (0)"); rc = modbus_read_registers(ctx, 0, 1, tab_rp_registers); - printf("* modbus_read_registers (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_read_registers (max)"); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_MAX + 1, tab_rp_registers); - printf("* modbus_read_registers (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_read_input_registers (0)"); rc = modbus_read_input_registers(ctx, 0, 1, tab_rp_registers); - printf("* modbus_read_input_registers (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_read_input_registers (max)"); rc = modbus_read_input_registers( ctx, UT_INPUT_REGISTERS_ADDRESS, UT_INPUT_REGISTERS_NB + 1, tab_rp_registers); - printf("* modbus_read_input_registers (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_bit (0)"); rc = modbus_write_bit(ctx, 0, ON); - printf("* modbus_write_bit (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_bit (max)"); rc = modbus_write_bit(ctx, UT_BITS_ADDRESS + UT_BITS_NB, ON); - printf("* modbus_write_bit (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_bits (0)"); rc = modbus_write_bits(ctx, 0, 1, tab_rp_bits); - printf("* modbus_write_bits (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_bits (max)"); rc = modbus_write_bits(ctx, UT_BITS_ADDRESS + UT_BITS_NB, UT_BITS_NB, tab_rp_bits); - printf("* modbus_write_bits (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_register (0)"); rc = modbus_write_register(ctx, 0, tab_rp_registers[0]); - printf("* modbus_write_register (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_register (max)"); rc = modbus_write_register( ctx, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX, tab_rp_registers[0]); - printf("* modbus_write_register (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_registers (0)"); rc = modbus_write_registers(ctx, 0, 1, tab_rp_registers); - printf("* modbus_write_registers (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_registers (max)"); rc = modbus_write_registers(ctx, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX, UT_REGISTERS_NB, tab_rp_registers); - printf("* modbus_write_registers (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_mask_write_registers (0)"); rc = modbus_mask_write_register(ctx, 0, 0xF2, 0x25); - printf("* modbus_mask_write_registers (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_mask_write_registers (max)"); rc = modbus_mask_write_register( ctx, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX, 0xF2, 0x25); - printf("* modbus_mask_write_registers (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_and_read_registers (0)"); rc = modbus_write_and_read_registers( ctx, 0, 1, tab_rp_registers, 0, 1, tab_rp_registers); - printf("* modbus_write_and_read_registers (0): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); + TEST_TITLE("* modbus_write_and_read_registers (max)"); rc = modbus_write_and_read_registers(ctx, UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX, UT_REGISTERS_NB, @@ -449,38 +462,37 @@ int main(int argc, char *argv[]) UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_MAX, UT_REGISTERS_NB, tab_rp_registers); - printf("* modbus_write_and_read_registers (max): "); ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); /** TOO MANY DATA **/ printf("\nTEST TOO MANY DATA ERROR:\n"); + TEST_TITLE("* modbus_read_bits"); rc = modbus_read_bits(ctx, UT_BITS_ADDRESS, MODBUS_MAX_READ_BITS + 1, tab_rp_bits); - printf("* modbus_read_bits: "); ASSERT_TRUE(rc == -1 && errno == EMBMDATA, ""); + TEST_TITLE("* modbus_read_input_bits"); rc = modbus_read_input_bits( ctx, UT_INPUT_BITS_ADDRESS, MODBUS_MAX_READ_BITS + 1, tab_rp_bits); - printf("* modbus_read_input_bits: "); ASSERT_TRUE(rc == -1 && errno == EMBMDATA, ""); + TEST_TITLE("* modbus_read_registers"); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, MODBUS_MAX_READ_REGISTERS + 1, tab_rp_registers); - printf("* modbus_read_registers: "); ASSERT_TRUE(rc == -1 && errno == EMBMDATA, ""); + TEST_TITLE("* modbus_read_input_registers"); rc = modbus_read_input_registers( ctx, UT_INPUT_REGISTERS_ADDRESS, MODBUS_MAX_READ_REGISTERS + 1, tab_rp_registers); - printf("* modbus_read_input_registers: "); ASSERT_TRUE(rc == -1 && errno == EMBMDATA, ""); + TEST_TITLE("* modbus_write_bits"); rc = modbus_write_bits(ctx, UT_BITS_ADDRESS, MODBUS_MAX_WRITE_BITS + 1, tab_rp_bits); - printf("* modbus_write_bits: "); ASSERT_TRUE(rc == -1 && errno == EMBMDATA, ""); + TEST_TITLE("* modbus_write_registers"); rc = modbus_write_registers( ctx, UT_REGISTERS_ADDRESS, MODBUS_MAX_WRITE_REGISTERS + 1, tab_rp_registers); - printf("* modbus_write_registers: "); ASSERT_TRUE(rc == -1 && errno == EMBMDATA, ""); /** SLAVE ADDRESS **/ @@ -488,32 +500,38 @@ int main(int argc, char *argv[]) printf("\nTEST SLAVE ADDRESS:\n"); - printf("1/2 Not compliant slave address is refused: "); + TEST_TITLE("1/3 Not compliant slave address is refused"); rc = modbus_set_slave(ctx, 248); ASSERT_TRUE(rc == -1, "Slave address of 248 shouldn't be allowed"); - printf("2/2 Not compliant slave address is allowed: "); + TEST_TITLE("2/3 Not compliant slave address is allowed (with a quirk)"); modbus_enable_quirks(ctx, MODBUS_QUIRK_MAX_SLAVE); rc = modbus_set_slave(ctx, 248); ASSERT_TRUE(rc == 0, "Not compliant slave address should have been accepted"); + TEST_TITLE("3/3 Old compliant slave address can be restored (without a quirk)"); modbus_disable_quirks(ctx, MODBUS_QUIRK_MAX_SLAVE); rc = modbus_set_slave(ctx, old_slave); ASSERT_TRUE(rc == 0, "Unable to restore slave value") /** BAD USE OF REPLY FUNCTION **/ + TEST_TITLE("* modbus_write_bit (triggers invalid reply)"); rc = modbus_write_bit(ctx, UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH, ON); - printf("* modbus_write_bit (triggers invalid reply): "); ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, ""); + TEST_TITLE("* modbus_write_register (triggers invalid reply)"); rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS_SPECIAL, 0x42); - printf("* modbus_write_register (triggers invalid reply): "); ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, ""); /** SLAVE REPLY **/ printf("\nTEST SLAVE REPLY:\n"); modbus_set_slave(ctx, INVALID_SERVER_ID); + if (use_backend == RTU) { + TEST_TITLE("1-A/3 No response from slave %d", INVALID_SERVER_ID); + } else { + TEST_TITLE("1/3 Response from slave %d", INVALID_SERVER_ID); + } rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); if (use_backend == RTU) { @@ -526,12 +544,14 @@ int main(int argc, char *argv[]) uint8_t rsp[MODBUS_RTU_MAX_ADU_LENGTH]; /* No response in RTU mode */ - printf("1-A/3 No response from slave %d: ", INVALID_SERVER_ID); + //above//TEST_TITLE("1-A/3 No response from slave %d: ", INVALID_SERVER_ID); ASSERT_TRUE(rc == -1 && errno == ETIMEDOUT, ""); /* The slave raises a timeout on a confirmation to ignore because if an * indication for another slave is received, a confirmation must follow */ + TEST_TITLE("1-B/3 No response from slave %d on indication/confirmation messages", + INVALID_SERVER_ID); /* Send a pair of indication/confirmation to the slave with a different * slave ID to simulate a communication on a RS485 bus. At first, the * slave will see the indication message then the confirmation, and it must @@ -540,48 +560,47 @@ int main(int argc, char *argv[]) modbus_send_raw_request(ctx, raw_rsp, RAW_RSP_LENGTH * sizeof(uint8_t)); rc = modbus_receive_confirmation(ctx, rsp); - printf("1-B/3 No response from slave %d on indication/confirmation messages: ", - INVALID_SERVER_ID); ASSERT_TRUE(rc == -1 && errno == ETIMEDOUT, ""); + TEST_TITLE("1-C/3 No response from slave %d with invalid request", + INVALID_SERVER_ID); /* Send an INVALID request for another slave */ modbus_send_raw_request(ctx, raw_invalid_req, RAW_REQ_LENGTH * sizeof(uint8_t)); rc = modbus_receive_confirmation(ctx, rsp); - - printf("1-C/3 No response from slave %d with invalid request: ", - INVALID_SERVER_ID); ASSERT_TRUE(rc == -1 && errno == ETIMEDOUT, ""); + TEST_TITLE("Can set broadcast address"); rc = modbus_set_slave(ctx, MODBUS_BROADCAST_ADDRESS); ASSERT_TRUE(rc == 0, "Invalid broadcast address"); + TEST_TITLE("2/3 No reply after a broadcast query"); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); - printf("2/3 No reply after a broadcast query: "); ASSERT_TRUE(rc == -1 && errno == ETIMEDOUT, ""); } else { /* Response in TCP mode */ - printf("1/3 Response from slave %d: ", INVALID_SERVER_ID); + //above//TEST_TITLE("1/3 Response from slave %d: ", INVALID_SERVER_ID); ASSERT_TRUE(rc == UT_REGISTERS_NB, ""); + TEST_TITLE("Can set broadcast address"); rc = modbus_set_slave(ctx, MODBUS_BROADCAST_ADDRESS); ASSERT_TRUE(rc == 0, "Invalid broacast address"); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); - printf("2/3 Reply after a query with unit id == 0: "); + TEST_TITLE("2/3 Reply after a query with unit id == 0: "); ASSERT_TRUE(rc == UT_REGISTERS_NB, ""); } + TEST_TITLE("3/3 Response with an invalid TID or slave"); /* Restore slave */ modbus_set_slave(ctx, old_slave); - printf("3/3 Response with an invalid TID or slave: "); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE, 1, tab_rp_registers); ASSERT_TRUE(rc == -1, ""); - printf("1/2 Report slave ID truncated: \n"); + TEST_TITLE("1/2 Report slave ID truncated"); /* Set a marker to ensure limit is respected */ tab_rp_bits[NB_REPORT_SLAVE_ID - 1] = 42; rc = modbus_report_slave_id(ctx, NB_REPORT_SLAVE_ID - 1, tab_rp_bits); @@ -592,7 +611,7 @@ int main(int argc, char *argv[]) NB_REPORT_SLAVE_ID, tab_rp_bits[NB_REPORT_SLAVE_ID - 1]); - printf("2/2 Report slave ID: \n"); + TEST_TITLE("2/2 Report slave ID"); /* tab_rp_bits is used to store bytes */ rc = modbus_report_slave_id(ctx, NB_REPORT_SLAVE_ID, tab_rp_bits); ASSERT_TRUE(rc == NB_REPORT_SLAVE_ID, ""); @@ -616,22 +635,22 @@ int main(int argc, char *argv[]) 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); + TEST_TITLE("1/8 Invalid response timeout (zero)"); rc = modbus_set_response_timeout(ctx, 0, 0); - printf("1/8 Invalid response timeout (zero): "); ASSERT_TRUE(rc == -1 && errno == EINVAL, ""); + TEST_TITLE("2/8 Invalid response timeout (too large us)"); rc = modbus_set_response_timeout(ctx, 0, 1000000); - printf("2/8 Invalid response timeout (too large us): "); ASSERT_TRUE(rc == -1 && errno == EINVAL, ""); + TEST_TITLE("3/8 Invalid byte timeout (too large us)"); rc = modbus_set_byte_timeout(ctx, 0, 1000000); - printf("3/8 Invalid byte timeout (too large us): "); ASSERT_TRUE(rc == -1 && errno == EINVAL, ""); + TEST_TITLE("4/8 1us response timeout"); modbus_set_response_timeout(ctx, 0, 1); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB, tab_rp_registers); - printf("4/8 1us response timeout: "); if (rc == -1 && errno == ETIMEDOUT) { printf("OK\n"); } else { @@ -647,35 +666,35 @@ int main(int argc, char *argv[]) /* Trigger a special behaviour on server to wait for 0.5 second before * replying whereas allowed timeout is 0.2 second */ + TEST_TITLE("5/8 Too short response timeout (0.2s < 0.5s)"); modbus_set_response_timeout(ctx, 0, 200000); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS, 1, tab_rp_registers); - printf("5/8 Too short response timeout (0.2s < 0.5s): "); ASSERT_TRUE(rc == -1 && errno == ETIMEDOUT, ""); /* Wait for reply (0.2 + 0.4 > 0.5 s) and flush before continue */ usleep(400000); modbus_flush(ctx); + TEST_TITLE("6/8 Adequate response timeout (0.6s > 0.5s)"); modbus_set_response_timeout(ctx, 0, 600000); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS, 1, tab_rp_registers); - printf("6/8 Adequate response timeout (0.6s > 0.5s): "); ASSERT_TRUE(rc == 1, ""); /* Disable the byte timeout. The full response must be available in the 600ms interval */ + TEST_TITLE("7/8 Disable byte timeout"); modbus_set_byte_timeout(ctx, 0, 0); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS_SLEEP_500_MS, 1, tab_rp_registers); - printf("7/8 Disable byte timeout: "); ASSERT_TRUE(rc == 1, ""); // Invalid in TCP or RTU mode... + TEST_TITLE("8/8 Connection timeout"); modbus_t *invalid_ctx = modbus_new_tcp("1.2.3.4", 1502); modbus_set_response_timeout(ctx, 0, 1); rc = modbus_connect(invalid_ctx); - printf("8/8 Connection timeout: "); ASSERT_TRUE(rc == -1 && errno == ETIMEDOUT, ""); modbus_free(invalid_ctx); @@ -687,10 +706,10 @@ int main(int argc, char *argv[]) * backend */ /* Timeout of 3ms between bytes */ + TEST_TITLE("1/2 Too small byte timeout (3ms < 5ms)"); 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): "); ASSERT_TRUE(rc == -1 && errno == ETIMEDOUT, ""); /* Wait remaining bytes before flushing */ @@ -698,10 +717,10 @@ int main(int argc, char *argv[]) modbus_flush(ctx); /* Timeout of 7ms between bytes */ + TEST_TITLE("2/2 Adapted byte timeout (7ms > 5ms)"); 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): "); ASSERT_TRUE(rc == 1, "FAILED (rc: %d != 1)", rc); } @@ -715,18 +734,19 @@ int main(int argc, char *argv[]) tab_rp_registers_bad = (uint16_t *) malloc(UT_REGISTERS_NB_SPECIAL * sizeof(uint16_t)); + TEST_TITLE("* modbus_read_registers"); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS, UT_REGISTERS_NB_SPECIAL, tab_rp_registers_bad); - printf("* modbus_read_registers: "); ASSERT_TRUE(rc == -1 && errno == EMBBADDATA, ""); free(tab_rp_registers_bad); /** MANUAL EXCEPTION **/ printf("\nTEST MANUAL EXCEPTION:\n"); + + TEST_TITLE("* modbus_read_registers at special address"); rc = modbus_read_registers( ctx, UT_REGISTERS_ADDRESS_SPECIAL, UT_REGISTERS_NB, tab_rp_registers); - printf("* modbus_read_registers at special address: "); ASSERT_TRUE(rc == -1 && errno == EMBXSBUSY, ""); /** Run a few tests to challenge the server code **/ @@ -853,18 +873,18 @@ int test_server(modbus_t *ctx, int use_backend) modbus_get_response_timeout(ctx, &old_response_to_sec, &old_response_to_usec); modbus_set_response_timeout(ctx, 0, 600000); + TEST_TITLE("* modbus_receive with invalid socket"); int old_s = modbus_get_socket(ctx); modbus_set_socket(ctx, -1); rc = modbus_receive(ctx, rsp); - modbus_set_socket(ctx, old_s); - printf("* modbus_receive with invalid socket: "); ASSERT_TRUE(rc == -1, "FAILED (rc: %d != -1)\n", rc); + modbus_set_socket(ctx, old_s); + TEST_TITLE("* modbus_send_raw_request"); req_length = modbus_send_raw_request(ctx, read_raw_req, READ_RAW_REQ_LEN); - printf("* modbus_send_raw_request: "); ASSERT_TRUE(req_length == (backend_length + 5), "FAILED (%d)\n", req_length); - printf("* modbus_receive_confirmation: "); + TEST_TITLE("* modbus_receive_confirmation"); rc = modbus_receive_confirmation(ctx, rsp); ASSERT_TRUE(rc == (backend_length + 12), "FAILED (%d)\n", rc); @@ -941,10 +961,10 @@ int test_server(modbus_t *ctx, int use_backend) goto close; /* Test invalid function code */ + TEST_TITLE("Return an exception on unknown function code"); modbus_send_raw_request( ctx, invalid_fc_raw_req, INVALID_FC_REQ_LEN * sizeof(uint8_t)); rc = modbus_receive_confirmation(ctx, rsp); - printf("Return an exception on unknown function code: "); ASSERT_TRUE(rc == (backend_length + EXCEPTION_RC) && rsp[backend_offset] == (0x80 + INVALID_FC), "") @@ -992,10 +1012,10 @@ int send_crafted_request(modbus_t *ctx, modbus_send_raw_request(ctx, req, req_len * sizeof(uint8_t)); if (j == 0) { - printf( - "* try function 0x%X: %s 0 values: ", function, bytes ? "write" : "read"); + TEST_TITLE( + "* try function 0x%X: %s 0 values", function, bytes ? "write" : "read"); } else { - printf("* try function 0x%X: %s %d values: ", + TEST_TITLE("* try function 0x%X: %s %d values", function, bytes ? "write" : "read", max_value); From 97f47f1a45342e109ff2cecae89a6ade04ccec22 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Jan 2025 17:50:08 +0100 Subject: [PATCH 4/6] tests/unit-test.h.in, tests/unit-test-client.c: introduce FLUSHOUT to help with console logs on WIN32 test runs Signed-off-by: Jim Klimov --- tests/unit-test-client.c | 4 ++++ tests/unit-test.h.in | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index b08f48ed..4e2c683d 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -41,8 +41,10 @@ static char last_test_title[256]; #define ASSERT_TRUE(_cond, _format, __args...) \ { \ + FLUSHOUT; \ if (_cond) { \ printf("%s: OK\n", last_test_title); \ + FLUSHOUT; \ } else { \ printf("%s: FAILED\n", last_test_title); \ BUG_REPORT(_cond, _format, ##__args); \ @@ -52,10 +54,12 @@ static char last_test_title[256]; #define TEST_TITLE(_format, _args...) \ { \ + FLUSHOUT; \ snprintf(last_test_title, sizeof(last_test_title), \ _format, ##_args); \ printf("\n=== Test at line %4d: %s :\n", \ __LINE__, last_test_title); \ + FLUSHOUT; \ }; int is_memory_equal(const void *s1, const void *s2, size_t size) diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in index 918cc438..afb33e23 100644 --- a/tests/unit-test.h.in +++ b/tests/unit-test.h.in @@ -88,4 +88,13 @@ const uint16_t UT_IREAL_DCBA[] = {0x0020, 0xF147}; const uint16_t UT_IREAL_BADC[] = {0xF147, 0x0020}; const uint16_t UT_IREAL_CDAB[] = {0x2000, 0x47F1}; +#ifdef _WIN32 +// It may also help to view console logs of the client+server +// on WIN32 builds without intermixing, by piping to "cat": +// make -j 8 && ( ./tests/unit-test-server|cat & sleep 1 ; ./tests/unit-test-client|cat ) +# define FLUSHOUT do { fflush(stdout); } while(0) +#else +# define FLUSHOUT (void)0 +#endif + #endif /* _UNIT_TEST_H_ */ From 161c40fa134e77317f056b723ebee5ccaf99e23f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Jan 2025 20:09:24 +0100 Subject: [PATCH 5/6] tests/unit-test-(server|client).c: satisfy older compilers that ip_or_device is safe to use Signed-off-by: Jim Klimov --- tests/unit-test-client.c | 2 +- tests/unit-test-server.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index 4e2c683d..02fe8689 100644 --- a/tests/unit-test-client.c +++ b/tests/unit-test-client.c @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) int use_backend; int success = FALSE; int old_slave; - char *ip_or_device; + char *ip_or_device = NULL; if (argc > 1) { if (strcmp(argv[1], "tcp") == 0) { diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c index ee844396..ea4455f1 100644 --- a/tests/unit-test-server.c +++ b/tests/unit-test-server.c @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) int use_backend; uint8_t *query; int header_length; - char *ip_or_device; + char *ip_or_device = NULL; if (argc > 1) { if (strcmp(argv[1], "tcp") == 0) { From 670d4e0d01983817f883b68458e175559bf909b8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Sat, 18 Jan 2025 20:10:35 +0100 Subject: [PATCH 6/6] tests/unit-test.h.in: satisfy some compilers that UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH is initialized correctly with constexpr Signed-off-by: Jim Klimov --- tests/unit-test.h.in | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in index afb33e23..3d83967a 100644 --- a/tests/unit-test.h.in +++ b/tests/unit-test.h.in @@ -27,10 +27,17 @@ #define SERVER_ID 17 #define INVALID_SERVER_ID 18 -const uint16_t UT_BITS_ADDRESS = 0x130; +/* https://stackoverflow.com/a/3025142/4715872 + * ...in section 6.6, the spec defines what must considered + * a constant expression. No where does it state that a + * const variable must be considered a constant expression. + * It is legal for a compiler to extend this... + */ +#define UT_BITS_ADDRESS_VAL 0x130 +const uint16_t UT_BITS_ADDRESS = UT_BITS_ADDRESS_VAL; const uint16_t UT_BITS_NB = 0x25; const uint8_t UT_BITS_TAB[] = { 0xCD, 0x6B, 0xB2, 0x0E, 0x1B }; -const uint16_t UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH = UT_BITS_ADDRESS + 2; +const uint16_t UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH = UT_BITS_ADDRESS_VAL + 2; const uint16_t UT_INPUT_BITS_ADDRESS = 0x1C4; const uint16_t UT_INPUT_BITS_NB = 0x16;