stephane / libmodbus

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

Modbus ASCII issue, #425

Open Ashis-Github opened 6 years ago

Ashis-Github commented 6 years ago

Please read the following carefully before submitting this new issue.

When you get here and you are still convinced that you want report a bug:

Good bug reports provide right and quick fixes!

Finally, thank you very much for using libmodbus and taking the time to file a good bug report. Doing so signals your respect for the developers.

The following template helps you to address the points above. Please delete everything up to and including the following line which starts with ---.


libmodbus version

## OS and/or distribution ## Environment ## Description <...> ## Expected behaviour <...> ## Actual behaviour <...> ## Steps to reproduce the behavior (commands or source code) <...> ## libmodbus output with debug mode enabled <...>
Ashis-Github commented 6 years ago

I'm using libmodbus for ASCII. I'm able to send the request but i'm not getting any response. Can you please help. here is my code below.

modbus_t *ctx = modbus_new_ascii("COM4", 9600, 'N', 8, 1);
int retVal = modbus_set_slave(ctx, 1);
if (retVal == -1)
{
    // no error
}
retVal = modbus_connect(ctx);
if (retVal == -1)
{
    // no error
}

uint16_t tab_reg[32];
memset(tab_reg, 0, 1 * sizeof(tab_reg));

retVal = modbus_read_registers(ctx, 25,1, tab_reg);
if (retVal == -1)
{
    // retrun -1 always
}
karlp commented 6 years ago

What does the documentation for modbus_read_registers say? What would a negative value for parameter number 3 mean?

Ashis-Github commented 6 years ago
  1. My appology, this is type error.@karlp
  2. While sending this info to slave, I have monitored the port(COM4), it looks like timeout error. Can anyone suggest why it's that. Did I miss anything.
  3. It throws MODBUS_EXCEPTION_GATEWAY_TARGET exception. what's this mean.
karlp commented 6 years ago

most likely the remote device doesn't understand you and ignored you. You are either using the wrong protocol, wrong wiring (on the other side of your gateway) or have the wrong configuration of your gateway/port/device itself. I don't believe you have any issue that can be resovled with libmodbus tickets though.

Ashis-Github commented 6 years ago

By considering your input i have sent the same Ascii frame to the same remote device by using some other external modus send tool. Im getting respnse in this way. So here we can't say this is the problem with remote device or any configuration issue.

karlp commented 6 years ago

I would guess you didn't send the same frame then :) if you turn on libmodbus' debug, you can see the bytes sent and received printed out. You can compare that with what your other tool has done.

Ashis-Github commented 6 years ago

I have send the same request(:010300190001E3) using libmodbus dll from my client code. I have used some external tool to monitor that particular port, I'm getting response i.e. :0103020903 and status is always success. But in the libmodbus dll client code I'm getting always return value -1. That means device sending response. But my libmodbus dll is unable to handle this response. Correct me if I'm wrong. If something I can look into the dll code, pls let me know.

KorlaMarch commented 5 years ago

Hi guys,

I have a similar problem in Modbus Ascii. In short, modbus_connect works correctly, but a subsequent call to modbus_write_bit yields -1.

The debug mode told that the library have received the confirmation incorrectly. After looking into the error, I have found that the problem originate from _modbus_receive_msg in modbus.c. _modbus_receive_msg somehow reads a wrong massage from a serial port (and sometime incomplete) An external tool confirms that a device sends back right confirmation.

A quick workaround for this would be to change

while (length_to_read != 0) { rc = ctx->backend->select(ctx, &rset, p_tv, length_to_read); if (rc == -1) {

in modbus.c line 386 to

while (length_to_read != 0) { rc = ctx->backend->select(ctx, &rset, p_tv, 1); if (rc == -1) {

I don't know how or why this works and the previous one doesn't. The error only happened in windows. Maybe something about windows' API?

Moinelly commented 5 years ago

@Ashis-Github where did you get modbus_ascii function from, i have been trying it here and i couldn't get anything. Can you help me out here. Thank you!

DLFenFen commented 2 years ago

@Ashis-Github @Moinelly I would like to know, where there modbus_ascii function, the latest libmodbus, I did not find.

blackpencil2019 commented 2 years ago

Hi guys,

I have a similar problem in Modbus Ascii too in 2022! I think the library in Windows have received the confirmation incorrectly indeed.

The library uses win32_ser_select to receive a msg from a serial port and win32_ser_read to read the msg from win32_ser.buf. win32_ser_select may receive some bytes according to length_to_read in modbus.c and _modbus_ascii_recv (calls win32_ser_read)read character by character to convert each character into byte, but when reading character from the win32_ser.buf, memcpy starts with the same source address(win32_ser.buf[0]) every time(in modbus-serial.c, line 111). That means if win32_ser_select receives data ':01', _modbus_ascii_recv may convert it to ':::' wrongly. That's the problem.

@KorlaMarch 's quick workaround works since win32_ser_select always receives one character now. Another way to avoid this problem is to add a pointer to struct win32_ser to save the position every time the libarary calls win32_ser_read. I have no idea which is better...

Add pos in modbus-serial-private.h

struct win32_ser {
    /* File handle */
    HANDLE fd;
    /* Receive buffer */
    uint8_t buf[PY_BUF_SIZE];
    /* Received chars */
    DWORD n_bytes;
    /* win32_ser_read position */
    uint8_t* pos;
};

change pos in win32_ser_read

int win32_ser_read(struct win32_ser *ws, uint8_t *p_msg,
                   unsigned int max_len)
{
    unsigned int n = ws->n_bytes;
    if (max_len < n) {
        n = max_len;
    }
    if (ws->pos - ws->buf > PY_BUF_SIZE || ws->pos -ws->buf < -PY_BUF_SIZE) {
        assert(0);
        ws->pos = ws->buf;
    }
    if (n > 0) {
        memcpy(p_msg, ws->pos, n);
    }
    ws->n_bytes -= n;
    ws->pos += n;
    return n;
}

reset pos when receiving new message

if (ReadFile(ws->fd, &ws->buf, max_len, &ws->n_bytes, NULL)) {
    /* Check if some bytes available */
    if (ws->n_bytes > 0) {
        /* Some bytes read */
    ws->pos = ws->buf;
        return 1;
    } else {
        /* Just timed out */
        return 0;
    }
} else {