CRC 16 -DECT с поли х ^ 16 + х ^ 10 + х ^ 8 + х ^ 7 + х ^ 3 + 1 - PullRequest
2 голосов
/ 27 ноября 2010

поверьте мне, я пытался закодировать это, пробовал Google, и мне не повезло. Я пытаюсь реализовать CRC16, используя этот поли

x^16 + x^10 + x^8 + x^7 + x^3 + 1

с использованием языка C. Так как я лучше понимаю PHP, я пытаюсь запустить функцию, но я не получаю правильный ответ 28713. Этот код генерирует CRC 32713.

function crc16($string,$crc=0) {

for ( $x=0; $x<strlen( $string ); $x++ ) {

    $crc = $crc ^ ord( $string[$x] );
    echo $crc.'<br />';
    for ($y = 0; $y < 8 ; $y++) {

        if ( ($crc & 0x0001) == 0x0001 ) $crc = ( ($crc >> 1 ) ^ 0x10589  );
        else                             $crc =    $crc >> 1;
    }
}

    return $crc;
}


echo 'CRC:'.crc16('10100011');

Пожалуйста, я прошу любого помочь с этим .. спасибо заранее.

Ответы [ 3 ]

3 голосов
/ 27 ноября 2010
  1. Некоторые CRC определены для обработки битов от каждого байта от MSB до LSB, а некоторые определены для обработки битов от LSB до MSB (последний обычно является порядком, который описывается как "отраженный")и использует обратный полином).Ваш код вставляет новые биты в конце LSB CRC и сдвигает вправо, что подходит для отраженного CRC, но CRC-16-DECT представляется одним из неотраженных.

  2. Ваш ввод «10100011» предполагает двоичный код, но обрабатывается как 8-байтовая строка ASCII.

Чтобы увидеть, что происходит, если вместо этого обработать 10100011 как двоичный код и работатьсначала из MSB, вот ручное вычисление (поскольку 8 бит ввода не требуют больших усилий):

polynomial coefficients
        |
        |            10100010  <--- quotient (irrelevant)
        v          __________
 10000010110001001 ) 10100011  <-------- input
                   ^ 10000010110001001
                     -----------------
                   =   100001110001001
                     ^ 10000010110001001
                       -----------------
                     =      101110101101
                          ^ 10000010110001001
                            -----------------
   remainder (CRC) -----> =   111000000101001
     = 0x7029 = 28713

Таким образом, обработка ввода как двоичного и работа с MSB в первую очередь - правильная вещь.

Вот некоторый код на C, который выполняет эту работу (поскольку я не очень разбираюсь в PHP, и, в конечном счете, вам все равно нужен код на C):

#include <stdio.h>
#include <stdint.h>

static uint16_t crc16(const uint8_t *data, size_t len)
{
    size_t i, j;
    uint16_t crc = 0;

    for (i = 0; i < len; i++) {
        crc ^= (data[i] << 8);              /* data at top end, not bottom */
        for (j = 0; j < 8; j++) {
            if ((crc & 0x8000) == 0x8000)   /* top bit, not bottom */
                crc = (crc << 1) ^ 0x0589;  /* shift left, not right */
            else
                crc <<= 1;                  /* shift left, not right */
        }
    }

    return crc;
}

int main(void)
{
    const uint8_t in[] = { 0xa3 };          /* = 10100011 in binary */
    uint16_t crc = crc16(in, sizeof(in));

    printf("%u (0x%x)\n", crc, crc);
    return 0;
}

Результат:

$ gcc -Wall -o crc16 crc16.c
$ ./crc16  
28713 (0x7029)
$ 
0 голосов
/ 28 ноября 2010

Этот код работает каждый раз, но я не совсем понимаю, что происходит.

  char *MakeCRC(char *BitString)
   {
  static char Res[17];                                 // CRC Result
  char CRC[16];
    int  i;
  char DoInvert;

   for (i=0; i<16; ++i)  CRC[i] = 0;                    // Init before calculation

   for (i=0; i<strlen(BitString); ++i)
    {
   DoInvert = ('1'==BitString[i]) ^ CRC[15];         // XOR required?

  CRC[15] = CRC[14];
  CRC[14] = CRC[13];
  CRC[13] = CRC[12];
  CRC[12] = CRC[11];
  CRC[11] = CRC[10];
  CRC[10] = CRC[9] ^ DoInvert;
  CRC[9] = CRC[8]; 
  CRC[8] = CRC[7] ^ DoInvert;
  CRC[7] = CRC[6] ^ DoInvert;
  CRC[6] = CRC[5];
  CRC[5] = CRC[4];
  CRC[4] = CRC[3];
  CRC[3] = CRC[2] ^ DoInvert;
  CRC[2] = CRC[1];
  CRC[1] = CRC[0];
  CRC[0] = DoInvert;
  }

  for (i=0; i<16; ++i)  Res[15-i] = CRC[i] ? '1' : '0'; // Convert binary to ASCII
  Res[16] = 0;                                         // Set string terminator

    return(Res);
    }


     // A simple test driver:

    #include <stdio.h>

   int main()
    {
    char *Data, *Result;                                       // Declare two strings

    Data = "1101000101000111";
    Result = MakeCRC(Data);                                    // Calculate CRC

    printf("CRC of [%s] is [%s] with P=[10000010110001001]\n", Data, Result);

     return(0);
      }
0 голосов
/ 27 ноября 2010

Попробуйте изменить 0x10589 на 0xA001:

function crc16($string,$crc=0) {

    for ( $x=0; $x<strlen( $string ); $x++ ) {

        $crc = $crc ^ ord( $string[$x] );
        for ($y = 0; $y < 8; $y++) {

            if ( ($crc & 0x0001) == 0x0001 ) $crc = ( ($crc >> 1 ) ^ 0xA001 );
            else                             $crc =    $crc >> 1;
        }
    }

    return $crc;
}
...