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 byte[] staticDataBuffer = new byte[BUFFER_SIZE]; private static int staticBufferPosition = 0; /** * 静态方法:接收串口原始数据并解析完整数据包 * @param rawData 原始数据 * @param debugEnabled 是否启用调试 * @param maxRawDataPrintLength 最大打印长度 * @return 解析出的完整数据包列表,如果没有完整包则返回空列表 */ public static List receiveData(byte[] rawData, boolean debugEnabled, int maxRawDataPrintLength) { List completePackets = new ArrayList<>(); if (rawData == null || rawData.length == 0) { return completePackets; } // 打印原始接收数据(调试用) if (debugEnabled) { printRawData("收到串口原始数据", rawData, maxRawDataPrintLength); } // 将数据添加到缓冲区 if (staticBufferPosition + rawData.length > staticDataBuffer.length) { // 缓冲区不足时,清理并重新开始 System.arraycopy(staticDataBuffer, staticBufferPosition - rawData.length, staticDataBuffer, 0, rawData.length); staticBufferPosition = rawData.length; } else { System.arraycopy(rawData, 0, staticDataBuffer, staticBufferPosition, rawData.length); staticBufferPosition += rawData.length; } // 处理缓冲区中的数据并收集完整包 processBuffer(completePackets, debugEnabled); return completePackets; } /** * 处理缓冲区中的数据,解析完整数据包 */ private static void processBuffer(List completePackets, boolean debugEnabled) { final int MIN_PACKET_LENGTH = 9; final byte[] START_MARKER = {(byte) 0xDD, (byte) 0xCC}; while (staticBufferPosition >= MIN_PACKET_LENGTH) { // 查找起始标记 int startIndex = findStartMarker(START_MARKER); if (startIndex == -1) { // 没有找到起始标记,清空无效数据 if (debugEnabled) { System.out.println("未找到起始标记,清空缓冲区"); } staticBufferPosition = 0; return; } // 检查是否有足够的数据读取数据长度 if (startIndex + 4 > staticBufferPosition) { // 数据不足,等待更多数据 compactBuffer(startIndex); return; } // 读取数据长度 (大端序) int dataLength = ((staticDataBuffer[startIndex + 2] & 0xFF) << 8) | (staticDataBuffer[startIndex + 3] & 0xFF); int totalPacketLength = 2 + 2 + dataLength + 2; // 起始标记2 + 数据长度2 + 数据内容 + CRC2 // 检查是否收到完整数据包 if (startIndex + totalPacketLength > staticBufferPosition) { // 数据包不完整,等待更多数据 compactBuffer(startIndex); return; } // 提取完整数据包 byte[] packet = new byte[totalPacketLength]; System.arraycopy(staticDataBuffer, startIndex, packet, 0, totalPacketLength); if (debugEnabled) { System.out.println("解析到完整数据包: " + bytesToHex(packet)); } // 添加到返回列表 completePackets.add(packet); // 移动缓冲区位置 int remaining = staticBufferPosition - (startIndex + totalPacketLength); if (remaining > 0) { System.arraycopy(staticDataBuffer, startIndex + totalPacketLength, staticDataBuffer, 0, remaining); } staticBufferPosition = remaining; } } /** * 查找起始标记位置 */ private static int findStartMarker(byte[] startMarker) { for (int i = 0; i <= staticBufferPosition - startMarker.length; i++) { if (staticDataBuffer[i] == startMarker[0] && staticDataBuffer[i + 1] == startMarker[1]) { return i; } } return -1; } /** * 压缩缓冲区,将有效数据移到开头 */ private static void compactBuffer(int startIndex) { if (startIndex > 0) { System.arraycopy(staticDataBuffer, startIndex, staticDataBuffer, 0, staticBufferPosition - startIndex); staticBufferPosition -= startIndex; } } /** * 打印原始数据(调试用) */ private static 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 static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02X ", b)); } return sb.toString().trim(); } /** * 清空缓冲区(避免内存泄漏) */ public static void clearBuffer() { staticBufferPosition = 0; // 可选:清空缓冲区内容 Arrays.fill(staticDataBuffer, (byte) 0); } /** * 获取当前缓冲区状态 */ public static int getBufferStatus() { return staticBufferPosition; } }