Как рассчитать продольную проверку избыточности (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;
}
Другие вопросы по тегам