P1 счетчик контрольной суммы CRC16

Я пытаюсь написать модульный тест для контрольной суммы CRC16 для сообщения счетчика P1 (и мне трудно понять это правильно ...).

Что у меня есть:

  • Сообщение счетчика P1
  • Снял его так, чтобы у меня была правильная деталь в соответствии со спецификацией (см. Ниже)
  • Превратил в байтовый массив (кодировка ASCII)
  • Вычислить контрольную сумму CRC16
  • Сравните это с контрольной суммой, это должно быть

Учитывая тот факт, что я разместил вопрос о SO, результат не в порядке ...

Пожалуйста, потерпите меня, я поделюсь тем, что у меня есть, ниже:

Сообщение P1

    private static readonly string telegramText =
        "/KFM5KAIFA-METER\n" +
        "\n" +
        "1-3:0.2.8(42)\n" +
        "0-0:1.0.0(170124213128W)\n" +
        "0-0:96.1.1(4530303236303030303234343934333135)\n" +
        "1-0:1.8.1(000306.946*kWh)\n" +
        "1-0:1.8.2(000210.088*kWh)\n" +
        "1-0:2.8.1(000000.000*kWh)\n" +
        "1-0:2.8.2(000000.000*kWh)\n" +
        "0-0:96.14.0(0001)\n" +
        "1-0:1.7.0(02.793*kW)\n" +
        "1-0:2.7.0(00.000*kW)\n" +
        "0-0:96.7.21(00001)\n" +
        "0-0:96.7.9(00001)\n" +
        "1-0:99.97.0(1)(0-0:96.7.19)(000101000006W)(2147483647*s)\n" +
        "1-0:32.32.0(00000)\n" +
        "1-0:52.32.0(00000)\n" +
        "1-0:72.32.0(00000)\n" +
        "1-0:32.36.0(00000)\n" +
        "1-0:52.36.0(00000)\n" +
        "1-0:72.36.0(00000)\n" +
        "0-0:96.13.1()\n" +
        "0-0:96.13.0()\n" +
        "1-0:31.7.0(003*A)\n" +
        "1-0:51.7.0(005*A)\n" +
        "1-0:71.7.0(005*A)\n" +
        "1-0:21.7.0(00.503*kW)\n" +
        "1-0:41.7.0(01.100*kW)\n" +
        "1-0:61.7.0(01.190*kW)\n" +
        "1-0:22.7.0(00.000*kW)\n" +
        "1-0:42.7.0(00.000*kW)\n" +
        "1-0:62.7.0(00.000*kW)\n" +
        "0-1:24.1.0(003)\n" +
        "0-1:96.1.0(4730303331303033333738373931363136)\n" +
        "0-1:24.2.1(170124210000W)(00671.790*m3)\n" +
        "!29ED\n";

Спецификация

Источник можно найти здесь

CRC - это значение CRC16, вычисленное по предыдущим символам в сообщении данных (от «/» до «!» С использованием полинома: x16 + x15 + x2 + 1).

CRC16 не использует ни входа XOR, ни выхода XOR и сначала вычисляется с младшим значащим битом. Значение представлено 4 шестнадцатеричными символами (сначала MSB).

Получите байты и выполните CRC

Прочитанное сообщение - это сообщение P1 выше, но затем от '/' до '!' (включая '/' и включая '!'), как того требует спецификация выше.

var bytes = Encoding.ASCII.GetBytes(_readMessage);
var computeChecksum = new Crc16().ComputeChecksum(bytes);

Наконец, код CRC

Источник можно найти здесь

public class Crc16
{
    const ushort polynomial = 0xA001;
    ushort[] table = new ushort[256];

    public ushort ComputeChecksum(byte[] bytes)
    {
        ushort crc = 0;
        for (int i = 0; i < bytes.Length; ++i)
        {
            byte index = (byte)(crc ^ bytes[i]);
            crc = (ushort)((crc >> 8) ^ table[index]);
        }
        return crc;
    }

    public byte[] ComputeChecksumBytes(byte[] bytes)
    {
        ushort crc = ComputeChecksum(bytes);
        return BitConverter.GetBytes(crc);
    }

    public Crc16()
    {
        ushort value;
        ushort temp;
        for (ushort i = 0; i < table.Length; ++i)
        {
            value = 0;
            temp = i;
            for (byte j = 0; j < 8; ++j)
            {
                if (((value ^ temp) & 0x0001) != 0)
                {
                    value = (ushort)((value >> 1) ^ polynomial);
                }
                else
                {
                    value >>= 1;
                }
                temp >>= 1;
            }
            table[i] = value;
        }
    }
}

Неудачный результат

Контрольная сумма телеграммы P1 должна быть: 0x29ED, но, к сожалению, я вычисляю 0x6500.

Может ли кто-нибудь указать мне правильное направление?

Обновлять

@Mark Adler, я исправил обнаруженную вами проблему, но все равно вычисляю неправильную контрольную сумму. Я снял все ненужные части ниже, не могли бы вы взглянуть еще раз? Вы можете просто скопировать и вставить приведенный ниже код, если хотите. Или отправьте обратно код, который вычисляет правильную контрольную сумму.

Заранее большое спасибо!

class Program
{
    private static readonly string telegramText =
        "/KFM5KAIFA-METER\r\n" +
        "\r\n" +
        "1-3:0.2.8(42)\r\n" +
        "0-0:1.0.0(170124213128W)\r\n" +
        "0-0:96.1.1(4530303236303030303234343934333135)\r\n" +
        "1-0:1.8.1(000306.946*kWh)\r\n" +
        "1-0:1.8.2(000210.088*kWh)\r\n" +
        "1-0:2.8.1(000000.000*kWh)\r\n" +
        "1-0:2.8.2(000000.000*kWh)\r\n" +
        "0-0:96.14.0(0001)\r\n" +
        "1-0:1.7.0(02.793*kW)\r\n" +
        "1-0:2.7.0(00.000*kW)\r\n" +
        "0-0:96.7.21(00001)\r\n" +
        "0-0:96.7.9(00001)\r\n" +
        "1-0:99.97.0(1)(0-0:96.7.19)(000101000006W)(2147483647*s)\r\n" +
        "1-0:32.32.0(00000)\r\n" +
        "1-0:52.32.0(00000)\r\n" +
        "1-0:72.32.0(00000)\r\n" +
        "1-0:32.36.0(00000)\r\n" +
        "1-0:52.36.0(00000)\r\n" +
        "1-0:72.36.0(00000)\r\n" +
        "0-0:96.13.1()\r\n" +
        "0-0:96.13.0()\r\n" +
        "1-0:31.7.0(003*A)\r\n" +
        "1-0:51.7.0(005*A)\r\n" +
        "1-0:71.7.0(005*A)\r\n" +
        "1-0:21.7.0(00.503*kW)\r\n" +
        "1-0:41.7.0(01.100*kW)\r\n" +
        "1-0:61.7.0(01.190*kW)\r\n" +
        "1-0:22.7.0(00.000*kW)\r\n" +
        "1-0:42.7.0(00.000*kW)\r\n" +
        "1-0:62.7.0(00.000*kW)\r\n" +
        "0-1:24.1.0(003)\r\n" +
        "0-1:96.1.0(4730303331303033333738373931363136)\r\n" +
        "0-1:24.2.1(170124210000W)(00671.790*m3)\r\n" +
        "!";

    static void Main(string[] args)
    {
        var bytes = Encoding.ASCII.GetBytes(telegramText);
        var computeChecksum = new Crc16().ComputeChecksum(bytes);
    }
}

public class Crc16
{
    const ushort polynomial = 0x8005;
    ushort[] table = new ushort[256];

    public ushort ComputeChecksum(byte[] bytes)
    {
        ushort crc = 0;
        for (int i = 0; i < bytes.Length; ++i)
        {
            byte index = (byte)(crc ^ bytes[i]);
            crc = (ushort)((crc >> 8) ^ table[index]);
        }
        return crc;
    }

    public byte[] ComputeChecksumBytes(byte[] bytes)
    {
        ushort crc = ComputeChecksum(bytes);
        return BitConverter.GetBytes(crc);
    }

    public Crc16()
    {
        ushort value;
        ushort temp;
        for (ushort i = 0; i < table.Length; ++i)
        {
            value = 0;
            temp = i;
            for (byte j = 0; j < 8; ++j)
            {
                if (((value ^ temp) & 0x0001) != 0)
                {
                    value = (ushort)((value >> 1) ^ polynomial);
                }
                else
                {
                    value >>= 1;
                }
                temp >>= 1;
            }
            table[i] = value;
        }
    }
}

person bas    schedule 27.01.2017    source источник
comment
Согласно вики, представление полинома, которое вы упомянули в режиме MSB-first, будет 0x8005, не 0xA001 (который является представлением LSB-first).   -  person Javier Martín    schedule 27.01.2017
comment
@ JavierMartín thx изменил это, но до сих пор нет правильного результата. '0x0a6a'. Есть ли у вас какие-либо другие советы, как действовать?   -  person bas    schedule 27.01.2017
comment
Не совсем, извините, я просто хотел низко висящий плод. Может быть, внимательно посмотрите на код, который вычисляет таблицу, а затем CRC, или найдите другие примеры.   -  person Javier Martín    schedule 28.01.2017


Ответы (1)


Код CRC выглядит нормально. Проблема в том, что он ожидает перевода строки на возврат каретки, а не только на перевод строки. Если перед каждым \n поставить \r, то вы получите 0x29ed для CRC байтов от / до ! включительно.

person Mark Adler    schedule 28.01.2017
comment
Привет, Марк, спасибо за это, но с этим исправлением я все еще вычисляю неправильную контрольную сумму. Я обновил свой вопрос с помощью программы копирования / вставки, в которой только соответствующие части. Не могли бы вы мне помочь? Спасибо - person bas; 28.01.2017
comment
Как я уже сказал, исходный код CRC выглядит нормально. По какой-то причине вы пошли и изменили многочлен на 0x8005. Оригинал 0xa001 правильный. - person Mark Adler; 28.01.2017
comment
Да! Спасибо! Это было предложено кем-то другим. Я наконец-то прошел модульный тест ....! Спасибо за вашу помощь! - person bas; 28.01.2017