Commit 0a6ea1ac033d9ae72547df6d9b78283bdb876dbf

Authored by Stéphane Raimbault
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
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 * This program is free software: you can redistribute it and/or modify 4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser Public License as published by 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,6 +252,8 @@ static unsigned int compute_response_length(modbus_param_t *mb_param,
252 length = 3; 252 length = 3;
253 break; 253 break;
254 case FC_REPORT_SLAVE_ID: 254 case FC_REPORT_SLAVE_ID:
  255 + /* The response is device specific (the header provides the
  256 + length) */
255 return MSG_LENGTH_UNDEFINED; 257 return MSG_LENGTH_UNDEFINED;
256 default: 258 default:
257 length = 5; 259 length = 5;
@@ -393,7 +395,7 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) @@ -393,7 +395,7 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
393 return (crc_hi << 8 | crc_lo); 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 static int check_crc16(modbus_param_t *mb_param, 399 static int check_crc16(modbus_param_t *mb_param,
398 uint8_t *msg, 400 uint8_t *msg,
399 const int msg_length) 401 const int msg_length)
@@ -407,7 +409,7 @@ static int check_crc16(modbus_param_t *mb_param, @@ -407,7 +409,7 @@ static int check_crc16(modbus_param_t *mb_param,
407 409
408 /* Check CRC of msg */ 410 /* Check CRC of msg */
409 if (crc_calc == crc_received) { 411 if (crc_calc == crc_received) {
410 - ret = 0; 412 + ret = msg_length;
411 } else { 413 } else {
412 char s_error[64]; 414 char s_error[64];
413 sprintf(s_error, 415 sprintf(s_error,
@@ -512,28 +514,35 @@ static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg) @@ -512,28 +514,35 @@ static int compute_query_length_data(modbus_param_t *mb_param, uint8_t *msg)
512 } \ 514 } \
513 \ 515 \
514 if (select_ret == 0) { \ 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 /* Waits a reply from a modbus slave or a query from a modbus master. 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 In 534 In
524 - msg_length_computed must be set to MSG_LENGTH_UNDEFINED if undefined 535 - msg_length_computed must be set to MSG_LENGTH_UNDEFINED if undefined
525 536
526 Out 537 Out
527 - msg is an array of uint8_t to receive the message 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 static int receive_msg(modbus_param_t *mb_param, 543 static int receive_msg(modbus_param_t *mb_param,
535 int msg_length_computed, 544 int msg_length_computed,
536 - uint8_t *msg, int *p_msg_length) 545 + uint8_t *msg)
537 { 546 {
538 int select_ret; 547 int select_ret;
539 int read_ret; 548 int read_ret;
@@ -544,9 +553,7 @@ static int receive_msg(modbus_param_t *mb_param, @@ -544,9 +553,7 @@ static int receive_msg(modbus_param_t *mb_param,
544 enum { FUNCTION, BYTE, COMPLETE }; 553 enum { FUNCTION, BYTE, COMPLETE };
545 int state; 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 if (mb_param->debug) { 558 if (mb_param->debug) {
552 if (msg_length_computed == MSG_LENGTH_UNDEFINED) 559 if (msg_length_computed == MSG_LENGTH_UNDEFINED)
@@ -599,7 +606,7 @@ static int receive_msg(modbus_param_t *mb_param, @@ -599,7 +606,7 @@ static int receive_msg(modbus_param_t *mb_param,
599 } 606 }
600 607
601 /* Sums bytes received */ 608 /* Sums bytes received */
602 - (*p_msg_length) += read_ret; 609 + msg_length += read_ret;
603 610
604 /* Display the hex code of each character received */ 611 /* Display the hex code of each character received */
605 if (mb_param->debug) { 612 if (mb_param->debug) {
@@ -608,9 +615,9 @@ static int receive_msg(modbus_param_t *mb_param, @@ -608,9 +615,9 @@ static int receive_msg(modbus_param_t *mb_param,
608 printf("<%.2X>", p_msg[i]); 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 /* Message incomplete */ 619 /* Message incomplete */
613 - length_to_read = msg_length_computed - (*p_msg_length); 620 + length_to_read = msg_length_computed - msg_length;
614 } else { 621 } else {
615 switch (state) { 622 switch (state) {
616 case FUNCTION: 623 case FUNCTION:
@@ -618,9 +625,9 @@ static int receive_msg(modbus_param_t *mb_param, @@ -618,9 +625,9 @@ static int receive_msg(modbus_param_t *mb_param,
618 length_to_read = compute_query_length_header( 625 length_to_read = compute_query_length_header(
619 msg[TAB_HEADER_LENGTH[mb_param->type_com]]); 626 msg[TAB_HEADER_LENGTH[mb_param->type_com]]);
620 msg_length_computed += length_to_read; 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 state = BYTE; 631 state = BYTE;
625 break; 632 break;
626 case BYTE: 633 case BYTE:
@@ -658,10 +665,12 @@ static int receive_msg(modbus_param_t *mb_param, @@ -658,10 +665,12 @@ static int receive_msg(modbus_param_t *mb_param,
658 printf("\n"); 665 printf("\n");
659 666
660 if (mb_param->type_com == RTU) { 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 } else { 671 } else {
663 /* OK */ 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,28 +679,24 @@ static int receive_msg(modbus_param_t *mb_param,
670 internal one of modbus_param_t. 679 internal one of modbus_param_t.
671 680
672 Returns: 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 - query, message received 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 if (sockfd != -1) { 688 if (sockfd != -1) {
682 mb_param->fd = sockfd; 689 mb_param->fd = sockfd;
683 } 690 }
684 691
685 /* The length of the query to receive isn't known. */ 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 /* Receives the response and checks values (and checksum in RTU). 696 /* Receives the response and checks values (and checksum in RTU).
692 697
693 Returns: 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 length if no value is returned 700 length if no value is returned
696 - less than 0 for exception errors 701 - less than 0 for exception errors
697 702
@@ -702,14 +707,12 @@ static int modbus_receive(modbus_param_t *mb_param, @@ -702,14 +707,12 @@ static int modbus_receive(modbus_param_t *mb_param,
702 uint8_t *response) 707 uint8_t *response)
703 { 708 {
704 int ret; 709 int ret;
705 - int response_length;  
706 int response_length_computed; 710 int response_length_computed;
707 int offset = TAB_HEADER_LENGTH[mb_param->type_com]; 711 int offset = TAB_HEADER_LENGTH[mb_param->type_com];
708 712
709 response_length_computed = compute_response_length(mb_param, query); 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 /* GOOD RESPONSE */ 716 /* GOOD RESPONSE */
714 int query_nb_value; 717 int query_nb_value;
715 int response_nb_value; 718 int response_nb_value;
@@ -740,7 +743,7 @@ static int modbus_receive(modbus_param_t *mb_param, @@ -740,7 +743,7 @@ static int modbus_receive(modbus_param_t *mb_param,
740 break; 743 break;
741 case FC_REPORT_SLAVE_ID: 744 case FC_REPORT_SLAVE_ID:
742 /* Report slave ID (bytes received) */ 745 /* Report slave ID (bytes received) */
743 - query_nb_value = response_nb_value = response_length; 746 + query_nb_value = response_nb_value = ret;
744 break; 747 break;
745 default: 748 default:
746 /* 1 Write functions & others */ 749 /* 1 Write functions & others */
@@ -757,55 +760,46 @@ static int modbus_receive(modbus_param_t *mb_param, @@ -757,55 +760,46 @@ static int modbus_receive(modbus_param_t *mb_param,
757 error_treat(mb_param, ret, s_error); 760 error_treat(mb_param, ret, s_error);
758 free(s_error); 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 return ret; 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 * This program is free software: you can redistribute it and/or modify 4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser Public License as published by 5 * it under the terms of the GNU Lesser Public License as published by
@@ -72,6 +72,8 @@ extern &quot;C&quot; { @@ -72,6 +72,8 @@ extern &quot;C&quot; {
72 /* Kept for compatibility reasons (deprecated) */ 72 /* Kept for compatibility reasons (deprecated) */
73 #define MAX_MESSAGE_LENGTH 260 73 #define MAX_MESSAGE_LENGTH 260
74 74
  75 +#define EXCEPTION_RESPONSE_LENGTH_RTU 5
  76 +
75 /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12) 77 /* Modbus_Application_Protocol_V1_1b.pdf (chapter 6 section 1 page 12)
76 * Quantity of Coils (2 bytes): 1 to 2000 (0x7D0) 78 * Quantity of Coils (2 bytes): 1 to 2000 (0x7D0)
77 */ 79 */
@@ -139,6 +141,7 @@ extern &quot;C&quot; { @@ -139,6 +141,7 @@ extern &quot;C&quot; {
139 #define SELECT_FAILURE -0x14 141 #define SELECT_FAILURE -0x14
140 #define SOCKET_FAILURE -0x15 142 #define SOCKET_FAILURE -0x15
141 #define CONNECTION_CLOSED -0x16 143 #define CONNECTION_CLOSED -0x16
  144 +#define MB_EXCEPTION -0x17
142 145
143 /* Internal using */ 146 /* Internal using */
144 #define MSG_LENGTH_UNDEFINED -1 147 #define MSG_LENGTH_UNDEFINED -1
@@ -318,15 +321,15 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection); @@ -318,15 +321,15 @@ int modbus_slave_listen_tcp(modbus_param_t *mb_param, int nb_connection);
318 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket); 321 int modbus_slave_accept_tcp(modbus_param_t *mb_param, int *socket);
319 322
320 /* Listens for any query from a modbus master in TCP, requires the socket file 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 Returns: 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 - query, message received 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 /* Manages the received query. 334 /* Manages the received query.
332 Analyses the query and constructs a response. 335 Analyses the query and constructs a response.
tests/bandwidth-slave-many-up.c
@@ -106,11 +106,10 @@ int main(void) @@ -106,11 +106,10 @@ int main(void)
106 } else { 106 } else {
107 /* An already connected master has sent a new query */ 107 /* An already connected master has sent a new query */
108 uint8_t query[MAX_MESSAGE_LENGTH]; 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 } else { 113 } else {
115 /* Connection closed by the client, end of server */ 114 /* Connection closed by the client, end of server */
116 printf("Connection closed on socket %d\n", master_socket); 115 printf("Connection closed on socket %d\n", master_socket);
tests/bandwidth-slave-one.c
@@ -44,11 +44,10 @@ int main(void) @@ -44,11 +44,10 @@ int main(void)
44 44
45 while (1) { 45 while (1) {
46 uint8_t query[MAX_MESSAGE_LENGTH]; 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 } else if (ret == CONNECTION_CLOSED) { 51 } else if (ret == CONNECTION_CLOSED) {
53 /* Connection closed by the client, end of server */ 52 /* Connection closed by the client, end of server */
54 break; 53 break;
tests/random-test-slave.c
@@ -44,11 +44,12 @@ int main(void) @@ -44,11 +44,12 @@ int main(void)
44 44
45 while (1) { 45 while (1) {
46 uint8_t query[MAX_MESSAGE_LENGTH]; 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 } else if (ret == CONNECTION_CLOSED) { 53 } else if (ret == CONNECTION_CLOSED) {
53 /* Connection closed by the client, end of server */ 54 /* Connection closed by the client, end of server */
54 break; 55 break;
tests/unit-test-slave.c
@@ -63,10 +63,9 @@ int main(void) @@ -63,10 +63,9 @@ int main(void)
63 63
64 while (1) { 64 while (1) {
65 uint8_t query[MAX_MESSAGE_LENGTH]; 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 if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4]) 69 if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4])
71 == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) { 70 == UT_HOLDING_REGISTERS_NB_POINTS_SPECIAL) {
72 /* Change the number of values (offset 71 /* Change the number of values (offset
@@ -75,7 +74,7 @@ int main(void) @@ -75,7 +74,7 @@ int main(void)
75 query[HEADER_LENGTH_TCP + 4] = UT_HOLDING_REGISTERS_NB_POINTS; 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 } else if (ret == CONNECTION_CLOSED) { 78 } else if (ret == CONNECTION_CLOSED) {
80 /* Connection closed by the client, end of server */ 79 /* Connection closed by the client, end of server */
81 break; 80 break;