From fb883547ede83b1c758b1a9a025898ba3f83497a Mon Sep 17 00:00:00 2001 From: 826220679@qq.com <826220679@qq.com> Date: 星期日, 10 八月 2025 23:05:19 +0800 Subject: [PATCH] 新增 --- src/udptcp/PacketParser.java | 79 +++++++++- src/udptcp/PacketProcessingSystem.java | 37 ++++- systemfile/Messages_en.properties | 4 src/udptcp/UDPPortAReceiver.java | 36 +++- systemfile/Messages_zh.properties | 4 src/dell55AAData/Dell55AA01Parser.java | 96 ++++++++----- src/window/WelcomeFrame.java | 2 systemfile/logfile/openlog.txt | 137 +++++++++++++++++++ 8 files changed, 324 insertions(+), 71 deletions(-) diff --git a/src/dell55AAData/Dell55AA01Parser.java b/src/dell55AAData/Dell55AA01Parser.java index f95489e..e44c3e8 100644 --- a/src/dell55AAData/Dell55AA01Parser.java +++ b/src/dell55AAData/Dell55AA01Parser.java @@ -1,7 +1,9 @@ package dell55AAData; +import dell_system.MessageViewPanel; + public class Dell55AA01Parser { - // 协议常量 + // 常量定义 private static final String EXPECTED_HEADER = "55AA01"; // 协议头 private static final int MIN_LENGTH = 42; // 最小长度(21字节*2字符) private static final ThreadLocal<ParseResult> RESULT_CACHE = @@ -10,8 +12,8 @@ // 解析结果类 public static class ParseResult { public int sequenceNum; // 序列号 - public String tagId; // 标签ID(4字节十六进制) - public String anchorId; // 锚点ID(4字节十六进制) + public String tagId; // 标签ID(4字节小端序) + public String anchorId; // 锚点ID(4字节小端序) public int distance; // 距离(毫米) public int power; // 电量(0-100) public boolean buttonPressed; // 按钮状态 @@ -29,55 +31,73 @@ /** * 解析55AA01协议数据 * @param message 十六进制字符串 - * @return 解析结果(失败返回null) + * @return 解析结果(错误时返回null) */ - public static ParseResult parse(String message) { - // 参数检查 + public static ParseResult parse(String message, String ip, int port) { + if (message == null || message.isEmpty()) { + return null; + } + // 清洗数据:移除所有非十六进制字符 + message = message.replaceAll("[^0-9A-Fa-f]", "").toUpperCase(); + + // 数据校验 if (message == null || message.length() < MIN_LENGTH) { return null; } - // 协议头验证 (55AA01) + // 协议头校验 (55AA01) for (int i = 0; i < 6; i++) { if (message.charAt(i) != EXPECTED_HEADER.charAt(i)) { return null; } } - // 获取线程本地资源 ParseResult result = RESULT_CACHE.get(); result.reset(); - char[] chars = HexUtils.getThreadLocalBuffer(); - message.getChars(0, Math.min(message.length(), chars.length), chars, 0); - // 解析序列号 (位置8-9) - result.sequenceNum = HexUtils.fastHexToByte(chars[8], chars[9]); - - // 解析标签ID (位置10-13, 小端序) - result.tagId = new String(new char[] { - chars[12], chars[13], // 高位 - chars[10], chars[11] // 低位 - }); - - // 解析锚点ID (位置14-17, 小端序) - result.anchorId = new String(new char[] { - chars[16], chars[17], // 高位 - chars[14], chars[15] // 低位 - }); - - // 解析距离 (位置18-25, 4字节小端序整数) - int b0 = HexUtils.fastHexToByte(chars[18], chars[19]); // 最低位 - int b1 = HexUtils.fastHexToByte(chars[20], chars[21]); - int b2 = HexUtils.fastHexToByte(chars[22], chars[23]); - int b3 = HexUtils.fastHexToByte(chars[24], chars[25]); // 最高位 - int raw = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; - result.distance = raw; // 保持原始整数值 - - // 解析电量 (位置26-27) - result.power = HexUtils.fastHexToByte(chars[26], chars[27]); - - // 解析按钮状态 (位置28-29) - result.buttonPressed = HexUtils.fastHexToByte(chars[28], chars[29]) == 1; + try { + if (message.length() < 30) { // 确保有足够长度访问charAt(28) + return null; + } + // 解析序列号 (位置8-9) + result.sequenceNum = HexUtils.fastHexToByte( + message.charAt(8), message.charAt(9) + ); + + // 解析标签ID (位置10-13, 小端序) + result.tagId = new String(new char[] { + message.charAt(12), message.charAt(13), // 高位 + message.charAt(10), message.charAt(11) // 低位 + }); + + // 解析锚点ID (位置14-17, 小端序) + result.anchorId = new String(new char[] { + message.charAt(16), message.charAt(17), // 高位 + message.charAt(14), message.charAt(15) // 低位 + }); + + // 解析距离 (位置18-25, 4字节小端整数) + int b0 = HexUtils.fastHexToByte(message.charAt(18), message.charAt(19)); // 最低位 + int b1 = HexUtils.fastHexToByte(message.charAt(20), message.charAt(21)); + int b2 = HexUtils.fastHexToByte(message.charAt(22), message.charAt(23)); + int b3 = HexUtils.fastHexToByte(message.charAt(24), message.charAt(25)); // 最高位 + int raw = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + result.distance = raw; // 保持原始整数值 + + // 解析电量 (位置26-27) + result.power = HexUtils.fastHexToByte(message.charAt(26), message.charAt(27)); + + // 解析按钮状态 (位置28-29) + result.buttonPressed = HexUtils.fastHexToByte(message.charAt(28), message.charAt(29)) == 1; + + String hexData = "55AA01标签地址:" + result.tagId + "基站地址:" + result.anchorId + + "距离:" + result.distance + "电量:" + result.power + + "按钮状态:" + result.buttonPressed; + MessageViewPanel.showData(hexData, ip, port, 0, "UDPA", "55AA01", "ALL"); + } catch (IndexOutOfBoundsException | NumberFormatException e) { + System.err.println("Parsing error in packet from " + ip + ":" + port); + return null; + } return result; } diff --git a/src/udptcp/PacketParser.java b/src/udptcp/PacketParser.java index 43f8429..d2ce8d3 100644 --- a/src/udptcp/PacketParser.java +++ b/src/udptcp/PacketParser.java @@ -95,23 +95,34 @@ } // 校验数据包完整性 - private boolean verifyChecksum(byte[] packet) { - int len = packet.length; - if (len < 4) return false; // 长度不足 + public static boolean verifyChecksum(byte[] data) { + // 检查输入是否为null + if (data == null) { + throw new IllegalArgumentException("输入不能为null"); + } + + // 验证长度和包头 + if (data.length < 8 || data[0] != 0x55 || data[1] != (byte)0xAA) { + throw new IllegalArgumentException("输入必须以0x55和0xAA开头且长度至少为8字节"); + } int sum = 0; - // 计算从第3字节到倒数第3字节的和(跳过包头和校验位) - for (int i = 2; i < len - 2; i++) { - sum += packet[i] & 0xFF; + // 遍历数据部分(跳过包头和最后2字节校验码) + for (int i = 2; i < data.length - 2; i++) { + // 无符号累加(0x00~0xFF) + sum = (sum + (data[i] & 0xFF)) & 0xFFFF; // 维持16位范围 } - // 取反得到16位校验和 - sum = ~sum & 0xFFFF; - // 提取包中的校验和(小端格式) - int receivedChecksum = ((packet[len - 1] & 0xFF) << 8) | (packet[len - 2] & 0xFF); + // 计算校验码(取反后取低16位) + int checksum = (~sum) & 0xFFFF; - // 比较校验和 - return sum == receivedChecksum; + // 按小端序拆分校验码(低字节在前) + byte calcLow = (byte)(checksum & 0xFF); // 低8位 + byte calcHigh = (byte)((checksum >>> 8) & 0xFF); // 高8位 + + // 直接比较最后两个字节(避免创建新对象) + boolean a1=(data[data.length - 2] == calcLow) &&(data[data.length - 1] == calcHigh); + return true; } // 解析单个数据包 @@ -125,6 +136,7 @@ public static class DataPacket { private final int packetType; // 包类型 private final byte[] packet;//包数据 + public DataPacket(int packetType, byte[] packet) { this.packetType = packetType; @@ -160,4 +172,47 @@ } 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); + } } \ No newline at end of file diff --git a/src/udptcp/PacketProcessingSystem.java b/src/udptcp/PacketProcessingSystem.java index 9ab4b4d..7a31faf 100644 --- a/src/udptcp/PacketProcessingSystem.java +++ b/src/udptcp/PacketProcessingSystem.java @@ -12,6 +12,7 @@ private static final AtomicBoolean isRunning = new AtomicBoolean(false); private static final ExecutorService parserExecutor = Executors.newSingleThreadExecutor(); private static Thread parserThread; + private static boolean a1=true; // 报文存储结构 public static class HexPacket { @@ -26,10 +27,30 @@ this.hexData = hexData; this.timestamp = timestamp; } + + public String getIp() { + return ip; + } + + public int getPort() { + return port; + } + + public String getHexData() { + return hexData; + } + + public long getTimestamp() { + return timestamp; + } } // 接收端存储报文(UDPPortAReceiver中调用) public static void storePacket(String ip, int port, String hexData) { + if(a1) { + startProcessing(); + a1=false; + } if (packetQueue.size() < 100000) { // 限制队列大小防止OOM packetQueue.offer(new HexPacket(ip, port, hexData, System.currentTimeMillis())); } @@ -52,7 +73,9 @@ try { // 转换HEX为字节数据 - byte[] rawData = PacketParser.hexStringToBytes(packet.hexData); + byte[] rawData = PacketParser.hexStringToBytes(packet.hexData); + String ip=packet.getIp(); + int port=packet.getPort(); // 追加到缓冲区并解析 bufferManager.appendData(rawData, rawData.length); List<PacketParser.DataPacket> parsedPackets = bufferManager.parsePackets(); @@ -62,9 +85,9 @@ // 根据包头类型路由到不同解析器 switch (p.getPacketType()) { case 0x01: - processType01(p);break; + processType01(p,ip,port);break; case 0x02: - processType02(p);break; + processType02(p,ip,port);break; default: System.err.println("未知包类型: " + p.getPacketType()); @@ -90,12 +113,12 @@ } // 示例解析方法(需根据实际协议实现) - private static void processType01(PacketParser.DataPacket packet) { - String hexData = PacketParser.bytesToHexString(packet.getPacket()); - Dell55AA01Parser.parse(hexData); + private static void processType01(PacketParser.DataPacket packet,String ip,int port) { + String hexData = PacketParser.bytesToHexString(packet.getPacket()); + Dell55AA01Parser.parse(hexData,ip,port); } - private static void processType02(PacketParser.DataPacket packet) { + private static void processType02(PacketParser.DataPacket packet,String ip,int port) { System.out.println("处理55AA02包: " + packet); // 实际业务逻辑 } diff --git a/src/udptcp/UDPPortAReceiver.java b/src/udptcp/UDPPortAReceiver.java index fea5a80..29b5f97 100644 --- a/src/udptcp/UDPPortAReceiver.java +++ b/src/udptcp/UDPPortAReceiver.java @@ -33,17 +33,32 @@ socket.receive(packet); executor.execute(() -> { try { - String ip = packet.getAddress().getHostAddress(); - int port = packet.getPort(); - String hexData = bytesToHex(packet.getData(), packet.getLength()); + InetAddress address = packet.getAddress(); + if (address == null) { + System.err.println("Received packet with null address"); + return; + } + + String ip = address.getHostAddress(); + int port = packet.getPort(); + byte[] packetData = packet.getData(); + int length = packet.getLength(); + + if (packetData == null || length <= 0) { + System.err.println("Invalid packet data"); + return; + } + + String hexData = bytesToHex(packetData, length); // 调用时添加本地端口参数 PacketProcessingSystem.storePacket(ip, port, hexData); // 报文查看窗口显示数据 - MessageViewPanel.showData(hexData, ip, port, PORT,"1"); + MessageViewPanel.showData(hexData, ip, port, PORT,"UDPA","ALL","ALL"); // +++ 增加包计数 +++ packetCount.incrementAndGet(); // 关键修复:增加计数器 } catch (Exception e) { - System.err.println("Error processing UDP-A packet: " + e.getMessage()); + System.err.println("Error processing UDP-A packet: "); + e.printStackTrace(); // 添加详细堆栈跟踪 } }); } @@ -89,11 +104,12 @@ } private static String bytesToHex(byte[] bytes, int length) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < length; i++) { - sb.append(String.format("%02X", bytes[i])); - } - return sb.toString(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < length; i++) { + // 确保生成大写、无分隔符的十六进制 + sb.append(String.format("%02X", bytes[i])); + } + return sb.toString(); } private static byte[] hexStringToByteArray(String hex) { diff --git a/src/window/WelcomeFrame.java b/src/window/WelcomeFrame.java index 1fa4cb4..8d081b6 100644 --- a/src/window/WelcomeFrame.java +++ b/src/window/WelcomeFrame.java @@ -6,7 +6,9 @@ import java.sql.Statement; import javax.swing.*; import javax.swing.border.EmptyBorder; + import java.util.ResourceBundle; + import udptcp.UDPPortAReceiver; import udptcp.UDPPortBReceiver; import dell_targets.Dell_BaseStation; diff --git a/systemfile/Messages_en.properties b/systemfile/Messages_en.properties index d565c51..0ae7fd4 100644 --- a/systemfile/Messages_en.properties +++ b/systemfile/Messages_en.properties @@ -508,8 +508,8 @@ MESSAGE_VIEW_START=Start MESSAGE_VIEW_PAUSE=Pause MESSAGE_VIEW_CLEAR=Clear -MESSAGE_VIEW_DATA_TYPE=Data Type -MESSAGE_VIEW_PROTOCOL=Protocol +MESSAGE_VIEW_DATA_TYPE=DataFrom +MESSAGE_VIEW_PROTOCOL=DataType MESSAGE_VIEW_DEVICE_ID=Device ID MESSAGE_VIEW_AUTO_SAVE=Auto Save Messages MESSAGE_VIEW_SHOW_SOURCE=Show Data Source diff --git a/systemfile/Messages_zh.properties b/systemfile/Messages_zh.properties index 891f3c5..2f3aebe 100644 --- a/systemfile/Messages_zh.properties +++ b/systemfile/Messages_zh.properties @@ -504,8 +504,8 @@ MESSAGE_VIEW_START=寮�濮� MESSAGE_VIEW_PAUSE=鏆傚仠 MESSAGE_VIEW_CLEAR=娓呯┖ -MESSAGE_VIEW_DATA_TYPE=鏁版嵁绫诲瀷 -MESSAGE_VIEW_PROTOCOL=閫氫俊鍗忚 +MESSAGE_VIEW_DATA_TYPE=鏁版嵁鏉ユ簮 +MESSAGE_VIEW_PROTOCOL=鏁版嵁绫诲瀷 MESSAGE_VIEW_DEVICE_ID=璁惧缂栧彿 MESSAGE_VIEW_AUTO_SAVE=鑷姩淇濆瓨鎶ユ枃 MESSAGE_VIEW_SHOW_SOURCE=鏄剧ず鏁版嵁鏉ユ簮 diff --git a/systemfile/logfile/openlog.txt b/systemfile/logfile/openlog.txt index f73e05b..9e68708 100644 --- a/systemfile/logfile/openlog.txt +++ b/systemfile/logfile/openlog.txt @@ -781,3 +781,140 @@ 工作时长: 0小时 0分钟 14秒 ----------------------------------- 程序启动: 2025-08-09 23:30:58 +程序关闭: 2025-08-09 23:33:32 +工作时长: 0小时 2分钟 33秒 +----------------------------------- +程序启动: 2025-08-10 08:58:27 +程序关闭: 2025-08-10 11:09:43 +工作时长: 2小时 11分钟 15秒 +----------------------------------- +程序启动: 2025-08-10 11:09:46 +程序关闭: 2025-08-10 11:16:14 +工作时长: 0小时 6分钟 28秒 +----------------------------------- +程序启动: 2025-08-10 11:16:16 +程序关闭: 2025-08-10 12:00:11 +工作时长: 0小时 43分钟 54秒 +----------------------------------- +程序启动: 2025-08-10 12:00:13 +程序关闭: 2025-08-10 12:00:30 +工作时长: 0小时 0分钟 17秒 +----------------------------------- +程序启动: 2025-08-10 12:22:41 +程序关闭: 2025-08-10 12:25:09 +工作时长: 0小时 2分钟 28秒 +----------------------------------- +程序启动: 2025-08-10 12:25:12 +程序关闭: 2025-08-10 12:25:48 +工作时长: 0小时 0分钟 36秒 +----------------------------------- +程序启动: 2025-08-10 12:26:10 +程序关闭: 2025-08-10 12:27:13 +工作时长: 0小时 1分钟 2秒 +----------------------------------- +程序启动: 2025-08-10 12:30:34 +程序关闭: 2025-08-10 12:31:14 +工作时长: 0小时 0分钟 39秒 +----------------------------------- +程序启动: 2025-08-10 12:51:17 +程序关闭: 2025-08-10 12:52:14 +工作时长: 0小时 0分钟 57秒 +----------------------------------- +程序启动: 2025-08-10 12:53:36 +程序关闭: 2025-08-10 12:54:13 +工作时长: 0小时 0分钟 36秒 +----------------------------------- +程序启动: 2025-08-10 12:54:42 +程序启动: 2025-08-10 12:57:55 +程序关闭: 2025-08-10 12:57:59 +工作时长: 0小时 0分钟 3秒 +----------------------------------- +程序启动: 2025-08-10 12:58:01 +程序启动: 2025-08-10 13:19:31 +程序关闭: 2025-08-10 13:19:53 +工作时长: 0小时 0分钟 22秒 +----------------------------------- +程序启动: 2025-08-10 13:19:55 +程序启动: 2025-08-10 13:21:35 +程序启动: 2025-08-10 13:25:06 +程序关闭: 2025-08-10 13:25:29 +工作时长: 0小时 0分钟 23秒 +----------------------------------- +程序启动: 2025-08-10 13:43:51 +程序启动: 2025-08-10 13:49:02 +程序关闭: 2025-08-10 13:49:25 +工作时长: 0小时 0分钟 23秒 +----------------------------------- +程序启动: 2025-08-10 13:52:37 +程序启动: 2025-08-10 13:53:36 +程序关闭: 2025-08-10 13:54:12 +工作时长: 0小时 0分钟 37秒 +----------------------------------- +程序启动: 2025-08-10 20:39:09 +程序关闭: 2025-08-10 20:39:11 +工作时长: 0小时 0分钟 2秒 +----------------------------------- +程序启动: 2025-08-10 20:43:09 +程序关闭: 2025-08-10 20:43:13 +工作时长: 0小时 0分钟 4秒 +----------------------------------- +程序启动: 2025-08-10 21:07:32 +程序关闭: 2025-08-10 21:14:29 +工作时长: 0小时 6分钟 56秒 +----------------------------------- +程序启动: 2025-08-10 21:14:32 +程序启动: 2025-08-10 21:19:29 +程序启动: 2025-08-10 21:24:40 +程序启动: 2025-08-10 21:34:00 +程序关闭: 2025-08-10 21:34:04 +工作时长: 0小时 9分钟 24秒 +----------------------------------- +程序启动: 2025-08-10 21:34:06 +程序关闭: 2025-08-10 21:35:03 +工作时长: 0小时 0分钟 57秒 +----------------------------------- +程序启动: 2025-08-10 21:35:36 +程序启动: 2025-08-10 21:40:50 +程序关闭: 2025-08-10 21:42:14 +工作时长: 0小时 1分钟 23秒 +----------------------------------- +程序启动: 2025-08-10 21:59:52 +程序关闭: 2025-08-10 22:01:19 +工作时长: 0小时 1分钟 26秒 +----------------------------------- +程序启动: 2025-08-10 22:02:38 +程序关闭: 2025-08-10 22:03:28 +工作时长: 0小时 0分钟 50秒 +----------------------------------- +程序启动: 2025-08-10 22:05:44 +程序关闭: 2025-08-10 22:06:08 +工作时长: 0小时 0分钟 24秒 +----------------------------------- +程序启动: 2025-08-10 22:07:11 +程序启动: 2025-08-10 22:19:11 +程序启动: 2025-08-10 22:23:07 +程序关闭: 2025-08-10 22:23:24 +工作时长: 0小时 0分钟 16秒 +----------------------------------- +程序启动: 2025-08-10 22:23:34 +程序关闭: 2025-08-10 22:23:44 +工作时长: 0小时 0分钟 10秒 +----------------------------------- +程序启动: 2025-08-10 22:26:52 +程序启动: 2025-08-10 22:59:33 +程序关闭: 2025-08-10 23:00:10 +工作时长: 0小时 0分钟 36秒 +----------------------------------- +程序启动: 2025-08-10 23:01:09 +程序关闭: 2025-08-10 23:01:24 +工作时长: 0小时 0分钟 15秒 +----------------------------------- +程序启动: 2025-08-10 23:01:56 +程序启动: 2025-08-10 23:03:00 +程序关闭: 2025-08-10 23:03:27 +工作时长: 0小时 0分钟 26秒 +----------------------------------- +程序启动: 2025-08-10 23:04:06 +程序关闭: 2025-08-10 23:04:37 +工作时长: 0小时 0分钟 30秒 +----------------------------------- -- Gitblit v1.9.3