PDA

Просмотр полной версии : CRC-16/ARC помогите перевести с С++ на мэк



Gvenihvivar
02.07.2014, 11:39
Добрый день.
Помогите перевести код CRC-16/ARC с С++


#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

static uint16_t CRC16_ARC(uint8_t *data, size_t len) {
uint16_t crc = 0x0000;
size_t j;
int i;
// Note: 0xA001 is the reflection of 0x8005
for (j=len; j>0; j--) {
crc ^= *data++;
for (i=0; i<8; i++) {
if (crc & 1) crc = (crc >> 1) ^ 0xA001;
else crc >>= 1;
}
}
return (crc);
}

У меня получилось следующее


var
data : POINTER TO BYTE;
SIZE : INT;
j: INT;
i: INT;
crc : WORD:=16#0000;
arr: array [0..3] of byte:= [10,11,12,13];
end_var

data :=ADR(arr[0]);
size :=4;
FOR j:=size TO 0 BY -1 DO
crc := data^;
FOR i:=0 TO 8 DO
IF WORD_TO_BOOL(crc AND 16#0001) THEN crc:= ( SHR(crc, 1) OR 16#A001);
ELSE crc := SHR(crc, 1); END_IF
END_FOR
data:=data + SIZEOF(data^);
END_FOR
crc16ROCplus_1 := crc;


должно получиться A819, но не получается. Помогите найти ошибку.

Вольд
02.07.2014, 11:51
Сразу вижу, что вместо FOR i:=0 TO 8 DO, должно быть FOR i:=0 TO 7 DO

Gvenihvivar
02.07.2014, 11:56
тогда вместо FOR j:=size TO 0 BY -1 DO должно быть FOR j:=size-1 TO 0 BY -1 DO или FOR j:=size TO 1 BY -1 DO
но все равно не сходится

Вольд
02.07.2014, 11:57
тогда вместо FOR j:=size TO 0 BY -1 DO должно быть FOR j:=size-1 TO 0 BY -1 DO или FOR j:=size TO 1 BY -1 DO
но все равно не сходится
Значит еще есть ошибки. Зачем вообще копировать код C++, ведь алгоритм расчета хорошо описан. Я в свое время по этому алгоритму свой код написал и все у меня срослось.

Gvenihvivar
02.07.2014, 12:08
Я не против использовать уже написанный код, просто я нашла только это для расчета контрольной суммы roc протокола.

Вольд
02.07.2014, 12:14
Я не против использовать уже написанный код, просто я нашла только это для расчета контрольной суммы roc протокола.
Какого протокола ?

Дмитрий Егоренков
02.07.2014, 12:24
( SHR(crc, 1) XOR 16#A001)

Gvenihvivar
02.07.2014, 12:40
XOR еще нужен в строке crc ^= *data++; , там же crc = crc ^ *data++; То есть crc := crc xor data^;
Теперь все сходиться, я там немного ошиблась с суммой, правильный ответ dfb6
Рабочий код. Контрольная сумма по протоколу ROC+ для плк ROC809


data:=ADR(arr[0]);
size:=4;
FOR j:=size TO 1 BY -1 DO
crc := crc xor data^;
FOR i:=0 TO 7 DO
IF WORD_TO_BOOL(crc AND 16#0001) THEN crc:= ( SHR(crc, 1) XOR 16#A001);
ELSE crc := SHR(crc, 1); END_IF
END_FOR
data:=data + SIZEOF(data^);
END_FOR
crc16ROCplus_1 := crc;


Всем большое спасибо!

Вольд
02.07.2014, 12:44
А почем этот ROC809, наверное, жутко дорогой ?

Gvenihvivar
02.07.2014, 12:52
точной цены не знаю, но удовольствие это не из дешевых

Yegor
02.07.2014, 13:36
Вот этот кусок
IF WORD_TO_BOOL(crc AND 16#0001) THEN crc:= ( SHR(crc, 1) XOR 16#A001);
ELSE crc := SHR(crc, 1); END_IF... можно упростить:
crc := SHR(crc, 1) XOR 16#A001 * BOOL_TO_WORD(crc.0);

Gvenihvivar
02.07.2014, 13:53
У умножения приоритет больше чем у XOR?
Без скобок проблем не будет?

Yegor
02.07.2014, 14:07
Так и надо, чтобы сначала умножалось. Я проверил, если что.

Кстати для прикола вообще без ветвлений в один цикл переписал:
FOR j := 0 TO size * 8 - 1 DO
crc := crc XOR arr[j / 8] * BOOL_TO_WORD(j MOD 8 = 0);
crc := SHR(crc, 1) XOR (16#A001 * BOOL_TO_WORD(crc.0));
END_FORТоже проверил. Компактнее, но медленнее (много бесполезного ксора с нулём).

melky
02.07.2014, 16:40
http://www.owen.ru/forum/showthread.php?t=17523

Может поможет, там тоже был алгоритм на Си и вариант на ST того же кода.

capzap
02.07.2014, 22:46
а если заглянуть в бибку ОСКАТ, то там есть готовый блок расчета любых контрольных сумм

Gvenihvivar
03.07.2014, 10:14
да, знаю, но там много лишнего. Он ведь универсален для всего на свете.

capzap
03.07.2014, 13:33
да, знаю, но там много лишнего. Он ведь универсален для всего на свете.

так кто мешает, лишнее убрать, там практически вся универсальность заключается в числе ограничивающем по модулю