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