Эх сурвалжийг харах

New function modbus_send_raw_request

The _modbus_send_raw_request()_ function shall send a request via
the socket of the context 'ctx'. This function must be used for
debugging purposes because you have to take care to make a valid
request by hand. The function only adds to the message, the header
or CRC of the selected backend, so 'raw_req' must start and contain
at least a slave/unit identifier and a function code. This function
can be used to send request not handled by the library.
Stéphane Raimbault 14 жил өмнө
parent
commit
0e4e82e8ce

+ 1 - 0
doc/Makefile.am

@@ -13,6 +13,7 @@ MAN3 = \
         modbus_read_input_bits.3 \
         modbus_read_input_registers.3 \
         modbus_read_registers.3 \
+        modbus_send_raw_request.3 \
         modbus_set_debug.3 \
         modbus_set_error_recovery.3 \
         modbus_set_slave.3 \

+ 64 - 0
doc/modbus_send_raw_request.txt

@@ -0,0 +1,64 @@
+modbus_send_raw_request(3)
+==========================
+
+
+NAME
+----
+modbus_send_raw_request - send a raw request
+
+
+SYNOPSIS
+--------
+*int modbus_send_raw_request(*modbus_t 'ctx', uint8_t *'raw_req, int 'raw_req_length');*
+
+
+DESCRIPTION
+-----------
+The _modbus_send_raw_request()_ function shall send a request via the socket of
+the context 'ctx'. This function must be used for debugging purposes because you
+have to take care to make a valid request by hand. The function only adds to the
+message, the header or CRC of the selected backend, so 'raw_req' must start and
+contain at least a slave/unit identifier and a function code. This function can
+be used to send request not handled by the library.
+
+
+RETURN VALUE
+------------
+The _modbus_send_raw_request()_ function shall return the full message length,
+counting the extra data relating to the backend, if successful. Otherwise it
+shall return -1 and set errno.
+
+
+EXAMPLE
+-------
+[source,c]
+-------------------
+modbus_t *ctx;
+/* Read 5 holding registers from address 1 */
+uint8_t raw_req[] = { 0xFF, 0x03, 0x00, 0x01, 0x0, 0x05 };
+int req_length;
+uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];
+
+ctx = modbus_new_tcp("127.0.0.1", 1502);
+if (modbus_connect(ctx) == -1) {
+    fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno));
+    modbus_free(ctx);
+    return -1;
+}
+
+req_length = modbus_send_raw_request(ctx, raw_req, 6 * sizeof(uint8_t));
+modbus_receive(ctx, -1, rsp);
+
+modbus_close(ctx);
+modbus_free(ctx);
+-------------------
+
+SEE ALSO
+--------
+linkmb:modbus_receive[3]
+
+
+AUTHORS
+-------
+The libmodbus documentation was written by Stéphane Raimbault
+<stephane.raimbault@gmail.com>

+ 28 - 0
src/modbus.c

@@ -175,6 +175,34 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length)
     return rc;
 }
 
+int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length)
+{
+    sft_t sft;
+    uint8_t req[MAX_MESSAGE_LENGTH];
+    int req_length;
+
+    if (raw_req_length < 2) {
+        /* The raw request must contain function and slave at least */
+        errno = EINVAL;
+        return -1;
+    }
+
+    sft.slave = raw_req[0];
+    sft.function = raw_req[1];
+    /* The t_id is left to zero */
+    sft.t_id = 0;
+    /* This response function only set the header so it's convenient here */
+    req_length = ctx->backend->build_response_basis(&sft, req);
+
+    if (raw_req_length > 2) {
+        /* Copy data after function code */
+        memcpy(req + req_length, raw_req + 2, raw_req_length - 2);
+        req_length += raw_req_length - 2;
+    }
+
+    return send_msg(ctx, req, req_length);
+}
+
 /*
     ---------- Request     Indication ----------
     | Client | ---------------------->| Server |

+ 2 - 0
src/modbus.h

@@ -173,6 +173,8 @@ modbus_mapping_t* modbus_mapping_new(int nb_coil_status, int nb_input_status,
                                      int nb_holding_registers, int nb_input_registers);
 void modbus_mapping_free(modbus_mapping_t *mb_mapping);
 
+int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length);
+
 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);

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

@@ -628,6 +628,39 @@ int main(int argc, char *argv[])
         goto close;
     }
 
+    /** RAW REQUEST */
+    printf("\nTEST RAW REQUEST:\n");
+    {
+        const int RAW_REQ_LENGTH = 6;
+        uint8_t raw_req[] = { (use_backend == RTU) ? SERVER_ID : 0xFF,
+                              0x03, 0x00, 0x01, 0x0, 0x05 };
+        int req_length;
+        uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH];
+
+        req_length = modbus_send_raw_request(ctx, raw_req,
+                                             RAW_REQ_LENGTH * sizeof(uint8_t));
+
+        if ((use_backend == RTU && req_length == (RAW_REQ_LENGTH + 2)) ||
+            ((use_backend == TCP || use_backend == TCP_PI) &&
+             req_length == (RAW_REQ_LENGTH + 6))) {
+            printf("OK\n");
+        } else {
+            printf("FAILED (%d)\n", req_length);
+            goto close;
+        }
+
+        printf("* modbus_receive: ");
+        rc  = modbus_receive(ctx, -1, rsp);
+        if ((use_backend == RTU && rc == 15) ||
+            ((use_backend == TCP || use_backend == TCP_PI) &&
+             rc == 19)) {
+            printf("OK\n");
+        } else {
+            printf("FAILED (%d)\n", rc);
+            goto close;
+        }
+    }
+
     printf("\nALL TESTS PASS WITH SUCCESS.\n");
 
 close: