Repository: stephane/libmodbus

Issue #231: costum request and response - response not fully received
Created: 2014-10-16T09:11:08Z
Good morning,
my question is - do you have problem with receiving of the messages with more bytes?
Because I have found out this strange behaviour:
The custom HW (slave) doesnt support standard Modbus functions (like read coils etc.) so I use only "modbus_send_raw_request" and "modbus_receive_confirmation" functions. (Is this correct? Or shall I use different functions?)
The request (from the master = PC) is sent correctly but the response from the slave is not fully received. I am able to receive only 5 useful bytes: ID (1B) - function code (1B) - data bytes quantity (1B) - data bytes (2B). Together 5 bytes (there are printed out in the terminal).
But I need to receive more than 2 data bytes, of course :-)
I checked this behaviour with ModbusPoll SW (http://www.modbustools.com/modbus_poll.asp) and the response is received correctly in this case.
So I went through the source code little bit (I am not fully familiar with libmodbus source code) and the problem could be in function "_modbus_receive_msg".
Probably one of the most important variable here is "length_to_read".
Here is the part of the source code:
/* We need to analyse the message step by step.  At the first step, we want
* to reach the function code because all packets contain this
* information. */
step = _STEP_FUNCTION;
length_to_read = ctx->backend->header_length + 1;
The variable "ctx->backend->header_length" still remains "1" and of course, I always get "2" in the variable "length_to_read". And it does not depend on lenght of the received message. Is this correct behaviour? Is this the reason why I can only read 2 data bytes?
But if I hardcoded the variable "length_to_read" to value e.g. 20 (length_to_read = 20;), because I want to receive 20 data bytes, all 20 data bytes are received correctly. That is strange.
Does anybody know what is wrong? Did I miss anything? Wrong settings etc...?
Thanks for the response.
Best regards,
Jiri
My HW and SW configuration:
PC - linux mint 17 Cinnamon 64b
usb/RS485 converter connected on /dev/ttyUSB0 at 38400, no parity, 8 data bits, 1 stop bit
libmodbus v 3.1.1,
RTU backend
debug on.

Duplicate issue #343: modbus_receive_confirmation ignore length for user function codes
Created: 2016-07-06T11:31:04Z
libmodbus version
3.1.4
Operating system
Windows 7
Description of the Modbus network (server, client, links, etc)
Modbus RTU client
Expected behavior
Read a full answer from user function on my device.
Actual behavior
Read only first bytes (minimal length).
Steps to reproduce the behavior (commands or source code)
int res;
uint8_t req[] = { 123 /* address */, 65 /* user function */, ... /* data */};
res = modbus_send_raw_request(modbus_ctx, req, req_size);
/* res check skipped */
uint8_t buf[MODBUS_RTU_MAX_ADU_LENGTH];
res = modbus_receive_raw_confirmation(modbus_ctx, buf);
/* res == -1 invalid checksum because the answer is not read to the end */

libmodbus output with debug mode enabled
None
Fix
I fixed it by adding this code in modbus.c (and prototype in modbus.h):
/* Waits a raw response from a modbus server or a request from a modbus client.
   This function blocks if there is no replies (3 timeouts).

   The function shall return the number of received characters and the received
   message in an array of uint8_t if successful. Otherwise it shall return -1
   and errno is set to one of the values defined below:
   - ECONNRESET
   - EMBBADDATA
   - EMBUNKEXC
   - ETIMEDOUT
   - read() or recv() error codes
*/

int _modbus_receive_raw_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
{
    int rc = 0;
    fd_set rset;
    struct timeval tv;
    struct timeval *p_tv;
    int length_to_read;
    int msg_length = 0;
    _step_t step = _STEP_FUNCTION;

    if (ctx->debug) {
        if (msg_type == MSG_INDICATION) {
            printf("Waiting for a raw indication...\n");
        } else {
            printf("Waiting for a raw confirmation...\n");
        }
    }

    /* Add a file descriptor to the set */
    FD_ZERO(&rset);
    FD_SET(ctx->s, &rset);

    length_to_read = ctx->backend->header_length + 1;

    if (msg_type == MSG_INDICATION) {
        /* Wait for a message, we don't know when the message will be
         * received */
        p_tv = NULL;
    } else {
        tv.tv_sec = ctx->response_timeout.tv_sec;
        tv.tv_usec = ctx->response_timeout.tv_usec;
        p_tv = &tv;
    }

    while (rc != -1) {
        rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read);
        if (rc == -1) {
            /* Timeout at end of msg */
            if(step == _STEP_DATA && errno == ETIMEDOUT){
                break;
            }
            _error_print(ctx, "select");
            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
                int saved_errno = errno;

                if (errno == ETIMEDOUT) {
                    _sleep_response_timeout(ctx);
                    modbus_flush(ctx);
                } else if (errno == EBADF) {
                    modbus_close(ctx);
                    modbus_connect(ctx);
                }
                errno = saved_errno;
            }
            return -1;
        }

        rc = ctx->backend->recv(ctx, msg + msg_length, length_to_read);
        if (rc == 0) {
            errno = ECONNRESET;
            rc = -1;
        }

        if (rc == -1) {
            _error_print(ctx, "read");
            if ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) &&
                (errno == ECONNRESET || errno == ECONNREFUSED ||
                 errno == EBADF)) {
                int saved_errno = errno;
                modbus_close(ctx);
                modbus_connect(ctx);
                /* Could be removed by previous calls */
                errno = saved_errno;
            }
            return -1;
        }

        /* Display the hex code of each character received */
        if (ctx->debug) {
            int i;
            for (i=0; i < rc; i++)
                printf("<%.2X>", msg[msg_length + i]);
        }

        /* Sums bytes received */
        msg_length += rc;

        if(step == _STEP_FUNCTION){
            /* Set byte timeout */
            if (ctx->byte_timeout.tv_sec > 0 || ctx->byte_timeout.tv_usec > 0) {
                tv.tv_sec = ctx->byte_timeout.tv_sec;
                tv.tv_usec = ctx->byte_timeout.tv_usec;
                p_tv = &tv;
            }
            /* Read one byte */
            length_to_read = 1;
            /* Data step */
            step = _STEP_DATA;
        }
    }

    if (ctx->debug)
        printf("\n");

    return ctx->backend->check_integrity(ctx, msg, msg_length);
}

/* Receives the raw confirmation.

   The function shall store the read response in rsp and return the number of
   values (bits or words). Otherwise, its shall return -1 and errno is set.

   The function doesn't check the confirmation is the expected response to the
   initial request.
*/
int modbus_receive_raw_confirmation(modbus_t *ctx, uint8_t *rsp)
{
    if (ctx == NULL) {
        errno = EINVAL;
        return -1;
    }

    return _modbus_receive_raw_msg(ctx, rsp, MSG_CONFIRMATION);
}

Closing comment (2017-04-11T16:21:07Z): Very related to #231