Commit 0e4e82e8cefefde1a233ad31529da0fd943b820f
1 parent
b00b27cb
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.
Showing
5 changed files
with
128 additions
and
0 deletions
doc/Makefile.am
doc/modbus_send_raw_request.txt
0 → 100644
| 1 | +modbus_send_raw_request(3) | |
| 2 | +========================== | |
| 3 | + | |
| 4 | + | |
| 5 | +NAME | |
| 6 | +---- | |
| 7 | +modbus_send_raw_request - send a raw request | |
| 8 | + | |
| 9 | + | |
| 10 | +SYNOPSIS | |
| 11 | +-------- | |
| 12 | +*int modbus_send_raw_request(*modbus_t 'ctx', uint8_t *'raw_req, int 'raw_req_length');* | |
| 13 | + | |
| 14 | + | |
| 15 | +DESCRIPTION | |
| 16 | +----------- | |
| 17 | +The _modbus_send_raw_request()_ function shall send a request via the socket of | |
| 18 | +the context 'ctx'. This function must be used for debugging purposes because you | |
| 19 | +have to take care to make a valid request by hand. The function only adds to the | |
| 20 | +message, the header or CRC of the selected backend, so 'raw_req' must start and | |
| 21 | +contain at least a slave/unit identifier and a function code. This function can | |
| 22 | +be used to send request not handled by the library. | |
| 23 | + | |
| 24 | + | |
| 25 | +RETURN VALUE | |
| 26 | +------------ | |
| 27 | +The _modbus_send_raw_request()_ function shall return the full message length, | |
| 28 | +counting the extra data relating to the backend, if successful. Otherwise it | |
| 29 | +shall return -1 and set errno. | |
| 30 | + | |
| 31 | + | |
| 32 | +EXAMPLE | |
| 33 | +------- | |
| 34 | +[source,c] | |
| 35 | +------------------- | |
| 36 | +modbus_t *ctx; | |
| 37 | +/* Read 5 holding registers from address 1 */ | |
| 38 | +uint8_t raw_req[] = { 0xFF, 0x03, 0x00, 0x01, 0x0, 0x05 }; | |
| 39 | +int req_length; | |
| 40 | +uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH]; | |
| 41 | + | |
| 42 | +ctx = modbus_new_tcp("127.0.0.1", 1502); | |
| 43 | +if (modbus_connect(ctx) == -1) { | |
| 44 | + fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); | |
| 45 | + modbus_free(ctx); | |
| 46 | + return -1; | |
| 47 | +} | |
| 48 | + | |
| 49 | +req_length = modbus_send_raw_request(ctx, raw_req, 6 * sizeof(uint8_t)); | |
| 50 | +modbus_receive(ctx, -1, rsp); | |
| 51 | + | |
| 52 | +modbus_close(ctx); | |
| 53 | +modbus_free(ctx); | |
| 54 | +------------------- | |
| 55 | + | |
| 56 | +SEE ALSO | |
| 57 | +-------- | |
| 58 | +linkmb:modbus_receive[3] | |
| 59 | + | |
| 60 | + | |
| 61 | +AUTHORS | |
| 62 | +------- | |
| 63 | +The libmodbus documentation was written by Stéphane Raimbault | |
| 64 | +<stephane.raimbault@gmail.com> | ... | ... |
src/modbus.c
| ... | ... | @@ -175,6 +175,34 @@ static int send_msg(modbus_t *ctx, uint8_t *msg, int msg_length) |
| 175 | 175 | return rc; |
| 176 | 176 | } |
| 177 | 177 | |
| 178 | +int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length) | |
| 179 | +{ | |
| 180 | + sft_t sft; | |
| 181 | + uint8_t req[MAX_MESSAGE_LENGTH]; | |
| 182 | + int req_length; | |
| 183 | + | |
| 184 | + if (raw_req_length < 2) { | |
| 185 | + /* The raw request must contain function and slave at least */ | |
| 186 | + errno = EINVAL; | |
| 187 | + return -1; | |
| 188 | + } | |
| 189 | + | |
| 190 | + sft.slave = raw_req[0]; | |
| 191 | + sft.function = raw_req[1]; | |
| 192 | + /* The t_id is left to zero */ | |
| 193 | + sft.t_id = 0; | |
| 194 | + /* This response function only set the header so it's convenient here */ | |
| 195 | + req_length = ctx->backend->build_response_basis(&sft, req); | |
| 196 | + | |
| 197 | + if (raw_req_length > 2) { | |
| 198 | + /* Copy data after function code */ | |
| 199 | + memcpy(req + req_length, raw_req + 2, raw_req_length - 2); | |
| 200 | + req_length += raw_req_length - 2; | |
| 201 | + } | |
| 202 | + | |
| 203 | + return send_msg(ctx, req, req_length); | |
| 204 | +} | |
| 205 | + | |
| 178 | 206 | /* |
| 179 | 207 | ---------- Request Indication ---------- |
| 180 | 208 | | Client | ---------------------->| Server | | ... | ... |
src/modbus.h
| ... | ... | @@ -173,6 +173,8 @@ modbus_mapping_t* modbus_mapping_new(int nb_coil_status, int nb_input_status, |
| 173 | 173 | int nb_holding_registers, int nb_input_registers); |
| 174 | 174 | void modbus_mapping_free(modbus_mapping_t *mb_mapping); |
| 175 | 175 | |
| 176 | +int modbus_send_raw_request(modbus_t *ctx, uint8_t *raw_req, int raw_req_length); | |
| 177 | + | |
| 176 | 178 | int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req); |
| 177 | 179 | int modbus_reply(modbus_t *ctx, const uint8_t *req, |
| 178 | 180 | int req_length, modbus_mapping_t *mb_mapping); | ... | ... |
tests/unit-test-client.c
| ... | ... | @@ -628,6 +628,39 @@ int main(int argc, char *argv[]) |
| 628 | 628 | goto close; |
| 629 | 629 | } |
| 630 | 630 | |
| 631 | + /** RAW REQUEST */ | |
| 632 | + printf("\nTEST RAW REQUEST:\n"); | |
| 633 | + { | |
| 634 | + const int RAW_REQ_LENGTH = 6; | |
| 635 | + uint8_t raw_req[] = { (use_backend == RTU) ? SERVER_ID : 0xFF, | |
| 636 | + 0x03, 0x00, 0x01, 0x0, 0x05 }; | |
| 637 | + int req_length; | |
| 638 | + uint8_t rsp[MODBUS_TCP_MAX_ADU_LENGTH]; | |
| 639 | + | |
| 640 | + req_length = modbus_send_raw_request(ctx, raw_req, | |
| 641 | + RAW_REQ_LENGTH * sizeof(uint8_t)); | |
| 642 | + | |
| 643 | + if ((use_backend == RTU && req_length == (RAW_REQ_LENGTH + 2)) || | |
| 644 | + ((use_backend == TCP || use_backend == TCP_PI) && | |
| 645 | + req_length == (RAW_REQ_LENGTH + 6))) { | |
| 646 | + printf("OK\n"); | |
| 647 | + } else { | |
| 648 | + printf("FAILED (%d)\n", req_length); | |
| 649 | + goto close; | |
| 650 | + } | |
| 651 | + | |
| 652 | + printf("* modbus_receive: "); | |
| 653 | + rc = modbus_receive(ctx, -1, rsp); | |
| 654 | + if ((use_backend == RTU && rc == 15) || | |
| 655 | + ((use_backend == TCP || use_backend == TCP_PI) && | |
| 656 | + rc == 19)) { | |
| 657 | + printf("OK\n"); | |
| 658 | + } else { | |
| 659 | + printf("FAILED (%d)\n", rc); | |
| 660 | + goto close; | |
| 661 | + } | |
| 662 | + } | |
| 663 | + | |
| 631 | 664 | printf("\nALL TESTS PASS WITH SUCCESS.\n"); |
| 632 | 665 | |
| 633 | 666 | close: | ... | ... |