Как рассчитать этот CRC с помощью Python? - PullRequest
0 голосов
/ 18 ноября 2018

Мне нужно рассчитать этот CRC с использованием Python для связи с солнечным инвертором Aurora (ABB).

Это документ: http://www.drhack.it/images/PDF/AuroraCommunicationProtocol_4_2.pdf на последней странице есть инструкции для расчета CRC, мне нужно сделать это на python.

Сообщение, которое у меня есть,

MESSAGE_GRID_VOLTAGE = bytes.fromhex("023b010000000000")

Результаты должны быть:

CRC_L = FF

CRC_H = 2C

Затем мне нужно отправить сообщение с CRC, например:

MESSAGE_GRID_VOLTAGE = bytes.fromhex("023b010000000000ff2c")

Как я могу сделать это в Python? Спасибо!

Вот код, который я попробовал:

message = "023b010000000000"

BccLo= int ("FF",16)
BccHi= int("FF", 16)

New = int(message, 16)

New = New ^ BccLo
Tmp=New << 4
New=Tmp ^ New
Tmp=New >> 5
BccLo=BccHi
BccHi= New ^ Tmp
Tmp=New << 3
BccLo=BccLo ^ Tmp
Tmp=New >> 4
BccLo=BccLo ^ Tmp

CRC_L = ~BccLo
CRC_H = ~BccHi

Ответы [ 2 ]

0 голосов
/ 18 ноября 2018

Согласно цитируемому документу, алгоритм на самом деле является стандартным 16-битным CCITT CRC. Это можно рассчитать с помощью Python 'стандарт crcmod.

Вот, пожалуйста,

import crcmod

# this is a standard CCITT CRC even if it does not look like
# (crcmod applies xorOut to initCrc, so initCrc is in reality 0xffff, not 0)
_CRC_FUNC = crcmod.mkCrcFun(0x11021, initCrc=0, xorOut=0xffff)

data = bytearray.fromhex("023b010000000000")
crc = _CRC_FUNC(data)
data.append(crc & 0xff)
data.append(((crc >> 8) & 0xff))

print (data.hex())

Выход: 023b010000000000ff2c

0 голосов
/ 18 ноября 2018

Вам необходимо применить этот алгоритм к каждому байту вашего сообщения. Небольшое усложнение заключается в том, что алгоритм, приведенный в PDF-файле Aurora, предполагает, что вычисление выполняется с использованием 8-битной арифметики без знака. Чтобы справиться с этим в Python, мы можем использовать битовую маску 0xff. Вот слегка оптимизированная версия этого кода.

def crc_16(msg):
    lo = hi = 0xff
    mask = 0xff
    for new in msg:
        new ^= lo
        new ^= (new << 4) & mask
        tmp = new >> 5
        lo = hi
        hi = new ^ tmp
        lo ^= (new << 3) & mask
        lo ^= new >> 4
    lo ^= mask
    hi ^= mask
    return hi << 8 | lo

# Test

msg = bytes.fromhex("023b010000000000")
out = crc_16(msg)
hi, lo = out >> 8, out & 0xff
print('{:04x} = {:02x} {:02x}'.format(out, hi, lo))

выход

2cff = 2c ff

Приведенный выше код работает, но существуют более простые способы вычисления CRC. И мы можем использовать таблицу для ускорения процесса, если вам нужно рассчитать много CRC.

Как упоминается в статье Википедии Проверка циклической избыточности , алгоритмы CRC обычно задаются в виде полинома, закодированного в виде шестнадцатеричного числа. Вот функция, которая делает это, используя обратное полиномиальное представление.

def crc_16_CCITT(msg):
    poly = 0x8408
    crc = 0xffff
    for byte in msg:
        for _ in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ poly
            else:
                crc >>= 1
            byte >>= 1
    return crc ^ 0xffff

Чтобы ускорить процесс, мы можем вычислить таблицу.

def make_crc_table():
    poly = 0x8408
    table = []
    for byte in range(256):
        crc = 0
        for bit in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ poly
            else:
                crc >>= 1
            byte >>= 1
        table.append(crc)
    return table

table = make_crc_table()

def crc_16_fast(msg):
    crc = 0xffff
    for byte in msg:
        crc = table[(byte ^ crc) & 0xff] ^ (crc >> 8)
    return crc ^ 0xffff

# Test

msg = bytes.fromhex("023b010000000000")
out = crc_16_fast(msg)
hi, lo = out >> 8, out & 0xff
print('{:04x} = {:02x} {:02x}'.format(out, hi, lo))

Если хотите, вы можете распечатать таблицу и вставить ее в свой скрипт, чтобы вам не приходилось вычислять таблицу каждый раз, когда вы запускаете скрипт.

...