stephane / libmodbus

A Modbus library for Linux, Mac OS, FreeBSD and Windows
http://libmodbus.org
GNU Lesser General Public License v2.1
3.29k stars 1.71k forks source link

indication timeout in server mode times out while receiving master message #712

Open martinwag opened 10 months ago

martinwag commented 10 months ago

libmodbus version

Git https://github.com/stephane/libmodbus/commit/b25629bfb508bdce7d519884c0fa9810b7d98d44 (Head as of 2023-08-10)

OS and/or distribution

Linux Debian 11

Environment

x86 32bit gcc (Debian 10.2.1-6) 10.2.1 20210110

Description

when using server mode with an indication timeout set by modbus_get_indication_timeout(), sometimes the indication timeout expires while a client message is currently being received. In my use case (indication timeout 250ms) this leads to a few failed client request per minute (client does one request per second, 9600baud).

Expected behavior or suggestion

When a message reception is active (first byte(s) already read from socket), finish it instead of timing out.

I've fixed it for test like this:

int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
{
...
    if (msg_type == MSG_INDICATION) {
        /* By default, the indication timeout isn't set */
        p_tv = NULL;
    } else {
        tv.tv_sec = ctx->response_timeout.tv_sec;
        tv.tv_usec = ctx->response_timeout.tv_usec;
        p_tv = &tv;
    }

    while (length_to_read != 0) {

        if (ctx->indication_timeout.tv_sec != 0 || ctx->indication_timeout.tv_usec != 0) {
            /* Wait for an indication (name of a received request by a server, see schema)
             */
            tv.tv_sec = ctx->indication_timeout.tv_sec;
            tv.tv_usec = ctx->indication_timeout.tv_usec;
            p_tv = &tv;
        }
        rc = select(...)

...

This solution reloads the indication timeout for every select call. This might extend the timeout by quite a bit, so I don't know if this suggestion would be good for main branch. Be aware that this is only proof-of-concept, e.g. it conflicts with byte_timeout.

libmodbus output with debug mode enabled

ERROR Connection timed out: select
Waiting for an indication...
ERROR Connection timed out: select
Waiting for an indication...
ERROR Connection timed out: select
<2A><10><04>Waiting for an indication...
<4C><00><64><C8><49><CE><80><60>
Request for slave 76 ignored (not 42)
Waiting for a confirmation...
<42><78><9D><ED><83>
Request for slave 66 ignored (not 42)
Confirmation to ignore
Waiting for an indication...
<E4><80><00><B2>
Request for slave 228 ignored (not 42)
Waiting for a confirmation...
<3F><B2><40><B2><41>
Request for slave 63 ignored (not 42)
Confirmation to ignore
Waiting for an indication...
<B2><42><B2><43>

(there is some order mixup because ERROR... are written to stderr, other to stdout)