¿Cuál es la forma correcta de este algoritmo CRC?

5

Estamos trabajando en la comunicación entre AVR y un Crous PTZ.

Encontramos su protocolo y ahora podemos activarlo y así.

Tenemos problemas con su CRC. Este es el protocolo de Crous doc (Lo tengo here ), al final, se describe el algoritmo CRC (ver imagen abajo), pero parece está mal porque el parámetro del contador nunca será 8, pero se verifica para ver si es 8 o no.

Nuestro codificador ha escrito el siguiente código para ese algoritmo, pero el CRC devuelto no es el mismo que el CRC devuelto por el dispositivo Crous.

#include <stdint.h>

unsigned int crc_chk(unsigned char dta, unsigned char length) 
{ 
  int16_t j;
  uint16_t a,b,c; 
  uint16_t reg_crc=0x0000; 
  for( c = 0; c < length; c++ ) 
  { 
    a = reg_crc / 256;
    a ^= test_crc[dta];
    dta++; 
    a *= 256;
    b = reg_crc&0xff;
    reg_crc = a | b;
    for( j = 0; j < 8; j++ ) 
    { 
      if ( reg_crc & 0x8000 ) 
        reg_crc = ( reg_crc * 2 ) ^ 0X8005; /* LSB(b0)=1 */ 
      else 
        reg_crc = reg_crc * 2;
    } 
  } 
  return reg_crc; // the value that sent back to the CRC register finally 
}

Encontró que el verdadero CRC en el dispositivo responde, por ejemplo, En este dispositivo responda

01 BF 15 0F 94 95 96 97 9F 9E A2 A0 98 99 72 6B 6A 88 89 64 62 63 65 66 03 2D AC

y de acuerdo con la página 45 de The protocol Doc, CRC of

0F 94 95 96 97 9F 9E A2 A0 98 99 72 6B 6A 88 89 64 62 63 65 66

debería ser 2DAC, 03 muestra el final de los datos, y 15 es el tamaño de los datos que, cuando lo calculamos en decimal, será 21 que usted ve que también tenemos 21 bytes.

¿Cuál es la forma correcta de este algoritmo?

    
pregunta dehqan

2 respuestas

4

De un vistazo, parece que el "contador = 8?" el bloque de decisión probablemente debería tener una ruta "NO" que se retroalimente a, probablemente, "el bit 15 CRC = 1?" Entrada del bloque de decisión. ¿Y la salida existente del "contador = 8?" el bloque de decisión debe estar etiquetado como "SÍ" ...

En cuanto a la implementación, tengo algunos problemas para darle sentido. ¿Qué es test_crc y dónde se define? ¿No debería ser dta un puntero en la firma de función? Hice algunas actualizaciones del código en tu publicación para mejorar la legibilidad.

Implementé fielmente una función basada en el diagrama de bloques y mi suposición, y la ejecuté en IDEOne y obtuve el resultado. esperado ... aquí está mi código.

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

unsigned int crc16(uint8_t * data, uint8_t length) 
{ 
  uint16_t CRC = 0;
  uint16_t A = 0, B = 0;
  uint8_t index = 0, Counter = 0; 

  for( index = 0; index < length; index++ )
  {
    uint8_t byte = data[index];

    A = CRC / 256;
    A = A ^ byte;
    A = A * 256;

    B = CRC & 0xFF;
    CRC = A | B;

    for( Counter = 0; Counter < 8; Counter++ ){
      if( CRC & 0x8000 )
      {
        CRC = CRC * 2;
        CRC = CRC ^ 0x8005;
      }
      else
      {
        CRC = CRC * 2;
      }
    }
  }
  return CRC;
}

int main(int argc, char *argv[]){
  uint8_t data[] = { 0x01, 0xBF, 0x15, 0x0F, 0x94, 0x95, 0x96, 0x97, 0x9F, 0x9E, 0xA2, 0xA0, 0x98, 0x99, 0x72, 0x6B, 0x6A, 0x88, 0x89, 0x64, 0x62, 0x63, 0x65, 0x66, 0x03 };
  uint8_t length = sizeof(data);
  uint16_t crc = 0;

  printf("Length = %d\n", length);
  crc = crc16(data, length);
  printf("CRC = %04x", crc);

  return 0;

}

Da salida:

Length = 25
CRC = ac2d
    
respondido por el vicatcu
2

No hay nada de malo en el cálculo de CRC, simplemente estás calculando el CRC para la cosa incorrecta.

Los datos que desea enviar son:

0F 94 95 96 97 9F 9E A2 A0 98 99 72 6B 6A 88 89 64 62 63 65 66

Una vez que lo hayas enmarcado adecuadamente para su transmisión a Crous PTZ, los bytes reales que estás enviando son

01 BF 15 0F 94 95 96 97 9F 9E A2 A0 98 99 72 6B 6A 88 89 64 62 63 65 66 03

El CRC 2DAC es para el marco en su totalidad, no solo los datos que contiene. El siguiente código es una versión esencialmente no modificada del código que calcula el CRC para el marco, y puede ver que deriva el valor correcto.

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

int main (void) { 
    unsigned char test_crc[] = {
        0x01, 0xBF, 0x15, 0x0F, 0x94, 0x95, 0x96, 0x97, 0x9F, 0x9E, 0xA2, 0xA0, 0x98, 0x99, 0x72, 0x6B, 0x6A, 0x88, 0x89, 0x64, 0x62, 0x63, 0x65, 0x66, 0x03
    };

    int length = sizeof test_crc / sizeof test_crc[0];
    unsigned char dta = 0;
    int16_t j;
    uint16_t a,b,c; 
    uint16_t reg_crc=0x0000; 
    for( c = 0; c < length; c++ ) 
    { 
        printf("0x%02x%c", test_crc[dta], (dta+1)%5?' ':'\n');

        a = reg_crc / 256;
        a ^= test_crc[dta];
        dta++; 
        a *= 256;
        b = reg_crc&0xff;
        reg_crc = a | b;
        for( j = 0; j < 8; j++ ) 
        { 
            if ( reg_crc & 0x8000 ) 
                reg_crc = ( reg_crc * 2 ) ^ 0X8005; /* LSB(b0)=1 */ 
            else 
            reg_crc = reg_crc * 2;
        } 
    } 
    printf("\n");
    printf("CRC: 0x%04X\n", reg_crc);
    return 0;
}

Cuando se ejecuta:

$ make crc16-orig && ./crc16-orig
cc     crc16-orig.c   -o crc16-orig
0x01 0xbf 0x15 0x0f 0x94
0x95 0x96 0x97 0x9f 0x9e
0xa2 0xa0 0x98 0x99 0x72
0x6b 0x6a 0x88 0x89 0x64
0x62 0x63 0x65 0x66 0x03

CRC: 0xAC2D

Si bien el código es funcionalmente correcto, podría hacer algunas mejoras. La versión de @vivatcu es mucho mejor.

    
respondido por el freespace

Lea otras preguntas en las etiquetas