package home;
|
import java.math.BigInteger;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
// 重命名为PacketParser,表示数据包解析器
|
public class PacketParser {
|
// 添加十六进制字符数组常量
|
private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
// 缓冲区字节数组
|
private byte[] buffer = new byte[4096];
|
// 当前缓冲区有效数据长度
|
private int bufferLength = 0;
|
|
// 追加新数据到缓冲区
|
public void appendData(byte[] newData, int length) {
|
// 检查缓冲区是否足够
|
if (bufferLength + length > buffer.length) {
|
// 创建新的更大缓冲区
|
byte[] newBuffer = new byte[bufferLength + length];
|
// 复制原有数据
|
System.arraycopy(buffer, 0, newBuffer, 0, bufferLength);
|
buffer = newBuffer;
|
}
|
// 追加新数据
|
System.arraycopy(newData, 0, buffer, bufferLength, length);
|
// 更新缓冲区长度
|
bufferLength += length;
|
}
|
|
// 新增方法:字节数组转十六进制字符串
|
public static String bytesToHexString(byte[] bytes) {
|
if (bytes == null) return "";
|
char[] hexChars = new char[bytes.length * 2];
|
for (int j = 0; j < bytes.length; j++) {
|
int v = bytes[j] & 0xFF;
|
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
|
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
|
}
|
return new String(hexChars);
|
}
|
|
// 解析缓冲区中的所有完整数据包
|
public List<DataPacket> parsePackets() {
|
List<DataPacket> packets = new ArrayList<>();
|
int index = 0; // 当前解析位置索引
|
|
// 遍历缓冲区查找完整数据包
|
while (index <= bufferLength - 4) { // 确保有足够数据检查包头
|
// 检查包头标识 0x55 0xAA
|
if (buffer[index] == 0x55 && (buffer[index + 1] & 0xFF) == 0xAA) {
|
// 获取包类型(第3字节)
|
int packetType = buffer[index + 2] & 0xFF;
|
// 获取数据长度(第4字节)
|
int dataLenField = buffer[index + 3] & 0xFF;
|
// 计算完整包长度(包头+数据+校验)
|
int totalPacketLen = 2 + dataLenField + 2; // 增加2字节校验位
|
|
// 检查是否有足够数据构成完整包
|
if (index + totalPacketLen > bufferLength) {
|
break; // 数据不足,等待更多数据
|
}
|
|
// 提取完整数据包
|
byte[] packetData = new byte[totalPacketLen];
|
System.arraycopy(buffer, index, packetData, 0, totalPacketLen);
|
|
// 验证校验和
|
if (verifyChecksum(packetData)) {
|
// 解析单个数据包
|
DataPacket packet = parseSinglePacket(packetType, packetData);
|
if (packet != null) {
|
packets.add(packet); // 添加到结果列表
|
}
|
index += totalPacketLen; // 移动到下一个包
|
} else {
|
index++; // 校验失败,跳过当前字节
|
}
|
} else {
|
index++; // 非包头标识,继续查找
|
}
|
}
|
|
// 清理已处理数据
|
if (index > 0) {
|
int remaining = bufferLength - index;
|
if (remaining > 0) {
|
// 移动剩余数据到缓冲区开头
|
System.arraycopy(buffer, index, buffer, 0, remaining);
|
}
|
bufferLength = remaining; // 更新缓冲区长度
|
}
|
|
return packets;
|
}
|
|
// 校验数据包
|
private boolean verifyChecksum(byte[] packet) {
|
int len = packet.length;
|
if (len < 4) return false;
|
|
int sum = 0;
|
// 从数据类型开始到校验码前结束 (包头2字节已跳过)
|
for (int i = 2; i < len - 2; i++) {
|
sum += packet[i] & 0xFF;
|
}
|
sum = ~sum & 0xFFFF; // 取反并保留16位
|
|
// 获取包中的校验码 (小端模式)
|
int receivedChecksum = ((packet[len - 1] & 0xFF) << 8) | (packet[len - 2] & 0xFF);
|
|
return sum == receivedChecksum;
|
}
|
|
|
|
// 解析单个数据包
|
private DataPacket parseSinglePacket(int packetType, byte[] packet) {
|
|
// 创建数据包对象(包含包类型)
|
return new DataPacket(packetType, packet);
|
}
|
|
// 数据包内部类
|
public static class DataPacket {
|
private final int packetType; // 包类型
|
private final byte[] packet;//包数据
|
|
|
public DataPacket(int packetType, byte[] packet) {
|
this.packetType = packetType;
|
this.packet = packet;
|
}
|
|
// 获取包类型
|
public int getPacketType() {
|
return packetType;
|
}
|
|
// 包数据
|
public byte[] getPacket() {
|
return packet;
|
}
|
|
}
|
|
// HEX字符串转字节数组
|
public static byte[] hexStringToBytes(String hex) {
|
// 移除空格
|
hex = hex.replaceAll("\\s", "");
|
int len = hex.length();
|
// 创建结果数组
|
byte[] data = new byte[len / 2];
|
// 每两个字符转换一个字节
|
for (int i = 0; i < len; i += 2) {
|
// 高位转换
|
int high = Character.digit(hex.charAt(i), 16) << 4;
|
// 低位转换
|
int low = Character.digit(hex.charAt(i + 1), 16);
|
data[i / 2] = (byte) (high | low);
|
}
|
return data;
|
}
|
|
|
|
|
/**输出校验码*/
|
public static String calculateChecksum(String input) {
|
// 检查输入是否为空
|
if (input == null) {
|
throw new IllegalArgumentException("输入不能为null");
|
}
|
// 移除所有空格
|
String cleanInput = input.replaceAll("\\s", "");
|
// 验证处理后的字符串
|
if (cleanInput.length() < 8 || !cleanInput.startsWith("55AA")) {
|
throw new IllegalArgumentException("输入字符串必须以55AA开头且长度至少为8(去除空格后)");
|
}
|
// 去掉包头(55AA)和最后4个字符
|
String dataPart = cleanInput.substring(4, cleanInput.length() - 4);
|
// 检查中间部分长度是否为偶数
|
if (dataPart.length() % 2 != 0) {
|
throw new IllegalArgumentException("校验出错中间部分长度必须是偶数(去除空格后)");
|
}
|
int sum = 0;
|
// 每两个字符解析为一个字节
|
for (int i = 0; i < dataPart.length(); i += 2) {
|
String byteStr = dataPart.substring(i, i + 2);
|
int byteValue = Integer.parseInt(byteStr, 16);
|
sum = (sum + byteValue) & 0xFFFF; // 保持16位范围
|
}
|
|
// 取反并保持16位
|
int checksum = (~sum) & 0xFFFF;
|
|
// 显式处理高位在前格式
|
int lowByte= (checksum >>> 8) & 0xFF; // 高8位
|
int highByte= checksum & 0xFF; // 低8位
|
|
// 格式化为4位十六进制字符串(大写),高位在前
|
return String.format("%02X%02X", highByte, lowByte);
|
}
|
|
/** 将字节数组转为十六进制字符串,例如 [55 AA 01 02 ...] */
|
private static String bytesToHex(byte[] bytes) {
|
if (bytes == null) return "null";
|
StringBuilder sb = new StringBuilder(bytes.length * 3);
|
for (byte b : bytes) {
|
sb.append(String.format("%02X ", b & 0xFF));
|
}
|
// 去掉最后一个空格
|
return sb.substring(0, sb.length() - 1);
|
}
|
|
|
}
|