package chuankou; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class SerialDataReceiver { private static final int BUFFER_SIZE = 1024; private static final int MIN_PACKET_LENGTH = 9; private static final byte[] START_MARKER = {(byte) 0xDD, (byte) 0xCC}; // 使用非静态成员避免多线程环境下的竞争条件 private byte[] dataBuffer = new byte[BUFFER_SIZE]; private int bufferPosition = 0; private final List reusablePackets = new ArrayList<>(); /** * 实例方法:接收串口原始数据并解析完整数据包 * @param rawData 原始数据 * @param debugEnabled 是否启用调试 * @param maxRawDataPrintLength 最大打印长度 * @return 解析出的完整数据包列表,如果没有完整包则返回空列表 */ public List receiveData(byte[] rawData, boolean debugEnabled, int maxRawDataPrintLength) { reusablePackets.clear(); if (rawData == null || rawData.length == 0) { return reusablePackets; } // 打印原始接收数据(调试用) if (debugEnabled) { printRawData("收到串口原始数据", rawData, maxRawDataPrintLength); } // 检查缓冲区容量,动态处理 if (!ensureBufferCapacity(rawData.length)) { // 缓冲区不足时,清理并重新开始 if (debugEnabled) { System.out.println("缓冲区不足,清空缓冲区重新开始"); } bufferPosition = 0; } // 将数据添加到缓冲区 System.arraycopy(rawData, 0, dataBuffer, bufferPosition, rawData.length); bufferPosition += rawData.length; // 处理缓冲区中的数据并收集完整包 processBuffer(reusablePackets, debugEnabled); return new ArrayList<>(reusablePackets); } /** * 确保缓冲区有足够容量,如不够则尝试压缩 */ private boolean ensureBufferCapacity(int required) { if (bufferPosition + required <= dataBuffer.length) { return true; } // 尝试通过压缩缓冲区来腾出空间 int startIndex = findStartMarker(); if (startIndex > 0) { compactBuffer(startIndex); return bufferPosition + required <= dataBuffer.length; } return false; } /** * 处理缓冲区中的数据,解析完整数据包 */ private void processBuffer(List completePackets, boolean debugEnabled) { while (bufferPosition >= MIN_PACKET_LENGTH) { // 查找起始标记 int startIndex = findStartMarker(); if (startIndex == -1) { // 没有找到起始标记,清空无效数据 if (debugEnabled) { System.out.println("未找到起始标记,清空缓冲区"); } bufferPosition = 0; return; } // 检查是否有足够的数据读取数据长度 if (startIndex + 4 > bufferPosition) { // 数据不足,等待更多数据 compactBuffer(startIndex); return; } // 读取数据长度 (大端序) int dataLength = ((dataBuffer[startIndex + 2] & 0xFF) << 8) | (dataBuffer[startIndex + 3] & 0xFF); int totalPacketLength = 2 + 2 + dataLength + 2; // 起始标记2 + 数据长度2 + 数据内容 + CRC2 // 检查数据长度有效性 if (dataLength < 0 || totalPacketLength > BUFFER_SIZE) { if (debugEnabled) { System.out.println("无效数据长度: " + dataLength + ", 跳过起始字节"); } // 跳过错误的起始标记,继续查找 compactBuffer(startIndex + 1); continue; } // 检查是否收到完整数据包 if (startIndex + totalPacketLength > bufferPosition) { // 数据包不完整,等待更多数据 compactBuffer(startIndex); return; } // 提取完整数据包 byte[] packet = Arrays.copyOfRange(dataBuffer, startIndex, startIndex + totalPacketLength); if (debugEnabled) { System.out.println("解析到完整数据包: " + bytesToHex(packet)); } // 添加到返回列表 completePackets.add(packet); // 移动缓冲区位置 int remaining = bufferPosition - (startIndex + totalPacketLength); if (remaining > 0) { System.arraycopy(dataBuffer, startIndex + totalPacketLength, dataBuffer, 0, remaining); } bufferPosition = remaining; } } /** * 查找起始标记位置 */ private int findStartMarker() { for (int i = 0; i <= bufferPosition - START_MARKER.length; i++) { if (dataBuffer[i] == START_MARKER[0] && dataBuffer[i + 1] == START_MARKER[1]) { return i; } } return -1; } /** * 压缩缓冲区,将有效数据移到开头 */ private void compactBuffer(int startIndex) { if (startIndex > 0 && startIndex < bufferPosition) { System.arraycopy(dataBuffer, startIndex, dataBuffer, 0, bufferPosition - startIndex); bufferPosition -= startIndex; } } /** * 打印原始数据(调试用) */ private void printRawData(String prefix, byte[] data, int maxPrintLength) { if (data == null || data.length == 0) { System.out.println(prefix + ": 空数据"); return; } StringBuilder sb = new StringBuilder(); sb.append(prefix).append(" [长度: ").append(data.length).append("]: "); int printLength = Math.min(data.length, maxPrintLength); for (int i = 0; i < printLength; i++) { sb.append(String.format("%02X ", data[i])); } if (data.length > maxPrintLength) { sb.append("... [截断,总长度: ").append(data.length).append("]"); } System.out.println(sb.toString()); } /** * 工具方法:字节数组转十六进制字符串 */ private String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X ", b)); } return sb.toString().trim(); } /** * 清空缓冲区(避免内存泄漏) */ public void clearBuffer() { bufferPosition = 0; // 可选:清空缓冲区内容 Arrays.fill(dataBuffer, (byte) 0); } /** * 获取当前缓冲区状态 */ public int getBufferStatus() { return bufferPosition; } /** * 获取缓冲区容量 */ public int getBufferCapacity() { return dataBuffer.length; } }