Britkat1980
Britkat1980

Reputation: 23

Python Minimal Modbus CRC byte order

I'm looking to use Minimal Modbus to connect to my Solar Invertor (GivEnergy) via an RS485-USB adaptor. Unfortunately the implementation of the Modbus Protocol has reversed the CRC bytes, so Minimal Modbus fails on the CRC check. Is there a way of reversing the CRC bytes in the call, perhaps with an option flag, or can I manually build the CRC and inject my own?

Upvotes: 2

Views: 746

Answers (1)

Marcos G.
Marcos G.

Reputation: 3516

You don't need to inject your own CRC, that would be more difficult than in fact is to solve your problem (you are free to do it if you want of course).

Just change this line in your minimalmodbus.py:

return _num_to_twobyte_string(register, lsb_first=True)

to:

return _num_to_twobyte_string(register, lsb_first=False)

You can find the location of the file running this command: python -m site and looking for the site-packages folder.

On most Linux distros with Python 3.x the folder is:

'/home/your_user_name/.local/lib/python3.x/site-packages'

If you are asking why should you be messing with the code, you are not alone. While I was musing that very same question myself (after writing this answer I swear) I found this issue.

I guess the short answer is: you should be complaining to the developers of your device.

For completeness: if you don't want to edit minimalmodbus.py as the answer to the issue recommends you should just overload the whole _calculate_crc_string(inputstring) function changing the last line as I wrote above.

For total completeness, I'm adding the code on the link above here. To overload the function just write all its code again in your Python script right after you import minimalmodbus:

import minimalmodbus

def _calculate_crc_string(inputstring):
    """Calculate CRC-16 for Modbus.

    Args:
        inputstring (str): An arbitrary-length message (without the CRC).

    Returns:
        A two-byte CRC string, where the least significant byte is first.

    """
    minimalmodbus._check_string(inputstring, description="input CRC string")

    # Preload a 16-bit register with ones
    register = 0xFFFF

    for char in inputstring:
        register = (register >> 8) ^ minimalmodbus._CRC16TABLE[(register ^ ord(char)) & 0xFF]

    return minimalmodbus._num_to_twobyte_string(register, lsb_first=False)

minimalmodbus._calculate_crc_string = _calculate_crc_string

Note the last line outside of the function to overload the _calculate_crc_string. After that, you can add the rest of your code.

Upvotes: 3

Related Questions