Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get the specific error message #133

Open
RobinGalipeau opened this issue Sep 25, 2024 · 1 comment
Open

How to get the specific error message #133

RobinGalipeau opened this issue Sep 25, 2024 · 1 comment

Comments

@RobinGalipeau
Copy link

Hi, I have a question, I am unable to extract the exact error message when a communication fail.
how to extract the exception code, a parity error message, bad CRC, or timeout?

Currently I can get the generic error flag but I don't understand how to evaluate the different cause.
my current code look like that:

 try :
         list = CImod.read_registers(14,2,4)
except IOError:
         print("COMs error occured")

thank you.

@pfrl
Copy link

pfrl commented Oct 7, 2024

Module exceptions are defined in minimalmodbus.py:

# ########## #
# Exceptions #
# ########## #


class ModbusException(IOError):
    """Base class for Modbus communication exceptions.

    Inherits from IOError, which is an alias for OSError in Python3.
    """


class SlaveReportedException(ModbusException):
    """Base class for exceptions that the slave (instrument) reports."""


class SlaveDeviceBusyError(SlaveReportedException):
    """The slave is busy processing some command."""


class NegativeAcknowledgeError(SlaveReportedException):
    """The slave can not fulfil the programming request.

    This typically happens when using function code 13 or 14 decimal.
    """


class IllegalRequestError(SlaveReportedException):
    """The slave has received an illegal request."""


class MasterReportedException(ModbusException):
    """Base class for exceptions that the master (computer) detects."""


class NoResponseError(MasterReportedException):
    """No response from the slave."""


class LocalEchoError(MasterReportedException):
    """There is some problem with the local echo."""


class InvalidResponseError(MasterReportedException):
    """The response does not fulfill the Modbus standad, for example wrong checksum."""


# ################ #
# Payload handling #
# ################ #

If you are interested in particular exception you could:

from minimalmodbus import NoResponseError

try:
    list = CImod.read_registers(14, 2, 4)
except NoResponseError:
    print("No response from device")
except IOError:
    print("Other communication error")

IOError is a parent class for all the excpetions so you should put it at the bottom in the exception except order.

  • CRC - InvalidResponseError
  • timeout NoResponseError

As far as I know Modbus exception codes are not explicitly passed to Exceptions in minimalmodbus.

In _check_response_slaveerrorcode appropriate excpetion and message is produced based on Modbus exception code. You could parse messages of those errors to extract exception code or fork the module and change this function to embed them into exceptions.

_check_response_slaveerrorcode
def _check_response_slaveerrorcode(response: bytes) -> None:
    """Check if the slave indicates an error.

    Args:
        * response: Response from the slave

    The response is in RTU format, but the checksum might be one or two bytes
    depending on whether it was sent in RTU or ASCII mode.

    Checking of type and length of the response should be done before calling
    this functions.

    Raises:
        SlaveReportedException or subclass
    """
    NON_ERRORS = [5]
    SLAVE_ERRORS = {
        1: IllegalRequestError("Slave reported illegal function"),
        2: IllegalRequestError("Slave reported illegal data address"),
        3: IllegalRequestError("Slave reported illegal data value"),
        4: SlaveReportedException("Slave reported device failure"),
        6: SlaveDeviceBusyError("Slave reported device busy"),
        7: NegativeAcknowledgeError("Slave reported negative acknowledge"),
        8: SlaveReportedException("Slave reported memory parity error"),
        10: SlaveReportedException("Slave reported gateway path unavailable"),
        11: SlaveReportedException(
            "Slave reported gateway target device failed to respond"
        ),
    }

    if len(response) < _BYTEPOSITION_FOR_SLAVE_ERROR_CODE + 1:
        return  # This check is also done before calling, do not raise exception here.

    received_functioncode = response[_BYTEPOSITION_FOR_FUNCTIONCODE]

    if _check_bit(received_functioncode, _BITNUMBER_FUNCTIONCODE_ERRORINDICATION):
        slave_error_code = response[_BYTEPOSITION_FOR_SLAVE_ERROR_CODE]

        if slave_error_code in NON_ERRORS:
            return

        error = SLAVE_ERRORS.get(
            slave_error_code,
            SlaveReportedException(
                "Slave reported error code " + str(slave_error_code)
            ),
        )
        raise error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants