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

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

Encontramos su protocolo y ahora podemos encenderlo y así.

Tenemos problema con su CRC. Este es el documento del protocolo Crous (lo obtuve aquí ), al final se describe el algoritmo CRC (vea la imagen a continuación), pero parece que está mal porque el parámetro del contador nunca será 8, pero se verifica para ver si es 8 o no .

ingrese la descripción de la imagen aquí

Nuestro codificador escribió 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ó CRC verdadero en la respuesta del dispositivo, por ejemplo, En este dispositivo responde

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 a la página 45 de The protocol Doc, CRC de

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 verá que también tenemos 21 bytes.

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

Personalmente, no tengo ningún problema con que esto esté en EE, pero creo que puede encontrar que la audiencia más grande de SO responderá esto más rápido, ya que parece ser una pregunta puramente de software.
@Kortuk Estaba pensando lo mismo.
@dehqan Parece que no puedo abrir el PDF que vinculaste...

Respuestas (2)

De un vistazo, parece que el "contador = 8?" el bloque de decisión probablemente debería tener una ruta "NO" que retroalimente, 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 etiquetarse como "SÍ"...

En cuanto a la implementación, tengo algunos problemas para darle sentido. ¿Qué es test_crcy dónde se define? ¿No debería dtaser un puntero en la firma de la función? Hice algunas actualizaciones en el código de 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 que creo que esperabas... 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;

}

Produce:

Length = 25
CRC = ac2d
Muchas gracias amigo, nuestro codificador tiene algunas preguntas que tal vez se le hagan mañana, nuevamente gracias amigo, que Dios lo bendiga.

No hay nada de malo con el cálculo de CRC: simplemente está calculando el CRC para algo incorrecto.

Los datos que quieres 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 haya enmarcado adecuadamente para su transmisión a Crous PTZ, los bytes reales que está 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 2DACes para el marco como un todo, no solo para los datos que contiene. El siguiente código es una versión esencialmente no modificada de su 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, le vendrían bien algunas mejoras. La versión de @vicatcu es mucho mejor.