Commit a4f7996eafbf701371db7c9fa826987fed119188
1 parent
311137cf
New function to reply to an indication with an exception message
Contributed by Dominic Storey. - new function modbus_reply_exception - unit test
Showing
5 changed files
with
55 additions
and
0 deletions
src/modbus.c
| @@ -818,6 +818,37 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | @@ -818,6 +818,37 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 818 | return send_msg(ctx, rsp, rsp_length); | 818 | return send_msg(ctx, rsp, rsp_length); |
| 819 | } | 819 | } |
| 820 | 820 | ||
| 821 | +int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, | ||
| 822 | + unsigned int exception_code) | ||
| 823 | +{ | ||
| 824 | + int offset = ctx->backend->header_length; | ||
| 825 | + int slave = req[offset - 1]; | ||
| 826 | + int function = req[offset]; | ||
| 827 | + uint8_t rsp[MAX_MESSAGE_LENGTH]; | ||
| 828 | + int rsp_length; | ||
| 829 | + int dummy_length = 99; | ||
| 830 | + sft_t sft; | ||
| 831 | + | ||
| 832 | + if (ctx->backend->filter_request(ctx, slave) == 1) { | ||
| 833 | + /* Filtered */ | ||
| 834 | + return 0; | ||
| 835 | + } | ||
| 836 | + | ||
| 837 | + sft.slave = slave; | ||
| 838 | + sft.function = function + 0x80;; | ||
| 839 | + sft.t_id = ctx->backend->prepare_response_tid(req, &dummy_length); | ||
| 840 | + rsp_length = ctx->backend->build_response_basis(&sft, rsp); | ||
| 841 | + | ||
| 842 | + /* Positive exception code */ | ||
| 843 | + if (exception_code < MODBUS_EXCEPTION_MAX) { | ||
| 844 | + rsp[rsp_length++] = exception_code; | ||
| 845 | + return send_msg(ctx, rsp, rsp_length); | ||
| 846 | + } else { | ||
| 847 | + errno = EINVAL; | ||
| 848 | + return -1; | ||
| 849 | + } | ||
| 850 | +} | ||
| 851 | + | ||
| 821 | /* Reads IO status */ | 852 | /* Reads IO status */ |
| 822 | static int read_io_status(modbus_t *ctx, int function, | 853 | static int read_io_status(modbus_t *ctx, int function, |
| 823 | int addr, int nb, uint8_t *data_dest) | 854 | int addr, int nb, uint8_t *data_dest) |
src/modbus.h
| @@ -171,6 +171,8 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping); | @@ -171,6 +171,8 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping); | ||
| 171 | int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req); | 171 | int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req); |
| 172 | int modbus_reply(modbus_t *ctx, const uint8_t *req, | 172 | int modbus_reply(modbus_t *ctx, const uint8_t *req, |
| 173 | int req_length, modbus_mapping_t *mb_mapping); | 173 | int req_length, modbus_mapping_t *mb_mapping); |
| 174 | +int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, | ||
| 175 | + unsigned int exception_code); | ||
| 174 | 176 | ||
| 175 | /** | 177 | /** |
| 176 | * UTILS FUNCTIONS | 178 | * UTILS FUNCTIONS |
tests/unit-test-client.c
| @@ -618,8 +618,23 @@ int main(int argc, char *argv[]) | @@ -618,8 +618,23 @@ int main(int argc, char *argv[]) | ||
| 618 | printf("FAILED\n"); | 618 | printf("FAILED\n"); |
| 619 | goto close; | 619 | goto close; |
| 620 | } | 620 | } |
| 621 | + | ||
| 621 | free(tab_rp_registers_bad); | 622 | free(tab_rp_registers_bad); |
| 622 | 623 | ||
| 624 | + /** MANUAL EXCEPTION **/ | ||
| 625 | + printf("\nTEST MANUAL EXCEPTION:\n"); | ||
| 626 | + | ||
| 627 | + rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_SPECIAL, | ||
| 628 | + UT_REGISTERS_NB_POINTS, | ||
| 629 | + tab_rp_registers); | ||
| 630 | + printf("* modbus_read_registers at special address: "); | ||
| 631 | + if (rc == -1 && errno == EMBXSBUSY) { | ||
| 632 | + printf("OK\n"); | ||
| 633 | + } else { | ||
| 634 | + printf("FAILED\n"); | ||
| 635 | + goto close; | ||
| 636 | + } | ||
| 637 | + | ||
| 623 | printf("\nALL TESTS PASS WITH SUCCESS.\n"); | 638 | printf("\nALL TESTS PASS WITH SUCCESS.\n"); |
| 624 | 639 | ||
| 625 | close: | 640 | close: |
tests/unit-test-server.c
| @@ -119,6 +119,11 @@ int main(int argc, char*argv[]) | @@ -119,6 +119,11 @@ int main(int argc, char*argv[]) | ||
| 119 | printf("Set an incorrect number of values\n"); | 119 | printf("Set an incorrect number of values\n"); |
| 120 | MODBUS_SET_INT16_TO_INT8(query, header_length + 3, | 120 | MODBUS_SET_INT16_TO_INT8(query, header_length + 3, |
| 121 | UT_REGISTERS_NB_POINTS); | 121 | UT_REGISTERS_NB_POINTS); |
| 122 | + } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) | ||
| 123 | + == UT_REGISTERS_ADDRESS_SPECIAL) { | ||
| 124 | + modbus_reply_exception(ctx, query, | ||
| 125 | + MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY); | ||
| 126 | + continue; | ||
| 122 | } | 127 | } |
| 123 | } | 128 | } |
| 124 | 129 |
tests/unit-test.h
| @@ -38,6 +38,8 @@ const uint16_t UT_INPUT_BITS_NB_POINTS = 0x16; | @@ -38,6 +38,8 @@ const uint16_t UT_INPUT_BITS_NB_POINTS = 0x16; | ||
| 38 | const uint8_t UT_INPUT_BITS_TAB[] = { 0xAC, 0xDB, 0x35 }; | 38 | const uint8_t UT_INPUT_BITS_TAB[] = { 0xAC, 0xDB, 0x35 }; |
| 39 | 39 | ||
| 40 | const uint16_t UT_REGISTERS_ADDRESS = 0x6B; | 40 | const uint16_t UT_REGISTERS_ADDRESS = 0x6B; |
| 41 | +/* Raise a manual exception when this adress is used for the first byte */ | ||
| 42 | +const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0x6C; | ||
| 41 | const uint16_t UT_REGISTERS_NB_POINTS = 0x3; | 43 | const uint16_t UT_REGISTERS_NB_POINTS = 0x3; |
| 42 | const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0000, 0x0064 }; | 44 | const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0000, 0x0064 }; |
| 43 | /* If the following value is used, a bad response is sent. | 45 | /* If the following value is used, a bad response is sent. |