Skip to content

Commit

Permalink
update modbusrtuframer.
Browse files Browse the repository at this point in the history
Co-authored-by: dlmoffett
  • Loading branch information
janiversen committed Mar 21, 2023
1 parent 1cedc47 commit a487a8c
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 5 deletions.
37 changes: 37 additions & 0 deletions pymodbus/framer/patched_rtuframer
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import logging

from pymodbus.framer.rtu_framer import ModbusRtuFramer


log = logging.getLogger(__name__)


class PatchedModbusRtuFramer(ModbusRtuFramer):

def processIncomingPacket(self, data, callback, unit, **kwargs):
if not isinstance(unit, (list, tuple)):
unit = [unit]
self.addToFrame(data)
single = kwargs.get("single", False)
while True:
if not self.isFrameIntendedForUs(unit):
if self.advanceToNextOccurrenceOfUnit(unit) == 0:
log.info(f"❌ Frame - [{data}] not intended for us, ignoring!!")
break
elif self.isFrameReady():
if self.checkFrame():
if self._validate_unit_id(unit, single):
self._process(callback)
log.info(f"✅ Frame - [{data}] responded to!!")
else:
header_txt = self._header["uid"]
log.info(f"Not a valid unit id - {header_txt}, ignoring!!")
self.resetFrame()
break
else:
log.info("Frame check failed, ignoring!!")
if self.advanceToNextOccurrenceOfUnit(unit) == 0:
break
else:
log.info(f"Frame - [{data}] not ready")
break
32 changes: 29 additions & 3 deletions pymodbus/framer/rtu_framer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# pylint: disable=missing-type-doc
import struct
import time
from typing import List

from pymodbus.exceptions import (
InvalidMessageReceivedException,
Expand Down Expand Up @@ -87,6 +88,16 @@ def checkFrame(self):
try:
self.populateHeader()
frame_size = self._header["len"]

if len(self._buffer) > frame_size:
# This means there are bytes *after* a valid frame intended to us.
# If there are bytes after that means we've probably de-sychronized
# and the master has considered us as having timed out and moved on.
# That or there is somehow a random sequence of bytes which looks like
# a real command to us and magically a crc.
# In either case, we must not respond.
return False

data = self._buffer[: frame_size - 2]
crc = self._header["crc"]
crc_val = (int(crc[0]) << 8) + int(crc[1])
Expand Down Expand Up @@ -191,6 +202,24 @@ def populateResult(self, result):
result.slave_id = self._header["uid"]
result.transaction_id = self._header["uid"]

def isFrameIntendedForUs(self, slaves: List[int]):
"""Check slave ID of frame."""
try:
return self._buffer[0] in slaves
except IndexError:
return True

def advanceToNextOccurrenceOfUnit(self, slaves: List[int]):
"""Skip to next slave id."""
newbuf = b""
for i, databyte in enumerate(self._buffer):
if databyte in slaves and i > 0:
newbuf = self._buffer[i:]
break
self._buffer = newbuf
self._header = {"uid": 0x00, "len": 0, "crc": b"\x00\x00"}
return len(self._buffer)

# ----------------------------------------------------------------------- #
# Public Member Functions
# ----------------------------------------------------------------------- #
Expand Down Expand Up @@ -331,6 +360,3 @@ def get_expected_response_length(self, data):
func_code = int(data[1])
pdu_class = self.decoder.lookupPduClass(func_code)
return pdu_class.calculateRtuFrameSize(data)


# __END__
1 change: 0 additions & 1 deletion test/test_client_multidrop.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ def test_wrapped_frame(self, framer, callback):
# and the master moved on and queried another device
callback.assert_not_called()

@pytest.mark.skip
def test_frame_with_trailing_data(self, framer, callback):
"""Test trailing data."""
garbage = b"\x05\x04\x03\x02\x01\x00"
Expand Down
2 changes: 1 addition & 1 deletion test/test_framers.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ def test_populate_result(rtu_framer): # pylint: disable=redefined-outer-name
True,
False,
), # incorrect slave id
(b"\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD\x11\x03", 17, False, True),
(b"\x11\x03\x06\xAE\x41\x56\x52\x43\x40\x49\xAD\x11\x03", 17, True, False),
# good frame + part of next frame
],
)
Expand Down

0 comments on commit a487a8c

Please sign in to comment.