Fundamentos Previos
En Java, el tipo byte tiene un rango de -128 a 127, representado en memoria como valores hexadecimales de 0x00 a 0xFF. Esto corresponde a un byte de 8 bits.
Problema de Manejo de Datos
Al inicializar un array de bytes con valores hexadecimales que exceden el rango del byte, como se muestra a continuación, ocurre un comportamiento inesperado:
byte[] datosHex = new byte[] {0x01, 0x03, 0x04, 0x02, 0x1F, 0x01, 0x4E, 0x4B, (byte)0xE9 };
Java interpreta los literales como enteros y luego los convirete a byte. El valer 0xE9 (233 en decimal) excede el rango del byte, por lo que la conversión forzada causa un desbordamiento. En consecuencia, datosHex[8] se almacena como un valor negativo en memoria.
Solución
Para extraer el valor correcto sin signo, se utiliza la operación AND con 0xFF:
int valorCorrecto = datosHex[8] & 0xFF;
Explicación Técnica
El tipo byte en Java es con signo y utiliza complemanto a dos para la representación de negativos. Los números se interpretan inicialmente como enteros (int). Al convertir un entero que supera 127 a byte, ocurre un desbordamiento hacia valores negativos. Por ejemplo, 233 (0xE9) se convierte en -23 en byte, cuya representación hexadecimal es 0xFFFFFFE9 en un entero de 32 bits. Aplicar & 0xFF enmascara los bits superiores, obteniendo el byte sin signo.
Para byte en el rango [-128, -1], se necesita esta operación; para valores en [0, 127], no es necesario. Además, al operar con bytes, es recomendable usar tipos más amplios como int para evitar conversiones automáticas problemáticas.
Implementaciones de Algoritmos CRC
A continuación, se presentan diversas implementaciones de algoritmos CRC en Java. Se ha modificado la estructura, nombres de variables y lógica para mayor claridad, manteniendo la corrección. Se aplica & 0xFF dentro de las funciones para manejar correctamente los bytes.
public class CalculadoraCRC {
public static byte crc4_ITU(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) != 0) {
checksum = (byte) (((checksum & 0xFF) >> 1) ^ 0x0C);
} else {
checksum = (byte) ((checksum & 0xFF) >> 1);
}
}
}
return (byte) (checksum & 0x0F);
}
public static byte crc5_EPC(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0x48;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; i++) {
if ((checksum & 0x80) != 0) {
checksum = (byte) ((checksum << 1) ^ 0x48);
} else {
checksum <<= 1;
}
}
}
return (byte) ((checksum >> 3) & 0x1F);
}
public static byte crc5_ITU(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) == 0) {
checksum = (byte) ((checksum & 0xFF) >> 1);
} else {
checksum = (byte) (((checksum & 0xFF) >> 1) ^ 0x15);
}
}
}
return (byte) (checksum & 0x1F);
}
public static byte crc5_USB(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0x1F;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) == 0) {
checksum = (byte) ((checksum & 0xFF) >> 1);
} else {
checksum = (byte) (((checksum & 0xFF) >> 1) ^ 0x14);
}
}
}
return (byte) ((checksum ^ 0x1F) & 0x1F);
}
public static byte crc6_ITU(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) == 0) {
checksum = (byte) ((checksum & 0xFF) >> 1);
} else {
checksum = (byte) (((checksum & 0xFF) >> 1) ^ 0x30);
}
}
}
return (byte) (checksum & 0x3F);
}
public static byte crc7_MMC(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; i++) {
if ((checksum & 0x80) == 0) {
checksum <<= 1;
} else {
checksum = (byte) ((checksum << 1) ^ 0x12);
}
}
}
return (byte) ((checksum >> 1) & 0x7F);
}
public static byte crc8(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; i++) {
if ((checksum & 0x80) == 0) {
checksum <<= 1;
} else {
checksum = (byte) ((checksum << 1) ^ 0x07);
}
}
}
return checksum;
}
public static byte crc8_ITU(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; i++) {
if ((checksum & 0x80) == 0) {
checksum <<= 1;
} else {
checksum = (byte) ((checksum << 1) ^ 0x07);
}
}
}
return (byte) (checksum ^ 0x55);
}
public static byte crc8_ROHC(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; i++) {
if ((checksum & 0x80) == 0) {
checksum = (byte) ((checksum & 0xFF) >> 1);
} else {
checksum = (byte) (((checksum & 0xFF) >> 1) ^ 0xE0);
}
}
}
return checksum;
}
public static byte crc8_MAXIM(byte[] datos, int inicio, int longitud) {
byte i;
byte checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; i++) {
if ((checksum & 1) == 0) {
checksum = (byte) ((checksum & 0xFF) >> 1);
} else {
checksum = (byte) (((checksum & 0xFF) >> 1) ^ 0x8C);
}
}
}
return checksum;
}
public static short crc16_IBM(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) == 0) {
checksum = (short) (checksum >> 1);
} else {
checksum = (short) ((checksum >> 1) ^ 0xA001);
}
}
}
return checksum;
}
public static short crc16_MAXIM(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) == 0) {
checksum = (short) (checksum >> 1);
} else {
checksum = (short) ((checksum >> 1) ^ 0xA001);
}
}
}
return (short) ~checksum;
}
public static short crc16_USB(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = (short) 0xFFFF;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) == 0) {
checksum = (short) (checksum >> 1);
} else {
checksum = (short) ((checksum >> 1) ^ 0xA001);
}
}
}
return (short) ~checksum;
}
public static short crc16_MODBUS(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = (short) 0xFFFF;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) == 0) {
checksum = (short) ((checksum & 0xFFFF) >> 1);
} else {
checksum = (short) (((checksum & 0xFFFF) >> 1) ^ 0xA001);
}
}
}
return checksum;
}
public static short crc16_CCITT(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) != 0) {
checksum = (short) ((checksum >> 1) ^ 0x8408);
} else {
checksum = (short) (checksum >> 1);
}
}
}
return checksum;
}
public static short crc16_CCITT_FALSO(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = (short) 0xFFFF;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= (short) ((datos[idx] & 0xFF) << 8);
for (i = 0; i < 8; ++i) {
if ((checksum & 0x8000) != 0) {
checksum = (short) ((checksum << 1) ^ 0x1021);
} else {
checksum <<= 1;
}
}
}
return checksum;
}
public static short crc16_X25(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = (short) 0xFFFF;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) != 0) {
checksum = (short) ((checksum >> 1) ^ 0x8408);
} else {
checksum = (short) (checksum >> 1);
}
}
}
return (short) ~checksum;
}
public static short crc16_XMODEM(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= (short) ((datos[idx] & 0xFF) << 8);
for (i = 0; i < 8; ++i) {
if ((checksum & 0x8000) != 0) {
checksum = (short) ((checksum << 1) ^ 0x1021);
} else {
checksum <<= 1;
}
}
}
return checksum;
}
public static short crc16_DNP(byte[] datos, int inicio, int longitud) {
byte i;
short checksum = 0;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) != 0) {
checksum = (short) ((checksum >> 1) ^ 0xA6BC);
} else {
checksum = (short) (checksum >> 1);
}
}
}
return (short) ~checksum;
}
public static int crc32(byte[] datos, int inicio, int longitud) {
byte i;
int checksum = 0xFFFFFFFF;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= datos[idx] & 0xFF;
for (i = 0; i < 8; ++i) {
if ((checksum & 1) != 0) {
checksum = (checksum >> 1) ^ 0xEDB88320;
} else {
checksum >>= 1;
}
}
}
return ~checksum;
}
public static int crc32_MPEG2(byte[] datos, int inicio, int longitud) {
byte i;
int checksum = 0xFFFFFFFF;
int fin = inicio + longitud;
for (int idx = inicio; idx < fin; idx++) {
checksum ^= (datos[idx] & 0xFF) << 24;
for (i = 0; i < 8; ++i) {
if ((checksum & 0x80000000) != 0) {
checksum = (checksum << 1) ^ 0x04C11DB7;
} else {
checksum <<= 1;
}
}
}
return checksum;
}
}