Skip to content

Modbus RTU client never recovers if bad serial line. Filling buffer. #356

@Jendem

Description

@Jendem

Versions

  • Python: 2.7
  • OS: Gentoo Linux
  • Pymodbus: 1.5.2 and 2.1.0
  • Modbus Hardware (if used): PLC using Modbus RTU over RS-485

Pymodbus Specific

  • Server: rtu - async

Description

What were you trying:

Modbus client on PLC is writing to pymodbus server using code 16 (Write Multiple Registers). If the serial line is disconnected and then connected again, the RTU framer never passes its checkFrame(self) method.

Code and Logs

Adding some logging to the file rtu_framer.py:

def checkFrame(self):
    """
    Check if the next frame is available.
    Return True if we were successful.

    1. Populate header
    2. Discard frame if UID does not match
    """
    try:
        self.populateHeader()
        _logger.debug("self._header: %s" % self._header)

        frame_size = self._header['len']
        _logger.debug("frame_size: %s" % frame_size)
        _logger.debug("buffer_size: %s" % len(self._buffer))
        data = self._buffer[:frame_size - 2]
        _logger.debug("data: %s" % hexlify_packets(data))

        crc = self._buffer[frame_size - 2:frame_size]
        _logger.debug("crc: %s" % hexlify_packets(crc))

        crc_val = (byte2int(crc[0]) << 8) + byte2int(crc[1])
        _logger.debug("crc_val: %s" % crc_val)
        return checkCRC(data, crc_val)
    # except (IndexError, KeyError):
    except Exception as ex:
        return False

What did you expect?
A normal log is like this:
The buffer grows until the package is complete, in this case to 33 elements.

factory:Factory Request[16]
framer.rtu_framer:Frame advanced, resetting header!!
framer.rtu_framer:self._header: {'crc': '', 'uid': 5, 'len': 33}
framer.rtu_framer:frame_size: 33
framer.rtu_framer:buffer_size: 8
framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0xc4
framer.rtu_framer:crc: 
framer.rtu_framer:RTU checkFrame: FALSE

server.async:Data Received: 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4
framer.rtu_framer:RTU isFrameReady:TRUE
framer.rtu_framer:self._header: {'crc': '', 'uid': 5, 'len': 33}
framer.rtu_framer:frame_size: 33
framer.rtu_framer:buffer_size: 16
framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4
framer.rtu_framer:crc: 
framer.rtu_framer:RTU checkFrame: FALSE

server.async:Data Received: 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4
framer.rtu_framer:RTU isFrameReady:TRUE
framer.rtu_framer:self._header: {'crc': '', 'uid': 5, 'len': 33}
framer.rtu_framer:frame_size: 33
framer.rtu_framer:buffer_size: 24
framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4
framer.rtu_framer:crc: 
framer.rtu_framer:RTU checkFrame: FALSE

server.async:Data Received: 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0x41
framer.rtu_framer:RTU isFrameReady:TRUE
framer.rtu_framer:self._header: {'crc': 'A', 'uid': 5, 'len': 33}
framer.rtu_framer:frame_size: 33
framer.rtu_framer:buffer_size: 32
framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc
framer.rtu_framer:crc: 0x41
framer.rtu_framer:RTU checkFrame: FALSE

server.async:Data Received: 0x35
framer.rtu_framer:RTU isFrameReady:TRUE
framer.rtu_framer:self._header: {'crc': 'A5', 'uid': 5, 'len': 33}
framer.rtu_framer:frame_size: 33
framer.rtu_framer:buffer_size: 33
framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc
framer.rtu_framer:crc: 0x41 0x35
framer.rtu_framer:crc_val: 16693
framer.rtu_framer:RTU checkFrame:TRUE
framer.rtu_framer:Getting Frame - 0x10 0x0 0xc8 0x0 0xc 0x18 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc 0xc4 0xc

What has happened, what went wrong
If the communication is broken, the buffer grows, because the CRC vil never match.
Notice the last two bytes 0x18 0x3a are wrong in the first pymodbus.server.async:Data Received log.

pymodbus.factory:Factory Request[16]
pymodbus.framer.rtu_framer:Frame advanced, resetting header!!
pymodbus.datastore.context:validate[16] 200:12
pymodbus.datastore.context:setValues[16] 200:12
pymodbus.server.async:send: 051000c8000c4076
modbus-slave:Data received.
pymodbus.server.async:Data Received: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a
pymodbus.framer.rtu_framer:RTU isFrameReady:TRUE
pymodbus.framer.rtu_framer:self._header: {'crc': '', 'uid': 5, 'len': 33}
pymodbus.framer.rtu_framer:frame_size: 33
pymodbus.framer.rtu_framer:buffer_size: 8
pymodbus.framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a
pymodbus.framer.rtu_framer:crc: 
pymodbus.framer.rtu_framer:RTU checkFrame: FALSE

pymodbus.server.async:Data Received: 0x18 0x3a 0x98 0xff
pymodbus.framer.rtu_framer:RTU isFrameReady:TRUE
pymodbus.framer.rtu_framer:self._header: {'crc': '', 'uid': 5, 'len': 33}
pymodbus.framer.rtu_framer:frame_size: 33
pymodbus.framer.rtu_framer:buffer_size: 12
pymodbus.framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a 0x18 0x3a 0x98 0xff
pymodbus.framer.rtu_framer:crc: 
pymodbus.framer.rtu_framer:RTU checkFrame: FALSE

pymodbus.server.async:Data Received: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x50
pymodbus.framer.rtu_framer:RTU isFrameReady:TRUE
pymodbus.framer.rtu_framer:self._header: {'crc': '', 'uid': 5, 'len': 33}
pymodbus.framer.rtu_framer:frame_size: 33
pymodbus.framer.rtu_framer:buffer_size: 20
pymodbus.framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a 0x18 0x3a 0x98 0xff 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x50
pymodbus.framer.rtu_framer:crc: 
pymodbus.framer.rtu_framer:RTU checkFrame: FALSE

pymodbus.server.async:Data Received: 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50
pymodbus.framer.rtu_framer:RTU isFrameReady:TRUE
pymodbus.framer.rtu_framer:self._header: {'crc': '', 'uid': 5, 'len': 33}
pymodbus.framer.rtu_framer:frame_size: 33
pymodbus.framer.rtu_framer:buffer_size: 28
pymodbus.framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a 0x18 0x3a 0x98 0xff 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50
pymodbus.framer.rtu_framer:crc: 
pymodbus.framer.rtu_framer:RTU checkFrame: FALSE

pymodbus.server.async:Data Received: 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50
pymodbus.framer.rtu_framer:RTU isFrameReady:TRUE
pymodbus.framer.rtu_framer:self._header: {'crc': 'P8', 'uid': 5, 'len': 33}
pymodbus.framer.rtu_framer:frame_size: 33
pymodbus.framer.rtu_framer:buffer_size: 36
pymodbus.framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a 0x18 0x3a 0x98 0xff 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38
pymodbus.framer.rtu_framer:crc: 0x50 0x38
pymodbus.framer.rtu_framer:crc_val: 20536
pymodbus.framer.rtu_framer:RTU checkFrame: FALSE

pymodbus.server.async:Data Received: 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x53
pymodbus.framer.rtu_framer:RTU isFrameReady:TRUE
pymodbus.framer.rtu_framer:self._header: {'crc': 'P8', 'uid': 5, 'len': 33}
pymodbus.framer.rtu_framer:frame_size: 33
pymodbus.framer.rtu_framer:buffer_size: 44
pymodbus.framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a 0x18 0x3a 0x98 0xff 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38
pymodbus.framer.rtu_framer:crc: 0x50 0x38
pymodbus.framer.rtu_framer:crc_val: 20536
pymodbus.framer.rtu_framer:RTU checkFrame: FALSE

pymodbus.server.async:Data Received: 0x99
pymodbus.framer.rtu_framer:RTU isFrameReady:TRUE
pymodbus.framer.rtu_framer:self._header: {'crc': 'P8', 'uid': 5, 'len': 33}
pymodbus.framer.rtu_framer:frame_size: 33
pymodbus.framer.rtu_framer:buffer_size: 45
pymodbus.framer.rtu_framer:data: 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x3a 0x18 0x3a 0x98 0xff 0x5 0x10 0x0 0xc8 0x0 0xc 0x18 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38 0x50 0x38
pymodbus.framer.rtu_framer:crc: 0x50 0x38
pymodbus.framer.rtu_framer:crc_val: 20536
pymodbus.framer.rtu_framer:RTU checkFrame: FALSE

What did you expect?
Some kind of reset if the buffer grows larger than the expected size.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions