package com.gzlh.utils; import cn.hutool.core.util.StrUtil; import javax.xml.bind.DatatypeConverter; public class CRC16Util { private static final int PRESET_VALUE = 0xFFFF; private static final int POLYNOMIAL = 0x8408; /** * 计算CRC16校验值 * @param bytes 需要计算的字节数组 * @return CRC16校验值 */ /** * 计算CRC16校验值 * @param bytes 需要计算的字节数组 * @return CRC16校验值 */ /** * 计算CRC16校验值 * * @param bytes 需要计算的字节数组 * @return CRC16校验值 */ public static int calculateCRC16(byte[] bytes) { int crcValue = PRESET_VALUE; for (byte b : bytes) { // 将byte转换为无符号整数 int unsignedByte = b & 0xFF; crcValue = crcValue ^ unsignedByte; for (int j = 0; j < 8; j++) { if ((crcValue & 0x0001) != 0) { crcValue = (crcValue >> 1) ^ POLYNOMIAL; } else { crcValue = crcValue >> 1; } } } return swapCRC16Bytes(crcValue); } /** * 将CRC16的高低位进行交换 * * @param crc 原始CRC16值 * @return 交换后的CRC16值 */ public static int swapCRC16Bytes(int crc) { // 获取高字节和低字节 int highByte = (crc >> 8) & 0xFF; // 右移8位得到高字节 int lowByte = crc & 0xFF; // 与0xFF相与得到低字节 // 交换高低字节 return (lowByte << 8) | highByte; } /** * 获取CRC16校验值的十六进制字符串 * * @param bytes 需要计算的字节数组 * @return CRC16校验值的十六进制字符串 */ public static String getCRC16Hex(byte[] bytes) { int crc = calculateCRC16(bytes); return String.format("%04X", crc); } public static String getCRC16Hex(String hexStr) { int crc = calculateCRC16(DatatypeConverter.parseHexBinary(hexStr)); return String.format("%04X", crc); } // 测试方法 public static void main(String[] args) { System.out.println("E20000001A0C02721820ECB8".length()); // 测试数据 String command = "2D000101030CE200001B170902202610C3A60CFEDC000000000000008102BA0CE200001D8817007817602D1F793F"; int len = command.length(); String crcStr = StrUtil.sub(command, len - 4, len); String packetStr = StrUtil.sub(command, 0, len - 4); String dataPack=StrUtil.subSuf(packetStr,10); int cardNum=Integer.parseInt(StrUtil.sub(packetStr,8,10)); int startIndex=2; for (int i = 0; i < cardNum; i++) { String cardHex = StrUtil.sub(dataPack, startIndex, startIndex+24); startIndex += 26; System.out.println(cardHex); } } }