zsh_root
2025-12-10 8d662de2fd262b3a485f16e197cb4d0ca2a61cdf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
package jiexi;
 
import java.util.Arrays;
 
public class Dell55AA51Parser {
    // 预期包头
    private static final String EXPECTED_HEADER = "55AA51";
    private static final ThreadLocal<ParseResult> RESULT_CACHE = 
            ThreadLocal.withInitial(ParseResult::new);
 
    // 解析结果类
    public static class ParseResult {
        public int dataLength;          // 数据长度(十进制)
        public String baseStationId;    // 基站ID(2字节,低位在前)
        public String tagId;            // 标签ID(2字节,低位在前)
        public int packetSequence;      // 包序(十进制)
        public int distance;            // 测距距离(十进制)
        public int horizontalAngle;     // 水平角度(十进制)
        public int verticalAngle;       // 俯仰角度(十进制,有符号)
        public int signalStrength;      // 信号强度(十进制)
        public int angleConfidence;     // 角度置信度(十进制)
        public int tagBattery;          // 标签电量(十进制)
        public int deviceStatus;        // 设备状态
        public int airPressure;         // 气压值(十进制)
        public String reserved;         // 保留字段
        public String checksum;         // 校验和
        
        public void reset() {
            dataLength = 0;
            baseStationId = "";
            tagId = "";
            packetSequence = 0;
            distance = 0;
            horizontalAngle = 0;
            verticalAngle = 0;
            signalStrength = 0;
            angleConfidence = 0;
            tagBattery = 0;
            deviceStatus = 0;
            airPressure = 0;
            reserved = "";
            checksum = "";
        }
        
        @Override
        public String toString() {
            return "ParseResult{" +
                    "dataLength=" + dataLength +
                    ", baseStationId='" + baseStationId + '\'' +
                    ", tagId='" + tagId + '\'' +
                    ", packetSequence=" + packetSequence +
                    ", distance=" + distance +
                    ", horizontalAngle=" + horizontalAngle +
                    ", verticalAngle=" + verticalAngle +
                    ", signalStrength=" + signalStrength +
                    ", angleConfidence=" + angleConfidence +
                    ", tagBattery=" + tagBattery +
                    ", deviceStatus=" + deviceStatus +
                    ", airPressure=" + airPressure +
                    ", reserved='" + reserved + '\'' +
                    ", checksum='" + checksum + '\'' +
                    '}';
        }
    }
 
    /**
     * 解析55AA51数据包
     * @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) {
            return null;
        }
 
        // 检查包头 (55AA51)
        if (cleanedMessage.length < 6 || 
            !new String(cleanedMessage, 0, 6).equals(EXPECTED_HEADER)) {
            return null;
        }
 
        ParseResult result = RESULT_CACHE.get();
        result.reset();
 
        try {
            // 解析数据长度 (位置6-7),转换为十进制
            result.dataLength = HexUtils.fastHexToByte(cleanedMessage[6], cleanedMessage[7]);
            
            // 计算期望的消息长度
            int expectedCharLength = 6 + // 包头(3字节)
                                    2 + // 数据长度(1字节)
                                    result.dataLength * 2 + // 数据内容
                                    4; // 校验和(2字节)
 
            if (cleanedMessage.length != expectedCharLength) {
                System.err.println("Data length mismatch: expected " + expectedCharLength + 
                                 ", got " + cleanedMessage.length);
                return null;
            }
 
            // 解析基站ID (位置8-11,2字节,低位在前)
            int baseIdLow = HexUtils.fastHexToByte(cleanedMessage[8], cleanedMessage[9]);
            int baseIdHigh = HexUtils.fastHexToByte(cleanedMessage[10], cleanedMessage[11]);
            int baseIdValue = (baseIdHigh << 8) | baseIdLow;
            result.baseStationId = String.valueOf(baseIdValue); // 转换为十进制字符串
 
            // 解析标签ID (位置12-15,2字节,低位在前)
            int tagIdLow = HexUtils.fastHexToByte(cleanedMessage[12], cleanedMessage[13]);
            int tagIdHigh = HexUtils.fastHexToByte(cleanedMessage[14], cleanedMessage[15]);
            int tagIdValue = (tagIdHigh << 8) | tagIdLow;
            result.tagId = String.valueOf(tagIdValue); // 转换为十进制字符串
 
            // 解析包序 (位置16-17),转换为十进制
            result.packetSequence = HexUtils.fastHexToByte(cleanedMessage[16], cleanedMessage[17]);
 
            // 解析测距距离 (位置18-21,2字节,低位在前),转换为十进制
            int distLow = HexUtils.fastHexToByte(cleanedMessage[18], cleanedMessage[19]);
            int distHigh = HexUtils.fastHexToByte(cleanedMessage[20], cleanedMessage[21]);
            result.distance = (distHigh << 8) | distLow;
 
            // 解析水平角度 (位置22-25,2字节,低位在前),转换为十进制
            int hAngleLow = HexUtils.fastHexToByte(cleanedMessage[22], cleanedMessage[23]);
            int hAngleHigh = HexUtils.fastHexToByte(cleanedMessage[24], cleanedMessage[25]);
            result.horizontalAngle = (hAngleHigh << 8) | hAngleLow;
 
            // 解析俯仰角度 (位置26-29,2字节,低位在前),转换为十进制
            // 注意:这是有符号数,范围-180到180度
            int vAngleLow = HexUtils.fastHexToByte(cleanedMessage[26], cleanedMessage[27]);
            int vAngleHigh = HexUtils.fastHexToByte(cleanedMessage[28], cleanedMessage[29]);
            short vAngleShort = (short) ((vAngleHigh << 8) | vAngleLow);
            result.verticalAngle = vAngleShort;
 
            // 解析信号强度 (位置30-31),转换为十进制
            result.signalStrength = HexUtils.fastHexToByte(cleanedMessage[30], cleanedMessage[31]);
 
            // 解析角度置信度 (位置32-33),转换为十进制
            result.angleConfidence = HexUtils.fastHexToByte(cleanedMessage[32], cleanedMessage[33]);
 
            // 解析标签电量 (位置34-35),转换为十进制
            result.tagBattery = HexUtils.fastHexToByte(cleanedMessage[34], cleanedMessage[35]);
 
            // 解析设备状态 (位置36-39,2字节,低位在前)
            int statusLow = HexUtils.fastHexToByte(cleanedMessage[36], cleanedMessage[37]);
            int statusHigh = HexUtils.fastHexToByte(cleanedMessage[38], cleanedMessage[39]);
            result.deviceStatus = (statusHigh << 8) | statusLow;
 
            // 解析气压值 (位置40-43,2字节,低位在前),转换为十进制
            int pressureLow = HexUtils.fastHexToByte(cleanedMessage[40], cleanedMessage[41]);
            int pressureHigh = HexUtils.fastHexToByte(cleanedMessage[42], cleanedMessage[43]);
            result.airPressure = (pressureHigh << 8) | pressureLow;
 
            // 解析保留字段 (位置44-51,4字节)
            result.reserved = new String(cleanedMessage, 44, 8);
 
            // 解析校验和 (最后4个字符)
            result.checksum = new String(cleanedMessage, cleanedMessage.length - 4, 4);
 
            // 验证校验和
            byte[] packetBytes = hexStringToByteArray(new String(cleanedMessage));
            if (!verifyChecksum(packetBytes)) {
                System.err.println("Checksum verification failed for packet from " + ip + ":" + port);
                return null;
            }
 
        } catch (IndexOutOfBoundsException | NumberFormatException e) {
            System.err.println("Parsing error in 55AA51 packet from " + ip + ":" + port);
            e.printStackTrace();
            return null;
        }
 
        return result;
    }
 
    /**
     * 将十六进制字符串转换为字节数组
     */
    private static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
 
    /**
     * 验证数据包校验和
     * 从数据类型字段开始到保留字段结束,校验和为双字节补码
     */
    private static boolean verifyChecksum(byte[] packet) {
        int len = packet.length;
        if (len < 4) return false;
 
        int sum = 0;
        // 从数据类型字段开始到保留字段结束 (跳过包头2字节)
        for (int i = 3; i < len - 2; i++) {
            sum += packet[i] & 0xFF;
        }
        sum = ~sum & 0xFFFF; // 取反并保留16位
 
        // 获取接收到的校验和 (低位在前)
        int receivedChecksum = ((packet[len - 2] & 0xFF) << 8) | (packet[len - 1] & 0xFF);
 
        return sum == receivedChecksum;
    }
 
    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);
    }
    
    
}