| | |
| | | |
| | | 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 = // 解析结果缓存 |
| | | private static final String HEADER = "55AA12"; // 协议头 |
| | | private static final int MIN_LENGTH = 34; // 最小数据长度 |
| | | private static final ThreadLocal<ParseResult> RESULT_CACHE = // 解析结果缓存 |
| | | ThreadLocal.withInitial(ParseResult::new); |
| | | // 重用StringBuilder减少内存分配 |
| | | // 重用StringBuilder减少内存分配 |
| | | private static final ThreadLocal<StringBuilder> hexDataBuilder = |
| | | ThreadLocal.withInitial(() -> new StringBuilder(64)); |
| | | |
| | | // 解析结果类 |
| | | // 解析结果类 |
| | | 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 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; |
| | |
| | | sosButtonPressed = false; |
| | | tagHeight = 0; |
| | | anchorCount = 0; |
| | | // 数组保持长度,只重置计数 |
| | | // 数组保持长度,只重置计数 |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 解析协议数据 |
| | | * @param message 原始16进制字符串 |
| | | * @return 解析结果对象(线程安全) |
| | | * 解析协议数据 |
| | | * @param message 原始16进制字符串 |
| | | * @return 解析结果对象(线程安全) |
| | | */ |
| | | public static ParseResult parse(String message,String ip,int port) { |
| | | // 长度校验 |
| | | // 长度校验 |
| | | if (message == null || message.length() < MIN_LENGTH) { |
| | | return null; |
| | | } |
| | | |
| | | // 协议头校验 |
| | | // 协议头校验 |
| | | if (!(message.charAt(0) == '5' && |
| | | message.charAt(1) == '5' && |
| | | message.charAt(2) == 'A' && |
| | |
| | | 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); |
| | | |
| | | if (MessageViewPanel.isWindowVisible) { |
| | | // 组装基站信息 |
| | | /* if (MessageViewPanel.isWindowVisible) { |
| | | // 组装基站信息 |
| | | StringBuilder ids = new StringBuilder(); |
| | | StringBuilder dists = new StringBuilder(); |
| | | StringBuilder powers = new StringBuilder(); |
| | |
| | | .append("],Dis:[").append(dists) |
| | | .append("],AncPowers:[").append(powers).append("]").append('\n'); |
| | | MessageViewPanel.showData(sb.toString(), ip, port, 0, "UDPA", "55AA12",result.tagId); |
| | | } |
| | | }*/ |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 解析标签信息 |
| | | * 解析标签信息 |
| | | */ |
| | | private static void parseTagInfo(char[] chars, ParseResult result) { |
| | | // 标签ID(小端序) |
| | | // 标签ID(小端序) |
| | | result.tagId = new String(new char[] { |
| | | chars[10], chars[11], // 高字节 |
| | | chars[8], chars[9] // 低字节 |
| | | 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.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.signalStrengths2 = new int[result.anchorCount]; |
| | | } |
| | | |
| | | int baseIndex = 34; // 锚点ID起始位置 |
| | | int distanceStart = baseIndex + result.anchorCount * 4; // 距离起始位置 |
| | | int powerStart = distanceStart + result.anchorCount * 4; // 电量起始位置 |
| | | int baseIndex = 34; // 锚点ID起始位置 |
| | | int distanceStart = baseIndex + result.anchorCount * 4; // 距离起始位置 |
| | | int powerStart = distanceStart + result.anchorCount * 4; // 电量起始位置 |
| | | |
| | | // 解析锚点ID(小端序) |
| | | // 解析锚点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 |
| | | 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]); |
| | |
| | | : rawDistance; |
| | | } |
| | | |
| | | // 解析锚点电量 |
| | | // 解析锚点电量 |
| | | for (int i = 0; i < result.anchorCount; i++) { |
| | | int powerOffset = powerStart + i * 2; |
| | | result.anchorPowers[i] = HexUtils.fastHexToByte(chars[powerOffset], chars[powerOffset + 1]); |