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
package home;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
 
// 重命名为PacketParser,表示数据包解析器
public class PacketParser {
    // 添加十六进制字符数组常量
    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
    // 缓冲区字节数组
    private byte[] buffer = new byte[4096];
    // 当前缓冲区有效数据长度
    private int bufferLength = 0;
 
    // 追加新数据到缓冲区
    public void appendData(byte[] newData, int length) {
        // 检查缓冲区是否足够
        if (bufferLength + length > buffer.length) {
            // 创建新的更大缓冲区
            byte[] newBuffer = new byte[bufferLength + length];
            // 复制原有数据
            System.arraycopy(buffer, 0, newBuffer, 0, bufferLength);
            buffer = newBuffer;
        }
        // 追加新数据
        System.arraycopy(newData, 0, buffer, bufferLength, length);
        // 更新缓冲区长度
        bufferLength += length;
    }
 
    // 新增方法:字节数组转十六进制字符串
    public static String bytesToHexString(byte[] bytes) {
        if (bytes == null) return "";
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = HEX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }
 
    // 解析缓冲区中的所有完整数据包
    public List<DataPacket> parsePackets() {
        List<DataPacket> packets = new ArrayList<>();
        int index = 0;  // 当前解析位置索引
 
        // 遍历缓冲区查找完整数据包
        while (index <= bufferLength - 4) { // 确保有足够数据检查包头
            // 检查包头标识 0x55 0xAA
            if (buffer[index] == 0x55 && (buffer[index + 1] & 0xFF) == 0xAA) {
                // 获取包类型(第3字节)
                int packetType = buffer[index + 2] & 0xFF;
                // 获取数据长度(第4字节)
                int dataLenField = buffer[index + 3] & 0xFF;
                // 计算完整包长度(包头+数据+校验)
                int totalPacketLen = 2 + dataLenField + 2;  // 增加2字节校验位
 
                // 检查是否有足够数据构成完整包
                if (index + totalPacketLen > bufferLength) {
                    break; // 数据不足,等待更多数据
                }
 
                // 提取完整数据包
                byte[] packetData = new byte[totalPacketLen];
                System.arraycopy(buffer, index, packetData, 0, totalPacketLen);
 
                // 验证校验和
                if (verifyChecksum(packetData)) {
                    // 解析单个数据包
                    DataPacket packet = parseSinglePacket(packetType, packetData);
                    if (packet != null) {
                        packets.add(packet); // 添加到结果列表
                    }
                    index += totalPacketLen; // 移动到下一个包
                } else {
                    index++; // 校验失败,跳过当前字节
                }
            } else {
                index++; // 非包头标识,继续查找
            }
        }
 
        // 清理已处理数据
        if (index > 0) {
            int remaining = bufferLength - index;
            if (remaining > 0) {
                // 移动剩余数据到缓冲区开头
                System.arraycopy(buffer, index, buffer, 0, remaining);
            }
            bufferLength = remaining; // 更新缓冲区长度
        }
 
        return packets;
    }
 
    // 校验数据包
    private boolean verifyChecksum(byte[] packet) {
        int len = packet.length;
        if (len < 4) return false;
 
        int sum = 0;
        // 从数据类型开始到校验码前结束 (包头2字节已跳过)
        for (int i = 2; i < len - 2; i++) {
            sum += packet[i] & 0xFF;
        }
        sum = ~sum & 0xFFFF; // 取反并保留16位
 
        // 获取包中的校验码 (小端模式)
        int receivedChecksum = ((packet[len - 1] & 0xFF) << 8) | (packet[len - 2] & 0xFF);
 
        return sum == receivedChecksum;
    }
 
 
 
    // 解析单个数据包
    private DataPacket parseSinglePacket(int packetType, byte[] packet) {        
 
        // 创建数据包对象(包含包类型)
        return new DataPacket(packetType, packet);
    }
 
    // 数据包内部类
    public static class DataPacket {
        private final int packetType;  // 包类型
        private final byte[] packet;//包数据
 
 
        public DataPacket(int packetType, byte[] packet) {
            this.packetType = packetType;
            this.packet = packet;
        }
 
        // 获取包类型
        public int getPacketType() {
            return packetType;
        }
 
        // 包数据
        public byte[] getPacket() {
            return packet;
        }
 
    }
 
    // HEX字符串转字节数组
    public static byte[] hexStringToBytes(String hex) {
        // 移除空格
        hex = hex.replaceAll("\\s", "");
        int len = hex.length();
        // 创建结果数组
        byte[] data = new byte[len / 2];
        // 每两个字符转换一个字节
        for (int i = 0; i < len; i += 2) {
            // 高位转换
            int high = Character.digit(hex.charAt(i), 16) << 4;
            // 低位转换
            int low = Character.digit(hex.charAt(i + 1), 16);
            data[i / 2] = (byte) (high | low);
        }
        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);
    }
 
    /** 将字节数组转为十六进制字符串,例如 [55 AA 01 02 ...] */
    private static String bytesToHex(byte[] bytes) {
        if (bytes == null) return "null";
        StringBuilder sb = new StringBuilder(bytes.length * 3);
        for (byte b : bytes) {
            sb.append(String.format("%02X ", b & 0xFF));
        }
        // 去掉最后一个空格
        return sb.substring(0, sb.length() - 1);
    }
    
    
}