Страница 1 из 1

Revert CRC

Добавлено: 12 фев 2011, 23:06
Oscar
может вопрос больше и к алгоритмам относится, но проблема возникла на C, потому пишу тут.

В данный момент я занимаюсь сбором данных через сериальный (RS485) интерфейс по "proprietary" протоколу. В создании протокола я не учавствовал, мне выдали только весьма ограниченую спецификацию, и общение с создателями протокола весьма затруднено.

При передачи данных для каждого пакета, как полагается, рассчитывается контрольная сумма. Алгоритм её рассчёта чётко указан в спецификации и практически идеально работает, но ... не всегда ))

Как тестовые данные, я получаю от прибора три сообщения. Они легко расшифровываются согласно спецификации. Но в двух из них контрольная сумма совпадает с моими рассчётами, а в самом главном - нет.

Вот алгоритм рассчёта CRC16 из спецификации (CRC-16-CCITT, как я понимаю):

Код: Выделить всё

unsigned short calcCheckSum(unsigned char *buffer, int length) {

    unsigned short usCRC = 0xFFFF;

    for (int i = 0; i < length; i++) {

        usCRC ^= (unsigned short)buffer[i] << 8;

        for (int j = 0; j < 8; j++) {
            usCRC = usCRC & 0x8000 ? (usCRC << 1) ^ 0x1021 : usCRC << 1;
        }
    }

    return usCRC ^= 0xFFFF;
} 
Правильное сообщение, которые я получаю выглядит в HeX так:

16 10 02 FF FF FF FF 10_10 4A 9F 30 E0 00 10 03 44 E5

Расшифровка:

--------------
16 SYN - synchronize, символ для начала синхронизации пакета данных
10 DLE - delimeter, разделитель пакетов
02 STX - start transmission начало пакета

FF FF FF FF // From-adress (32-bit)

10_10 4A 9F 30 // To-address (32-bit)

E0 // Packet type

00 // Packet number (00 = last packet) // на случай, если данные не поместились

10 DLE - delimeter, разделитель пакетов
03 ETX - end transmission конец пакета

44 E5 - CRC в формате Мотороллы, старший байт - первый, младший - второй
--------------

причём в спецификации сказано, что для различия байтов со значением 10 в данных от обрамляющих пакет байтов, байты со значением 10 в данных - дублируются при передаче.

Потому To-address состоит из 5-ти байтов. Возможно это не важно, но может быть что CRC считается не так как я предполагаю, и тогда эти лишние байты сиграют свою роль.

========================

Неправильный пакет, который я получаю выглядит так:

16 10 02 FF FF FF FF 10 10 4A 9F 30 FD 00 20 10 03 1A 62

Расшифровка:
-----------

16 SYN - synchronize, символ для начала синхронизации пакета данных
10 DLE - delimeter, разделитель пакетов
02 STX - start transmission начало пакета

FF FF FF FF // From-adress (32-bit)

10_10 4A 9F 30 // To-address (32-bit)

FD // Packet type

00 // Packet number (00 = last packet) // на случай, если данные не поместились

20 // данные

10 DLE - delimeter, разделитель пакетов
03 ETX - end transmission конец пакета

1A 62 - CRC в формате Мотороллы, старший байт - первый, младший - второй

========================

В спецификации сказано, что CRC рассчитывается только по байтам данных,
то есть начиная со следующего за STX и заканчивая тем что перед парой "DLE ETX".
Однако при рассчёте CRC по вышеуказанному алгоритму, для данного пакета я получаю значение D6 1F, что не соответствует сумме 1A 62 которую я получаю от прибора.

.........................................................................................

И потому я хочу задать два вопроса:

1. Может у кого-то родится спонтанно (исходя из опыта) идея, в чём может заключаться проблема?

2. Возможно ли по этому алгоритму и конкретному значению CRC восстановить данные, на которых была рассчитана эта сумма?

.........................................................................................


P. S. для удобства тестирования проблемы вот код на яве:

Код: Выделить всё

public class CRC16 {
    
    static int[] test1 = {
        0xFF,
        0xFF,
        0xFF,
        0xFF,

        0x10,
        0x4A,
        0x9F,
        0x30,

        0xE0,
        0x00,
    };
    
    static int[] test2 = {
        0xFF,
        0xFF,
        0xFF,
        0xFF,

        0x10,
        0x4A,
        0x9F,
        0x30,

        0xFD,
        0x00,
        0x20,
    };
    
    public static void main(String[] args) {
        
        int check = 0x44E5;
        
//        check = 0x1A62;
        
        int[] data = (check == 0x44E5) ? test1 : test2;
        
        int crc = 0xFFFF;
        for (int b : data) {
            
            crc ^= b << 8;
            
            for (int j = 0; j < 8; j++) {
                crc = (crc & 0x8000) != 0 ? ((crc << 1) ^ 0x1021) : ( crc << 1);
            }
            System.out.format("%2X => %2X %2X\n", b & 0xFF, (byte)(crc >> 8), (byte)crc);
        }
        
        crc ^= 0xFFFF;
        
        System.out.format("\nResult   : %2X %2X\n", (byte)(crc >> 8), (byte)crc);
        System.out.format("\nShould be: %2X %2X\n", (byte)(check >> 8), (byte)check);
    }
}