From 9a9c91b401662c98a4e61ba7d4bf95ef1dfaffb7 Mon Sep 17 00:00:00 2001 From: Ryan Parry-Jones Date: Wed, 12 Dec 2018 18:10:01 +1100 Subject: [PATCH] Task Cancellation and CRC Errors Alternate solution for #356 and #360. Changes the RTU to make the transaction ID as the unit ID instead of an ever incrementing number. Previously this transaction ID was always 0 on the receiving end but was the unique transaction ID on sending. As such the FIFO buffer made the most sense. By tying it to the unit ID, we can recover from failure modes such as: - - Asyncio task cancellations (eg. timeouts) #360 - Skipped responses from slaves. (hangs on master #360) - CRC Errors #356 - Busy response --- pymodbus/client/sync.py | 5 +---- pymodbus/framer/rtu_framer.py | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pymodbus/client/sync.py b/pymodbus/client/sync.py index 01ca0fcbe..04af8a25c 100644 --- a/pymodbus/client/sync.py +++ b/pymodbus/client/sync.py @@ -39,10 +39,7 @@ def __init__(self, framer, **kwargs): :param framer: The modbus framer implementation to use """ self.framer = framer - if isinstance(self.framer, ModbusSocketFramer): - self.transaction = DictTransactionManager(self, **kwargs) - else: - self.transaction = FifoTransactionManager(self, **kwargs) + self.transaction = DictTransactionManager(self, **kwargs) self._debug = False self._debugfd = None diff --git a/pymodbus/framer/rtu_framer.py b/pymodbus/framer/rtu_framer.py index 4c343dbf9..fb808b125 100644 --- a/pymodbus/framer/rtu_framer.py +++ b/pymodbus/framer/rtu_framer.py @@ -186,6 +186,7 @@ def populateResult(self, result): :param result: The response packet """ result.unit_id = self._header['uid'] + result.transaction_id = self._header['uid'] # ----------------------------------------------------------------------- # # Public Member Functions @@ -221,6 +222,9 @@ def processIncomingPacket(self, data, callback, unit, **kwargs): _logger.debug("Not a valid unit id - {}, " "ignoring!!".format(self._header['uid'])) self.resetFrame() + else: + _logger.debug("Frame check failed, ignoring!!") + self.resetFrame() else: _logger.debug("Frame - [{}] not ready".format(data)) @@ -235,6 +239,7 @@ def buildPacket(self, message): message.unit_id, message.function_code) + data packet += struct.pack(">H", computeCRC(packet)) + message.transaction_id = message.unit_id # Ensure that transaction is actually the unit id for serial comms return packet def sendPacket(self, message):