| | |
| | | package dell55AAData; |
| | | |
| | | import java.util.Arrays; |
| | | |
| | | import dell_system.MessageViewPanel; |
| | | import dell_targets.Dell_BaseStation; |
| | | import dell_targets.Dell_tag; |
| | | import publicsWay.EfficientTimeFormatter; |
| | | |
| | | 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); |
| | | // 常量定义 |
| | | 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; |
| | | } |
| | | } |
| | | // 解析结果类 |
| | | 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 int buttonPressed; // 按钮状态 |
| | | |
| | | /** |
| | | * 解析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; |
| | | } |
| | | public void reset() { |
| | | sequenceNum = 0; |
| | | tagId = ""; |
| | | anchorId = ""; |
| | | distance = 0; |
| | | power = 0; |
| | | buttonPressed = 0; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 解析55AA01协议数据 |
| | | * @param message 十六进制字符串 |
| | | * @return 解析结果(错误时返回null) |
| | | */ |
| | | public static ParseResult parse(String message, String ip, int port) { |
| | | if (message == null || message.isEmpty()) { |
| | | return null; |
| | | } |
| | | |
| | | // 清洗数据:移除所有非十六进制字符 |
| | | char[] cleanedMessage = cleanMessage(message); |
| | | |
| | | // 数据校验 |
| | | if (cleanedMessage == null || cleanedMessage.length < MIN_LENGTH) { |
| | | return null; |
| | | } |
| | | |
| | | // 协议头校验 (55AA01) |
| | | if (!new String(cleanedMessage, 0, 6).equals(EXPECTED_HEADER)) { |
| | | return null; |
| | | } |
| | | |
| | | ParseResult result = RESULT_CACHE.get(); |
| | | result.reset(); |
| | | |
| | | try { |
| | | if (cleanedMessage.length < 30) { // 确保有足够长度访问charAt(28) |
| | | return null; |
| | | } |
| | | |
| | | // 解析序列号 (位置8-9) |
| | | result.sequenceNum = HexUtils.fastHexToByte(cleanedMessage[8], cleanedMessage[9]); |
| | | |
| | | // 解析标签ID (位置10-13, 小端序) |
| | | result.tagId = new String(new char[]{ |
| | | cleanedMessage[12], cleanedMessage[13], // 高位 |
| | | cleanedMessage[10], cleanedMessage[11] // 低位 |
| | | }); |
| | | |
| | | // 解析锚点ID (位置14-17, 小端序) |
| | | result.anchorId = new String(new char[]{ |
| | | cleanedMessage[16], cleanedMessage[17], // 高位 |
| | | cleanedMessage[14], cleanedMessage[15] // 低位 |
| | | }); |
| | | |
| | | // 解析距离 (位置18-25, 4字节小端整数) |
| | | int b0 = HexUtils.fastHexToByte(cleanedMessage[18], cleanedMessage[19]); // 最低位 |
| | | int b1 = HexUtils.fastHexToByte(cleanedMessage[20], cleanedMessage[21]); |
| | | int b2 = HexUtils.fastHexToByte(cleanedMessage[22], cleanedMessage[23]); |
| | | int b3 = HexUtils.fastHexToByte(cleanedMessage[24], cleanedMessage[25]); // 最高位 |
| | | int raw = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; |
| | | result.distance = raw; // 保持原始整数值 |
| | | |
| | | // 解析电量 (位置26-27) |
| | | result.power = HexUtils.fastHexToByte(cleanedMessage[26], cleanedMessage[27]); |
| | | |
| | | // 解析按钮状态 (位置28-29) |
| | | result.buttonPressed = HexUtils.fastHexToByte(cleanedMessage[28], cleanedMessage[29]); |
| | | |
| | | // 日志和更新操作可以考虑优化或减少调用频率 |
| | | String hexData = "55AA01 包序:" + result.sequenceNum + ",标签编号:" + result.tagId + ",基站编号:" + result.anchorId + |
| | | ",距离:" + result.distance + ",电量:" + result.power + |
| | | ",按钮状态:" + result.buttonPressed; |
| | | MessageViewPanel.showData(hexData, ip, port, 0, "UDPA", "55AA01", "ALL"); |
| | | |
| | | String time = EfficientTimeFormatter.getCurrentTimeFormatted(); |
| | | Dell_BaseStation.updateBaseStationProperty(result.anchorId, "ipAddress", ip); |
| | | Dell_BaseStation.updateBaseStationProperty(result.anchorId, "port", port + ""); |
| | | Dell_BaseStation.updateBaseStationProperty(result.anchorId, "status", "1"); |
| | | Dell_BaseStation.updateBaseStationProperty(result.anchorId, "onlineTime", time); |
| | | |
| | | Dell_tag.updateLocationTagProperty(result.tagId, "sosStatus", result.buttonPressed + ""); |
| | | Dell_tag.updateLocationTagProperty(result.tagId, "onlineStatus", "1"); |
| | | Dell_tag.updateLocationTagProperty(result.tagId, "lastUwbSignalTime", time); |
| | | Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingSeq", result.sequenceNum + ""); |
| | | Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingBaseId", result.anchorId); |
| | | Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingDistance", result.distance + ""); |
| | | Dell_tag.updateLocationTagProperty(result.tagId, "latestRangingBaseCount", "1"); |
| | | |
| | | } catch (IndexOutOfBoundsException | NumberFormatException e) { |
| | | System.err.println("Parsing error in packet from " + ip + ":" + port); |
| | | return null; |
| | | } |
| | | |
| | | return result; |
| | | } |
| | | |
| | | private static char[] cleanMessage(String message) { |
| | | char[] cleaned = new char[message.length()]; |
| | | int j = 0; |
| | | for (char c : message.toCharArray()) { |
| | | if (Character.isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) { |
| | | cleaned[j++] = Character.toUpperCase(c); |
| | | } |
| | | } |
| | | if (j == 0) return null; |
| | | return Arrays.copyOf(cleaned, j); |
| | | } |
| | | |
| | | public static void updateBase(String baseStationId, String propertyName, String value) { |
| | | Dell_BaseStation.updateBaseStationProperty(baseStationId, propertyName, value); |
| | | Dell_BaseStation.updateBaseStationProperty(baseStationId, propertyName, value); |
| | | } |
| | | } |