CRC 16 -DECT con poli x ^ 16 + x ^ 10 + x ^ 8 + x ^ 7 + x ^ 3 + 1
Pregunta
créanme que he tratado de código de esto, Google tratado, y no he tenido un poco de suerte. Estoy tratando de implementar un CRC16 el uso de este poli
x^16 + x^10 + x^8 + x^7 + x^3 + 1
usando el lenguaje C. Desde PHP entiendo mejor estoy tratando de conseguir una función de ir, pero ahora no recibo la respuesta correcta de 28713. Este código está generando un CRC de 32 713.
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');
Por favor, le ruego que cualquiera pueda dar una mano con this..thanks de antemano.
Solución
-
Algunos CRCs se definen para procesar los bits de cada byte de MSB a LSB, y algunos se definen a los bits de proceso de LSB a MSB (la última es generalmente el orden que se describe como "refleja" y utiliza una invertido polinomio). Sus código coloca nuevos bits en en el LSB final de la CDN y desplazamientos a la derecha, que es adecuado para un CRC reflejada, pero CRC-16-DECT parece ser uno de los no-reflejada.
-
Su entrada de "10100011" sugiere binaria, pero se está procesando como una cadena ASCII de 8 bytes.
Para ver lo que sucede cuando el tratamiento 10100011 como binario en lugar, y trabajar desde MSB primero, aquí hay un cálculo manual (como 8 bits de entrada no requiere mucho esfuerzo):
polynomial coefficients
|
| 10100010 <--- quotient (irrelevant)
v __________
10000010110001001 ) 10100011 <-------- input
^ 10000010110001001
-----------------
= 100001110001001
^ 10000010110001001
-----------------
= 101110101101
^ 10000010110001001
-----------------
remainder (CRC) -----> = 111000000101001
= 0x7029 = 28713
Así que el tratamiento de la entrada binaria y se MSB trabajando primero es lo que hay que hacer.
Aquí hay un código C para hacer el trabajo (ya que no estoy realmente en PHP, y en última instancia quiero código C de todos modos):
#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;
}
Resultados:
$ gcc -Wall -o crc16 crc16.c
$ ./crc16
28713 (0x7029)
$
Otros consejos
Intente cambiar a 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;
}
Este código funciona cada vez, pero no me entender exactamente lo que está pasando.
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);
}