2017-02-04 7 views
1

У меня есть терминал, который обменивается данными через RS232 COM с компьютером. Протокол, который мне дал, говорит о том, что мне нужно отправить определенную комбинацию байтов и CRC 16 IBM вычисление данных, отправленных в концеРасчет CRC-16 C#

Мне также было предоставлено C-приложение, которое я могу проверить с помощью этого приложения записывает журнал с данными отправки и полученными данными. В этом журнале я вижу, отправляю ли я терминал этой строке hexString = "02 00 04 a0 00 01 01 03". Я также должен отправить этот результат данных CRC16 IBM 06 35.

Мне удалось каким-то образом перевести метод C, который был приведен в качестве примера, на C#. Но мой результат далек от того, что я знаю, я должен получить.

Я протестировал отправку данных из журнала, и все в порядке. Должно быть, мои расчеты сделаны неправильно. Я делаю что-то неправильно здесь?

Вот мой код:

CRC класс:

public enum Crc16Mode : ushort 
    { 
     ARINC_NORMAL = 0XA02B, ARINC_REVERSED = 0xD405, ARINC_REVERSED_RECIPROCAL = 0XD015, 
     CCITT_NORMAL = 0X1021, CCITT_REVERSED = 0X8408, CCITT_REVERSED_RECIPROCAL = 0X8810, 
     CDMA2000_NORMAL = 0XC867, CDMA2000_REVERSED = 0XE613, CDMA2000_REVERSED_RECIPROCAL = 0XE433, 
     DECT_NORMAL = 0X0589, DECT_REVERSED = 0X91A0, DECT_REVERSED_RECIPROCAL = 0X82C4, 
     T10_DIF_NORMAL = 0X8BB7, T10_DIF_REVERSED = 0XEDD1, T10_DIF_REVERSED_RECIPROCAL = 0XC5DB, 
     DNP_NORMAL = 0X3D65, DNP_REVERSED = 0XA6BC, DNP_REVERSED_RECIPROCAL = 0X9EB2, 
     IBM_NORMAL = 0X8005, IBM_REVERSED = 0XA001, IBM_REVERSED_RECIPROCAL = 0XC002, 
     OPENSAFETY_A_NORMAL = 0X5935, OPENSAFETY_A_REVERSED = 0XAC9A, OPENSAFETY_A_REVERSED_RECIPROCAL = 0XAC9A, 
     OPENSAFETY_B_NORMAL = 0X755B, OPENSAFETY_B_REVERSED = 0XDDAE, OPENSAFETY_B_REVERSED_RECIPROCAL = 0XBAAD, 
     PROFIBUS_NORMAL = 0X1DCF, PROFIBUS_REVERSED = 0XF3B8, PROFIBUS_REVERSED_RECIPROCAL = 0X8EE7 

    } 

public class Crc16 
{ 
    readonly ushort[] table = new ushort[256]; 

    public ushort ComputeChecksum(params 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(params byte[] bytes) 
    { 
     ushort crc = ComputeChecksum(bytes); 
     return BitConverter.GetBytes(crc); 
    } 

    public Crc16(Crc16Mode mode) 
    { 
     ushort polynomial = (ushort)mode; 
     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; 
     } 
    } 
} 

Способ обработки полученных байт:

public ushort CalculateCRC(byte[] data) 
    { 
     Crc16 crcCalc = new Crc16(Crc16Mode.IBM_NORMAL); 
     ushort crc = crcCalc.ComputeChecksum(data); 
     return crc; 
    } 

В этом методе вы можете выбрать полином из Enum.

Главных в программе Класс:

статической силы основной (String [] арг) { попробовать { Metode м = новый Metode();

  string hexString = "02 00 04 a0 00 01 01 03"; 
      byte[] bytes = m.HexStringToByteArray(hexString); 


      ushort crc = m.CalculateCRC(bytes); 

      string hexResult; 
      int myInt = crc; 
      hexResult = myInt.ToString("X"); 


      //Console.WriteLine(crc.ToString()); 
      Console.WriteLine(hexResult); 
      Console.ReadLine(); 
     } 
     catch (Exception ex) 
     { 
      Metode m = new Metode(); 
      m.writeError(ex.Message); 
     } 
    } 

Преобразование из шестнадцатеричной в массив байтов:

public byte[] HexStringToByteArray(string hexString) 
    { 
     hexString = hexString.Replace(" ", ""); 

     return Enumerable.Range(0, hexString.Length) 
       .Where(x => x % 2 == 0) 
       .Select(x => Convert.ToByte(hexString.Substring(x, 2), 16)) 
       .ToArray(); 
    } 

Преобразовать из массива байтов в шестнадцатеричной строки:

public string ByteArrayToHexString(byte[] byteArray) 
    { 
     return BitConverter.ToString(byteArray); 
    } 

Что я здесь делаю неправильно?

UPDATE:

Благодаря @MarkAdler мне удалось перевести расчет. То, что я не заметил допоздна, был тот факт, что расчет CRC должен был быть в Интернете DATA, отправленный на терминал, а не все сообщение!

Таким образом, hexString должен был быть фактически «a0 00 01 01», данные без STX/length/ETX.

Вот код для этого конкретного CRC16 Исчисления в C#:

public ushort CalculateCRC(byte[] data, int len) 
     { 
      int crc = 0, i = 0; 
      while (len-- != 0) 
      { 
       crc ^= data[i++] << 8; 
       for (int k = 0; k < 8; k++) 
        crc = ((crc & 0x8000) != 0) ? (crc << 1)^0x8005 : (crc << 1); 
      } 
      return (ushort)(crc & 0xffff); 
     } 
+1

* Что я здесь делаю неправильно? * Написал ли это сам? https://www.nuget.org/packages?q=Tags%3A%22Crc16%22 –

+0

можете ли вы разместить главную в классе программы: Методы m = новые методы(); код полностью? – Thennarasan

+0

Можете ли вы предоставить ссылку на документацию, с которой вы пытаетесь работать? –

ответ

2

Вы должны были бы предоставить более подробную информацию о спецификации, которую вы пытаетесь реализовать. Однако я могу сразу сказать, что вы используете неправильный полином. Процедуры CRC сдвигаются вправо, а это означает, что многочлен должен быть обращен бит. В результате IBM_NORMAL не может быть прав.

В то время как IBM_REVERSED был бы подходящим полиномом для смещения вправо, который может быть или не быть полиномом, необходимым для соответствия вашим требованиям.Также может быть исключение - или входить или выходить из процедуры CRC, которая необходима.

Update:

Связанная документация содержит фактический код для вычисления CRC. Почему ты не смотришь на это? Поиск случайного кода в сетях для вычисления CRC, не глядя на то, что находится в документации, вряд ли доставит вас далеко. И это не так.

Документированный код сдвигает CRC слева, напротив кода, который вы отправили в вопросе. Вам нужно сдвинуть влево. Полином равен 0x8005. Не существует окончательного исключения - или, а начальное значение CRC равно нулю.

Вот упрощенная версия кода в документе, написанном в C (этот код избегает мало-младшему предположение, что встроен в код в документе):

#include <stddef.h> 
typedef unsigned char byte; 
typedef unsigned short ushort; 

ushort crc16ecr(byte data[], int len) { 
    ushort crc = 0; 
    for (int i = 0; i < len; i++) { 
     crc ^= (ushort)(data[i]) << 8; 
     for (int k = 0; k < 8; k++) 
      crc = crc & 0x8000 ? (crc << 1)^0x8005 : crc << 1; 
    } 
    return crc; 
} 

Согласно документу, CRC вычисляется по тегам, len и данным, которые для вашего сообщения a0 00 01 01. Не все. (Полное чтение документации всегда является отличным первым шагом.) Запустив это с помощью кода CRC в документе, вы получите 0x0635. В документе говорится, что сначала передается старший байт, поэтому 0x06 0x35.