package home;
|
|
import java.util.Arrays;
|
|
public class Dell55AA51Parser {
|
// Ô¤ÆÚ°üÍ·
|
private static final String EXPECTED_HEADER = "55AA51";
|
private static final ThreadLocal<ParseResult> RESULT_CACHE =
|
ThreadLocal.withInitial(ParseResult::new);
|
|
// ½âÎö½á¹ûÀà
|
public static class ParseResult {
|
public int dataLength; // Êý¾Ý³¤¶È(Ê®½øÖÆ)
|
public String baseStationId; // »ùÕ¾ID(2×Ö½Ú£¬µÍλÔÚǰ)
|
public String tagId; // ±êÇ©ID(2×Ö½Ú£¬µÍλÔÚǰ)
|
public int packetSequence; // °üÐò(Ê®½øÖÆ)
|
public int distance; // ²â¾à¾àÀë(Ê®½øÖÆ)
|
public int horizontalAngle; // ˮƽ½Ç¶È(Ê®½øÖÆ)
|
public int verticalAngle; // ¸©Ñö½Ç¶È(Ê®½øÖÆ£¬ÓзûºÅ)
|
public int signalStrength; // ÐźÅÇ¿¶È(Ê®½øÖÆ)
|
public int angleConfidence; // ½Ç¶ÈÖÃÐŶÈ(Ê®½øÖÆ)
|
public int tagBattery; // ±êÇ©µçÁ¿(Ê®½øÖÆ)
|
public int deviceStatus; // É豸״̬
|
public int airPressure; // ÆøÑ¹Öµ(Ê®½øÖÆ)
|
public String reserved; // ±£Áô×Ö¶Î
|
public String checksum; // УÑéºÍ
|
|
public void reset() {
|
dataLength = 0;
|
baseStationId = "";
|
tagId = "";
|
packetSequence = 0;
|
distance = 0;
|
horizontalAngle = 0;
|
verticalAngle = 0;
|
signalStrength = 0;
|
angleConfidence = 0;
|
tagBattery = 0;
|
deviceStatus = 0;
|
airPressure = 0;
|
reserved = "";
|
checksum = "";
|
}
|
|
@Override
|
public String toString() {
|
return "ParseResult{" +
|
"dataLength=" + dataLength +
|
", baseStationId='" + baseStationId + '\'' +
|
", tagId='" + tagId + '\'' +
|
", packetSequence=" + packetSequence +
|
", distance=" + distance +
|
", horizontalAngle=" + horizontalAngle +
|
", verticalAngle=" + verticalAngle +
|
", signalStrength=" + signalStrength +
|
", angleConfidence=" + angleConfidence +
|
", tagBattery=" + tagBattery +
|
", deviceStatus=" + deviceStatus +
|
", airPressure=" + airPressure +
|
", reserved='" + reserved + '\'' +
|
", checksum='" + checksum + '\'' +
|
'}';
|
}
|
}
|
|
/**
|
* ½âÎö55AA51Êý¾Ý°ü
|
* @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;
|
}
|
|
// ¼ì²é°üÍ· (55AA51)
|
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 = 6 + // °üÍ·(3×Ö½Ú)
|
2 + // Êý¾Ý³¤¶È(1×Ö½Ú)
|
result.dataLength * 2 + // Êý¾ÝÄÚÈÝ
|
4; // УÑéºÍ(2×Ö½Ú)
|
|
if (cleanedMessage.length != expectedCharLength) {
|
System.err.println("Data length mismatch: expected " + expectedCharLength +
|
", got " + cleanedMessage.length);
|
return null;
|
}
|
|
// ½âÎö»ùÕ¾ID (λÖÃ8-11£¬2×Ö½Ú£¬µÍλÔÚǰ)
|
int baseIdLow = HexUtils.fastHexToByte(cleanedMessage[8], cleanedMessage[9]);
|
int baseIdHigh = HexUtils.fastHexToByte(cleanedMessage[10], cleanedMessage[11]);
|
int baseIdValue = (baseIdHigh << 8) | baseIdLow;
|
result.baseStationId = String.valueOf(baseIdValue); // ת»»ÎªÊ®½øÖÆ×Ö·û´®
|
|
// ½âÎö±êÇ©ID (λÖÃ12-15£¬2×Ö½Ú£¬µÍλÔÚǰ)
|
int tagIdLow = HexUtils.fastHexToByte(cleanedMessage[12], cleanedMessage[13]);
|
int tagIdHigh = HexUtils.fastHexToByte(cleanedMessage[14], cleanedMessage[15]);
|
int tagIdValue = (tagIdHigh << 8) | tagIdLow;
|
result.tagId = String.valueOf(tagIdValue); // ת»»ÎªÊ®½øÖÆ×Ö·û´®
|
|
// ½âÎö°üÐò (λÖÃ16-17)£¬×ª»»ÎªÊ®½øÖÆ
|
result.packetSequence = HexUtils.fastHexToByte(cleanedMessage[16], cleanedMessage[17]);
|
|
// ½âÎö²â¾à¾àÀë (λÖÃ18-21£¬2×Ö½Ú£¬µÍλÔÚǰ)£¬×ª»»ÎªÊ®½øÖÆ
|
int distLow = HexUtils.fastHexToByte(cleanedMessage[18], cleanedMessage[19]);
|
int distHigh = HexUtils.fastHexToByte(cleanedMessage[20], cleanedMessage[21]);
|
result.distance = (distHigh << 8) | distLow;
|
|
// ½âÎöˮƽ½Ç¶È (λÖÃ22-25£¬2×Ö½Ú£¬µÍλÔÚǰ)£¬×ª»»ÎªÊ®½øÖÆ
|
int hAngleLow = HexUtils.fastHexToByte(cleanedMessage[22], cleanedMessage[23]);
|
int hAngleHigh = HexUtils.fastHexToByte(cleanedMessage[24], cleanedMessage[25]);
|
result.horizontalAngle = (hAngleHigh << 8) | hAngleLow;
|
|
// ½âÎö¸©Ñö½Ç¶È (λÖÃ26-29£¬2×Ö½Ú£¬µÍλÔÚǰ)£¬×ª»»ÎªÊ®½øÖÆ
|
// ×¢Ò⣺ÕâÊÇÓзûºÅÊý£¬·¶Î§-180µ½180¶È
|
int vAngleLow = HexUtils.fastHexToByte(cleanedMessage[26], cleanedMessage[27]);
|
int vAngleHigh = HexUtils.fastHexToByte(cleanedMessage[28], cleanedMessage[29]);
|
short vAngleShort = (short) ((vAngleHigh << 8) | vAngleLow);
|
result.verticalAngle = vAngleShort;
|
|
// ½âÎöÐźÅÇ¿¶È (λÖÃ30-31)£¬×ª»»ÎªÊ®½øÖÆ
|
result.signalStrength = HexUtils.fastHexToByte(cleanedMessage[30], cleanedMessage[31]);
|
|
// ½âÎö½Ç¶ÈÖÃÐÅ¶È (λÖÃ32-33)£¬×ª»»ÎªÊ®½øÖÆ
|
result.angleConfidence = HexUtils.fastHexToByte(cleanedMessage[32], cleanedMessage[33]);
|
|
// ½âÎö±êÇ©µçÁ¿ (λÖÃ34-35)£¬×ª»»ÎªÊ®½øÖÆ
|
result.tagBattery = HexUtils.fastHexToByte(cleanedMessage[34], cleanedMessage[35]);
|
|
// ½âÎöÉ豸״̬ (λÖÃ36-39£¬2×Ö½Ú£¬µÍλÔÚǰ)
|
int statusLow = HexUtils.fastHexToByte(cleanedMessage[36], cleanedMessage[37]);
|
int statusHigh = HexUtils.fastHexToByte(cleanedMessage[38], cleanedMessage[39]);
|
result.deviceStatus = (statusHigh << 8) | statusLow;
|
|
// ½âÎöÆøÑ¹Öµ (λÖÃ40-43£¬2×Ö½Ú£¬µÍλÔÚǰ)£¬×ª»»ÎªÊ®½øÖÆ
|
int pressureLow = HexUtils.fastHexToByte(cleanedMessage[40], cleanedMessage[41]);
|
int pressureHigh = HexUtils.fastHexToByte(cleanedMessage[42], cleanedMessage[43]);
|
result.airPressure = (pressureHigh << 8) | pressureLow;
|
|
// ½âÎö±£Áô×Ö¶Î (λÖÃ44-51£¬4×Ö½Ú)
|
result.reserved = new String(cleanedMessage, 44, 8);
|
|
// ½âÎöУÑéºÍ (×îºó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 55AA51 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 = 3; 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);
|
}
|
|
|
}
|