Commit a4f7996eafbf701371db7c9fa826987fed119188

Authored by Stéphane Raimbault
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
src/modbus.c
... ... @@ -818,6 +818,37 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
818 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 852 /* Reads IO status */
822 853 static int read_io_status(modbus_t *ctx, int function,
823 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 171 int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req);
172 172 int modbus_reply(modbus_t *ctx, const uint8_t *req,
173 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 178 * UTILS FUNCTIONS
... ...
tests/unit-test-client.c
... ... @@ -618,8 +618,23 @@ int main(int argc, char *argv[])
618 618 printf("FAILED\n");
619 619 goto close;
620 620 }
  621 +
621 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 638 printf("\nALL TESTS PASS WITH SUCCESS.\n");
624 639  
625 640 close:
... ...
tests/unit-test-server.c
... ... @@ -119,6 +119,11 @@ int main(int argc, char*argv[])
119 119 printf("Set an incorrect number of values\n");
120 120 MODBUS_SET_INT16_TO_INT8(query, header_length + 3,
121 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 38 const uint8_t UT_INPUT_BITS_TAB[] = { 0xAC, 0xDB, 0x35 };
39 39  
40 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 43 const uint16_t UT_REGISTERS_NB_POINTS = 0x3;
42 44 const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0000, 0x0064 };
43 45 /* If the following value is used, a bad response is sent.
... ...