Browse Source

New function to reply to an indication with an exception message

Contributed by Dominic Storey.
- new function modbus_reply_exception
- unit test
Stéphane Raimbault 14 years ago
parent
commit
a4f7996eaf
5 changed files with 55 additions and 0 deletions
  1. 31 0
      src/modbus.c
  2. 2 0
      src/modbus.h
  3. 15 0
      tests/unit-test-client.c
  4. 5 0
      tests/unit-test-server.c
  5. 2 0
      tests/unit-test.h

+ 31 - 0
src/modbus.c

@@ -818,6 +818,37 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
     return send_msg(ctx, rsp, rsp_length);
 }
 
+int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
+                           unsigned int exception_code)
+{
+    int offset = ctx->backend->header_length;
+    int slave = req[offset - 1];
+    int function = req[offset];
+    uint8_t rsp[MAX_MESSAGE_LENGTH];
+    int rsp_length;
+    int dummy_length = 99;
+    sft_t sft;
+
+    if (ctx->backend->filter_request(ctx, slave) == 1) {
+        /* Filtered */
+        return 0;
+    }
+
+    sft.slave = slave;
+    sft.function = function + 0x80;;
+    sft.t_id = ctx->backend->prepare_response_tid(req, &dummy_length);
+    rsp_length = ctx->backend->build_response_basis(&sft, rsp);
+
+    /* Positive exception code */
+    if (exception_code < MODBUS_EXCEPTION_MAX) {
+        rsp[rsp_length++] = exception_code;
+        return send_msg(ctx, rsp, rsp_length);
+    } else {
+        errno = EINVAL;
+        return -1;
+    }
+}
+
 /* Reads IO status */
 static int read_io_status(modbus_t *ctx, int function,
                           int addr, int nb, uint8_t *data_dest)

+ 2 - 0
src/modbus.h

@@ -171,6 +171,8 @@ void modbus_mapping_free(modbus_mapping_t *mb_mapping);
 int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req);
 int modbus_reply(modbus_t *ctx, const uint8_t *req,
                  int req_length, modbus_mapping_t *mb_mapping);
+int modbus_reply_exception(modbus_t *ctx, const uint8_t *req,
+                           unsigned int exception_code);
 
 /**
  * UTILS FUNCTIONS

+ 15 - 0
tests/unit-test-client.c

@@ -618,8 +618,23 @@ int main(int argc, char *argv[])
         printf("FAILED\n");
         goto close;
     }
+
     free(tab_rp_registers_bad);
 
+    /** MANUAL EXCEPTION **/
+    printf("\nTEST MANUAL EXCEPTION:\n");
+
+    rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS_SPECIAL,
+                               UT_REGISTERS_NB_POINTS,
+                               tab_rp_registers);
+    printf("* modbus_read_registers at special address: ");
+    if (rc == -1 && errno == EMBXSBUSY) {
+        printf("OK\n");
+    } else {
+        printf("FAILED\n");
+        goto close;
+    }
+
     printf("\nALL TESTS PASS WITH SUCCESS.\n");
 
 close:

+ 5 - 0
tests/unit-test-server.c

@@ -119,6 +119,11 @@ int main(int argc, char*argv[])
                 printf("Set an incorrect number of values\n");
                 MODBUS_SET_INT16_TO_INT8(query, header_length + 3,
                                          UT_REGISTERS_NB_POINTS);
+            } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1)
+                == UT_REGISTERS_ADDRESS_SPECIAL) {
+                modbus_reply_exception(ctx, query,
+                                       MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY);
+                continue;
             }
         }
 

+ 2 - 0
tests/unit-test.h

@@ -38,6 +38,8 @@ const uint16_t UT_INPUT_BITS_NB_POINTS = 0x16;
 const uint8_t UT_INPUT_BITS_TAB[] = { 0xAC, 0xDB, 0x35 };
 
 const uint16_t UT_REGISTERS_ADDRESS = 0x6B;
+/* Raise a manual exception when this adress is used for the first byte */
+const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0x6C;
 const uint16_t UT_REGISTERS_NB_POINTS = 0x3;
 const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0000, 0x0064 };
 /* If the following value is used, a bad response is sent.