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 1 libmodbus 2.1.1 (2010-XX-XX)
2 2 ============================
3 3  
  4 +- New API
4 5 - Remove the internal function set_message_length_tcp
5 6 - Restore slave ID (server ID) argument in functions
6 7 - Error conventions of POSIX systems and error recover
... ... @@ -13,6 +14,7 @@ libmodbus 2.1.1 (2010-XX-XX)
13 14 - Fix #591142 - Slave id check should be disabled in TCP connection
14 15 Reported by aladdinwu.
15 16 - Parity setting is now a single char ('N', 'E' or 'O')
  17 +- Report slave ID server side
16 18  
17 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 479 }
480 480  
481 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 484 int length;
485 485  
... ... @@ -492,6 +492,28 @@ static uint8_t compute_request_length_header(int function)
492 492 /* Multiple write */
493 493 length = 5;
494 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 517 length = 1;
496 518 else
497 519 length = 0;
... ... @@ -500,17 +522,17 @@ static uint8_t compute_request_length_header(int function)
500 522 }
501 523  
502 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 527 int function = msg[TAB_HEADER_LENGTH[ctx->type_com]];
506 528 int length;
507 529  
508 530 if (function == FC_WRITE_MULTIPLE_COILS ||
509   - function == FC_WRITE_MULTIPLE_REGISTERS)
  531 + function == FC_WRITE_MULTIPLE_REGISTERS) {
510 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 534 length = msg[TAB_HEADER_LENGTH[ctx->type_com] + 1];
513   - else
  535 + } else
514 536 length = 0;
515 537  
516 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 595 - ETIMEDOUT
574 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 607 int s_rc;
579 608 int read_rc;
... ... @@ -586,11 +615,16 @@ static int receive_msg(modbus_t *ctx, int msg_length_computed, uint8_t *msg)
586 615 int msg_length = 0;
587 616  
588 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 624 if (msg_length_computed == MSG_LENGTH_UNDEFINED)
590   - printf("Waiting for a message...\n");
  625 + printf("...\n");
591 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 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 695 switch (state) {
662 696 case FUNCTION:
663 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 705 msg_length_computed += length_to_read;
667 706 /* It's useless to check the value of
668 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 709 state = DATA;
671 710 break;
672 711 case DATA:
673   - length_to_read = compute_request_length_data(ctx, msg);
  712 + length_to_read = compute_msg_length_data(ctx, msg);
674 713 msg_length_computed += length_to_read;
675 714 if (msg_length_computed > TAB_MAX_ADU_LENGTH[ctx->type_com]) {
676 715 errno = EMBBADDATA;
... ... @@ -727,7 +766,7 @@ int modbus_receive(modbus_t *ctx, int sockfd, uint8_t *req)
727 766 }
728 767  
729 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 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 783 int offset = TAB_HEADER_LENGTH[ctx->type_com];
745 784  
746 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 787 if (rc != -1) {
749 788 /* GOOD RESPONSE */
750 789 int req_nb_value;
... ... @@ -776,7 +815,7 @@ static int receive_msg_req(modbus_t *ctx, uint8_t *req, uint8_t *rsp)
776 815 break;
777 816 case FC_REPORT_SLAVE_ID:
778 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 819 break;
781 820 default:
782 821 /* 1 Write functions & others */
... ... @@ -1088,8 +1127,15 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req,
1088 1127 }
1089 1128 }
1090 1129 break;
1091   - case FC_READ_EXCEPTION_STATUS:
1092 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 1139 if (ctx->debug) {
1094 1140 fprintf(stderr, "FIXME Not implemented\n");
1095 1141 }
... ... @@ -1127,11 +1173,11 @@ static int read_io_status(modbus_t *ctx, int function,
1127 1173 if (rc == -1)
1128 1174 return -1;
1129 1175  
1130   - offset = TAB_HEADER_LENGTH[ctx->type_com];
  1176 + offset = TAB_HEADER_LENGTH[ctx->type_com] + 2;
1131 1177 offset_end = offset + rc;
1132 1178 for (i = offset; i < offset_end; i++) {
1133 1179 /* Shift reg hi_byte to temp */
1134   - temp = rsp[i + 2];
  1180 + temp = rsp[i];
1135 1181  
1136 1182 for (bit = 0x01; (bit & 0xff) && (pos < nb);) {
1137 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 1456 }
1411 1457  
1412 1458 /* Send a request to get the slave ID of the device (only available in serial
1413   - * communication) */
  1459 + * communication). */
1414 1460 int modbus_report_slave_id(modbus_t *ctx, uint8_t *data_dest)
1415 1461 {
1416 1462 int rc;
1417 1463 int req_length;
1418 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 1466 req_length = build_request_basis(ctx, FC_REPORT_SLAVE_ID, 0, 0, req);
1427 1467  
1428 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 1472 if (rc > 0) {
1433 1473 int i;
1434 1474 int offset;
1435   - int offset_end;
1436 1475 uint8_t rsp[MAX_MESSAGE_LENGTH];
1437 1476  
1438 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 1480 if (rc == -1)
1442 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 1490 return rc;
... ...
tests/unit-test-client.c
... ... @@ -443,7 +443,7 @@ int main(void)
443 443 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
444 444 UT_REGISTERS_NB_POINTS,
445 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 447 if (is_mode_rtu) {
448 448 /* No response in RTU mode */
449 449 if (rc == -1 && errno == ETIMEDOUT) {
... ... @@ -466,7 +466,7 @@ int main(void)
466 466 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
467 467 UT_REGISTERS_NB_POINTS,
468 468 tab_rp_registers);
469   - printf("2/3 Reply after a broadcast query: ");
  469 + printf("2/4 Reply after a broadcast query: ");
470 470 if (rc == UT_REGISTERS_NB_POINTS) {
471 471 printf("OK\n");
472 472 } else {
... ... @@ -481,6 +481,22 @@ int main(void)
481 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 500 /* Save original timeout */
485 501 modbus_get_timeout_begin(ctx, &timeout_begin_old);
486 502  
... ... @@ -492,7 +508,7 @@ int main(void)
492 508 rc = modbus_read_registers(ctx, UT_REGISTERS_ADDRESS,
493 509 UT_REGISTERS_NB_POINTS,
494 510 tab_rp_registers);
495   - printf("3/3 Too short timeout: ");
  511 + printf("4/4 Too short timeout: ");
496 512 if (rc == -1 && errno == ETIMEDOUT) {
497 513 printf("OK\n");
498 514 } else {
... ...
tests/unit-test-server.c
... ... @@ -39,10 +39,11 @@ int main(void)
39 39 modbus_set_debug(ctx, TRUE);
40 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 47 if (mb_mapping == NULL) {
47 48 fprintf(stderr, "Failed to allocate the mapping: %s\n",
48 49 modbus_strerror(errno));
... ... @@ -72,7 +73,8 @@ int main(void)
72 73  
73 74 rc = modbus_receive(ctx, -1, query);
74 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 78 == UT_REGISTERS_NB_POINTS_SPECIAL) {
77 79 /* Change the number of values (offset
78 80 TCP = 6) */
... ...