Commit 1941fd4aa96007b69b4c119bd39491d39ef2373e
1 parent
6bad3494
Check slave only in RTU backend and add unit tests
- new function _modbus_rtu_pre_check_confirmation - new special test value to trigger an invalid response - add unit test to cover invalid TID too
Showing
5 changed files
with
50 additions
and
13 deletions
src/modbus-rtu.c
| ... | ... | @@ -313,6 +313,24 @@ ssize_t _modbus_rtu_recv(modbus_t *ctx, uint8_t *rsp, int rsp_length) |
| 313 | 313 | |
| 314 | 314 | int _modbus_rtu_flush(modbus_t *); |
| 315 | 315 | |
| 316 | +int _modbus_rtu_pre_check_confirmation(modbus_t *ctx, const uint8_t *req, | |
| 317 | + const uint8_t *rsp, int rsp_length) | |
| 318 | +{ | |
| 319 | + /* Check responding slave is the slave we requested (except for broacast | |
| 320 | + * request) */ | |
| 321 | + if (req[0] != 0 && req[0] != rsp[0]) { | |
| 322 | + if (ctx->debug) { | |
| 323 | + fprintf(stderr, | |
| 324 | + "The responding slave %d it not the requested slave %d", | |
| 325 | + rsp[0], req[0]); | |
| 326 | + } | |
| 327 | + errno = EMBBADSLAVE; | |
| 328 | + return -1; | |
| 329 | + } else { | |
| 330 | + return 0; | |
| 331 | + } | |
| 332 | +} | |
| 333 | + | |
| 316 | 334 | /* The check_crc16 function shall return the message length if the CRC is |
| 317 | 335 | valid. Otherwise it shall return -1 and set errno to EMBADCRC. */ |
| 318 | 336 | int _modbus_rtu_check_integrity(modbus_t *ctx, uint8_t *msg, |
| ... | ... | @@ -940,7 +958,7 @@ const modbus_backend_t _modbus_rtu_backend = { |
| 940 | 958 | _modbus_rtu_send, |
| 941 | 959 | _modbus_rtu_recv, |
| 942 | 960 | _modbus_rtu_check_integrity, |
| 943 | - NULL, | |
| 961 | + _modbus_rtu_pre_check_confirmation, | |
| 944 | 962 | _modbus_rtu_connect, |
| 945 | 963 | _modbus_rtu_close, |
| 946 | 964 | _modbus_rtu_flush, | ... | ... |
src/modbus.c
| ... | ... | @@ -494,12 +494,6 @@ static int check_confirmation(modbus_t *ctx, uint8_t *req, |
| 494 | 494 | } |
| 495 | 495 | } |
| 496 | 496 | |
| 497 | - /* Check responding slave is the slave we requested */ | |
| 498 | - if (req[0] != 0 && rsp[0] != req[0]) { | |
| 499 | - errno = EMBBADSLAVE; | |
| 500 | - return -1; | |
| 501 | - } | |
| 502 | - | |
| 503 | 497 | rsp_length_computed = compute_response_length_from_request(ctx, req); |
| 504 | 498 | |
| 505 | 499 | /* Check length */ | ... | ... |
tests/unit-test-client.c
| ... | ... | @@ -495,7 +495,7 @@ int main(int argc, char *argv[]) |
| 495 | 495 | uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH]; |
| 496 | 496 | |
| 497 | 497 | /* No response in RTU mode */ |
| 498 | - printf("1/4-A No response from slave %d: ", INVALID_SERVER_ID); | |
| 498 | + printf("1/5-A No response from slave %d: ", INVALID_SERVER_ID); | |
| 499 | 499 | |
| 500 | 500 | if (rc == -1 && errno == ETIMEDOUT) { |
| 501 | 501 | printf("OK\n"); |
| ... | ... | @@ -509,7 +509,7 @@ int main(int argc, char *argv[]) |
| 509 | 509 | RAW_REQ_LENGTH * sizeof(uint8_t)); |
| 510 | 510 | rc = modbus_receive_confirmation(ctx, rsp); |
| 511 | 511 | |
| 512 | - printf("1/4-B No response from slave %d with invalid request: ", | |
| 512 | + printf("1/5-B No response from slave %d with invalid request: ", | |
| 513 | 513 | INVALID_SERVER_ID); |
| 514 | 514 | |
| 515 | 515 | if (rc == -1 && errno == ETIMEDOUT) { |
| ... | ... | @@ -539,7 +539,7 @@ int main(int argc, char *argv[]) |
| 539 | 539 | |
| 540 | 540 | rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, |
| 541 | 541 | UT_REGISTERS_NB, tab_rp_registers); |
| 542 | - printf("2/4 Reply after a broadcast query: "); | |
| 542 | + printf("2/5 Reply after a broadcast query: "); | |
| 543 | 543 | if (rc == UT_REGISTERS_NB) { |
| 544 | 544 | printf("OK\n"); |
| 545 | 545 | } else { |
| ... | ... | @@ -554,7 +554,7 @@ int main(int argc, char *argv[]) |
| 554 | 554 | modbus_set_slave(ctx, MODBUS_TCP_SLAVE); |
| 555 | 555 | } |
| 556 | 556 | |
| 557 | - printf("3/4 Report slave ID: \n"); | |
| 557 | + printf("3/5 Report slave ID: \n"); | |
| 558 | 558 | /* tab_rp_bits is used to store bytes */ |
| 559 | 559 | rc = modbus_report_slave_id(ctx, tab_rp_bits); |
| 560 | 560 | if (rc == -1) { |
| ... | ... | @@ -587,6 +587,16 @@ int main(int argc, char *argv[]) |
| 587 | 587 | printf("\n"); |
| 588 | 588 | } |
| 589 | 589 | |
| 590 | + printf("5/5 Response with an invalid TID or slave: "); | |
| 591 | + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE, | |
| 592 | + 1, tab_rp_registers); | |
| 593 | + if (rc == -1) { | |
| 594 | + printf("OK\n"); | |
| 595 | + } else { | |
| 596 | + printf("FAILED\n"); | |
| 597 | + goto close; | |
| 598 | + } | |
| 599 | + | |
| 590 | 600 | /* Save original timeout */ |
| 591 | 601 | modbus_get_response_timeout(ctx, &old_response_timeout); |
| 592 | 602 | ... | ... |
tests/unit-test-server.c
| ... | ... | @@ -128,11 +128,23 @@ int main(int argc, char*argv[]) |
| 128 | 128 | MODBUS_SET_INT16_TO_INT8(query, header_length + 3, |
| 129 | 129 | UT_REGISTERS_NB_SPECIAL - 1); |
| 130 | 130 | } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) |
| 131 | - == UT_REGISTERS_ADDRESS_SPECIAL) { | |
| 131 | + == UT_REGISTERS_ADDRESS_SPECIAL) { | |
| 132 | 132 | printf("Reply to this special register address by an exception\n"); |
| 133 | 133 | modbus_reply_exception(ctx, query, |
| 134 | 134 | MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY); |
| 135 | 135 | continue; |
| 136 | + } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) | |
| 137 | + == UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE) { | |
| 138 | + const int RAW_REQ_LENGTH = 5; | |
| 139 | + uint8_t raw_req[] = { | |
| 140 | + (use_backend == RTU) ? INVALID_SERVER_ID : 0xFF, | |
| 141 | + 0x03, | |
| 142 | + 0x02, 0x00, 0x00 | |
| 143 | + }; | |
| 144 | + | |
| 145 | + printf("Reply with an invalid TID or slave\n"); | |
| 146 | + modbus_send_raw_request(ctx, raw_req, RAW_REQ_LENGTH * sizeof(uint8_t)); | |
| 147 | + continue; | |
| 136 | 148 | } |
| 137 | 149 | } |
| 138 | 150 | ... | ... |
tests/unit-test.h.in
| ... | ... | @@ -45,8 +45,11 @@ const uint16_t UT_INPUT_BITS_NB = 0x16; |
| 45 | 45 | const uint8_t UT_INPUT_BITS_TAB[] = { 0xAC, 0xDB, 0x35 }; |
| 46 | 46 | |
| 47 | 47 | const uint16_t UT_REGISTERS_ADDRESS = 0x6B; |
| 48 | -/* Raise a manual exception when this adress is used for the first byte */ | |
| 48 | +/* Raise a manual exception when this address is used for the first byte */ | |
| 49 | 49 | const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0x6C; |
| 50 | +/* The response of the server will contains an invalid TID or slave */ | |
| 51 | +const uint16_t UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE = 0x6D; | |
| 52 | + | |
| 50 | 53 | const uint16_t UT_REGISTERS_NB = 0x3; |
| 51 | 54 | const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0001, 0x0064 }; |
| 52 | 55 | /* If the following value is used, a bad response is sent. | ... | ... |