Commit 4d3bf7beeaa8c196957c8daa76fa7dc51941b859

Authored by Stéphane Raimbault
1 parent 86418cf3

Implement report slave ID on server side

- return only useful data client side
- available in TCP when a gateway to RTU is used
- need to add isolated handling of indication/confirmation messages
1 libmodbus 2.1.1 (2010-XX-XX) 1 libmodbus 2.1.1 (2010-XX-XX)
2 ============================ 2 ============================
3 3
  4 +- New API
4 - Remove the internal function set_message_length_tcp 5 - Remove the internal function set_message_length_tcp
5 - Restore slave ID (server ID) argument in functions 6 - Restore slave ID (server ID) argument in functions
6 - Error conventions of POSIX systems and error recover 7 - Error conventions of POSIX systems and error recover
@@ -13,6 +14,7 @@ libmodbus 2.1.1 (2010-XX-XX) @@ -13,6 +14,7 @@ libmodbus 2.1.1 (2010-XX-XX)
13 - Fix #591142 - Slave id check should be disabled in TCP connection 14 - Fix #591142 - Slave id check should be disabled in TCP connection
14 Reported by aladdinwu. 15 Reported by aladdinwu.
15 - Parity setting is now a single char ('N', 'E' or 'O') 16 - Parity setting is now a single char ('N', 'E' or 'O')
  17 +- Report slave ID server side
16 18
17 libmodbus 2.1.0 (2010-03-24) 19 libmodbus 2.1.0 (2010-03-24)
18 ============================ 20 ============================
src/modbus.c
@@ -479,7 +479,7 @@ static int send_msg(modbus_t *ctx, uint8_t *req, int req_length) @@ -479,7 +479,7 @@ static int send_msg(modbus_t *ctx, uint8_t *req, int req_length)
479 } 479 }
480 480
481 /* Computes the length of the header following the function code */ 481 /* Computes the length of the header following the function code */
482 -static uint8_t compute_request_length_header(int function) 482 +static uint8_t compute_indication_length_header(int function)
483 { 483 {
484 int length; 484 int length;
485 485
@@ -492,6 +492,28 @@ static uint8_t compute_request_length_header(int function) @@ -492,6 +492,28 @@ static uint8_t compute_request_length_header(int function)
492 /* Multiple write */ 492 /* Multiple write */
493 length = 5; 493 length = 5;
494 else if (function == FC_REPORT_SLAVE_ID) 494 else if (function == FC_REPORT_SLAVE_ID)
  495 + length = 0;
  496 + else
  497 + length = 0;
  498 +
  499 + return length;
  500 +}
  501 +
  502 +/* Computes the length of the header following the function code */
  503 +static uint8_t compute_confirmation_length_header(int function)
  504 +{
  505 + int length;
  506 +
  507 + if (function <= FC_WRITE_SINGLE_COIL ||
  508 + function == FC_WRITE_SINGLE_REGISTER)
  509 + /* Read and single write */
  510 + length = 4;
  511 + else if (function == FC_WRITE_MULTIPLE_COILS ||
  512 + function == FC_WRITE_MULTIPLE_REGISTERS)
  513 + /* Multiple write */
  514 + length = 5;
  515 + else if (function == FC_REPORT_SLAVE_ID)
  516 + /* Report slave_ID */
495 length = 1; 517 length = 1;
496 else 518 else
497 length = 0; 519 length = 0;
@@ -500,17 +522,17 @@ static uint8_t compute_request_length_header(int function) @@ -500,17 +522,17 @@ static uint8_t compute_request_length_header(int function)
500 } 522 }
501 523
502 /* Computes the length of the data to write in the request */ 524 /* Computes the length of the data to write in the request */
503 -static int compute_request_length_data(modbus_t *ctx, uint8_t *msg) 525 +static int compute_msg_length_data(modbus_t *ctx, uint8_t *msg)
504 { 526 {
505 int function = msg[TAB_HEADER_LENGTH[ctx->type_com]]; 527 int function = msg[TAB_HEADER_LENGTH[ctx->type_com]];
506 int length; 528 int length;
507 529
508 if (function == FC_WRITE_MULTIPLE_COILS || 530 if (function == FC_WRITE_MULTIPLE_COILS ||
509 - function == FC_WRITE_MULTIPLE_REGISTERS) 531 + function == FC_WRITE_MULTIPLE_REGISTERS) {
510 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 5]; 532 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 5];
511 - else if (function == FC_REPORT_SLAVE_ID) 533 + } else if (function == FC_REPORT_SLAVE_ID) {
512 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 1]; 534 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 1];
513 - else 535 + } else
514 length = 0; 536 length = 0;
515 537
516 length += TAB_CHECKSUM_LENGTH[ctx->type_com]; 538 length += TAB_CHECKSUM_LENGTH[ctx->type_com];
@@ -573,7 +595,14 @@ static int compute_request_length_data(modbus_t *ctx, uint8_t *msg) @@ -573,7 +595,14 @@ static int compute_request_length_data(modbus_t *ctx, uint8_t *msg)
573 - ETIMEDOUT 595 - ETIMEDOUT
574 - read() or recv() error codes 596 - read() or recv() error codes
575 */ 597 */
576 -static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg) 598 +enum {
  599 + /* Request message on the server side */
  600 + MSG_INDICATION,
  601 + /* Request message on the client side */
  602 + MSG_CONFIRMATION
  603 +};
  604 +
  605 +static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg, int type)
577 { 606 {
578 int s_rc; 607 int s_rc;
579 int read_rc; 608 int read_rc;
@@ -586,11 +615,16 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg) @@ -586,11 +615,16 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg)
586 int msg_length = 0; 615 int msg_length = 0;
587 616
588 if (ctx->debug) { 617 if (ctx->debug) {
  618 + if (type == MSG_INDICATION) {
  619 + printf("Waiting for a indication");
  620 + } else {
  621 + printf("Waiting for a confirmation");
  622 + }
  623 +
589 if (msg_length_computed == MSG_LENGTH_UNDEFINED) 624 if (msg_length_computed == MSG_LENGTH_UNDEFINED)
590 - printf("Waiting for a message...\n"); 625 + printf("...\n");
591 else 626 else
592 - printf("Waiting for a message (%d bytes)...\n",  
593 - msg_length_computed); 627 + printf("(%d bytes)...\n", msg_length_computed);
594 } 628 }
595 629
596 /* Add a file descriptor to the set */ 630 /* Add a file descriptor to the set */
@@ -661,8 +695,13 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg) @@ -661,8 +695,13 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg)
661 switch (state) { 695 switch (state) {
662 case FUNCTION: 696 case FUNCTION:
663 /* Function code position */ 697 /* Function code position */
664 - length_to_read = compute_request_length_header(  
665 - msg[TAB_HEADER_LENGTH[ctx->type_com]]); 698 + if (type == MSG_INDICATION) {
  699 + length_to_read = compute_indication_length_header(
  700 + msg[TAB_HEADER_LENGTH[ctx->type_com]]);
  701 + } else {
  702 + length_to_read = compute_confirmation_length_header(
  703 + msg[TAB_HEADER_LENGTH[ctx->type_com]]);
  704 + }
666 msg_length_computed += length_to_read; 705 msg_length_computed += length_to_read;
667 /* It's useless to check the value of 706 /* It's useless to check the value of
668 msg_length_computed in this case (only 707 msg_length_computed in this case (only
@@ -670,7 +709,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg) @@ -670,7 +709,7 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg)
670 state = DATA; 709 state = DATA;
671 break; 710 break;
672 case DATA: 711 case DATA:
673 - length_to_read = compute_request_length_data(ctx, msg); 712 + length_to_read = compute_msg_length_data(ctx, msg);
674 msg_length_computed += length_to_read; 713 msg_length_computed += length_to_read;
675 if (msg_length_computed > TAB_MAX_ADU_LENGTH[ctx->type_com]) { 714 if (msg_length_computed > TAB_MAX_ADU_LENGTH[ctx->type_com]) {
676 errno = EMBBADDATA; 715 errno = EMBBADDATA;
@@ -727,7 +766,7 @@ int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req) @@ -727,7 +766,7 @@ int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req)
727 } 766 }
728 767
729 /* The length of the request to receive isn't known. */ 768 /* The length of the request to receive isn't known. */
730 - return receive_msg(ctx, MSG_LENGTH_UNDEFINED, req); 769 + return receive_msg(ctx, MSG_LENGTH_UNDEFINED, req, MSG_INDICATION);
731 } 770 }
732 771
733 /* Receives the response and checks values (and checksum in RTU). 772 /* Receives the response and checks values (and checksum in RTU).
@@ -744,7 +783,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -744,7 +783,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
744 int offset = TAB_HEADER_LENGTH[ctx->type_com]; 783 int offset = TAB_HEADER_LENGTH[ctx->type_com];
745 784
746 rsp_length_computed = compute_response_length(ctx, req); 785 rsp_length_computed = compute_response_length(ctx, req);
747 - rc = receive_msg(ctx, rsp_length_computed, rsp); 786 + rc = receive_msg(ctx, rsp_length_computed, rsp, MSG_CONFIRMATION);
748 if (rc != -1) { 787 if (rc != -1) {
749 /* GOOD RESPONSE */ 788 /* GOOD RESPONSE */
750 int req_nb_value; 789 int req_nb_value;
@@ -776,7 +815,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp) @@ -776,7 +815,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
776 break; 815 break;
777 case FC_REPORT_SLAVE_ID: 816 case FC_REPORT_SLAVE_ID:
778 /* Report slave ID (bytes received) */ 817 /* Report slave ID (bytes received) */
779 - req_nb_value = rsp_nb_value = rc; 818 + req_nb_value = rsp_nb_value = rsp[offset + 1];
780 break; 819 break;
781 default: 820 default:
782 /* 1 Write functions & others */ 821 /* 1 Write functions & others */
@@ -1088,8 +1127,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, @@ -1088,8 +1127,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1088 } 1127 }
1089 } 1128 }
1090 break; 1129 break;
1091 - case FC_READ_EXCEPTION_STATUS:  
1092 case FC_REPORT_SLAVE_ID: 1130 case FC_REPORT_SLAVE_ID:
  1131 + resp_length = build_response_basis(ctx, &sft, rsp);
  1132 + /* 2 bytes */
  1133 + rsp[resp_length++] = 2;
  1134 + rsp[resp_length++] = ctx->slave;
  1135 + /* Slave is ON */
  1136 + rsp[resp_length++] = 0xFF;
  1137 + break;
  1138 + case FC_READ_EXCEPTION_STATUS:
1093 if (ctx->debug) { 1139 if (ctx->debug) {
1094 fprintf(stderr, "FIXME Not implemented\n"); 1140 fprintf(stderr, "FIXME Not implemented\n");
1095 } 1141 }
@@ -1127,11 +1173,11 @@ static int read_io_status(modbus_t *ctx, int function, @@ -1127,11 +1173,11 @@ static int read_io_status(modbus_t *ctx, int function,
1127 if (rc == -1) 1173 if (rc == -1)
1128 return -1; 1174 return -1;
1129 1175
1130 - offset = TAB_HEADER_LENGTH[ctx->type_com]; 1176 + offset = TAB_HEADER_LENGTH[ctx->type_com] + 2;
1131 offset_end = offset + rc; 1177 offset_end = offset + rc;
1132 for (i = offset; i < offset_end; i++) { 1178 for (i = offset; i < offset_end; i++) {
1133 /* Shift reg hi_byte to temp */ 1179 /* Shift reg hi_byte to temp */
1134 - temp = rsp[i + 2]; 1180 + temp = rsp[i];
1135 1181
1136 for (bit = 0x01; (bit & 0xff) && (pos < nb);) { 1182 for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
1137 data_dest[pos++] = (temp & bit) ? TRUE : FALSE; 1183 data_dest[pos++] = (temp & bit) ? TRUE : FALSE;
@@ -1410,19 +1456,13 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data @@ -1410,19 +1456,13 @@ int modbus_write_registers(modbus_t *ctx, int addr, int nb, const uint16_t *data
1410 } 1456 }
1411 1457
1412 /* Send a request to get the slave ID of the device (only available in serial 1458 /* Send a request to get the slave ID of the device (only available in serial
1413 - * communication) */ 1459 + * communication). */
1414 int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest) 1460 int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1415 { 1461 {
1416 int rc; 1462 int rc;
1417 int req_length; 1463 int req_length;
1418 uint8_t req[MIN_REQ_LENGTH]; 1464 uint8_t req[MIN_REQ_LENGTH];
1419 1465
1420 - if (ctx->type_com != RTU) {  
1421 - /* Only for serial communications */  
1422 - errno = EINVAL;  
1423 - return -1;  
1424 - }  
1425 -  
1426 req_length = build_request_basis(ctx, FC_REPORT_SLAVE_ID, 0, 0, req); 1466 req_length = build_request_basis(ctx, FC_REPORT_SLAVE_ID, 0, 0, req);
1427 1467
1428 /* HACKISH, addr and count are not used */ 1468 /* HACKISH, addr and count are not used */
@@ -1432,7 +1472,6 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest) @@ -1432,7 +1472,6 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1432 if (rc > 0) { 1472 if (rc > 0) {
1433 int i; 1473 int i;
1434 int offset; 1474 int offset;
1435 - int offset_end;  
1436 uint8_t rsp[MAX_MESSAGE_LENGTH]; 1475 uint8_t rsp[MAX_MESSAGE_LENGTH];
1437 1476
1438 /* Byte count, slave id, run indicator status, 1477 /* Byte count, slave id, run indicator status,
@@ -1441,11 +1480,11 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest) @@ -1441,11 +1480,11 @@ int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1441 if (rc == -1) 1480 if (rc == -1)
1442 return -1; 1481 return -1;
1443 1482
1444 - offset = TAB_HEADER_LENGTH[ctx->type_com] - 1;  
1445 - offset_end = offset + rc; 1483 + offset = TAB_HEADER_LENGTH[ctx->type_com] + 2;
1446 1484
1447 - for (i = offset; i < offset_end; i++)  
1448 - data_dest[i] = rsp[i]; 1485 + for (i=0; i < rc; i++) {
  1486 + data_dest[i] = rsp[offset + i];
  1487 + }
1449 } 1488 }
1450 1489
1451 return rc; 1490 return rc;
tests/unit-test-client.c
@@ -443,7 +443,7 @@ int main(void) @@ -443,7 +443,7 @@ int main(void)
443 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 443 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
444 UT_REGISTERS_NB_POINTS, 444 UT_REGISTERS_NB_POINTS,
445 tab_rp_registers); 445 tab_rp_registers);
446 - printf("1/3 No or response from slave %d: ", 18); 446 + printf("1/4 No or response from slave %d: ", 18);
447 if (is_mode_rtu) { 447 if (is_mode_rtu) {
448 /* No response in RTU mode */ 448 /* No response in RTU mode */
449 if (rc == -1 && errno == ETIMEDOUT) { 449 if (rc == -1 && errno == ETIMEDOUT) {
@@ -466,7 +466,7 @@ int main(void) @@ -466,7 +466,7 @@ int main(void)
466 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 466 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
467 UT_REGISTERS_NB_POINTS, 467 UT_REGISTERS_NB_POINTS,
468 tab_rp_registers); 468 tab_rp_registers);
469 - printf("2/3 Reply after a broadcast query: "); 469 + printf("2/4 Reply after a broadcast query: ");
470 if (rc == UT_REGISTERS_NB_POINTS) { 470 if (rc == UT_REGISTERS_NB_POINTS) {
471 printf("OK\n"); 471 printf("OK\n");
472 } else { 472 } else {
@@ -481,6 +481,22 @@ int main(void) @@ -481,6 +481,22 @@ int main(void)
481 modbus_set_slave(ctx, MODBUS_TCP_SLAVE); 481 modbus_set_slave(ctx, MODBUS_TCP_SLAVE);
482 } 482 }
483 483
  484 + printf("3/4 Report slave ID: \n");
  485 + /* tab_rp_bits is used to store bytes */
  486 + rc = modbus_report_slave_id(ctx, tab_rp_bits);
  487 + if (rc == -1) {
  488 + printf("FAILED\n");
  489 + goto close;
  490 + }
  491 +
  492 + if ((is_mode_rtu && tab_rp_bits[0] == SERVER_ID)
  493 + || tab_rp_bits[0] == 0xFF) {
  494 + printf("OK\n");
  495 + } else {
  496 + printf("FAILED\n");
  497 + goto close;
  498 + }
  499 +
484 /* Save original timeout */ 500 /* Save original timeout */
485 modbus_get_timeout_begin(ctx, &timeout_begin_old); 501 modbus_get_timeout_begin(ctx, &timeout_begin_old);
486 502
@@ -492,7 +508,7 @@ int main(void) @@ -492,7 +508,7 @@ int main(void)
492 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS, 508 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
493 UT_REGISTERS_NB_POINTS, 509 UT_REGISTERS_NB_POINTS,
494 tab_rp_registers); 510 tab_rp_registers);
495 - printf("3/3 Too short timeout: "); 511 + printf("4/4 Too short timeout: ");
496 if (rc == -1 && errno == ETIMEDOUT) { 512 if (rc == -1 && errno == ETIMEDOUT) {
497 printf("OK\n"); 513 printf("OK\n");
498 } else { 514 } else {
tests/unit-test-server.c
@@ -39,10 +39,11 @@ int main(void) @@ -39,10 +39,11 @@ int main(void)
39 modbus_set_debug(ctx, TRUE); 39 modbus_set_debug(ctx, TRUE);
40 modbus_set_error_recovery(ctx, TRUE); 40 modbus_set_error_recovery(ctx, TRUE);
41 41
42 - mb_mapping = modbus_mapping_new(UT_BITS_ADDRESS + UT_BITS_NB_POINTS,  
43 - UT_INPUT_BITS_ADDRESS + UT_INPUT_BITS_NB_POINTS,  
44 - UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_POINTS,  
45 - UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS); 42 + mb_mapping = modbus_mapping_new(
  43 + UT_BITS_ADDRESS + UT_BITS_NB_POINTS,
  44 + UT_INPUT_BITS_ADDRESS + UT_INPUT_BITS_NB_POINTS,
  45 + UT_REGISTERS_ADDRESS + UT_REGISTERS_NB_POINTS,
  46 + UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB_POINTS);
46 if (mb_mapping == NULL) { 47 if (mb_mapping == NULL) {
47 fprintf(stderr, "Failed to allocate the mapping: %s\n", 48 fprintf(stderr, "Failed to allocate the mapping: %s\n",
48 modbus_strerror(errno)); 49 modbus_strerror(errno));
@@ -72,7 +73,8 @@ int main(void) @@ -72,7 +73,8 @@ int main(void)
72 73
73 rc = modbus_receive(ctx, -1, query); 74 rc = modbus_receive(ctx, -1, query);
74 if (rc > 0) { 75 if (rc > 0) {
75 - if (((query[HEADER_LENGTH_TCP + 3] << 8) + query[HEADER_LENGTH_TCP + 4]) 76 + if (((query[HEADER_LENGTH_TCP + 3] << 8) +
  77 + query[HEADER_LENGTH_TCP + 4])
76 == UT_REGISTERS_NB_POINTS_SPECIAL) { 78 == UT_REGISTERS_NB_POINTS_SPECIAL) {
77 /* Change the number of values (offset 79 /* Change the number of values (offset
78 TCP = 6) */ 80 TCP = 6) */