package home; import java.util.Arrays; public class Dell55AA51Parser { // Ô¤ÆÚ°üÍ· private static final String EXPECTED_HEADER = "55AA51"; private static final ThreadLocal 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); } }