using System;
using System.Collections.Generic;
namespace Crc16
{
class Program
{
public static byte[] Crc16( byte[] bytes )
{
int hi = 0xFF, lo = 0xFF;
foreach ( var b in bytes )
{
var t = ( byte ) ( lo ^ b );
lo = hi;
hi = t;
// Место флага (старшего разряда) занимает появляющийся при сдвиге влево нулевой разряд.
// Его комбинация (XOR) с младшим разрядом полинома 0x1021 должна всегда давать единицу.
// Поскольку флаг всегда равен единице, то мы должны обнулить младший разряд полинома,
// чтобы получить результат итерации аналогичный другим методам.
// По-простому: мы двигаем на каждой из 8 итераций не текущее значение crc, а полином, но
// в обратную сторону. Причём сдвиг циклический, т.к. в оригинале при сдвиге влево каждый
// раз получается один нулевой битик. Мы суём его на место старшего разряда, который нас
// безвременно покидает.
// 0001000000100001 1021 - полином
// Расчёт констант:
// 0000 1000 0001 0000 (0x1021 >> 1) & 0x7FFF = 0x0810
// 0000 0100 0000 1000 (0x1021 >> 2) & 0xBFFF = 0x0408
// 0000 0010 0000 0100 (0x1021 >> 3) & 0xDFFF = 0x0204
// 0000 0001 0000 0010 (0x1021 >> 4) & 0xEFFF = 0x0102
// 0000 0000 1000 0001 (0x1021 >> 5) & 0xF7FF = 0x0081
// 1000 0000 0100 0000 (0x1021 >> 6) & 0xFBFF = 0x8040
// 0100 0000 0010 0000 (0x1021 >> 7) & 0xFDFF = 0x4020
// 0010 0000 0001 0000 (0x1021 >> 8) & 0xFEFF = 0x2010
if ( ( hi & 0x80 ) != 0 ) { hi ^= 0x08; lo ^= 0x10; }
if ( ( hi & 0x40 ) != 0 ) { hi ^= 0x04; lo ^= 0x08; }
if ( ( hi & 0x20 ) != 0 ) { hi ^= 0x02; lo ^= 0x04; }
if ( ( hi & 0x10 ) != 0 ) { hi ^= 0x01; lo ^= 0x02; }
if ( ( hi & 0x08 ) != 0 ) { hi ^= 0x00; lo ^= 0x81; }
if ( ( hi & 0x04 ) != 0 ) { hi ^= 0x80; lo ^= 0x40; }
if ( ( hi & 0x02 ) != 0 ) { hi ^= 0x40; lo ^= 0x20; }
if ( ( hi & 0x01 ) != 0 ) { hi ^= 0x20; lo ^= 0x10; }
}
return new [] { ( byte ) lo, ( byte ) hi };
}
static void Main( string[] args )
{
var query = new List<byte> { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 };
query.AddRange( Crc16( query.ToArray() ) );
// Вывод: 31-32-33-34-35-36-37-38-39-29-B1
Console.WriteLine( BitConverter.ToString( query.ToArray() ) );
}
}
}