张世豪
2025-12-11 6f59464fc6e12a525ba3004864eceb1bc1573a31
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
package yaokong;
 
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
 
public class Control02 {
    
    /**
     * 构建基准站坐标指令(指令类型0x02)的HEX格式字符串
     * 
     * @param baseStationCoords 基准站坐标字符串,格式:"纬度值,纬度方向,经度值,经度方向"
     *                          例如:"3949.90238860,N,11616.75692000,E"
     * @return 基准站坐标指令的HEX格式字符串
     */
    public static String buildBaseStationCommandHex(String baseStationCoords) {
        // 解析坐标字符串
        String[] parts = baseStationCoords.split(",");
        if (parts.length != 4) {
            throw new IllegalArgumentException("基准站坐标格式错误,应为:纬度,纬度方向,经度,经度方向");
        }
        
        double latitude = parseDMToDecimal(parts[0].trim(), parts[1].trim());
        double longitude = parseDMToDecimal(parts[2].trim(), parts[3].trim());
        char latDirection = parts[1].trim().charAt(0);
        char lonDirection = parts[3].trim().charAt(0);
        
        byte[] commandBytes = buildBaseStationCommandBytes(latitude, longitude, latDirection, lonDirection);
        return bytesToHex(commandBytes);
    }
    
    /**
     * 构建基准站坐标指令的字节数组
     */
    public static byte[] buildBaseStationCommandBytes(double latitude, double longitude, 
                                                      char latDirection, char lonDirection) {
        // 验证参数
        if (latitude < -90.0 || latitude > 90.0) {
            throw new IllegalArgumentException("纬度值必须在-90.0到90.0之间");
        }
        if (longitude < -180.0 || longitude > 180.0) {
            throw new IllegalArgumentException("经度值必须在-180.0到180.0之间");
        }
        if (!(latDirection == 'N' || latDirection == 'S')) {
            throw new IllegalArgumentException("纬度方向必须是'N'或'S'");
        }
        if (!(lonDirection == 'E' || lonDirection == 'W')) {
            throw new IllegalArgumentException("经度方向必须是'E'或'W'");
        }
        
        int dataLength = 32; // 固定长度32字节
        
        ByteBuffer buffer = ByteBuffer.allocate(2 + 1 + 2 + 2 + dataLength + 2 + 1);
        buffer.order(ByteOrder.LITTLE_ENDIAN);
        
        // 帧头
        buffer.put(BluetoothProtocol.FRAME_HEADER);
        
        // 指令类型
        buffer.put((byte) 0x02);
        
        // 数据长度
        buffer.putShort((short) dataLength);
        
        // 序列号
        buffer.putShort((short) BluetoothProtocol.getNextSequence());
        
        // 纬度值 (double, 8字节)
        buffer.putDouble(latitude);
        
        // 经度值 (double, 8字节)
        buffer.putDouble(longitude);
        
        // 纬度方向 (char, 1字节)
        buffer.put((byte) latDirection);
        
        // 经度方向 (char, 1字节)
        buffer.put((byte) lonDirection);
        
        // 保留字段 (14字节,全部填0)
        for (int i = 0; i < 14; i++) {
            buffer.put((byte) 0x00);
        }
        
        // 计算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();
    }
    
    /**
     * 将度分格式转换为十进制格式
     * 例如:3949.90238860 -> 39.83170647666667
     */
    private static double parseDMToDecimal(String dmm, String direction) {
        try {
            // 找到小数点的位置
            int dotIndex = dmm.indexOf('.');
            if (dotIndex < 2) {
                throw new IllegalArgumentException("度分格式错误: " + dmm);
            }
            
            // 提取度和分
            int degrees = Integer.parseInt(dmm.substring(0, dotIndex - 2));
            double minutes = Double.parseDouble(dmm.substring(dotIndex - 2));
            
            // 转换为十进制
            double decimal = degrees + minutes / 60.0;
            
            // 根据方向调整正负
            if ("S".equalsIgnoreCase(direction) || "W".equalsIgnoreCase(direction)) {
                decimal = -decimal;
            }
            
            return decimal;
        } catch (Exception e) {
            throw new IllegalArgumentException("坐标格式解析错误: " + dmm, e);
        }
    }
    
    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();
    }    
   
}