package home; import java.util.Arrays; public class TagDell55AA03Parser { // Ô¤ÆÚ±¨ÎÄÍ· private static final String EXPECTED_HEADER = "55AA03"; // ×îС³¤¶È£¨¸ù¾ÝÎĵµ£¬ÖÁÉÙÓ¦ÓÐ40¸ö×ֶΣ¬Ã¿¸ö×Ö¶Î2×Ö½Ú£¬¼ÓÉϰüÍ·ºÍÀàÐ͹²4×Ö½Ú£© private static final int MIN_LENGTH = 84; // (4 + 40*2) * 2×Ö·û = 168×Ö·û£¬µ«Êµ¼Ê¿ÉÄܸü¶à private static final ThreadLocal RESULT_CACHE = ThreadLocal.withInitial(ParseResult::new); // ½âÎö½á¹ûÀà public static class ParseResult { public String header; // Êý¾Ý°üÍ·(55AA) public int dataType; // Êý¾ÝÀàÐÍ(03) public int dataLength; // Êý¾Ý³¤¶È public String version; // °æ±¾ºÅ(XX.XX¸ñʽ) public int deviceId; // É豸±àºÅ(С¶ËÐò) public int commFrequency; // ͨÐÅÆµÂÊ(ºÁÃë) public int maxAnchors; // µ¥´ÎͨÐÅ»ùÕ¾Êý public int minAnchors; // С×é±àºÅ/×îÉÙ»ùÕ¾Êý public int distanceCalibration;// ¾àÀëУ׼ֵ public int deviceType; // É豸ÀàÐÍ(0:»ùÕ¾, 1:±êÇ©) public int anchorActiveRanging;// »ùÕ¾Ö÷¶¯²â¾à public int alarmDevice; // ±¨¾¯É豸 public int imuIdleTime; // IMU¾²Ö¹Ê±¼ä public int pressureAnchorId; // ÆøÑ¹»ùÕ¾±àºÅ public int peripheralControl; // ÍâÉè¿ØÖÆ(1:´ò¿ªRTK, 2:¹Ø±ÕRTK) public int pairingId; // Åä¶Ô±àºÅ public int uwbStatus; // UWB¿ª¹Ø×´Ì¬(0:¹Ø±Õ) public int modbusMode; // MODBUSģʽ public int vibrationDuration; // Õð¶¯Ê±³¤(Ãë) public int[] neighborAnchorIds = new int[10]; // ÁÙ½ü»ùÕ¾ID(10¸ö) public int power; // ¹¦ÂÊ public int accelerometerThreshold; // ¼ÓËÙ¼ÆãÐÖµ public int idleSleepTime; // ¾²Ö¹ÐÝÃßʱ¼ä public int vibrationEnable; // Õð¶¯Ê¹ÄÜ public int accelerometerEnable;// ¼ÓËÙ¼ÆÊ¹ÄÜ public int configStatus; // ±êǩϷ¢ÅäÖÃ״̬ public int accelerometerDuration; // ¼ÓËÙ¼ÆÊ±³¤ public int activationStatus; // É豸¼¤»î״̬λ(0:δ¼¤»î, 1:¼¤»î) public int syncAnchorType; // ͬ²½»ùÕ¾ÀàÐÍ(0:²»·¢Í¬²½, 1:Ö÷»ùÕ¾, 2:´Ó»ùÕ¾) public int speedFilterLimit; // ËÙ¶ÈÂ˲¨ÏÞÖµ public int pressureCalibration;// ÆøÑ¹¸ß¶ÈУ׼ֵ public void reset() { header = ""; dataType = 0; dataLength = 0; version = ""; deviceId = 0; commFrequency = 0; maxAnchors = 0; minAnchors = 0; distanceCalibration = 0; deviceType = 0; anchorActiveRanging = 0; alarmDevice = 0; imuIdleTime = 0; pressureAnchorId = 0; peripheralControl = 0; pairingId = 0; uwbStatus = 0; modbusMode = 0; vibrationDuration = 0; Arrays.fill(neighborAnchorIds, 0); power = 0; accelerometerThreshold = 0; idleSleepTime = 0; vibrationEnable = 0; accelerometerEnable = 0; configStatus = 0; accelerometerDuration = 0; activationStatus = 0; syncAnchorType = 0; speedFilterLimit = 0; pressureCalibration = 0; } } /** * ½âÎö55AA03ЭÒ鱨ÎÄ * @param message ½ÓÊÕµ½µÄÊ®Áù½øÖÆ×Ö·û´® * @return ½âÎö½á¹û(½âÎöʧ°Ü·µ»Ønull) */ public static ParseResult parse(String message, String ip, int port) { if (message == null || message.isEmpty()) { return null; } // ÇåÀíÏûÏ¢£ºÖ»±£ÁôÊý×ÖºÍA-F×Ö·û char[] cleanedMessage = cleanMessage(message); // ¼ì²é×îС³¤¶È if (cleanedMessage == null || cleanedMessage.length < MIN_LENGTH) { return null; } // ¼ì²é±¨ÎÄÍ· (55AA03) if (!new String(cleanedMessage, 0, 6).equals(EXPECTED_HEADER)) { return null; } ParseResult result = RESULT_CACHE.get(); result.reset(); try { // ÉèÖðüÍ·ºÍÊý¾ÝÀàÐÍ result.header = new String(cleanedMessage, 0, 4); result.dataType = HexUtils.fastHexToByte(cleanedMessage[4], cleanedMessage[5]); // ½âÎöÊý¾Ý³¤¶È (λÖÃ6-7) result.dataLength = HexUtils.fastHexToByte(cleanedMessage[6], cleanedMessage[7]); // ½âÎö°æ±¾ºÅ (λÖÃ8-11, ÐÎÈçXX.XX) int versionPart1 = HexUtils.fastHexToByte(cleanedMessage[8], cleanedMessage[9]); int versionPart2 = HexUtils.fastHexToByte(cleanedMessage[10], cleanedMessage[11]); result.version = String.format("%d.%02d", versionPart1, versionPart2); // ½âÎöÉ豸±àºÅ (λÖÃ12-15, µÍλÔÚǰ) result.deviceId = parseLittleEndian(cleanedMessage, 12); // ½âÎöͨÐÅÆµÂÊ (λÖÃ16-19) result.commFrequency = parseLittleEndian(cleanedMessage, 16); // ½âÎöµ¥´ÎͨÐÅ»ùÕ¾Êý (λÖÃ20-23) result.maxAnchors = parseLittleEndian(cleanedMessage, 20); // ½âÎöС×é±àºÅ/×îÉÙ»ùÕ¾Êý (λÖÃ24-27) result.minAnchors = parseLittleEndian(cleanedMessage, 24); // ½âÎö¾àÀëУ׼ֵ (λÖÃ28-31) result.distanceCalibration = parseLittleEndian(cleanedMessage, 28); // ½âÎöÉ豸ÀàÐÍ (λÖÃ32-35, 0:»ùÕ¾, 1:±êÇ©) result.deviceType = parseLittleEndian(cleanedMessage, 32); // ½âÎö»ùÕ¾Ö÷¶¯²â¾à (λÖÃ36-39) result.anchorActiveRanging = parseLittleEndian(cleanedMessage, 36); // ½âÎö±¨¾¯É豸 (λÖÃ40-43) result.alarmDevice = parseLittleEndian(cleanedMessage, 40); // ½âÎöIMU¾²Ö¹Ê±¼ä (λÖÃ44-47) result.imuIdleTime = parseLittleEndian(cleanedMessage, 44); // ½âÎöÆøÑ¹»ùÕ¾±àºÅ (λÖÃ48-51) result.pressureAnchorId = parseLittleEndian(cleanedMessage, 48); // ½âÎöÍâÉè¿ØÖÆ (λÖÃ52-55, 1:´ò¿ªRTK, 2:¹Ø±ÕRTK) result.peripheralControl = parseLittleEndian(cleanedMessage, 52); // ½âÎöÅä¶Ô±àºÅ (λÖÃ56-59) result.pairingId = parseLittleEndian(cleanedMessage, 56); // ½âÎöUWB¿ª¹Ø×´Ì¬ (λÖÃ60-63, 0:¹Ø±Õ) result.uwbStatus = parseLittleEndian(cleanedMessage, 60); // ½âÎöMODBUSģʽ (λÖÃ64-67) result.modbusMode = parseLittleEndian(cleanedMessage, 64); // ½âÎöÕð¶¯Ê±³¤ (λÖÃ68-71, µ¥Î»Ãë) result.vibrationDuration = parseLittleEndian(cleanedMessage, 68); // ½âÎöÁÙ½ü»ùÕ¾ID (λÖÃ72-111, 10¸ö»ùÕ¾) for (int i = 0; i < 10; i++) { result.neighborAnchorIds[i] = parseLittleEndian(cleanedMessage, 72 + i * 4); } // ½âÎö¹¦ÂÊ (λÖÃ112-115) result.power = parseLittleEndian(cleanedMessage, 112); // ½âÎö¼ÓËÙ¼ÆãÐÖµ (λÖÃ116-119) result.accelerometerThreshold = parseLittleEndian(cleanedMessage, 116); // ½âÎö¾²Ö¹ÐÝÃßʱ¼ä (λÖÃ120-123) result.idleSleepTime = parseLittleEndian(cleanedMessage, 120); // ½âÎöÕð¶¯Ê¹ÄÜ (λÖÃ124-127) result.vibrationEnable = parseLittleEndian(cleanedMessage, 124); // ½âÎö¼ÓËÙ¼ÆÊ¹ÄÜ (λÖÃ128-131) result.accelerometerEnable = parseLittleEndian(cleanedMessage, 128); // ½âÎö±êǩϷ¢ÅäÖÃ״̬ (λÖÃ132-135) result.configStatus = parseLittleEndian(cleanedMessage, 132); // ½âÎö¼ÓËÙ¼ÆÊ±³¤ (λÖÃ136-139) result.accelerometerDuration = parseLittleEndian(cleanedMessage, 136); // ½âÎöÉ豸¼¤»î״̬λ (λÖÃ140-143, 0:δ¼¤»î, 1:¼¤»î) result.activationStatus = parseLittleEndian(cleanedMessage, 140); // ½âÎöͬ²½»ùÕ¾ÀàÐÍ (λÖÃ144-147, 0:²»·¢Í¬²½, 1:Ö÷»ùÕ¾, 2:´Ó»ùÕ¾) result.syncAnchorType = parseLittleEndian(cleanedMessage, 144); // ½âÎöËÙ¶ÈÂ˲¨ÏÞÖµ (λÖÃ148-151) result.speedFilterLimit = parseLittleEndian(cleanedMessage, 148); // ½âÎöÆøÑ¹¸ß¶ÈУ׼ֵ (λÖÃ152-155) result.pressureCalibration = parseLittleEndian(cleanedMessage, 152); } catch (IndexOutOfBoundsException | NumberFormatException e) { System.err.println("Parsing error in packet from " + ip + ":" + port); return null; } return result; } /** * ½âÎöС¶ËÐòµÄ16λÕûÊý(4¸ö×Ö·û) */ private static int parseLittleEndian(char[] message, int startIndex) { int lowByte = HexUtils.fastHexToByte(message[startIndex], message[startIndex + 1]); int highByte = HexUtils.fastHexToByte(message[startIndex + 2], message[startIndex + 3]); return (highByte << 8) | lowByte; } /** * ÇåÀíÏûÏ¢£¬Ö»±£ÁôÊ®Áù½øÖÆ×Ö·û */ 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); } }