package home;
|
import java.util.Arrays;
|
|
public class Dell55AA1FParser {
|
// ³£Á¿¶¨Òå
|
private static final String EXPECTED_HEADER = "55AA1F"; // ÐÒéÍ·
|
private static final int FIXED_FIELDS_LENGTH = 11; // ´Ó±êÇ©IDµ½±£Áô×ֶεĹ̶¨³¤¶È(×Ö½Ú)
|
private static final ThreadLocal<ParseResult> RESULT_CACHE =
|
ThreadLocal.withInitial(ParseResult::new);
|
|
// ½âÎö½á¹ûÀà
|
public static class ParseResult {
|
public int dataLength; // Êý¾Ý³¤¶È
|
public int messageType; // ÏûÏ¢ÀàÐÍ
|
public String tagId; // ±êÇ©ID(2×Ö½Ú)
|
public int distance; // ¾àÀë(ÀåÃ×)
|
public int angle; // ½Ç¶È(¶È)
|
public int signalQuality; // ÐźÅÖÊÁ¿(0-255)
|
public int buttonPressed; // °´Å¥×´Ì¬
|
public int power; // µçÁ¿
|
public String reserved; // ±£Áô×Ö¶Î
|
public String userData; // Óû§Êý¾Ý
|
public String checksum; // УÑéºÍ
|
|
public void reset() {
|
dataLength = 0;
|
messageType = 0;
|
tagId = "";
|
distance = 0;
|
angle = 0;
|
signalQuality = 0;
|
buttonPressed = 0;
|
power = 0;
|
reserved = "";
|
userData = "";
|
checksum = "";
|
}
|
}
|
|
/**
|
* ½âÎö55AA1FÐÒéÊý¾Ý
|
* @param message Ê®Áù½øÖÆ×Ö·û´®
|
* @return ½âÎö½á¹û(´íÎóʱ·µ»Ønull)
|
*/
|
public static ParseResult parse(String message, String ip, int port) {
|
if (message == null || message.isEmpty()) {
|
return null;
|
}
|
|
// ÇåÏ´Êý¾Ý£ºÒƳýËùÓзÇÊ®Áù½øÖÆ×Ö·û
|
char[] cleanedMessage = cleanMessage(message);
|
|
if (cleanedMessage == null) {
|
return null;
|
}
|
|
// ÐÒéͷУÑé (55AA1F)
|
if (cleanedMessage.length < 6 ||
|
!new String(cleanedMessage, 0, 6).equals(EXPECTED_HEADER)) {
|
return null;
|
}
|
|
ParseResult result = RESULT_CACHE.get();
|
result.reset();
|
|
try {
|
// ½âÎöÊý¾Ý³¤¶È (λÖÃ6-7)
|
result.dataLength = HexUtils.fastHexToByte(cleanedMessage[6], cleanedMessage[7]);
|
|
// ¼ÆËãÆÚÍûµÄ×Ü×Ö·û³¤¶È
|
int expectedCharLength = 8 + // °üÍ·(4×Ö·û) + ÏûÏ¢ÀàÐÍ(2×Ö·û) + Êý¾Ý³¤¶È(2×Ö·û)
|
result.dataLength * 2 + // Êý¾Ý²¿·Ö
|
4; // УÑéºÍ(4×Ö·û)
|
|
// if (cleanedMessage.length != expectedCharLength) {
|
// System.err.println("Data length mismatch: expected " + expectedCharLength +
|
// ", got " + cleanedMessage.length);
|
// return null;
|
// }
|
|
// ½âÎöÏûÏ¢ÀàÐÍ (λÖÃ4-5)
|
result.messageType = HexUtils.fastHexToByte(cleanedMessage[4], cleanedMessage[5]);
|
|
// ½âÎö±êÇ©ID (λÖÃ8-11)£¬Ö±½ÓÈ¡×Ö·û´®
|
result.tagId = new String(cleanedMessage, 8, 4);
|
|
// ½âÎö¾àÀë (λÖÃ12-15, 2×Ö½ÚС¶ËÕûÊý)
|
int distLow = HexUtils.fastHexToByte(cleanedMessage[12], cleanedMessage[13]);
|
int distHigh = HexUtils.fastHexToByte(cleanedMessage[14], cleanedMessage[15]);
|
result.distance = (distHigh << 8) | distLow;
|
|
// ½âÎö½Ç¶È (λÖÃ16-19, 2×Ö½ÚС¶ËÓзûºÅÕûÊý)
|
int angleLow = HexUtils.fastHexToByte(cleanedMessage[16], cleanedMessage[17]);
|
int angleHigh = HexUtils.fastHexToByte(cleanedMessage[18], cleanedMessage[19]);
|
short angleShort = (short) ((angleHigh << 8) | angleLow);
|
result.angle = angleShort;
|
|
// ½âÎöÐźÅÖÊÁ¿ (λÖÃ20-21)
|
result.signalQuality = HexUtils.fastHexToByte(cleanedMessage[20], cleanedMessage[21]);
|
|
// ½âÎö°´Å¥×´Ì¬ (λÖÃ22-23)
|
result.buttonPressed = HexUtils.fastHexToByte(cleanedMessage[22], cleanedMessage[23]);
|
|
// ½âÎöµçÁ¿ (λÖÃ24-25)
|
result.power = HexUtils.fastHexToByte(cleanedMessage[24], cleanedMessage[25]);
|
|
// ½âÎö±£Áô×Ö¶Î (λÖÃ26-29)
|
result.reserved = new String(cleanedMessage, 26, 4);
|
|
// ½âÎöÓû§Êý¾Ý
|
// int userDataStart = 30;
|
// int userDataCharLength = (result.dataLength - FIXED_FIELDS_LENGTH) * 2;
|
// if (userDataCharLength > 0) {
|
// result.userData = new String(cleanedMessage, userDataStart, userDataCharLength);
|
// } else {
|
// result.userData = "";
|
// }
|
|
// ½âÎöУÑéºÍ (×îºó4¸ö×Ö·û)
|
result.checksum = new String(cleanedMessage, cleanedMessage.length - 4, 4);
|
|
// Ñé֤УÑéºÍ
|
// byte[] packetBytes = hexStringToByteArray(new String(cleanedMessage));
|
// if (!verifyChecksum(packetBytes)) {
|
// System.err.println("Checksum verification failed for packet from " + ip + ":" + port);
|
// return null;
|
// }
|
|
} catch (IndexOutOfBoundsException | NumberFormatException e) {
|
System.err.println("Parsing error in 55AA1F packet from " + ip + ":" + port);
|
e.printStackTrace();
|
return null;
|
}
|
|
return result;
|
}
|
|
/**
|
* ½«Ê®Áù½øÖÆ×Ö·û´®×ª»»Îª×Ö½ÚÊý×é
|
*/
|
private static byte[] hexStringToByteArray(String s) {
|
int len = s.length();
|
byte[] data = new byte[len / 2];
|
for (int i = 0; i < len; i += 2) {
|
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
+ Character.digit(s.charAt(i+1), 16));
|
}
|
return data;
|
}
|
|
/**
|
* УÑéÊý¾Ý°ü
|
* È¥µô°üÍ·ÇóºÍÈ¡·´£¬Ð£ÑéÂëΪС¶Ëģʽ
|
*/
|
private static 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 - 2] & 0xFF) << 8) | (packet[len - 1] & 0xFF);
|
|
return sum == receivedChecksum;
|
}
|
|
private static char[] cleanMessage(String message) {
|
char[] cleaned = new char[message.length()];
|
int j = 0;
|
for (char c : message.toCharArray()) {
|
if (Character.isDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) {
|
cleaned[j++] = Character.toUpperCase(c);
|
}
|
}
|
if (j == 0) return null;
|
return Arrays.copyOf(cleaned, j);
|
}
|
|
}
|