From 4a818be9ee70eee19a5f9197ef27d2eca4a35155 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Wed, 10 Mar 2021 13:05:06 +0100 Subject: [PATCH 1/2] Fix docstring of pdu_to_function_code_or_raise_error(). --- umodbus/functions.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/umodbus/functions.py b/umodbus/functions.py index 4db3cec..f46b1a6 100644 --- a/umodbus/functions.py +++ b/umodbus/functions.py @@ -104,11 +104,10 @@ def pdu_to_function_code_or_raise_error(resp_pdu): - """ Parse response PDU and return of :class:`ModbusFunction` or - raise error. + """Parse response PDU and return function code or raise error. :param resp_pdu: PDU of response. - :return: Subclass of :class:`ModbusFunction` matching the response. + :return: Function code contained in the response. :raises ModbusError: When response contains error code. """ function_code = struct.unpack('>B', resp_pdu[0:1])[0] From 964d09f5bb0adb073e59a5d039f83f98c51c4853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Colomb?= Date: Wed, 10 Mar 2021 13:08:12 +0100 Subject: [PATCH 2/2] RTU: Check CRC before signalling an exception response. The first five response ADU bytes received are checked for a valid function code, assuming an error if it is unknown. The received ADU part is then treated as an exception frame. But even those must pass the CRC validation, otherwise the supposed "wrong" function code cannot even be trusted at all. This change adds the CRC check for the first five bytes, falling through to further processing when it fails. The overall CRC and function code is checked later in parse_response_adu(), so an invalid code will be detected again at that point. This is mainly relevant if the responses are received partially from the serial input buffer, which will cause many CRC and parsing failures. In those cases, the reported exception will likely be a CRCError or ValueError for the whole ADU, instead of an invalid function code based on only the first 5 bytes. --- umodbus/client/serial/rtu.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/umodbus/client/serial/rtu.py b/umodbus/client/serial/rtu.py index 4c01580..4ffe485 100644 --- a/umodbus/client/serial/rtu.py +++ b/umodbus/client/serial/rtu.py @@ -45,6 +45,7 @@ import struct from umodbus.client.serial.redundancy_check import get_crc, validate_crc +from umodbus.client.serial.redundancy_check import CRCError from umodbus.functions import (create_function_from_response_pdu, expected_response_pdu_size_from_request_pdu, pdu_to_function_code_or_raise_error, ReadCoils, @@ -199,7 +200,13 @@ def raise_for_exception_adu(resp_adu): :raises ModbusError: When a response contains an error code. """ resp_pdu = resp_adu[1:-2] - pdu_to_function_code_or_raise_error(resp_pdu) + try: + validate_crc(resp_adu) + pdu_to_function_code_or_raise_error(resp_pdu) + except CRCError: + # The response cannot be trusted at all, so ignore any + # possibly invalid function code. + pass def send_message(adu, serial_port):