package yaokong;
|
|
import java.nio.ByteBuffer;
|
import java.nio.ByteOrder;
|
|
import chuankou.SerialPortService;
|
import chuankou.sendmessage;
|
public class Control04 {
|
|
/**
|
* 构建开始/停止割草指令(指令类型0x04)的HEX格式字符串
|
*
|
* @param action 控制动作:0-停止, 1-开始, 2-暂停, 3-急停
|
* @param emergencyLevel 紧急等级:0-正常, 1-警告, 2-紧急
|
* @return 控制指令的HEX格式字符串(空格分隔)
|
*/
|
public static String buildControlCommandHex(int action, int emergencyLevel) {
|
// 验证参数范围
|
if (action < 0 || action > 3) {
|
throw new IllegalArgumentException("控制动作参数无效,必须是0-3之间的整数");
|
}
|
if (emergencyLevel < 0 || emergencyLevel > 2) {
|
throw new IllegalArgumentException("紧急等级参数无效,必须是0-2之间的整数");
|
}
|
|
// 创建缓冲区:帧头2 + 指令类型1 + 数据长度2 + 序列号2 + 数据内容2 + CRC16 2 + 帧尾1 = 12字节
|
ByteBuffer buffer = ByteBuffer.allocate(12);
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
// 帧头 (0xAA, 0x55)
|
buffer.put(BluetoothProtocol.FRAME_HEADER);
|
|
// 指令类型 (0x04)
|
buffer.put(BluetoothProtocol.CMD_CONTROL);
|
|
// 数据长度 (固定为2)
|
buffer.putShort((short) 2);
|
|
// 序列号 (使用协议中的递增序列号)
|
buffer.putShort((short) BluetoothProtocol.getNextSequence());
|
|
// 数据内容
|
buffer.put((byte) action); // 控制动作
|
buffer.put((byte) emergencyLevel); // 紧急等级
|
|
// 计算CRC16校验
|
byte[] dataForCRC = new byte[7]; // 指令类型1 + 数据长度2 + 序列号2 + 控制动作1 + 紧急等级1
|
System.arraycopy(buffer.array(), 2, dataForCRC, 0, dataForCRC.length);
|
int crc = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length);
|
buffer.putShort((short) crc);
|
|
// 帧尾 (0x0D)
|
buffer.put(BluetoothProtocol.FRAME_FOOTER);
|
|
// 转换为HEX字符串(空格分隔)
|
byte[] commandBytes = buffer.array();
|
return bytesToHex(commandBytes);
|
}
|
|
/**
|
* 构建开始/停止割草指令(指令类型0x04)的字节数组
|
*
|
* @param action 控制动作:0-停止, 1-开始, 2-暂停, 3-急停
|
* @param emergencyLevel 紧急等级:0-正常, 1-警告, 2-紧急
|
* @return 控制指令的字节数组
|
*/
|
public static byte[] buildControlCommandBytes(int action, int emergencyLevel) {
|
// 验证参数范围
|
if (action < 0 || action > 3) {
|
throw new IllegalArgumentException("控制动作参数无效,必须是0-3之间的整数");
|
}
|
if (emergencyLevel < 0 || emergencyLevel > 2) {
|
throw new IllegalArgumentException("紧急等级参数无效,必须是0-2之间的整数");
|
}
|
|
// 创建缓冲区:帧头2 + 指令类型1 + 数据长度2 + 序列号2 + 数据内容2 + CRC16 2 + 帧尾1 = 12字节
|
ByteBuffer buffer = ByteBuffer.allocate(12);
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
// 帧头 (0xAA, 0x55)
|
buffer.put(BluetoothProtocol.FRAME_HEADER);
|
|
// 指令类型 (0x04)
|
buffer.put(BluetoothProtocol.CMD_CONTROL);
|
|
// 数据长度 (固定为2)
|
buffer.putShort((short) 2);
|
|
// 序列号 (使用协议中的递增序列号)
|
buffer.putShort((short) BluetoothProtocol.getNextSequence());
|
|
// 数据内容
|
buffer.put((byte) action); // 控制动作
|
buffer.put((byte) emergencyLevel); // 紧急等级
|
|
// 计算CRC16校验
|
byte[] dataForCRC = new byte[7]; // 指令类型1 + 数据长度2 + 序列号2 + 控制动作1 + 紧急等级1
|
System.arraycopy(buffer.array(), 2, dataForCRC, 0, dataForCRC.length);
|
int crc = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length);
|
buffer.putShort((short) crc);
|
|
// 帧尾 (0x0D)
|
buffer.put(BluetoothProtocol.FRAME_FOOTER);
|
|
return buffer.array();
|
}
|
|
/**
|
* 当系统调试串口处于打开状态时发送开始割草指令。
|
*/
|
public static boolean sendStartCommandIfDebugSerialOpen() {
|
return sendControlCommandIfDebugSerialOpen(1, 0);
|
}
|
|
/**
|
* 当系统调试串口处于打开状态时发送暂停割草指令。
|
*/
|
public static boolean sendPauseCommandIfDebugSerialOpen() {
|
return sendControlCommandIfDebugSerialOpen(2, 0);
|
}
|
|
/**
|
* 当系统调试串口处于打开状态时发送停止割草指令。
|
*/
|
public static boolean sendStopCommandIfDebugSerialOpen() {
|
return sendControlCommandIfDebugSerialOpen(0, 0);
|
}
|
|
private static boolean sendControlCommandIfDebugSerialOpen(int action, int emergencyLevel) {
|
SerialPortService service = sendmessage.getActiveService();
|
if (service == null || !service.isOpen()) {
|
return false;
|
}
|
byte[] payload = buildControlCommandBytes(action, emergencyLevel);
|
return sendmessage.sendViaActive(payload);
|
}
|
|
/**
|
* 构建常用控制指令的快捷方法
|
*/
|
|
// 开始割草(正常)
|
public static String startMowing() {
|
return buildControlCommandHex(1, 0);
|
}
|
|
// 停止割草(正常)
|
public static String stopMowing() {
|
return buildControlCommandHex(0, 0);
|
}
|
|
// 暂停割草(正常)
|
public static String pauseMowing() {
|
return buildControlCommandHex(2, 0);
|
}
|
|
// 紧急停止(紧急)
|
public static String emergencyStop() {
|
return buildControlCommandHex(3, 2);
|
}
|
|
/**
|
* 字节数组转换为HEX字符串
|
*/
|
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();
|
}
|
|
/**
|
* 解析控制指令的HEX字符串(反向解析,用于调试)
|
*/
|
public static String parseControlCommandHex(String hexString) {
|
String[] hexParts = hexString.trim().split("\\s+");
|
if (hexParts.length != 12) {
|
return "无效的HEX格式:需要12个字节";
|
}
|
|
try {
|
// 解析帧头
|
if (!hexParts[0].equals("AA") || !hexParts[1].equals("55")) {
|
return "错误的帧头";
|
}
|
|
// 解析指令类型
|
if (!hexParts[2].equals("04")) {
|
return "非控制指令(0x04)";
|
}
|
|
// 解析数据长度
|
int dataLength = Integer.parseInt(hexParts[4] + hexParts[3], 16); // 小端序
|
if (dataLength != 2) {
|
return "数据长度错误:" + dataLength;
|
}
|
|
// 解析序列号
|
int sequence = Integer.parseInt(hexParts[6] + hexParts[5], 16);
|
|
// 解析控制动作
|
int action = Integer.parseInt(hexParts[7], 16);
|
String actionStr;
|
switch (action) {
|
case 0: actionStr = "停止"; break;
|
case 1: actionStr = "开始"; break;
|
case 2: actionStr = "暂停"; break;
|
case 3: actionStr = "急停"; break;
|
default: actionStr = "未知(" + action + ")"; break;
|
}
|
|
// 解析紧急等级
|
int emergencyLevel = Integer.parseInt(hexParts[8], 16);
|
String levelStr;
|
switch (emergencyLevel) {
|
case 0: levelStr = "正常"; break;
|
case 1: levelStr = "警告"; break;
|
case 2: levelStr = "紧急"; break;
|
default: levelStr = "未知(" + emergencyLevel + ")"; break;
|
}
|
|
// 解析CRC
|
int receivedCRC = Integer.parseInt(hexParts[10] + hexParts[9], 16);
|
|
// 解析帧尾
|
if (!hexParts[11].equals("0D")) {
|
return "错误的帧尾";
|
}
|
|
return String.format("控制指令解析:动作=%s(%d), 紧急等级=%s(%d), 序列号=%d",
|
actionStr, action, levelStr, emergencyLevel, sequence);
|
} catch (Exception e) {
|
return "解析错误:" + e.getMessage();
|
}
|
}
|
|
}
|