Commit 0a6ea1ac033d9ae72547df6d9b78283bdb876dbf
1 parent
f20a1860
Remove one argument to receive_msg and modbus_slave_receive
- the return value is used to pass the message length - remove the hack on exception check in modbus receive - update tests
Showing
6 changed files
with
100 additions
and
105 deletions
src/modbus.c
| 1 | 1 | /* |
| 2 | - * Copyright © 2001-2008 Stéphane Raimbault <stephane.raimbault@gmail.com> | |
| 2 | + * Copyright © 2001-2010 Stéphane Raimbault <stephane.raimbault@gmail.com> | |
| 3 | 3 | * |
| 4 | 4 | * This program is free software: you can redistribute it and/or modify |
| 5 | 5 | * it under the terms of the GNU Lesser Public License as published by |
| ... | ... | @@ -252,6 +252,8 @@ static unsigned int compute_response_length(modbus_param_t *mb_param, |
| 252 | 252 | length = 3; |
| 253 | 253 | break; |
| 254 | 254 | case FC_REPORT_SLAVE_ID: |
| 255 | + /* The response is device specific (the header provides the | |
| 256 | + length) */ | |
| 255 | 257 | return MSG_LENGTH_UNDEFINED; |
| 256 | 258 | default: |
| 257 | 259 | length = 5; |
| ... | ... | @@ -393,7 +395,7 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) |
| 393 | 395 | return (crc_hi << 8 | crc_lo); |
| 394 | 396 | } |
| 395 | 397 | |
| 396 | -/* If CRC is correct returns 0 else returns INVALID_CRC */ | |
| 398 | +/* If CRC is correct returns msg_length else returns INVALID_CRC */ | |
| 397 | 399 | static int check_crc16(modbus_param_t *mb_param, |
| 398 | 400 | uint8_t *msg, |
| 399 | 401 | const int msg_length) |
| ... | ... | @@ -407,7 +409,7 @@ static int check_crc16(modbus_param_t *mb_param, |
| 407 | 409 | |
| 408 | 410 | /* Check CRC of msg */ |
| 409 | 411 | if (crc_calc == crc_received) { |
| 410 | - ret = 0; | |
| 412 | + ret = msg_length; | |
| 411 | 413 | } else { |
| 412 | 414 | char s_error[64]; |
| 413 | 415 | sprintf(s_error, |
| ... | ... | @@ -512,28 +514,35 @@ static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg) |
| 512 | 514 | } \ |
| 513 | 515 | \ |
| 514 | 516 | if (select_ret == 0) { \ |
| 515 | - /* Call to error_treat is done later to manage exceptions */ \ | |
| 516 | - return SELECT_TIMEOUT; \ | |
| 517 | + /* Timeout */ \ | |
| 518 | + if (msg_length == (TAB_HEADER_LENGTH[mb_param->type_com] + 2 + \ | |
| 519 | + TAB_CHECKSUM_LENGTH[mb_param->type_com])) { \ | |
| 520 | + /* Optimization allowed because exception response is \ | |
| 521 | + the smallest trame in modbus protocol (3) so always \ | |
| 522 | + raise a timeout error */ \ | |
| 523 | + return MB_EXCEPTION; \ | |
| 524 | + } else { \ | |
| 525 | + /* Call to error_treat is done later to manage exceptions */ \ | |
| 526 | + return SELECT_TIMEOUT; \ | |
| 527 | + } \ | |
| 517 | 528 | } \ |
| 518 | 529 | } |
| 519 | 530 | |
| 520 | 531 | /* Waits a reply from a modbus slave or a query from a modbus master. |
| 521 | - This function blocks for timeout seconds if there is no reply. | |
| 532 | + This function blocks if there is no replies (3 timeouts). | |
| 522 | 533 | |
| 523 | 534 | In |
| 524 | 535 | - msg_length_computed must be set to MSG_LENGTH_UNDEFINED if undefined |
| 525 | 536 | |
| 526 | 537 | Out |
| 527 | 538 | - msg is an array of uint8_t to receive the message |
| 528 | - - p_msg_length, the variable is assigned to the number of | |
| 529 | - characters received. This value won't be greater than | |
| 530 | - msg_length_computed. | |
| 531 | 539 | |
| 532 | - Returns 0 in success or a negative value if an error occured. | |
| 540 | + On success, return the number of received characters. On error, return | |
| 541 | + a negative value. | |
| 533 | 542 | */ |
| 534 | 543 | static int receive_msg(modbus_param_t *mb_param, |
| 535 | 544 | int msg_length_computed, |
| 536 | - uint8_t *msg, int *p_msg_length) | |
| 545 | + uint8_t *msg) | |
| 537 | 546 | { |
| 538 | 547 | int select_ret; |
| 539 | 548 | int read_ret; |
| ... | ... | @@ -544,9 +553,7 @@ static int receive_msg(modbus_param_t *mb_param, |
| 544 | 553 | enum { FUNCTION, BYTE, COMPLETE }; |
| 545 | 554 | int state; |
| 546 | 555 | |
| 547 | - /* Initialize the return length before a call to WAIT_DATA because a | |
| 548 | - * time out can quit the function. */ | |
| 549 | - (*p_msg_length) = 0; | |
| 556 | + int msg_length = 0; | |
| 550 | 557 | |
| 551 | 558 | if (mb_param->debug) { |
| 552 | 559 | if (msg_length_computed == MSG_LENGTH_UNDEFINED) |
| ... | ... | @@ -599,7 +606,7 @@ static int receive_msg(modbus_param_t *mb_param, |
| 599 | 606 | } |
| 600 | 607 | |
| 601 | 608 | /* Sums bytes received */ |
| 602 | - (*p_msg_length) += read_ret; | |
| 609 | + msg_length += read_ret; | |
| 603 | 610 | |
| 604 | 611 | /* Display the hex code of each character received */ |
| 605 | 612 | if (mb_param->debug) { |
| ... | ... | @@ -608,9 +615,9 @@ static int receive_msg(modbus_param_t *mb_param, |
| 608 | 615 | printf("<%.2X>", p_msg[i]); |
| 609 | 616 | } |
| 610 | 617 | |
| 611 | - if ((*p_msg_length) < msg_length_computed) { | |
| 618 | + if (msg_length < msg_length_computed) { | |
| 612 | 619 | /* Message incomplete */ |
| 613 | - length_to_read = msg_length_computed - (*p_msg_length); | |
| 620 | + length_to_read = msg_length_computed - msg_length; | |
| 614 | 621 | } else { |
| 615 | 622 | switch (state) { |
| 616 | 623 | case FUNCTION: |
| ... | ... | @@ -618,9 +625,9 @@ static int receive_msg(modbus_param_t *mb_param, |
| 618 | 625 | length_to_read = compute_query_length_header( |
| 619 | 626 | msg[TAB_HEADER_LENGTH[mb_param->type_com]]); |
| 620 | 627 | msg_length_computed += length_to_read; |
| 621 | - /* It's useless to check | |
| 622 | - p_msg_length_computed value in this | |
| 623 | - case (only defined values are used). */ | |
| 628 | + /* It's useless to check the value of | |
| 629 | + msg_length_computed in this case (only | |
| 630 | + defined values are used). */ | |
| 624 | 631 | state = BYTE; |
| 625 | 632 | break; |
| 626 | 633 | case BYTE: |
| ... | ... | @@ -658,10 +665,12 @@ static int receive_msg(modbus_param_t *mb_param, |
| 658 | 665 | printf("\n"); |
| 659 | 666 | |
| 660 | 667 | if (mb_param->type_com == RTU) { |
| 661 | - return check_crc16(mb_param, msg, (*p_msg_length)); | |
| 668 | + /* Returns msg_length on success and a negative value on | |
| 669 | + failure */ | |
| 670 | + return check_crc16(mb_param, msg, msg_length); | |
| 662 | 671 | } else { |
| 663 | 672 | /* OK */ |
| 664 | - return 0; | |
| 673 | + return msg_length; | |
| 665 | 674 | } |
| 666 | 675 | } |
| 667 | 676 | |
| ... | ... | @@ -670,28 +679,24 @@ static int receive_msg(modbus_param_t *mb_param, |
| 670 | 679 | internal one of modbus_param_t. |
| 671 | 680 | |
| 672 | 681 | Returns: |
| 673 | - - 0 on success, or a negative error number if the request fails | |
| 682 | + - byte length of the message on success, or a negative error number if the | |
| 683 | + request fails | |
| 674 | 684 | - query, message received |
| 675 | - - query_length, length in bytes of the message */ | |
| 676 | -int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, | |
| 677 | - uint8_t *query, int *query_length) | |
| 685 | +*/ | |
| 686 | +int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query) | |
| 678 | 687 | { |
| 679 | - int ret; | |
| 680 | - | |
| 681 | 688 | if (sockfd != -1) { |
| 682 | 689 | mb_param->fd = sockfd; |
| 683 | 690 | } |
| 684 | 691 | |
| 685 | 692 | /* The length of the query to receive isn't known. */ |
| 686 | - ret = receive_msg(mb_param, MSG_LENGTH_UNDEFINED, query, query_length); | |
| 687 | - | |
| 688 | - return ret; | |
| 693 | + return receive_msg(mb_param, MSG_LENGTH_UNDEFINED, query); | |
| 689 | 694 | } |
| 690 | 695 | |
| 691 | 696 | /* Receives the response and checks values (and checksum in RTU). |
| 692 | 697 | |
| 693 | 698 | Returns: |
| 694 | - - the number of values (bits or word) if success or the response | |
| 699 | + - the number of values (bits or words) if success or the response | |
| 695 | 700 | length if no value is returned |
| 696 | 701 | - less than 0 for exception errors |
| 697 | 702 | |
| ... | ... | @@ -702,14 +707,12 @@ static int modbus_receive(modbus_param_t *mb_param, |
| 702 | 707 | uint8_t *response) |
| 703 | 708 | { |
| 704 | 709 | int ret; |
| 705 | - int response_length; | |
| 706 | 710 | int response_length_computed; |
| 707 | 711 | int offset = TAB_HEADER_LENGTH[mb_param->type_com]; |
| 708 | 712 | |
| 709 | 713 | response_length_computed = compute_response_length(mb_param, query); |
| 710 | - ret = receive_msg(mb_param, response_length_computed, | |
| 711 | - response, &response_length); | |
| 712 | - if (ret == 0) { | |
| 714 | + ret = receive_msg(mb_param, response_length_computed, response); | |
| 715 | + if (ret >= 0) { | |
| 713 | 716 | /* GOOD RESPONSE */ |
| 714 | 717 | int query_nb_value; |
| 715 | 718 | int response_nb_value; |
| ... | ... | @@ -740,7 +743,7 @@ static int modbus_receive(modbus_param_t *mb_param, |
| 740 | 743 | break; |
| 741 | 744 | case FC_REPORT_SLAVE_ID: |
| 742 | 745 | /* Report slave ID (bytes received) */ |
| 743 | - query_nb_value = response_nb_value = response_length; | |
| 746 | + query_nb_value = response_nb_value = ret; | |
| 744 | 747 | break; |
| 745 | 748 | default: |
| 746 | 749 | /* 1 Write functions & others */ |
| ... | ... | @@ -757,55 +760,46 @@ static int modbus_receive(modbus_param_t *mb_param, |
| 757 | 760 | error_treat(mb_param, ret, s_error); |
| 758 | 761 | free(s_error); |
| 759 | 762 | } |
| 760 | - } else if (ret == SELECT_TIMEOUT) { | |
| 761 | - | |
| 762 | - if (response_length == (offset + 2 + TAB_CHECKSUM_LENGTH[mb_param->type_com])) { | |
| 763 | - /* EXCEPTION CODE RECEIVED */ | |
| 764 | - | |
| 765 | - /* Optimization allowed because exception response is | |
| 766 | - the smallest trame in modbus protocol (3) so always | |
| 767 | - raise a timeout error */ | |
| 768 | - | |
| 769 | - /* CRC must be checked here (not done in receive_msg) */ | |
| 770 | - if (mb_param->type_com == RTU) { | |
| 771 | - ret = check_crc16(mb_param, response, response_length); | |
| 772 | - if (ret != 0) | |
| 773 | - return ret; | |
| 774 | - } | |
| 763 | + } else if (ret == MB_EXCEPTION) { | |
| 764 | + /* EXCEPTION CODE RECEIVED */ | |
| 765 | + | |
| 766 | + /* CRC must be checked here (not done in receive_msg) */ | |
| 767 | + if (mb_param->type_com == RTU) { | |
| 768 | + ret = check_crc16(mb_param, response, EXCEPTION_RESPONSE_LENGTH_RTU); | |
| 769 | + if (ret < 0) | |
| 770 | + return ret; | |
| 771 | + } | |
| 775 | 772 | |
| 776 | - /* Check for exception response. | |
| 777 | - 0x80 + function is stored in the exception | |
| 778 | - response. */ | |
| 779 | - if (0x80 + query[offset] == response[offset]) { | |
| 780 | - | |
| 781 | - int exception_code = response[offset + 1]; | |
| 782 | - // FIXME check test | |
| 783 | - if (exception_code < NB_TAB_ERROR_MSG) { | |
| 784 | - error_treat(mb_param, -exception_code, | |
| 785 | - TAB_ERROR_MSG[response[offset + 1]]); | |
| 786 | - /* RETURN THE EXCEPTION CODE */ | |
| 787 | - /* Modbus error code is negative */ | |
| 788 | - return -exception_code; | |
| 789 | - } else { | |
| 790 | - /* The chances are low to hit this | |
| 791 | - case but it can avoid a vicious | |
| 792 | - segfault */ | |
| 793 | - char *s_error = malloc(64 * sizeof(char)); | |
| 794 | - sprintf(s_error, | |
| 795 | - "Invalid exception code %d", | |
| 796 | - response[offset + 1]); | |
| 797 | - error_treat(mb_param, INVALID_EXCEPTION_CODE, | |
| 798 | - s_error); | |
| 799 | - free(s_error); | |
| 800 | - return INVALID_EXCEPTION_CODE; | |
| 801 | - } | |
| 773 | + /* Check for exception response. | |
| 774 | + 0x80 + function is stored in the exception | |
| 775 | + response. */ | |
| 776 | + if (0x80 + query[offset] == response[offset]) { | |
| 777 | + | |
| 778 | + int exception_code = response[offset + 1]; | |
| 779 | + // FIXME check test | |
| 780 | + if (exception_code < NB_TAB_ERROR_MSG) { | |
| 781 | + error_treat(mb_param, -exception_code, | |
| 782 | + TAB_ERROR_MSG[response[offset + 1]]); | |
| 783 | + /* RETURN THE EXCEPTION CODE */ | |
| 784 | + /* Modbus error code is negative */ | |
| 785 | + return -exception_code; | |
| 786 | + } else { | |
| 787 | + /* The chances are low to hit this | |
| 788 | + case but it can avoid a vicious | |
| 789 | + segfault */ | |
| 790 | + char *s_error = malloc(64 * sizeof(char)); | |
| 791 | + sprintf(s_error, | |
| 792 | + "Invalid exception code %d", | |
| 793 | + response[offset + 1]); | |
| 794 | + error_treat(mb_param, INVALID_EXCEPTION_CODE, | |
| 795 | + s_error); | |
| 796 | + free(s_error); | |
| 797 | + return INVALID_EXCEPTION_CODE; | |
| 802 | 798 | } |
| 803 | - /* If doesn't return previously, return as | |
| 804 | - TIME OUT here */ | |
| 805 | 799 | } |
| 806 | - | |
| 807 | - error_treat(mb_param, ret, "Select timeout"); | |
| 808 | - return ret; | |
| 800 | + } else { | |
| 801 | + /* Other errors */ | |
| 802 | + error_treat(mb_param, ret, "receive_msg"); | |
| 809 | 803 | } |
| 810 | 804 | |
| 811 | 805 | return ret; | ... | ... |
src/modbus.h
| 1 | 1 | /* |
| 2 | - * Copyright © 2001-2009 Stéphane Raimbault <stephane.raimbault@gmail.com> | |
| 2 | + * Copyright © 2001-2010 Stéphane Raimbault <stephane.raimbault@gmail.com> | |
| 3 | 3 | * |
| 4 | 4 | * This program is free software: you can redistribute it and/or modify |
| 5 | 5 | * it under the terms of the GNU Lesser Public License as published by |
| ... | ... | @@ -72,6 +72,8 @@ extern "C" { |
| 72 | 72 | /* Kept for compatibility reasons (deprecated) */ |
| 73 | 73 | #define MAX_MESSAGE_LENGTH 260 |
| 74 | 74 | |
| 75 | +#define EXCEPTION_RESPONSE_LENGTH_RTU 5 | |
| 76 | + | |
| 75 | 77 | /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12) |
| 76 | 78 | * Quantity of Coils (2 bytes): 1 to 2000 (0x7D0) |
| 77 | 79 | */ |
| ... | ... | @@ -139,6 +141,7 @@ extern "C" { |
| 139 | 141 | #define SELECT_FAILURE -0x14 |
| 140 | 142 | #define SOCKET_FAILURE -0x15 |
| 141 | 143 | #define CONNECTION_CLOSED -0x16 |
| 144 | +#define MB_EXCEPTION -0x17 | |
| 142 | 145 | |
| 143 | 146 | /* Internal using */ |
| 144 | 147 | #define MSG_LENGTH_UNDEFINED -1 |
| ... | ... | @@ -318,15 +321,15 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection); |
| 318 | 321 | int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket); |
| 319 | 322 | |
| 320 | 323 | /* Listens for any query from a modbus master in TCP, requires the socket file |
| 321 | - descriptor etablished with the master device in argument. | |
| 324 | + descriptor etablished with the master device in argument or -1 to use the | |
| 325 | + internal one of modbus_param_t. | |
| 322 | 326 | |
| 323 | 327 | Returns: |
| 324 | - - 0 on success, or a negative error number if the request fails | |
| 328 | + - byte length of the message on success, or a negative error number if the | |
| 329 | + request fails | |
| 325 | 330 | - query, message received |
| 326 | - - query_length, length in bytes of the message | |
| 327 | 331 | */ |
| 328 | -int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, | |
| 329 | - uint8_t *query, int *query_length); | |
| 332 | +int modbus_slave_receive(modbus_param_t *mb_param, int sockfd, uint8_t *query); | |
| 330 | 333 | |
| 331 | 334 | /* Manages the received query. |
| 332 | 335 | Analyses the query and constructs a response. | ... | ... |
tests/bandwidth-slave-many-up.c
| ... | ... | @@ -106,11 +106,10 @@ int main(void) |
| 106 | 106 | } else { |
| 107 | 107 | /* An already connected master has sent a new query */ |
| 108 | 108 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 109 | - int query_size; | |
| 110 | 109 | |
| 111 | - ret = modbus_slave_receive(&mb_param, master_socket, query, &query_size); | |
| 112 | - if (ret == 0) { | |
| 113 | - modbus_slave_manage(&mb_param, query, query_size, &mb_mapping); | |
| 110 | + ret = modbus_slave_receive(&mb_param, master_socket, query); | |
| 111 | + if (ret >= 0) { | |
| 112 | + modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 114 | 113 | } else { |
| 115 | 114 | /* Connection closed by the client, end of server */ |
| 116 | 115 | printf("Connection closed on socket %d\n", master_socket); | ... | ... |
tests/bandwidth-slave-one.c
| ... | ... | @@ -44,11 +44,10 @@ int main(void) |
| 44 | 44 | |
| 45 | 45 | while (1) { |
| 46 | 46 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 47 | - int query_size; | |
| 48 | 47 | |
| 49 | - ret = modbus_slave_receive(&mb_param, -1, query, &query_size); | |
| 50 | - if (ret == 0) { | |
| 51 | - modbus_slave_manage(&mb_param, query, query_size, &mb_mapping); | |
| 48 | + ret = modbus_slave_receive(&mb_param, -1, query); | |
| 49 | + if (ret >= 0) { | |
| 50 | + modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 52 | 51 | } else if (ret == CONNECTION_CLOSED) { |
| 53 | 52 | /* Connection closed by the client, end of server */ |
| 54 | 53 | break; | ... | ... |
tests/random-test-slave.c
| ... | ... | @@ -44,11 +44,12 @@ int main(void) |
| 44 | 44 | |
| 45 | 45 | while (1) { |
| 46 | 46 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 47 | - int query_size; | |
| 47 | + int ret; | |
| 48 | 48 | |
| 49 | - ret = modbus_slave_receive(&mb_param, -1, query, &query_size); | |
| 50 | - if (ret == 0) { | |
| 51 | - modbus_slave_manage(&mb_param, query, query_size, &mb_mapping); | |
| 49 | + ret = modbus_slave_receive(&mb_param, -1, query); | |
| 50 | + if (ret >= 0) { | |
| 51 | + /* ret is the query size */ | |
| 52 | + modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 52 | 53 | } else if (ret == CONNECTION_CLOSED) { |
| 53 | 54 | /* Connection closed by the client, end of server */ |
| 54 | 55 | break; | ... | ... |
tests/unit-test-slave.c
| ... | ... | @@ -63,10 +63,9 @@ int main(void) |
| 63 | 63 | |
| 64 | 64 | while (1) { |
| 65 | 65 | uint8_t query[MAX_MESSAGE_LENGTH]; |
| 66 | - int query_size; | |
| 67 | 66 | |
| 68 | - ret = modbus_slave_receive(&mb_param, -1, query, &query_size); | |
| 69 | - if (ret == 0) { | |
| 67 | + ret = modbus_slave_receive(&mb_param, -1, query); | |
| 68 | + if (ret >= 0) { | |
| 70 | 69 | if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4]) |
| 71 | 70 | == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) { |
| 72 | 71 | /* Change the number of values (offset |
| ... | ... | @@ -75,7 +74,7 @@ int main(void) |
| 75 | 74 | query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS; |
| 76 | 75 | } |
| 77 | 76 | |
| 78 | - modbus_slave_manage(&mb_param, query, query_size, &mb_mapping); | |
| 77 | + modbus_slave_manage(&mb_param, query, ret, &mb_mapping); | |
| 79 | 78 | } else if (ret == CONNECTION_CLOSED) { |
| 80 | 79 | /* Connection closed by the client, end of server */ |
| 81 | 80 | break; | ... | ... |