From 1562f05c0c85fb45cc8ffba8ac6984e9b6f96bd4 Mon Sep 17 00:00:00 2001 From: 826220679@qq.com <826220679@qq.com> Date: 星期五, 08 八月 2025 23:07:50 +0800 Subject: [PATCH] 串口通信 --- /dev/null | 180 ------------ src/dell55AAData/Dell55AA12HighPerf.java | 168 ++++++++++++ systemfile/Messages_zh.properties | 22 src/dell55AAData/Dell55AA01Parser.java | 84 ++++++ src/dell55AAData/PacketParser.java | 105 +++++++ src/dell55AAData/HexUtils.java | 40 ++ src/dell_system/SerialCommPanel.java | 110 +------ systemfile/logfile/openlog.txt | 79 +++++ 8 files changed, 502 insertions(+), 286 deletions(-) diff --git a/src/Dell55aa/Dell55AA01.java b/src/Dell55aa/Dell55AA01.java deleted file mode 100644 index 4ca9bef..0000000 --- a/src/Dell55aa/Dell55AA01.java +++ /dev/null @@ -1,5 +0,0 @@ -package Dell55aa; - -public class Dell55AA01 { - -} diff --git a/src/Dell55aa/Dell55AA12HighPerf.java b/src/Dell55aa/Dell55AA12HighPerf.java deleted file mode 100644 index 5a754a9..0000000 --- a/src/Dell55aa/Dell55AA12HighPerf.java +++ /dev/null @@ -1,180 +0,0 @@ -package Dell55aa; - -public class Dell55AA12HighPerf { // 高性能解析类 - - // 常量定义(避免重复创建) - private static final String HEADER = "55AA12"; // 包头常量 - private static final int MIN_LENGTH = 34; // 最小有效长度 - private static final ThreadLocal<ParseResult> RESULT_CACHE = // 线程本地结果缓存 - ThreadLocal.withInitial(ParseResult::new); - private static final ThreadLocal<char[]> CHAR_BUF_CACHE = // 字符缓冲区缓存 - ThreadLocal.withInitial(() -> new char[256]); - - // 十六进制字符转换表(避免重复计算) - private static final int[] HEX_VALUES = new int[128]; - static { - for (int i = 0; i < HEX_VALUES.length; i++) { - char c = (char) i; - if (c >= '0' && c <= '9') HEX_VALUES[i] = c - '0'; - else if (c >= 'A' && c <= 'F') HEX_VALUES[i] = 10 + (c - 'A'); - else if (c >= 'a' && c <= 'f') HEX_VALUES[i] = 10 + (c - 'a'); - else HEX_VALUES[i] = -1; // 非法字符标记 - } - } - - // 解析结果复用类(对象池模式) - public static class ParseResult { - public int tagId; - public int sequenceNum; - public int power; - public int vibrationState; - public boolean tagRemoved; - public boolean isSleeping; - public boolean isStatic; - public boolean sosButtonPressed; - public int tagHeight; - public int anchorCount; - public int[] anchorIds = new int[0]; - public int[] distances = new int[0]; - public int[] anchorPowers = new int[0]; - public int[] signalStrengths1 = new int[0]; - public int[] signalStrengths2 = new int[0]; - - // 重置方法(避免重新创建数组) - public void reset() { - tagId = 0; - sequenceNum = 0; - power = 0; - vibrationState = 0; - tagRemoved = false; - isSleeping = false; - isStatic = false; - sosButtonPressed = false; - tagHeight = 0; - anchorCount = 0; - // 保留数组,仅重置长度 - } - } - - /** - * 高性能解析方法 - * @param message 原始16进制消息 - * @return 解析结果对象(线程内复用) - */ - public static ParseResult parse(String message) { - // 快速长度校验 - if (message == null || message.length() < MIN_LENGTH) { - return null; // 快速失败 - } - - // 包头检查(避免创建子字符串) - if (!(message.charAt(0) == '5' && - message.charAt(1) == '5' && - message.charAt(2) == 'A' && - message.charAt(3) == 'A' && - message.charAt(4) == '1' && - message.charAt(5) == '2')) { - return null; // 包头无效 - } - - // 从线程缓存获取结果对象 - ParseResult result = RESULT_CACHE.get(); - result.reset(); // 重置对象状态 - - // 直接操作字符数组(避免字符串操作) - char[] chars = CHAR_BUF_CACHE.get(); - message.getChars(0, Math.min(message.length(), chars.length), chars, 0); - - // 解析数据长度(直接计算) - int dataLength = (fastHexToByte(chars[6], chars[7]) * 2) + 8; - if (message.length() != dataLength) { - return null; // 长度不匹配 - } - - // 解析标签信息(无临时对象创建) - parseTagInfo(chars, result); - - // 解析基站信息(数组复用) - parseAnchorInfo(chars, result); - - return result; - } - - /** - * 标签信息解析(无对象创建) - */ - private static void parseTagInfo(char[] chars, ParseResult result) { - // 标签ID(直接计算) - result.tagId = (fastHexToByte(chars[10], chars[11]) << 8) | - fastHexToByte(chars[8], chars[9]); - - // 包序列号(直接计算) - result.sequenceNum = (fastHexToByte(chars[14], chars[15]) << 8) | - fastHexToByte(chars[12], chars[13]); - - // 电量(单字节转换) - result.power = fastHexToByte(chars[16], chars[17]); - - // 按键状态(位运算代替字符串操作) - int buttonState = fastHexToByte(chars[18], chars[19]); - result.vibrationState = (buttonState >> 5) & 1; // 第2位 - result.tagRemoved = ((buttonState >> 3) & 1) == 1; // 第4位 - result.isSleeping = ((buttonState >> 2) & 1) == 1; // 第5位 - result.isStatic = ((buttonState >> 1) & 1) == 1; // 第6位 - result.sosButtonPressed = (buttonState & 1) == 1; // 第7位 - - // 标签高度(直接计算) - result.tagHeight = (fastHexToByte(chars[22], chars[23]) << 8) | - fastHexToByte(chars[20], chars[21]); - } - - /** - * 基站信息解析(数组复用) - */ - private static void parseAnchorInfo(char[] chars, ParseResult result) { - // 基站数量 - result.anchorCount = fastHexToByte(chars[32], chars[33]); - if (result.anchorCount == 0) return; - - // 数组复用检查(避免重复创建) - if (result.anchorIds.length < result.anchorCount) { - result.anchorIds = new int[result.anchorCount]; - result.distances = new int[result.anchorCount]; - result.anchorPowers = new int[result.anchorCount]; - result.signalStrengths1 = new int[result.anchorCount]; - result.signalStrengths2 = new int[result.anchorCount]; - } - - // 基站信息解析(直接索引计算) - int baseIndex = 34; - int powerIndex = 34 + result.anchorCount * 4; - - for (int i = 0; i < result.anchorCount; i++) { - // 基站ID(小端序) - int idLow = fastHexToByte(chars[baseIndex], chars[baseIndex+1]); - int idHigh = fastHexToByte(chars[baseIndex+2], chars[baseIndex+3]); - result.anchorIds[i] = (idHigh << 8) | idLow; - - // 基站距离 - int distLow = fastHexToByte(chars[baseIndex+4], chars[baseIndex+5]); - int distHigh = fastHexToByte(chars[baseIndex+6], chars[baseIndex+7]); - result.distances[i] = (distHigh << 8) | distLow; - - // 基站电量 - result.anchorPowers[i] = fastHexToByte(chars[powerIndex], chars[powerIndex+1]); - - baseIndex += 8; // 每个基站占用8字符 - powerIndex += 2; // 每个电量占用2字符 - } - } - - /** - * 快速十六进制转字节(查表法) - */ - private static int fastHexToByte(char c1, char c2) { - int high = (c1 < 128) ? HEX_VALUES[c1] : -1; - int low = (c2 < 128) ? HEX_VALUES[c2] : -1; - if (high < 0 || low < 0) return 0; // 无效字符处理 - return (high << 4) | low; - } -} \ No newline at end of file diff --git a/src/dell55AAData/Dell55AA01Parser.java b/src/dell55AAData/Dell55AA01Parser.java new file mode 100644 index 0000000..f95489e --- /dev/null +++ b/src/dell55AAData/Dell55AA01Parser.java @@ -0,0 +1,84 @@ +package dell55AAData; + +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 = + ThreadLocal.withInitial(ParseResult::new); + + // 解析结果类 + public static class ParseResult { + public int sequenceNum; // 序列号 + public String tagId; // 标签ID(4字节十六进制) + public String anchorId; // 锚点ID(4字节十六进制) + public int distance; // 距离(毫米) + public int power; // 电量(0-100) + public boolean buttonPressed; // 按钮状态 + + public void reset() { + sequenceNum = 0; + tagId = ""; + anchorId = ""; + distance = 0; + power = 0; + buttonPressed = false; + } + } + + /** + * 解析55AA01协议数据 + * @param message 十六进制字符串 + * @return 解析结果(失败返回null) + */ + public static ParseResult parse(String message) { + // 参数检查 + if (message == null || message.length() < MIN_LENGTH) { + return null; + } + + // 协议头验证 (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; + + return result; + } +} \ No newline at end of file diff --git a/src/dell55AAData/Dell55AA12HighPerf.java b/src/dell55AAData/Dell55AA12HighPerf.java new file mode 100644 index 0000000..06f29dd --- /dev/null +++ b/src/dell55AAData/Dell55AA12HighPerf.java @@ -0,0 +1,168 @@ +package dell55AAData; + +public class Dell55AA12HighPerf { + + // 协议常量 + @SuppressWarnings("unused") + private static final String HEADER = "55AA12"; // 协议头 + private static final int MIN_LENGTH = 34; // 最小数据长度 + private static final ThreadLocal<ParseResult> RESULT_CACHE = // 解析结果缓存 + ThreadLocal.withInitial(ParseResult::new); + + // 解析结果类 + public static class ParseResult { + public String tagId; // 标签ID + public int sequenceNum; // 序列号 + public int power; // 电量 + public int vibrationState; // 振动状态 + public boolean tagRemoved; // 标签移除状态 + public boolean isSleeping; // 休眠状态 + public boolean isStatic; // 静止状态 + public boolean sosButtonPressed; // SOS按钮状态 + public int tagHeight; // 标签高度 + public int anchorCount; // 锚点数量 + public String[] anchorIds = new String[0]; // 锚点ID数组 + public int[] distances = new int[0]; // 距离数组 + public int[] anchorPowers = new int[0]; // 锚点电量数组 + public int[] signalStrengths1 = new int[0]; // 信号强度1 + public int[] signalStrengths2 = new int[0]; // 信号强度2 + + // 重置方法 + public void reset() { + tagId = ""; + sequenceNum = 0; + power = 0; + vibrationState = 0; + tagRemoved = false; + isSleeping = false; + isStatic = false; + sosButtonPressed = false; + tagHeight = 0; + anchorCount = 0; + // 数组保持长度,只重置计数 + } + } + + /** + * 解析协议数据 + * @param message 原始16进制字符串 + * @return 解析结果对象(线程安全) + */ + public static ParseResult parse(String message) { + // 长度校验 + if (message == null || message.length() < MIN_LENGTH) { + return null; + } + + // 协议头校验 + if (!(message.charAt(0) == '5' && + message.charAt(1) == '5' && + message.charAt(2) == 'A' && + message.charAt(3) == 'A' && + message.charAt(4) == '1' && + message.charAt(5) == '2')) { + return null; + } + + // 获取线程本地结果对象 + ParseResult result = RESULT_CACHE.get(); + result.reset(); + + // 获取字符缓冲区 + char[] chars = HexUtils.getThreadLocalBuffer(); + message.getChars(0, Math.min(message.length(), chars.length), chars, 0); + + // 解析数据长度 + int dataLength = (HexUtils.fastHexToByte(chars[6], chars[7]) * 2) + 8; + if (message.length() != dataLength) { + return null; + } + + // 解析标签信息 + parseTagInfo(chars, result); + + // 解析锚点信息 + parseAnchorInfo(chars, result); + + return result; + } + + /** + * 解析标签信息 + */ + private static void parseTagInfo(char[] chars, ParseResult result) { + // 标签ID(小端序) + result.tagId = new String(new char[] { + chars[10], chars[11], // 高字节 + chars[8], chars[9] // 低字节 + }); + // 序列号(小端序) + result.sequenceNum = (HexUtils.fastHexToByte(chars[14], chars[15]) << 8 | + HexUtils.fastHexToByte(chars[12], chars[13])); + + // 电量 + result.power = HexUtils.fastHexToByte(chars[16], chars[17]); + + // 状态标志 + int buttonState = HexUtils.fastHexToByte(chars[18], chars[19]); + result.vibrationState = (buttonState >> 5) & 1; + result.tagRemoved = ((buttonState >> 3) & 1) == 1; + result.isSleeping = ((buttonState >> 2) & 1) == 1; + result.isStatic = ((buttonState >> 1) & 1) == 1; + result.sosButtonPressed = (buttonState & 1) == 1; + + // 标签高度(小端序) + result.tagHeight = (HexUtils.fastHexToByte(chars[22], chars[23]) << 8 | + HexUtils.fastHexToByte(chars[20], chars[21])); + } + + /** + * 解析锚点信息 + */ + private static void parseAnchorInfo(char[] chars, ParseResult result) { + // 锚点数量 + result.anchorCount = HexUtils.fastHexToByte(chars[32], chars[33]); + if (result.anchorCount == 0) return; + + // 动态扩展数组 + if (result.anchorIds.length < result.anchorCount) { + result.anchorIds = new String[result.anchorCount]; + result.distances = new int[result.anchorCount]; + result.anchorPowers = new int[result.anchorCount]; + result.signalStrengths1 = new int[result.anchorCount]; + result.signalStrengths2 = new int[result.anchorCount]; + } + + int baseIndex = 34; // 锚点ID起始位置 + int distanceStart = baseIndex + result.anchorCount * 4; // 距离起始位置 + int powerStart = distanceStart + result.anchorCount * 4; // 电量起始位置 + + // 解析锚点ID(小端序) + for (int i = 0; i < result.anchorCount; i++) { + int idOffset = baseIndex + i * 4; + result.anchorIds[i] = new String(new char[]{ + chars[idOffset + 2], // 高字节1 + chars[idOffset + 3], // 高字节2 + chars[idOffset], // 低字节1 + chars[idOffset + 1] // 低字节2 + }); + } + + // 解析距离(有符号整数处理) + for (int i = 0; i < result.anchorCount; i++) { + int distOffset = distanceStart + i * 4; + int distLow = HexUtils.fastHexToByte(chars[distOffset], chars[distOffset + 1]); + int distHigh = HexUtils.fastHexToByte(chars[distOffset + 2], chars[distOffset + 3]); + int rawDistance = (distHigh << 8) | distLow; + result.distances[i] = (rawDistance > 0x7FFF) + ? (rawDistance - 0x10000) + : rawDistance; + } + + // 解析锚点电量 + for (int i = 0; i < result.anchorCount; i++) { + int powerOffset = powerStart + i * 2; + result.anchorPowers[i] = HexUtils.fastHexToByte(chars[powerOffset], chars[powerOffset + 1]); + } + } +} \ No newline at end of file diff --git a/src/dell55AAData/HexUtils.java b/src/dell55AAData/HexUtils.java new file mode 100644 index 0000000..162b2e0 --- /dev/null +++ b/src/dell55AAData/HexUtils.java @@ -0,0 +1,40 @@ +package dell55AAData; + +public class HexUtils { + // 十六进制字符快速转换表 (ASCII范围内) + private static final int[] HEX_VALUES = new int[128]; + static { + for (int i = 0; i < HEX_VALUES.length; i++) { + char c = (char) i; + if (c >= '0' && c <= '9') HEX_VALUES[i] = c - '0'; + else if (c >= 'A' && c <= 'F') HEX_VALUES[i] = 10 + (c - 'A'); + else if (c >= 'a' && c <= 'f') HEX_VALUES[i] = 10 + (c - 'a'); + else HEX_VALUES[i] = -1; + } + } + + // 线程安全的字符缓冲区 (初始大小256) + private static final ThreadLocal<char[]> CHAR_BUF_CACHE = + ThreadLocal.withInitial(() -> new char[256]); + + /** + * 获取线程本地字符缓冲区 + * @return 可复用的char[256]缓冲区 + */ + public static char[] getThreadLocalBuffer() { + return CHAR_BUF_CACHE.get(); + } + + /** + * 快速将两个十六进制字符转换为字节 + * @param c1 高位字符 (0-9, A-F, a-f) + * @param c2 低位字符 (0-9, A-F, a-f) + * @return 转换后的字节值 (无效字符返回0) + */ + public static int fastHexToByte(char c1, char c2) { + int high = (c1 < 128) ? HEX_VALUES[c1] : -1; + int low = (c2 < 128) ? HEX_VALUES[c2] : -1; + if (high < 0 || low < 0) return 0; + return (high << 4) | low; + } +} \ No newline at end of file diff --git a/src/dell55AAData/PacketParser.java b/src/dell55AAData/PacketParser.java new file mode 100644 index 0000000..bc75351 --- /dev/null +++ b/src/dell55AAData/PacketParser.java @@ -0,0 +1,105 @@ +package dell55AAData; +import dell55AAData.Dell55AA12HighPerf; +import dell55AAData.Dell55AA12HighPerf.ParseResult; +import dell55AAData.Dell55AA01Parser; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.ResourceBundle; + +/** + * 公共解析器:根据包头统一解析 55AA01 / 55AA12 / 未知协议 + * 可被任何 UI 或业务类直接调用 + */ +public final class PacketParser { + + private static final SimpleDateFormat SDF = new SimpleDateFormat("HH:mm:ss.SSS"); + + private PacketParser() { /* 工具类,禁止实例化 */ } + + /** + * 解析入口 + * + * @param data 完整字节数组 + * @param bundle 国际化资源 + * @param showTime 是否在结果前加时间戳 + * @return 解析后的可读字符串,若解析失败返回提示 + */ + public static String parse(byte[] data,ResourceBundle bundle,boolean showTime) { + String hex = bytesToHex(data).toUpperCase(); + StringBuilder sb = new StringBuilder(); + if (showTime) { + sb.append('[').append(SDF.format(new Date())).append("]"); + } + + if (hex.startsWith("55AA01")) { + Dell55AA01Parser.ParseResult r = Dell55AA01Parser.parse(hex); + if (r == null) { + sb.append(bundle.getString("parser.invalid")).append(" 55AA01"); + return sb.toString(); + } + + String button = r.buttonPressed ? bundle.getString("yes") : bundle.getString("no"); + sb.append(bundle.getString("label.sequence")).append(": ").append(r.sequenceNum).append(',') + .append(bundle.getString("label.id")).append(": ").append(r.tagId).append(',') + .append(bundle.getString("label.anchor_ids")).append(": ").append(r.anchorId).append(',') + .append(bundle.getString("label.distances")).append(": ").append(r.distance).append(',') + .append(bundle.getString("label.power")).append(": ").append(r.power).append("%,") + .append(bundle.getString("status.button")).append(": ").append(button); + + } else if (hex.startsWith("55AA12")) { + ParseResult r = Dell55AA12HighPerf.parse(hex); + if (r == null) { + sb.append(bundle.getString("parser.invalid")).append(" 55AA12"); + return sb.toString(); + } + + // 组装基站信息 + StringBuilder ids = new StringBuilder(); + StringBuilder dists = new StringBuilder(); + StringBuilder powers = new StringBuilder(); + for (int i = 0; i < r.anchorCount; i++) { + if (i > 0) { + ids.append(','); + dists.append(','); + powers.append(','); + } + ids.append(r.anchorIds[i]); + dists.append(r.distances[i]); + powers.append(r.anchorPowers[i]); + } + + String button = r.sosButtonPressed ? bundle.getString("yes") : bundle.getString("no"); + String stat = r.isStatic ? bundle.getString("yes") : bundle.getString("no"); + String sleep = r.isSleeping ? bundle.getString("yes") : bundle.getString("no"); + String vibrate = (r.vibrationState == 1) ? bundle.getString("on") : bundle.getString("off"); + String uwb = r.tagRemoved ? bundle.getString("off") : bundle.getString("on"); + + sb.append(bundle.getString("label.id")).append(": ").append(r.tagId).append('\n') + .append(bundle.getString("label.sequence")).append(": ").append(r.sequenceNum).append('\n') + .append(bundle.getString("label.power")).append(": ").append(r.power).append("%\n") + .append(bundle.getString("label.status")).append(": ") + .append(bundle.getString("status.button")).append('[').append(button).append("], ") + .append(bundle.getString("status.static")).append('[').append(stat).append("], ") + .append(bundle.getString("status.sleeping")).append('[').append(sleep).append("], ") + .append(bundle.getString("status.vibration")).append('[').append(vibrate).append("], ") + .append(bundle.getString("status.uwb_switch")).append('[').append(uwb).append("]\n") + .append(bundle.getString("label.tag_height")).append(": ").append(r.tagHeight).append('\n') + .append(bundle.getString("label.anchor_count")).append(": ").append(r.anchorCount).append('\n') + .append(bundle.getString("label.anchor_ids")).append(": (").append(ids).append(")\n") + .append(bundle.getString("label.distances")).append(": (").append(dists).append(")\n") + .append(bundle.getString("label.anchor_powers")).append(": (").append(powers).append(")\n"); + + } else { + sb.append(bundle.getString("parser.unknown")); + } + + sb.append("\n"); + return sb.toString(); + } + + private static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(bytes.length * 2); + for (byte b : bytes) sb.append(String.format("%02X", b)); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/dell_system/SerialCommPanel.java b/src/dell_system/SerialCommPanel.java index 2ab154d..a4aee12 100644 --- a/src/dell_system/SerialCommPanel.java +++ b/src/dell_system/SerialCommPanel.java @@ -1,7 +1,6 @@ package dell_system; import com.fazecast.jSerialComm.SerialPort; -import Dell55aa.Dell55AA12HighPerf; -import Dell55aa.Dell55AA12HighPerf.ParseResult; +import dell55AAData.PacketParser; import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.event.PopupMenuEvent; @@ -327,97 +326,27 @@ /* ================= 解析数据显示 ================= */ private void appendParsedData(byte[] data) { if (!chkEnableParsing.isSelected()) return; - + SwingUtilities.invokeLater(() -> { packetCounter++; - lblPacketCount.setText(String.format(messages.getString("packet.count.format"), packetCounter)); // 更新计数标签 - + lblPacketCount.setText(String.format(messages.getString("packet.count.format"), packetCounter)); + try { - // 将字节数据转换为十六进制字符串 - String hexData = bytesToHex(data).toUpperCase(); - // 使用Dell55AA12HighPerf解析 - ParseResult result = Dell55AA12HighPerf.parse(hexData); - - if (result != null) { - // 构建状态字符串 - String buttonStatus = result.sosButtonPressed ? messages.getString("yes") : messages.getString("no"); - String staticStatus = result.isStatic ? messages.getString("yes") : messages.getString("no"); - String sleepStatus = result.isSleeping ? messages.getString("yes") : messages.getString("no"); - String vibrationStatus = (result.vibrationState == 1) ? messages.getString("on") : messages.getString("off"); - String uwbStatus = result.tagRemoved ? messages.getString("off") : messages.getString("on"); - - // 构建基站信息 - StringBuilder anchorIds = new StringBuilder(); - StringBuilder distances = new StringBuilder(); - StringBuilder anchorPowers = new StringBuilder(); - - for (int i = 0; i < result.anchorCount; i++) { - if (i > 0) { - anchorIds.append(","); - distances.append(","); - anchorPowers.append(","); - } - anchorIds.append(result.anchorIds[i]); - distances.append(result.distances[i]); - anchorPowers.append(result.anchorPowers[i]); - } - - // 格式化输出 - StringBuilder parsedOutput = new StringBuilder(); - - // 添加时间戳(如果勾选) - if (chkTimestamp.isSelected()) { - parsedOutput.append("[").append(sdf.format(new Date())).append("]\n"); - } - - parsedOutput.append(String.format( - "%s: %d\n%s: %d\n%s: %d%%\n%s: %s[%s], %s[%s], %s[%s], %s[%s], %s[%s]\n%s: %d\n%s: %d\n%s: (%s)\n%s: (%s)\n%s: (%s)\n\n", - messages.getString("label.id"), result.tagId, - messages.getString("label.sequence"), result.sequenceNum, - messages.getString("label.power"), result.power, - messages.getString("label.status"), - messages.getString("status.button"), buttonStatus, - messages.getString("status.static"), staticStatus, - messages.getString("status.sleeping"), sleepStatus, - messages.getString("status.vibration"), vibrationStatus, - messages.getString("status.uwb_switch"), uwbStatus, - messages.getString("label.tag_height"), result.tagHeight, - messages.getString("label.anchor_count"), result.anchorCount, - messages.getString("label.anchor_ids"), anchorIds.toString(), - messages.getString("label.distances"), distances.toString(), - messages.getString("label.anchor_powers"), anchorPowers.toString() - )); - - txtParsedData.append(parsedOutput.toString()); - txtParsedData.setCaretPosition(txtParsedData.getDocument().getLength()); - lblParseStatus.setText(String.format("%s (Packets: %d)", messages.getString("parser.ready"), packetCounter)); - } else { - StringBuilder invalidMsg = new StringBuilder(); - // 添加时间戳(如果勾选) - if (chkTimestamp.isSelected()) { - - invalidMsg.append("[").append(sdf.format(new Date())).append("]\n"); - } - invalidMsg.append(String.format("[Packet #%d] Not a valid 55AA12 packet\n\n", packetCounter)); - - txtParsedData.append(invalidMsg.toString()); - lblParseStatus.setText(String.format("Parser: Invalid (Packets: %d)", packetCounter)); - } - } catch (Exception e) { - StringBuilder errorMsg = new StringBuilder(); - // 添加时间戳(如果勾选) - if (chkTimestamp.isSelected()) { - errorMsg.append("[").append(sdf.format(new Date())).append("]\n"); - } - errorMsg.append(String.format("[Packet #%d] Parse error: %s\n\n", - packetCounter, e.getMessage())); - - txtParsedData.append(errorMsg.toString()); + String parsed = PacketParser.parse(data, messages, chkTimestamp.isSelected()); + txtParsedData.append(parsed); + txtParsedData.setCaretPosition(txtParsedData.getDocument().getLength()); + lblParseStatus.setText( + String.format("%s (Packets: %d)", + messages.getString("parser.ready"), packetCounter)); + } catch (Exception ex) { + StringBuilder sb = new StringBuilder(); + if (chkTimestamp.isSelected()) sb.append('[').append(sdf.format(new Date())).append("]\n"); + sb.append(String.format("[Packet #%d] Parse error: %s\n\n", packetCounter, ex.getMessage())); + txtParsedData.append(sb.toString()); lblParseStatus.setText(String.format("Parser: Error (Packets: %d)", packetCounter)); } }); } - /* ================= UI 更新 ================= */ private void appendRawData(byte[] bytes) { SwingUtilities.invokeLater(() -> { @@ -564,15 +493,6 @@ } }); } - } - - // 新增辅助方法:字节数组转十六进制字符串 - private String bytesToHex(byte[] bytes) { - StringBuilder sb = new StringBuilder(); - for (byte b : bytes) { - sb.append(String.format("%02X", b)); - } - return sb.toString(); } // 修改clearDisplay方法 diff --git a/systemfile/Messages_zh.properties b/systemfile/Messages_zh.properties index b2607af..3fd7abd 100644 --- a/systemfile/Messages_zh.properties +++ b/systemfile/Messages_zh.properties @@ -1,24 +1,24 @@ # 鏂板璧勬簮閿�煎 packet.count.format=鏀跺埌鏁版嵁:%d鏉� label.id=鏍囩缂栧彿 -label.sequence=鍖呭簭 -label.power=鐢甸噺 -label.status=鐘舵�� -label.tag_height=鏍囩楂� -label.anchor_count=鍩虹珯鏁� +label.sequence=閫氫俊鍖呭簭 +label.power=鏍囩鐢甸噺 +label.status=鏍囩鐘舵�� +label.tag_height=鏍囩楂樺害 +label.anchor_count=鍩虹珯鏁伴噺 label.anchor_ids=鍩虹珯缂栧彿 -label.distances=娴嬭窛鍊� +label.distances=娴嬭窛璺濈 label.anchor_powers=鍩虹珯鐢甸噺 status.button=鎸夐敭 status.static=闈欐 status.sleeping=浼戠湢 status.vibration=闇囧姩 status.uwb_switch=UWB寮�鍏� -parser.ready=瑙f瀽鍣�: 灏辩华 -yes=鏄� -no=鍚� -on=寮� -off=鍏� +parser.ready=瑙f瀽鍣�:灏辩华 +yes=1 +no=0 +on=1 +off=0 ENABLE_PARSING=Enable Parsing PARSER=Parser EXPORT=Export diff --git a/systemfile/logfile/openlog.txt b/systemfile/logfile/openlog.txt index 56da0b0..1950da1 100644 --- a/systemfile/logfile/openlog.txt +++ b/systemfile/logfile/openlog.txt @@ -555,3 +555,82 @@ 程序关闭: 2025-08-07 23:52:43 工作时长: 0小时 0分钟 36秒 ----------------------------------- +程序启动: 2025-08-08 11:29:39 +程序启动: 2025-08-08 11:29:41 +程序关闭: 2025-08-08 12:01:06 +工作时长: 0小时 31分钟 26秒 +----------------------------------- +程序启动: 2025-08-08 12:17:57 +程序关闭: 2025-08-08 12:18:22 +工作时长: 0小时 0分钟 25秒 +----------------------------------- +程序启动: 2025-08-08 12:23:35 +程序关闭: 2025-08-08 12:34:34 +工作时长: 0小时 10分钟 59秒 +----------------------------------- +程序启动: 2025-08-08 12:34:36 +程序关闭: 2025-08-08 12:37:55 +工作时长: 0小时 3分钟 18秒 +----------------------------------- +程序启动: 2025-08-08 12:39:03 +程序关闭: 2025-08-08 14:23:40 +工作时长: 1小时 44分钟 37秒 +----------------------------------- +程序启动: 2025-08-08 14:23:43 +程序关闭: 2025-08-08 14:59:18 +工作时长: 0小时 35分钟 35秒 +----------------------------------- +程序启动: 2025-08-08 15:15:56 +程序关闭: 2025-08-08 15:50:22 +工作时长: 0小时 34分钟 26秒 +----------------------------------- +程序启动: 2025-08-08 17:16:52 +程序关闭: 2025-08-08 17:54:58 +工作时长: 0小时 38分钟 5秒 +----------------------------------- +程序启动: 2025-08-08 21:57:21 +程序启动: 2025-08-08 22:21:20 +程序关闭: 2025-08-08 22:21:27 +工作时长: 0小时 24分钟 6秒 +----------------------------------- +程序启动: 2025-08-08 22:21:29 +程序关闭: 2025-08-08 22:22:07 +工作时长: 0小时 0分钟 38秒 +----------------------------------- +程序启动: 2025-08-08 22:25:06 +程序关闭: 2025-08-08 22:25:45 +工作时长: 0小时 0分钟 38秒 +----------------------------------- +程序启动: 2025-08-08 22:26:08 +程序关闭: 2025-08-08 22:26:57 +工作时长: 0小时 0分钟 48秒 +----------------------------------- +程序启动: 2025-08-08 22:27:44 +程序关闭: 2025-08-08 22:28:32 +工作时长: 0小时 0分钟 48秒 +----------------------------------- +程序启动: 2025-08-08 22:29:10 +程序关闭: 2025-08-08 22:29:41 +工作时长: 0小时 0分钟 31秒 +----------------------------------- +程序启动: 2025-08-08 22:30:36 +程序关闭: 2025-08-08 22:31:01 +工作时长: 0小时 0分钟 24秒 +----------------------------------- +程序启动: 2025-08-08 22:31:22 +程序启动: 2025-08-08 23:02:47 +程序关闭: 2025-08-08 23:02:51 +工作时长: 0小时 31分钟 29秒 +----------------------------------- +程序启动: 2025-08-08 23:02:53 +程序关闭: 2025-08-08 23:03:18 +工作时长: 0小时 0分钟 25秒 +----------------------------------- +程序启动: 2025-08-08 23:04:41 +程序关闭: 2025-08-08 23:04:58 +工作时长: 0小时 0分钟 16秒 +----------------------------------- +程序启动: 2025-08-08 23:05:41 +程序关闭: 2025-08-08 23:06:23 +工作时长: 0小时 0分钟 41秒 +----------------------------------- -- Gitblit v1.9.3