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 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); } }