Revert CRC
Добавлено: 12 фев 2011, 23:06
может вопрос больше и к алгоритмам относится, но проблема возникла на C, потому пишу тут.
В данный момент я занимаюсь сбором данных через сериальный (RS485) интерфейс по "proprietary" протоколу. В создании протокола я не учавствовал, мне выдали только весьма ограниченую спецификацию, и общение с создателями протокола весьма затруднено.
При передачи данных для каждого пакета, как полагается, рассчитывается контрольная сумма. Алгоритм её рассчёта чётко указан в спецификации и практически идеально работает, но ... не всегда ))
Как тестовые данные, я получаю от прибора три сообщения. Они легко расшифровываются согласно спецификации. Но в двух из них контрольная сумма совпадает с моими рассчётами, а в самом главном - нет.
Вот алгоритм рассчёта CRC16 из спецификации (CRC-16-CCITT, как я понимаю):
Правильное сообщение, которые я получаю выглядит в 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. для удобства тестирования проблемы вот код на яве:
В данный момент я занимаюсь сбором данных через сериальный (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;
}
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);
}
}