diff --git a/doc/Makefile.am b/doc/Makefile.am index 12d3319..460eaf2 100644 --- a/doc/Makefile.am +++ b/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 \ diff --git a/doc/modbus_send_raw_request.txt b/doc/modbus_send_raw_request.txt new file mode 100644 index 0000000..82ffe78 --- /dev/null +++ b/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 + diff --git a/src/modbus.c b/src/modbus.c index fdea066..66ada51 100644 --- a/src/modbus.c +++ b/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 | diff --git a/src/modbus.h b/src/modbus.h index 794998f..6d51762 100644 --- a/src/modbus.h +++ b/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); diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c index 0458b41..093aa97 100644 --- a/tests/unit-test-client.c +++ b/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: