0
\$\begingroup\$

We are using libmodbus library to read register values from energy meter EM6400 which supports Modbus over RTU. We are facing the following two issues.

1) We are facing issue with Modbus_read_registers API, this API returns -1 and the error message is “ERROR Connection timed out: select”. After debugging the library, we found this issue is due to the echo of request bytes in the response message. read() API call in _modbus_rtu_recv returns request bytes first followed by response bytes. As a result, length_to_read is calculated in compute_data_length_after_meta() based on the request bytes instead of response bytes(which contains the number of bytes read) and connection timed out issue occurs. We tried to use both 3.0.6 and 3.1.2 libmodbus versions but same issue occurs in both the versions.

2) modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485) returns ‘BAD file descriptor’.

Please confirm if there is any API call missing or any parameter is not set correctly. Please suggest any pointers to resolve these issues.

Our sample code to read register value is as follows.

int main()
{
    modbus_t *ctx;
    uint16_t tab_reg[2] = {0,0};
    float avgVLL = -1;;
    // EMValue *pemVal = new EMValue;
    int res = 0;
    int rc;
    int i;
    struct timeval response_timeout;
    uint32_t tv_sec = 0;
    uint32_t tv_usec = 0;
    response_timeout.tv_sec = 5;
    response_timeout.tv_usec = 0;

    ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'E', 8, 1);
    if (NULL == ctx)
    {
                    printf("Unable to create libmodbus context\n");
                    res = 1;
    }
    else
    {
        printf("created libmodbus context\n");
        modbus_set_debug(ctx, TRUE);
        //modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK |MODBUS_ERROR_RECOVERY_PROTOCOL);
        rc = modbus_set_slave(ctx, 1);
        printf("modbus_set_slave return: %d\n",rc);
        if (rc != 0)
        {
            printf("modbus_set_slave: %s \n",modbus_strerror(errno));
        }

        /* Commented - Giving 'Bad File Descriptor' issue
        rc = modbus_rtu_set_serial_mode(ctx, MODBUS_RTU_RS485);
        printf("modbus_rtu_set_serial_mode: %d \n",rc);

        if (rc != 0)
        {
            printf("modbus_rtu_set_serial_mode: %s \n",modbus_strerror(errno));
        }
        */

        // This code is for version 3.0.6
        modbus_get_response_timeout(ctx, &response_timeout); 
        printf("Default response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );

        response_timeout.tv_sec = 60;
        response_timeout.tv_usec = 0;

        modbus_set_response_timeout(ctx, &response_timeout); 
        modbus_get_response_timeout(ctx, &response_timeout); 
        printf("Set response timeout:%ld sec %ld usec \n", response_timeout.tv_sec, response_timeout.tv_usec );


        /* This code is for version 3.1.2
        modbus_get_response_timeout(ctx, &tv_sec, &tv_usec); 
        printf("Default response timeout:%d sec %d usec \n",tv_sec,tv_usec );

        tv_sec = 60;
        tv_usec = 0;

        modbus_set_response_timeout(ctx, tv_sec,tv_usec); 
        modbus_get_response_timeout(ctx, &tv_sec, &tv_usec); 
        printf("Set response timeout:%d sec %d usec \n",tv_sec,tv_usec );
        */

        rc = modbus_connect(ctx);
        printf("modbus_connect: %d \n",rc);

        if (rc == -1) {
            printf("Connection failed: %s\n", modbus_strerror(errno));
            res = 1;
        }

        rc = modbus_read_registers(ctx, 3908, 2, tab_reg);
        printf("modbus_read_registers: %d \n",rc);

        if (rc == -1) {
            printf("Read registers failed:  %s\n", modbus_strerror(errno));
            res = 1;
        }

        for (i=0; i < 2; i++) {
            printf("reg[%d]=%d (0x%X)\n", i, tab_reg[i], tab_reg[i]);
        }

        avgVLL = modbus_get_float(tab_reg);

        printf("Average Line to Line Voltage = %f\n", avgVLL);

        modbus_close(ctx);
        modbus_free(ctx);
    }
}



Output of this sample is as follows:
created libmodbus context
modbus_set_slave return: 0
modbus_rtu_set_serial_mode: -1 
modbus_rtu_set_serial_mode: Bad file descriptor 
Default response timeout:0 sec 500000 usec 
Set response timeout:60 sec 0 usec 
Opening /dev/ttyUSB0 at 19200 bauds (E, 8, 1)
modbus_connect: 0 
[01][03][0F][44][00][02][87][0A]
Waiting for a confirmation...
ERROR Connection timed out: select
<01><03><0F><44><00><02><87><0A><01><03><04><C4><5F><43><D4><C6><7E>modbus_read_registers: -1 
Read registers failed:  Connection timed out
reg[0]=0 (0x0)
reg[1]=0 (0x0)
Average Line to Line Voltage = 0.000000
\$\endgroup\$
  • \$\begingroup\$ when some function returns an error indication, why is the code continuing as if the function were successful? \$\endgroup\$ – user3629249 Aug 30 '15 at 5:26
  • \$\begingroup\$ the variable errno is modified by EVERY system call, so when a modbus function is called, if there is an error indication returned, handle the error immediately, because the defining value will be overlayed by a intervening call to printf() \$\endgroup\$ – user3629249 Aug 30 '15 at 5:57
1
\$\begingroup\$

I guess something is wrong with the connection, I mean hardware of RS485 or the device driver. You shouldn't receive while transmitting, this is done with RTS pin and electronic switch inside rs485 transceiver. Also the port shall use halfduplex. Trace how come the TX signal comes at RX.

\$\endgroup\$
1
\$\begingroup\$

"Bad File Descriptor" is not one of the return values for the modbus_rtu_set_serial_mode function (see here). It's an error returned by ioctl() and likely indicates that you don't have the proper privileges to modify communications on /dev/ttyUSB0. Since that's happening, all of your calls to read/write registers are going to time-out because the mode is incorrect and your modbus slave isn't able to interpret the commands or give a proper response. Ensure that you have access to /dev/ttyUSB0 and if not, either change permissions in the file system or run your program as a user with proper access to /dev/ttyUSB0.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.