张世豪
2025-12-12 350782fa02a61cbe112d32905b4ecc39198710cb
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
package yaokong;
 
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
 
public class Control01 {
    
    /**
     * 构建路径坐标指令(指令类型0x01)的HEX格式字符串
     * 
     * @param coordinates 坐标字符串,格式:"X1,Y1;X2,Y2;X3,Y3"(分号分隔,逗号分隔XY)
     * @return 路径坐标指令的HEX格式字符串
     */
    public static String buildPathCommandHex(String coordinates) {
        List<Point> points = parseCoordinates(coordinates);
        byte[] commandBytes = buildPathCommandBytes(points);
        return bytesToHex(commandBytes);
    }
    
    /**
     * 构建路径坐标指令的字节数组
     */
    public static byte[] buildPathCommandBytes(List<Point> points) {
        if (points == null || points.isEmpty() || points.size() > 255) {
            throw new IllegalArgumentException("路径点数量必须在1-255之间");
        }
        
        int pointCount = points.size();
        int dataLength = 1 + pointCount * 16; // 1字节点数 + 每个点16字节(两个double)
        
        ByteBuffer buffer = ByteBuffer.allocate(2 + 1 + 2 + 2 + dataLength + 2 + 1);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        
        // 帧头
        buffer.put(BluetoothProtocol.FRAME_HEADER);
        
        // 指令类型
        buffer.put((byte) 0x01);
        
        // 数据长度
        buffer.putShort((short) dataLength);
        
        // 序列号
        buffer.putShort((short) BluetoothProtocol.getNextSequence());
        
        // 路径点数量
        buffer.put((byte) pointCount);
        
        // 路径点数据
        for (Point point : points) {
            buffer.putDouble(point.x);
            buffer.putDouble(point.y);
        }
        
        // 计算CRC16
        byte[] dataForCRC = new byte[1 + 2 + 2 + dataLength];
        System.arraycopy(buffer.array(), 2, dataForCRC, 0, dataForCRC.length);
        int crc = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length);
        buffer.putShort((short) crc);
        
        // 帧尾
        buffer.put((byte) 0x0D);
        
        return buffer.array();
    }
    
    /**
     * 解析坐标字符串
     */
    private static List<Point> parseCoordinates(String coordinates) {
        if (coordinates == null || coordinates.trim().isEmpty()) {
            throw new IllegalArgumentException("坐标字符串不能为空");
        }
        
        List<Point> points = new ArrayList<>();
        String[] pointStrings = coordinates.split(";");
        
        for (String pointStr : pointStrings) {
            String[] xy = pointStr.split(",");
            if (xy.length != 2) {
                throw new IllegalArgumentException("坐标格式错误,应为X,Y格式");
            }
            
            try {
                double x = Double.parseDouble(xy[0].trim());
                double y = Double.parseDouble(xy[1].trim());
                points.add(new Point(x, y));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("坐标必须是数字: " + pointStr);
            }
        }
        
        return points;
    }
    
    public static class Point {
        public double x;
        public double y;
        
        public Point(double x, double y) {
            this.x = x;
            this.y = y;
        }
    }
    
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
            if (i < bytes.length - 1) {
                hexString.append(' ');
            }
        }
        return hexString.toString().toUpperCase();
    }    
}