Вычисление CRC для Modbus RTU

Ха! Вот, удивил!

Та, не-е! Совсем не собирался никого удивлять. Просто возникла такая необходимость — написать быстренько прогу, которая посылает/принимает пакеты по Modbus. Ну, на одном предприятии случилась крупная авария, пострадало оборудование. Теперь это оборудование нужно как-то «поднимать». Что-то там работает, что — нет. В общем понадобилась тестилка, с функцией эмуляции. Ничего уже готового и проверенного, естественно, нет. Практика показывает, что в таких случаях получается быстрее состряпать что-то самому, чем лазить по Всемирной помойке в поисках годных для употребления шмоток.

Написать-то сниффер, который «вынюхивает» пролетающие в сети для RS485 пакеты — не столь трудно. Нужно только уметь работать с питоновским пакетом serial. Может быть (если я не забуду, и мне не будет лениво) я приведу ниже код сниффера. А здесь я опубликую код функции, которая подсчитывает CRC. Честно говоря, то разнообразие питоновских программ для расчёта CRC, которое имеется в этих ваших тырнетах, на меня наводит дикую тоску и печаль. Такое ощущение, что авторы тырили друг у друга код, не понимая как он работает. В общем, посмотрев эту порнографию я решил изобрести свой «велисапед».

Денег за не него требую и копирайт не ставлю — берите и пользуйтесь, кому надо! Единственное пожелание — в качестве оплаты помогите тому, кто ниже вас социально и хочет приподняться. Просто, будьте человечными по отношению к другим людям! Собственно, это всё!

Код-под-катом. Простите за каламбур!

#!/usr/bin/env python3


''' modbus_crc16.py '''


HIBYTE = b'\
\x00\xC0\xC1\x01\xC3\x03\x02\xC2\xC6\x06\x07\xC7\x05\xC5\xC4\x04\
\xCC\x0C\x0D\xCD\x0F\xCF\xCE\x0E\x0A\xCA\xCB\x0B\xC9\x09\x08\xC8\
\xD8\x18\x19\xD9\x1B\xDB\xDA\x1A\x1E\xDE\xDF\x1F\xDD\x1D\x1C\xDC\
\x14\xD4\xD5\x15\xD7\x17\x16\xD6\xD2\x12\x13\xD3\x11\xD1\xD0\x10\
\xF0\x30\x31\xF1\x33\xF3\xF2\x32\x36\xF6\xF7\x37\xF5\x35\x34\xF4\
\x3C\xFC\xFD\x3D\xFF\x3F\x3E\xFE\xFA\x3A\x3B\xFB\x39\xF9\xF8\x38\
\x28\xE8\xE9\x29\xEB\x2B\x2A\xEA\xEE\x2E\x2F\xEF\x2D\xED\xEC\x2C\
\xE4\x24\x25\xE5\x27\xE7\xE6\x26\x22\xE2\xE3\x23\xE1\x21\x20\xE0\
\xA0\x60\x61\xA1\x63\xA3\xA2\x62\x66\xA6\xA7\x67\xA5\x65\x64\xA4\
\x6C\xAC\xAD\x6D\xAF\x6F\x6E\xAE\xAA\x6A\x6B\xAB\x69\xA9\xA8\x68\
\x78\xB8\xB9\x79\xBB\x7B\x7A\xBA\xBE\x7E\x7F\xBF\x7D\xBD\xBC\x7C\
\xB4\x74\x75\xB5\x77\xB7\xB6\x76\x72\xB2\xB3\x73\xB1\x71\x70\xB0\
\x50\x90\x91\x51\x93\x53\x52\x92\x96\x56\x57\x97\x55\x95\x94\x54\
\x9C\x5C\x5D\x9D\x5F\x9F\x9E\x5E\x5A\x9A\x9B\x5B\x99\x59\x58\x98\
\x88\x48\x49\x89\x4B\x8B\x8A\x4A\x4E\x8E\x8F\x4F\x8D\x4D\x4C\x8C\
\x44\x84\x85\x45\x87\x47\x46\x86\x82\x42\x43\x83\x41\x81\x80\x40'

LOBYTE = b'\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x01\xC0\x80\x41\x00\xC1\x81\x40\x00\xC1\x81\x40\x01\xC0\x80\x41\
\x00\xC1\x81\x40\x01\xC0\x80\x41\x01\xC0\x80\x41\x00\xC1\x81\x40'


def crc16(data : b'') -> ():
    crchi = 0xFF
    crclo = 0xFF
    index = 0

    for byte in data :
        index = crchi ^ int(byte)
        crchi = crclo ^ LOBYTE[index]
        crclo = HIBYTE[index]
        
    # print("{0:02X} {1:02X}".format(crclo, crchi))
    return crchi, crclo
    
    
if __name__ == "__main__":
    pass

Программа для примера использования функции и проверки правильности подсчётов контрольной суммы:

#!/usr/bin/env python3


''' test_modbus_crc16.py '''


from modbus_crc16 import crc16


if __name__ == "__main__":
    
    print("Примеры использования функции для подсчёта контрольной суммы")
    print()
    
    # Вычисляем CRC для пакетета
    hi, lo = crc16(b'\x02\x03\x00\x00\x00\x01')
    print("Вычисленная контрольная сумма пакета = {0:02X} {1:02X}".format(hi, lo)) # 84 39
    
    # Вычисление контрольной суммы полного пакет, с уже имеющейся в нём CRC, должно давать ноль
    hi, lo = crc16(b'\x02\x03\x02\x00\x00\xFC\x44')
    print("Вычисленная контрольная сумма полного пакета = {0:02X} {1:02X}".format(hi, lo)) # 00 00

    print()

    # Другие пакеты, у которых контрольная сумма уже известна
    hi, lo = crc16(b'\x01\x06\x03\xE9\x00\x00')      # CRC = b'\x58\x7A'
    print("{0:02X} {1:02X}".format(hi, lo))

    hi, lo = crc16(b'\x01\x86\x03')                  # CRC = b'\x02\x61'
    print("{0:02X} {1:02X}".format(hi, lo))
  
    hi, lo = crc16(b'\x01\x03\x49\x15\x00\x01')      # CRC = b'\x83\x92'
    print("{0:02X} {1:02X}".format(hi, lo))
  
    hi, lo = crc16(b'\x01\x03\x00\x00\x00\x0A')      # CRC = b'\xC5\xCD'
    print("{0:02X} {1:02X}".format(hi, lo))

    hi, lo = crc16(b'\x01\x01\x00\x00\x00\x0A')      # CRC = b'\xBC\x0D'
    print("{0:02X} {1:02X}".format(hi, lo))

    hi, lo = crc16(b'\x01\01\x02\00\x00')            # CRC = b'\xB9\xFC'
    print("{0:02X} {1:02X}".format(hi, lo))

    hi, lo = crc16(b'\x01\x06\x00\x01\x00\x7B')      # CRC = b'\x98\x29'
    print("{0:02X} {1:02X}".format(hi, lo))

    hi, lo = crc16(b'\x01\x10\x00\x00\x00\x0A')      # CRC = b'\x40\x0E'
    print("{0:02X} {1:02X}".format(hi, lo))

    print()

    hi, lo = crc16(b'\x01\x03\x00\x00\x00\x0A\xC5\xCD') # == 00 00
    print("{0:02X} {1:02X}".format(hi, lo))

    hi, lo = crc16(b'\x01\x01\x00\x00\x00\x0A\xBC\x0D') # == 00 00'
    print("{0:02X} {1:02X}".format(hi, lo))

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s