package yaokong;
|
|
import java.nio.ByteBuffer;
|
import java.nio.ByteOrder;
|
|
public class Control80 {
|
|
/**
|
* 解析应答指令(指令类型0x80)
|
*
|
* @param responseHex 接收到的应答指令HEX字符串
|
* @return 解析后的应答信息对象
|
*/
|
public static AckResponse parseAckResponseHex(String responseHex) {
|
// 将HEX字符串转换为字节数组
|
byte[] responseBytes = hexStringToByteArray(responseHex);
|
return parseAckResponseBytes(responseBytes);
|
}
|
|
/**
|
* 解析应答指令字节数组
|
*/
|
public static AckResponse parseAckResponseBytes(byte[] responseBytes) {
|
if (responseBytes == null || responseBytes.length < 12) {
|
throw new IllegalArgumentException("应答数据长度不足");
|
}
|
|
ByteBuffer buffer = ByteBuffer.wrap(responseBytes).order(ByteOrder.LITTLE_ENDIAN);
|
|
// 检查帧头
|
byte header1 = buffer.get();
|
byte header2 = buffer.get();
|
if (header1 != BluetoothProtocol.FRAME_HEADER[0] || header2 != BluetoothProtocol.FRAME_HEADER[1]) {
|
throw new IllegalArgumentException("无效的帧头");
|
}
|
|
// 检查指令类型
|
byte commandType = buffer.get();
|
if (commandType != (byte) 0x80) {
|
throw new IllegalArgumentException("非应答指令");
|
}
|
|
// 数据长度
|
short dataLength = buffer.getShort();
|
if (dataLength != 5) {
|
throw new IllegalArgumentException("应答数据长度应为5,实际为" + dataLength);
|
}
|
|
// 序列号
|
short sequence = buffer.getShort();
|
|
// 原指令类型
|
byte originalCommand = buffer.get();
|
|
// 执行结果
|
byte result = buffer.get();
|
|
// 错误代码
|
byte errorCode = buffer.get();
|
|
// CRC16
|
short receivedCRC = buffer.getShort();
|
|
// 帧尾
|
byte footer = buffer.get();
|
if (footer != 0x0D) {
|
throw new IllegalArgumentException("无效的帧尾");
|
}
|
|
// 验证CRC
|
byte[] dataForCRC = new byte[1 + 2 + 2 + dataLength];
|
System.arraycopy(responseBytes, 2, dataForCRC, 0, dataForCRC.length);
|
int calculatedCRC = CRC16.calculateCRC16(dataForCRC, 0, dataForCRC.length);
|
|
boolean crcValid = (calculatedCRC == (receivedCRC & 0xFFFF));
|
|
return new AckResponse(sequence, originalCommand, result, errorCode, crcValid);
|
}
|
|
/**
|
* 应答信息类
|
*/
|
public static class AckResponse {
|
private short sequence; // 序列号
|
private byte originalCommand; // 原指令类型
|
private byte result; // 执行结果
|
private byte errorCode; // 错误代码
|
private boolean crcValid; // CRC校验是否有效
|
|
public AckResponse(short sequence, byte originalCommand, byte result,
|
byte errorCode, boolean crcValid) {
|
this.sequence = sequence;
|
this.originalCommand = originalCommand;
|
this.result = result;
|
this.errorCode = errorCode;
|
this.crcValid = crcValid;
|
}
|
|
public short getSequence() {
|
return sequence;
|
}
|
|
public byte getOriginalCommand() {
|
return originalCommand;
|
}
|
|
public byte getResult() {
|
return result;
|
}
|
|
public byte getErrorCode() {
|
return errorCode;
|
}
|
|
public boolean isCrcValid() {
|
return crcValid;
|
}
|
|
public boolean isSuccess() {
|
return result == 0x00;
|
}
|
|
public String getOriginalCommandName() {
|
switch (originalCommand & 0xFF) {
|
case 0x01: return "路径坐标指令";
|
case 0x02: return "基准站坐标指令";
|
case 0x03: return "控制转向指令";
|
case 0x04: return "控制指令";
|
case 0x05: return "路径分片指令";
|
default: return "未知指令(0x" + String.format("%02X", originalCommand) + ")";
|
}
|
}
|
|
public String getResultDescription() {
|
switch (result) {
|
case 0x00: return "成功";
|
case 0x01: return "失败";
|
case 0x02: return "忙";
|
default: return "未知(" + result + ")";
|
}
|
}
|
|
public String getErrorDescription() {
|
switch (errorCode) {
|
case 0x00: return "SUCCESS";
|
case 0x01: return "CRC_ERROR";
|
case 0x02: return "DATA_LENGTH_ERROR";
|
case 0x03: return "MEMORY_FULL";
|
case 0x04: return "INVALID_COORDINATE";
|
case 0x05: return "SYSTEM_BUSY";
|
case 0x06: return "EMERGENCY_STOP";
|
default: return "未知错误码(0x" + String.format("%02X", errorCode) + ")";
|
}
|
}
|
|
@Override
|
public String toString() {
|
return String.format("应答信息: [序列号=%d, 原指令=%s, 执行结果=%s, 错误码=%s, CRC校验=%s]",
|
sequence & 0xFFFF,
|
getOriginalCommandName(),
|
getResultDescription(),
|
getErrorDescription(),
|
crcValid ? "有效" : "无效");
|
}
|
}
|
|
/**
|
* 模拟接收到的应答指令用于测试
|
*/
|
public static String createMockResponse(short sequence, byte originalCommand,
|
byte result, byte errorCode) {
|
int dataLength = 5; // 固定长度
|
|
ByteBuffer buffer = ByteBuffer.allocate(2 + 1 + 2 + 2 + dataLength + 2 + 1);
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
// 帧头
|
buffer.put(BluetoothProtocol.FRAME_HEADER);
|
|
// 指令类型
|
buffer.put((byte) 0x80);
|
|
// 数据长度
|
buffer.putShort((short) dataLength);
|
|
// 序列号
|
buffer.putShort(sequence);
|
|
// 原指令类型
|
buffer.put(originalCommand);
|
|
// 执行结果
|
buffer.put(result);
|
|
// 错误代码
|
buffer.put(errorCode);
|
|
// 计算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 bytesToHex(buffer.array());
|
}
|
|
/**
|
* HEX字符串转换为字节数组
|
*/
|
private static byte[] hexStringToByteArray(String hexString) {
|
if (hexString == null || hexString.trim().isEmpty()) {
|
throw new IllegalArgumentException("HEX字符串不能为空");
|
}
|
|
// 移除空格
|
String cleanHex = hexString.replaceAll("\\s+", "");
|
|
if (cleanHex.length() % 2 != 0) {
|
throw new IllegalArgumentException("HEX字符串长度必须是偶数");
|
}
|
|
byte[] data = new byte[cleanHex.length() / 2];
|
for (int i = 0; i < cleanHex.length(); i += 2) {
|
String hex = cleanHex.substring(i, i + 2);
|
data[i / 2] = (byte) Integer.parseInt(hex, 16);
|
}
|
|
return data;
|
}
|
|
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();
|
}
|
|
}
|