PDA

Просмотр полной версии : Расчет CRC в протоколе ОВЕН



Hemann
07.04.2015, 10:27
Добрый день, уважаемые коллеги!

Занялся я изучением MasterOPC, в частности скриптов, поскольку в перспективе нужно будет связать СКАДу с нестандартным оборудованием. Потренироваться решил на протоколе ОВЕН, т.к. есть на чем проверять свои изыски. Взял для испытаний ТРМ101. Получилось почти все, за исключением подсчета контрольной суммы - и хэширование имени параметров получается, и упаковка "тетрада-в-ASCII", а вот контрольная сумма считается неправильно (я сравниваю что получается у меня и что видит сниффер при работе конфигуратора ТРМ101, разница как раз в CRC). Прошу объяснить методику подсчета CRC в протоколе ОВЕН, особенно сам алгоритм (я его прописал, но может как-то неправильно), какие байты в него входят, байты в чистом виде или уже упакованные по методу "тетрада-в-ASCII"? Желательно чем подробней, тем лучше.

Привожу скрипт на Lua (DataBlock - это строка, в которую вставлены все байты сообщение, за исключением самой CRC, '#' и '0D'):

function CRCcalc(DataBlock)
local dCRC={};
local i,dbLen,tbLen=0;
local j=1;

dbLen=string.len(DataBlock);
for i=1,dbLen,2 do
dCRC[j]=(string.byte(string.sub(DataBlock,i,i))*10)+strin g.byte(string.sub(DataBlock,i+1,i+1));
j=j+1;
end
tbLen=table.maxn(dCRC);
local H0,H1=0;
for i=1,tbLen,1 do
H1=server.RunFunctionFromDevice("Hashing",1,bit.BitLshift(dCRC[i],1),7,H0);
H0=H1;
end
return H1;
end

function Hashing (Byte,nbit,Hash)
i=0;
Aux=0;

for i=1,nbit,1 do
Aux=bit.BitAnd(bit.BitXor(bit.BitAnd(Byte,0x00ff), bit.BitRshift(Hash,8)),0x80);
if Aux ~= 0 then
Hash=bit.BitLshift(Hash,1);
Hash=bit.BitXor(Hash,0x8F57);
else
Hash=bit.BitLshift(Hash,1);
end
Byte=bit.BitLshift(Byte,1);
end
Hash=bit.BitAnd(Hash,0x0000ffff);
return Hash;
end

Я уже задавал вопрос в разделе MasterSCADA, но там посоветовали обратиться сюда, так что прошу не ругать за "удвоение" темы.

Hemann
07.04.2015, 22:33
Добрый вечер, уважаемые коллеги!
В предыдущем посте ошибка была моя, их даже было 2. Во-первых был применен неправильный алгоритм расчета CRC, а во вторых неправильно обрабатывалась входная строка данных. Когда я с этими ошибками разобрался, то у меня начал отвечать прибор, появились не только исходящие, но и входящие посылки. На всякий случай выкладываю скрипт расчета контрольной суммы на языке Lua:

function CRCcalc(DataBlock)
local dCRC={};
local i,dbLen,tbLen,t1,t2=0;
local j=1;

local wCRC=0;
dbLen=string.len(DataBlock);
for i=1,dbLen,2 do
t1=string.byte(string.sub(DataBlock,i,i));
if t1>=48 and t1<=57 then
t1=t1-48;
elseif t1>=65 and t1<=70 then
t1=(t1-65)+10;
end
t2=string.byte(string.sub(DataBlock,i+1,i+1));
if t2>=48 and t2<=57 then
t2=t2-48;
elseif t2>=65 and t2<=70 then
t2=(t2-65)+10;
end
dCRC[j]=t1*16+t2;
j=j+1;
end
tbLen=table.maxn(dCRC);
local Byte,Aux1,Aux2,Aux=0;
for i=1,tbLen,1 do
Byte=bit.BitAnd(dCRC[i],0x00ff);
for j=1,8,1 do
Aux1=bit.BitRshift(bit.BitAnd(wCRC,0x0000ffff),8);
Aux1=bit.BitAnd(Aux1,0x0000ffff);
Aux2=bit.BitXor(Byte,Aux1);
Aux2=bit.BitAnd(Aux2,0x0000ffff);
Aux=bit.BitAnd(Aux2,0x80);
Aux=bit.BitAnd(Aux,0x0000ffff);
if Aux~=0 then
wCRC=bit.BitLshift(bit.BitAnd(wCRC,0x0000ffff),1);
wCRC=bit.BitXor(bit.BitAnd(wCRC,0x0000ffff),0x8f57 );
else
wCRC=bit.BitLshift(bit.BitAnd(wCRC,0x0000ffff),1);
end
Byte=bit.BitLshift(Byte,1);
end
end
return bit.BitAnd(wCRC,0x0000ffff);
end

Несколько переменных Aux,Aux1,Aux2 были использованы просто для собственного понимания процесса и не более того, всю эту группу строк можно собрать в одну. Ну и постоянные накладывания масок остались от тех времен, когда уже не знал где выискивать ошибку, так что прошу сильно не пинать.