Как рассчитать продольную проверку избыточности (LRC)?
Я попробовал пример из Википедии: http://en.wikipedia.org/wiki/Longitudinal_redundancy_check
Это код для lrc (C#):
/// <summary>
/// Longitudinal Redundancy Check (LRC) calculator for a byte array.
/// ex) DATA (hex 6 bytes): 02 30 30 31 23 03
/// LRC (hex 1 byte ): EC
/// </summary>
public static byte calculateLRC(byte[] bytes)
{
byte LRC = 0x00;
for (int i = 0; i < bytes.Length; i++)
{
LRC = (LRC + bytes[i]) & 0xFF;
}
return ((LRC ^ 0xFF) + 1) & 0xFF;
}
Он сказал, что результат "ЕС", но я получаю "71", что я делаю не так?
Благодарю.
5 ответов
Вот очищенная версия, которая не выполняет все эти бесполезные операции (вместо того, чтобы отбрасывать старшие биты каждый раз, в конце они сбрасываются все сразу), и она дает результат, который вы наблюдали. Это версия, которая использует сложение, но в конце имеет отрицание - может также вычесть и пропустить отрицание. Это допустимое преобразование даже в случае переполнения.
public static byte calculateLRC(byte[] bytes)
{
int LRC = 0;
for (int i = 0; i < bytes.Length; i++)
{
LRC -= bytes[i];
}
return (byte)LRC;
}
Вот альтернативный LRC (простой xor байтов)
public static byte calculateLRC(byte[] bytes)
{
byte LRC = 0;
for (int i = 0; i < bytes.Length; i++)
{
LRC ^= bytes[i];
}
return LRC;
}
И Википедия просто ошибочна в этом случае, как в коде (не компилируется), так и в ожидаемом результате.
Думаю, это выглядит круче;)
public static byte calculateLRC(byte[] bytes)
{
return bytes.Aggregate<byte, byte>(0, (x, y) => (byte) (x^ y));
}
Если кто-то хочет получить символ LRC из строки:
public static char CalculateLRC(string toEncode)
{
byte[] bytes = Encoding.ASCII.GetBytes(toEncode);
byte LRC = 0;
for (int i = 0; i < bytes.Length; i++)
{
LRC ^= bytes[i];
}
return Convert.ToChar(LRC);
}
Исправленная версия Википедии выглядит следующим образом:
private byte calculateLRC(byte[] b)
{
byte lrc = 0x00;
for (int i = 0; i < b.Length; i++)
{
lrc = (byte)((lrc + b[i]) & 0xFF);
}
lrc = (byte)(((lrc ^ 0xff) + 2) & 0xFF);
return lrc;
}
Я создал это для Arduino, чтобы понять алгоритм (конечно, он написан не самым эффективным способом)
String calculateModbusAsciiLRC(String input)
{
//Refer this document http://www.simplymodbus.ca/ASCII.htm
if((input.length()%2)!=0) { return "ERROR COMMAND SHOULD HAVE EVEN NUMBER OF CHARACTERS"; }
// Make sure to omit the semicolon in input string and input String has even number of characters
byte byteArray[input.length()+1];
input.getBytes(byteArray, sizeof(byteArray));
byte LRC = 0;
for (int i = 0; i <sizeof(byteArray)/2; i++)
{
// Gettting the sum of all registers
uint x=0;
if(47<byteArray[i*2] && byteArray[i*2] <58) {x=byteArray[i*2] -48;}
else { x=byteArray[i*2] -55; }
uint y=0;
if(47<byteArray[i*2+1] && byteArray[i*2+1] <58) {y=byteArray[i*2+1] -48;}
else { y=byteArray[i*2+1] -55; }
LRC += x*16 + y;
}
LRC = ~LRC + 1; // Getting twos Complement
String checkSum = String(LRC, HEX);
checkSum.toUpperCase(); // Converting to upper case eg: bc to BC - Optional somedevices are case insensitve
return checkSum;
}
Я понимаю, что этот вопрос довольно старый, но мне было трудно понять, как это сделать. Это работает сейчас, поэтому я решил, что я должен вставить код. В моем случае контрольная сумма должна возвращаться как строка ASCII.
public function getLrc($string)
{
$LRC = 0;
// Get hex checksum.
foreach (str_split($string, 1) as $char) {
$LRC ^= ord($char);
}
$hex = dechex($LRC);
// convert hex to string
$str = '';
for($i=0;$i<strlen($hex);$i+=2) $str .= chr(hexdec(substr($hex,$i,2)));
return $str;
}