bin/home/AOAFollowSystem$1.classBinary files differ
bin/home/AOAFollowSystem$HomePanel$1.classBinary files differ
bin/home/AOAFollowSystem$HomePanel$2.classBinary files differ
bin/home/AOAFollowSystem$HomePanel.classBinary files differ
bin/home/AOAFollowSystem.classBinary files differ
bin/home/Dell55AA1FParser$ParseResult.classBinary files differ
bin/home/Dell55AA1FParser.classBinary files differ
bin/home/VisualizationPanel$1.classBinary files differ
bin/home/VisualizationPanel.classBinary files differ
src/home/AOAFollowSystem.java
@@ -110,6 +110,12 @@ case "ascii": return "ASCII"; case "hex_send": return "HEXåé"; case "display_format": return "æ¾ç¤ºæ ¼å¼"; case "pair_tooltip": return currentLocale.equals(Locale.SIMPLIFIED_CHINESE) ? "ç¹å»åéåè¿å ¥20ç§é 对模å¼" : "Enter 20-second pairing mode after clicking send"; case "scale": return currentLocale.equals(Locale.SIMPLIFIED_CHINESE) ? "缩æ¾" : "Scale"; default: return key; } } @@ -188,7 +194,10 @@ // æ´æ°å颿¿ææ¬ homePanel.updateLanguage(); configPanel.updateLanguage(); // æ´æ°é 对å¤éæ¡çæç¤ºä¿¡æ¯ homePanel.updatePairCheckboxTooltip(); } private JButton createNavButton(String text, Color color) { JButton button = new JButton(text); @@ -301,10 +310,26 @@ formatPanel.add(displayFormatLabel); ButtonGroup formatGroup = new ButtonGroup(); hexRadio = new JRadioButton(getString("hex"), true); // é»è®¤éä¸HEX asciiRadio = new JRadioButton(getString("ascii")); asciiRadio = new JRadioButton(getString("ascii"), true); // é»è®¤éä¸ASCI asciiRadio.addItemListener(e -> { if (asciiRadio.isSelected()) { asciiRadio.setForeground(Color.RED); } else { asciiRadio.setForeground(null); // æ¢å¤é»è®¤é¢è² } }); hexRadio = new JRadioButton(getString("hex"), false); // é»è®¤ä¸éä¸HEX hexRadio.addItemListener(e -> { if (hexRadio.isSelected()) { hexRadio.setForeground(Color.RED); } else { hexRadio.setForeground(null); // æ¢å¤é»è®¤é¢è² } }); pairCheckBox = new JCheckBox(getString("pair"), false); // é»è®¤ä¸å¾é // 为é 对å¤éæ¡æ·»å æç¤ºä¿¡æ¯ pairCheckBox.setToolTipText(getString("pair_tooltip")); pairCheckBox.addItemListener(e -> { if (pairCheckBox.isSelected()) { sendField.setText("55AA030304F5FF"); @@ -413,7 +438,7 @@ sendBtn.addActionListener(e -> sendData()); // æ°å¢ï¼HEXåéå¤éæ¡ hexSendCheckBox = new JCheckBox(getString("hex_send"), true); // é»è®¤å¾é hexSendCheckBox = new JCheckBox(getString("hex_send"), false); // é»è®¤å¾é sendControlPanel.add(hexSendCheckBox, BorderLayout.WEST); sendControlPanel.add(sendBtn, BorderLayout.EAST); @@ -426,6 +451,11 @@ // æ·»å å·¦å³é¢æ¿ add(leftPanel, BorderLayout.CENTER); add(rightPanel, BorderLayout.EAST); } // å¨HomePanelç±»ä¸æ·»å æ´æ°é 对å¤éæ¡æç¤ºä¿¡æ¯çæ¹æ³ public void updatePairCheckboxTooltip() { pairCheckBox.setToolTipText(getString("pair_tooltip")); } private JButton createColoredButton(String text, Color color) { @@ -566,74 +596,116 @@ } private void processReceivedData(byte[] data) { // ä¼åï¼éç¨StringBuilder对象 hexBuilder.setLength(0); for (byte b : data) { hexBuilder.append(String.format("%02X", b)); } String displayText = hexBuilder.toString(); String displayText1 = new String(data).replaceAll("\\s+", ""); if (displayText.startsWith("55AA1F")) { Dell55AA1FParser.ParseResult result = Dell55AA1FParser.parse(displayText, "127.0.0.1", 0); if (result != null) { updateTable(result); visualizationPanel.updatePosition(result.distance, result.angle,result.signalQuality); visualizationPanel.setTagId(result.tagId); } }else if(displayText.startsWith("55AA01")) { ParseResult result=Dell55AA01Parser.parse(displayText, "127.0.0.1", 0); visualizationPanel.updatePosition(result.distance,270,0); visualizationPanel.setTagId(result.tagId); } // ä¼åï¼éç¨StringBuilder对象 hexBuilder.setLength(0); for (byte b : data) { hexBuilder.append(String.format("%02X", b)); } String displayText = hexBuilder.toString(); String displayText1 = new String(data).replaceAll("\\s+", ""); // å æ£æ¥æ°æ®é¿åº¦æ¯å¦è¶³å¤è¿è¡è§£æ if (displayText.length() < 30) { // è³å°éè¦30个å符(15åè)æè½è§£æåºæ¬å段 appendLog("æ°æ®é¿åº¦ä¸è¶³: " + displayText); return; } if (displayText.startsWith("55AA1F")) { Dell55AA1FParser.ParseResult result = Dell55AA1FParser.parse(displayText, "127.0.0.1", 0); if (result != null) { updateTable(result); visualizationPanel.updatePosition(result.distance, result.angle, result.signalQuality); visualizationPanel.setTagId(result.tagId); } else { appendLog("55AA1Få议解æå¤±è´¥: " + displayText); } } else if(displayText.startsWith("55AA01")) { ParseResult result = Dell55AA01Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { visualizationPanel.updatePosition(result.distance, 270, 0); visualizationPanel.setTagId(result.tagId); } else { appendLog("55AA01å议解æå¤±è´¥: " + displayText); } } else if(displayText.startsWith("55AA51")) { Dell55AA51Parser.ParseResult result = Dell55AA51Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { visualizationPanel.updatePosition(result.distance, result.horizontalAngle, result.signalStrength); visualizationPanel.setTagId(result.tagId); } else { appendLog("55AA51å议解æå¤±è´¥: " + displayText); } } else { // 妿䏿¯å·²ç¥åè®®ï¼ç´æ¥è®°å½åå§æ°æ® appendLog("æªç¥åè®®: " + displayText); } if (hexRadio.isSelected()) { appendLog(displayText); } else { if (displayText.startsWith("55AA1F")) { Dell55AA1FParser.ParseResult result = Dell55AA1FParser.parse(displayText, "127.0.0.1", 0); // ä¼åï¼éç¨StringBuilder对象 displayBuilder.setLength(0); displayBuilder.append("1F:") .append(result.dataLength) .append(",") .append(result.messageType) .append(",id:") .append(result.tagId) .append(",Dis:") .append(result.distance) .append("cm,Angle:") .append(result.angle) .append("°,Signal:") .append(result.signalQuality) .append(",Button:") .append(result.buttonPressed) .append(",Power:") .append(result.power); appendLog(displayBuilder.toString()); }else if(displayText.startsWith("55AA01")) { ParseResult result=Dell55AA01Parser.parse(displayText, "127.0.0.1", 0); // ä¼åï¼éç¨StringBuilder对象 displayBuilder.setLength(0); displayBuilder.append("55AA01 Seq:") .append(result.sequenceNum) .append(",Tagid:") .append(result.tagId) .append(",Anchorid:") .append(result.anchorId) .append(",Distance:") .append(result.distance) .append(",Power:") .append(result.power) .append(",Button:") .append(result.buttonPressed); appendLog(displayBuilder.toString()); }else { appendLog(displayText1); } } if (hexRadio.isSelected()) { appendLog(displayText); } else { if (displayText.startsWith("55AA1F")) { Dell55AA1FParser.ParseResult result = Dell55AA1FParser.parse(displayText, "127.0.0.1", 0); if (result != null) { // ä¼åï¼éç¨StringBuilder对象 displayBuilder.setLength(0); displayBuilder.append(result.tagId) .append(",Dis:") .append(result.distance) .append("cm,Angle:") .append(result.angle) .append("°,Signal:") .append(result.signalQuality) .append(",Button:") .append(result.buttonPressed) .append(",Power:") .append(result.power); appendLog(displayBuilder.toString()); } } else if(displayText.startsWith("55AA01")) { ParseResult result = Dell55AA01Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { // ä¼åï¼éç¨StringBuilder对象 displayBuilder.setLength(0); displayBuilder.append("55AA01 Seq:") .append(result.sequenceNum) .append(",Tagid:") .append(result.tagId) .append(",Anchorid:") .append(result.anchorId) .append(",Distance:") .append(result.distance) .append(",Power:") .append(result.power) .append(",Button:") .append(result.buttonPressed); appendLog(displayBuilder.toString()); } } else if(displayText.startsWith("55AA51")) { Dell55AA51Parser.ParseResult result = Dell55AA51Parser.parse(displayText, "127.0.0.1", 0); if (result != null) { displayBuilder.setLength(0); displayBuilder.append(result.tagId) .append(",Dis:") .append(result.distance) .append("cm,HAngle:") .append(result.horizontalAngle) .append("°,VAngle:") .append(result.verticalAngle) .append("°,Signal:") .append(result.signalStrength) .append("°,ASignal:") .append(result.angleConfidence) .append(",Power:") .append(result.tagBattery) .append("%,Status:") .append(result.deviceStatus); appendLog(displayBuilder.toString()); } } else { appendLog(displayText1); } } } private void appendLog(String message) { @@ -732,7 +804,8 @@ asciiRadio.setText(getString("ascii")); hexSendCheckBox.setText(getString("hex_send")); pairCheckBox.setText(getString("pair")); // æ´æ°é 对å¤éæ¡çæç¤ºä¿¡æ¯ updatePairCheckboxTooltip(); // æ´æ°è¾¹æ¡æ é¢ updateBorderTitles(this); src/home/Dell55AA1FParser.java
@@ -4,6 +4,7 @@ public class Dell55AA1FParser { // 常éå®ä¹ private static final String EXPECTED_HEADER = "55AA1F"; // å议头 private static final int MIN_PACKET_LENGTH = 36; // æå°å é¿åº¦(å符æ°): åºå®å段18åè=36å符 private static final int FIXED_FIELDS_LENGTH = 11; // 仿 ç¾IDå°ä¿çåæ®µçåºå®é¿åº¦(åè) private static final ThreadLocal<ParseResult> RESULT_CACHE = ThreadLocal.withInitial(ParseResult::new); @@ -44,6 +45,7 @@ */ public static ParseResult parse(String message, String ip, int port) { if (message == null || message.isEmpty()) { System.err.println("Empty message from " + ip + ":" + port); return null; } @@ -51,12 +53,22 @@ char[] cleanedMessage = cleanMessage(message); if (cleanedMessage == null) { System.err.println("Invalid characters in message from " + ip + ":" + port); return null; } // æ£æ¥æå°é¿åº¦ if (cleanedMessage.length < MIN_PACKET_LENGTH) { System.err.println("Message too short from " + ip + ":" + port + ". Expected at least " + MIN_PACKET_LENGTH + " characters, got " + cleanedMessage.length); return null; } // åè®®å¤´æ ¡éª (55AA1F) if (cleanedMessage.length < 6 || !new String(cleanedMessage, 0, 6).equals(EXPECTED_HEADER)) { System.err.println("Invalid header in message from " + ip + ":" + port); return null; } @@ -68,13 +80,12 @@ result.dataLength = HexUtils.fastHexToByte(cleanedMessage[6], cleanedMessage[7]); // è®¡ç®ææçæ»å符é¿åº¦ int expectedCharLength = 8 + // å 头(4å符) + æ¶æ¯ç±»å(2å符) + æ°æ®é¿åº¦(2å符) result.dataLength * 2 + // æ°æ®é¨å 4; // æ ¡éªå(4å符) int expectedCharLength = 14 + result.dataLength * 2; // 14=å 头6+æ¶æ¯ç±»å2+æ°æ®é¿åº¦2+æ ¡éªå4 // if (cleanedMessage.length != expectedCharLength) { // System.err.println("Data length mismatch: expected " + expectedCharLength + // ", got " + cleanedMessage.length); // if (cleanedMessage.length < expectedCharLength) { // System.err.println("Incomplete message from " + ip + ":" + port + // ". Expected " + expectedCharLength + // " characters, got " + cleanedMessage.length); // return null; // } @@ -83,6 +94,12 @@ // è§£ææ ç¾ID (ä½ç½®8-11)ï¼ç´æ¥åå符串 result.tagId = new String(cleanedMessage, 8, 4); // æ£æ¥æ¯å¦æè¶³å¤é¿åº¦è§£æåºå®å段 if (cleanedMessage.length < 30) { // éè¦è³å°15åè=30å符 System.err.println("Message too short for fixed fields from " + ip + ":" + port); return null; } // è§£æè·ç¦» (ä½ç½®12-15, 2åèå°ç«¯æ´æ°) int distLow = HexUtils.fastHexToByte(cleanedMessage[12], cleanedMessage[13]); @@ -111,7 +128,12 @@ // int userDataStart = 30; // int userDataCharLength = (result.dataLength - FIXED_FIELDS_LENGTH) * 2; // if (userDataCharLength > 0) { // result.userData = new String(cleanedMessage, userDataStart, userDataCharLength); // if (userDataStart + userDataCharLength <= cleanedMessage.length) { // result.userData = new String(cleanedMessage, userDataStart, userDataCharLength); // } else { // System.err.println("User data truncated in message from " + ip + ":" + port); // result.userData = ""; // } // } else { // result.userData = ""; // } src/home/Dell55AA51Parser.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,228 @@ 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); } } src/home/TagDell55AA03Parser.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,236 @@ 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<ParseResult> 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); } } src/home/VisualizationPanel.java
@@ -4,11 +4,16 @@ import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.JPanel; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.io.File; import java.io.IOException; // å¯è§å颿¿ç±» class VisualizationPanel extends JPanel { @@ -30,12 +35,20 @@ private Font boldFont = new Font("Microsoft YaHei", Font.BOLD, 14); private Font normalFont = new Font("Microsoft YaHei", Font.PLAIN, 12); private Font titleFont = new Font("Microsoft YaHei", Font.BOLD, 12); private Image logoImage; // æ·»å å¾çåé public VisualizationPanel(AOAFollowSystem parentFrame) { this.parentFrame = parentFrame; setPreferredSize(new Dimension(400, 400)); setBorder(BorderFactory.createTitledBorder(parentFrame.getString("visualization"))); // å è½½å¾ç try { logoImage = ImageIO.read(new File("systemfile/1.png")); } catch (IOException e) { System.err.println("æ æ³å è½½å¾ç: systemfile/1.png"); e.printStackTrace(); } // æ·»å é¼ æ æ»è½®çå¬å¨ addMouseWheelListener(new MouseWheelListener() { @Override @@ -84,11 +97,22 @@ int centerX = getWidth() / 2; int centerY = getHeight()/ 2 - 30; int maxRadius = (int) (Math.min(centerX, centerY) * scaleFactor - 20); int baseRadius = Math.min(centerX, centerY) - 20; // åºç¡åå¾ï¼ä¸ç¼©æ¾ï¼ int maxRadius = (int) (baseRadius * scaleFactor); // 缩æ¾åçåå¾ // è®¾ç½®èæ¯é¢è² g2d.setColor(new Color(240, 240, 240)); g2d.fillRect(0, 0, getWidth(), getHeight()); // å¨å·¦ä¸è§ç»å¶å¾ç if (logoImage != null) { int imgWidth = logoImage.getWidth(this); int imgHeight = logoImage.getHeight(this); // è°æ´å¾ç大å°ï¼ä½¿å ¶éå颿¿ int scaledWidth =150; // 设置å¾ç宽度 int scaledHeight = (int) (imgHeight * (scaledWidth * 1.0 / imgWidth)); // ææ¯ä¾è®¡ç®é«åº¦ g2d.drawImage(logoImage, 5, getHeight() - scaledHeight - 5, scaledWidth, scaledHeight, this); } // ç»å¶åæ è½´ g2d.setColor(Color.LIGHT_GRAY); @@ -123,8 +147,8 @@ for (int i = 1; i <= 5; i++) { int radius = maxRadius * i / 5; g2d.drawOval(centerX - radius, centerY - radius, radius * 2, radius * 2); // ä¿®æ¹ï¼å°è·ç¦»æ ç¾æ¾ç¤ºå¨å忣忹ä¸é´ String distanceLabel = (int)(i * 200 * scaleFactor) + "cm"; // ä¿®æ¹ï¼ä¹ä»¥scaleFactorè䏿¯é¤ä»¥ // ä¿®æ¹ï¼è·ç¦»æ ç¾ä¸é缩æ¾ååï¼ä¿æå®é è·ç¦» String distanceLabel = i * 200 + "cm"; int labelWidth = g2d.getFontMetrics().stringWidth(distanceLabel); g2d.drawString(distanceLabel, centerX - labelWidth / 2, centerY + radius + 15); } @@ -140,7 +164,7 @@ // ç»å¶Bç¹ï¼æ ç¾ç¹ï¼ if (distance > 0) { // æ ¹æ®è·ç¦»è®¡ç®ç¼©æ¾æ¯ä¾ï¼æå¤§1000åç±³ï¼ double scaledDistance = Math.min(distance, 1000) * maxRadius / 1000.0 ; // ä¿®æ¹ï¼æ·»å ä¹ä»¥scaleFactor double scaledDistance = Math.min(distance, 1000) * maxRadius / 1000.0; // å°å¯¼èªè§åº¦è½¬æ¢ä¸ºæ°å¦è§åº¦ï¼ä»æ£ä¸æ¹åå¼å§ï¼éæ¶é为æ£ï¼ double mathAngle = 90 - angle; // 导èªè§åº¦è½¬æ¢ä¸ºæ°å¦è§åº¦ @@ -162,13 +186,7 @@ g2d.setFont(boldFont); g2d.setColor(Color.RED); // è®¡ç®ææ¬ä½ç½®ï¼Bç¹æ£ä¸æ¹ï¼ int textY = bY + 25; g2d.drawString(distanceText, bX - g2d.getFontMetrics().stringWidth(distanceText)/2, textY); g2d.drawString(angleText, bX - g2d.getFontMetrics().stringWidth(angleText)/2, textY + 20); // æ¢å¤åå§åä½ g2d.setFont(normalFont); // å¨é¢æ¿åºé¨æ¾ç¤ºè·ç¦»åè§åº¦ä¿¡æ¯ - 宿¶è·åå符串ï¼ä¸ä½¿ç¨ç¼å g2d.setFont(boldFont); @@ -179,18 +197,30 @@ g2d.drawString(parentFrame.getString("signal") + signalQuality, 10, 100); g2d.setFont(normalFont); g2d.setColor(Color.BLUE); g2d.fillOval(bX - 5, bY - 5, 10, 10); g2d.fillOval(bX -10, bY -10, 20, 20); // Bç¹æ£ä¸æ¹æ¾ç¤ºè®¾å¤ç¼å· g2d.setFont(titleFont); g2d.drawString(tagid, bX - g2d.getFontMetrics().stringWidth(tagid)/2, bY - 15); g2d.setColor(Color.BLUE); g2d.drawString(tagid, bX - g2d.getFontMetrics().stringWidth(tagid)/2, bY - 25); g2d.setFont(normalFont); // è®¡ç®ææ¬ä½ç½®ï¼Bç¹æ£ä¸æ¹ï¼ int textY = bY + 25; g2d.setColor(Color.BLUE); g2d.drawString(distanceText, bX - g2d.getFontMetrics().stringWidth(distanceText)/2, textY); g2d.drawString(angleText, bX - g2d.getFontMetrics().stringWidth(angleText)/2, textY + 20); g2d.setFont(normalFont); } // æ¾ç¤ºå½åç¼©æ¾æ¯ä¾ g2d.setColor(Color.DARK_GRAY); g2d.drawString(String.format("缩æ¾: %.1fx", scaleFactor), getWidth() - 80, 20); g2d.drawString(String.format("%s: %.1fx", parentFrame.getString("scale"), scaleFactor), getWidth() - 80, 20); } public void updateLanguage() { systemfile/1.png
systemfile/Messages_en.properties
@@ -48,4 +48,7 @@ hex=HEX ascii=ASCII hex_send=HEX Send close_serial=Close Serial close_serial=Close Serial signal=Signal: pair=Pair pair_tooltip=Enter 20-second pairing mode after clicking send systemfile/Messages_zh.properties
@@ -48,4 +48,7 @@ hex=HEX ascii=ASCII hex_send=HEXåé close_serial=å ³éä¸²å£ close_serial=å ³éä¸²å£ signal=ä¿¡å·ï¼ pair=é 对 pair_tooltip=ç¹å»åéåè¿å ¥20ç§é å¯¹æ¨¡å¼ systemfile/logfile/openlog.txt
@@ -380,3 +380,223 @@ 工使¶é¿: 1å°æ¶ 9åé 40ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 17:12:20 ç¨åºå ³é: 2025-08-26 17:22:39 工使¶é¿: 0å°æ¶ 10åé 18ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 17:22:41 ç¨åºå¯å¨: 2025-08-26 21:05:09 ç¨åºå ³é: 2025-08-26 21:27:08 工使¶é¿: 0å°æ¶ 21åé 58ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 21:29:00 ç¨åºå ³é: 2025-08-26 21:29:29 工使¶é¿: 0å°æ¶ 0åé 29ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 21:29:42 ç¨åºå ³é: 2025-08-26 21:35:17 工使¶é¿: 0å°æ¶ 5åé 35ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 21:35:22 ç¨åºå ³é: 2025-08-26 21:35:38 工使¶é¿: 0å°æ¶ 0åé 16ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 21:35:48 ç¨åºå¯å¨: 2025-08-26 21:40:46 ç¨åºå¯å¨: 2025-08-26 21:40:46 ç¨åºå ³é: 2025-08-26 21:48:25 工使¶é¿: 0å°æ¶ 12åé 36ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 21:56:14 ç¨åºå ³é: 2025-08-26 21:58:13 工使¶é¿: 0å°æ¶ 1åé 58ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 21:58:15 ç¨åºå ³é: 2025-08-26 21:58:35 工使¶é¿: 0å°æ¶ 0åé 20ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 21:59:03 ç¨åºå¯å¨: 2025-08-26 22:14:47 ç¨åºå ³é: 2025-08-26 22:14:51 工使¶é¿: 0å°æ¶ 15åé 47ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:14:53 ç¨åºå ³é: 2025-08-26 22:23:31 工使¶é¿: 0å°æ¶ 8åé 38ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:28:20 ç¨åºå ³é: 2025-08-26 22:30:20 工使¶é¿: 0å°æ¶ 2åé 0ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:37:12 ç¨åºå ³é: 2025-08-26 22:37:24 工使¶é¿: 0å°æ¶ 0åé 11ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:39:02 ç¨åºå¯å¨: 2025-08-26 22:40:39 ç¨åºå ³é: 2025-08-26 22:40:44 工使¶é¿: 0å°æ¶ 1åé 41ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:40:46 ç¨åºå ³é: 2025-08-26 22:41:08 工使¶é¿: 0å°æ¶ 0åé 22ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:44:30 ç¨åºå ³é: 2025-08-26 22:45:02 工使¶é¿: 0å°æ¶ 0åé 32ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:45:54 ç¨åºå ³é: 2025-08-26 22:47:55 工使¶é¿: 0å°æ¶ 2åé 1ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:47:58 ç¨åºå ³é: 2025-08-26 22:48:09 工使¶é¿: 0å°æ¶ 0åé 10ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:52:06 ç¨åºå¯å¨: 2025-08-26 22:52:52 ç¨åºå ³é: 2025-08-26 22:52:56 工使¶é¿: 0å°æ¶ 0åé 50ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:52:57 ç¨åºå ³é: 2025-08-26 22:54:36 工使¶é¿: 0å°æ¶ 1åé 38ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 22:55:43 ç¨åºå ³é: 2025-08-26 22:56:31 工使¶é¿: 0å°æ¶ 0åé 48ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-26 23:00:05 ç¨åºå ³é: 2025-08-26 23:01:59 工使¶é¿: 0å°æ¶ 1åé 53ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 07:28:02 ç¨åºå ³é: 2025-08-27 07:38:02 工使¶é¿: 0å°æ¶ 10åé 0ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 07:38:04 ç¨åºå ³é: 2025-08-27 07:38:33 工使¶é¿: 0å°æ¶ 0åé 28ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 07:45:36 ç¨åºå ³é: 2025-08-27 07:45:46 工使¶é¿: 0å°æ¶ 0åé 10ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 07:46:16 ç¨åºå ³é: 2025-08-27 07:48:27 工使¶é¿: 0å°æ¶ 2åé 11ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 07:48:29 ç¨åºå ³é: 2025-08-27 07:48:40 工使¶é¿: 0å°æ¶ 0åé 10ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 07:49:58 ç¨åºå ³é: 2025-08-27 07:50:13 工使¶é¿: 0å°æ¶ 0åé 14ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 07:54:23 ç¨åºå ³é: 2025-08-27 08:00:10 工使¶é¿: 0å°æ¶ 5åé 46ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 08:00:12 ç¨åºå ³é: 2025-08-27 08:07:42 工使¶é¿: 0å°æ¶ 7åé 30ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 08:07:44 ç¨åºå ³é: 2025-08-27 08:29:47 工使¶é¿: 0å°æ¶ 22åé 2ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 08:29:50 ç¨åºå ³é: 2025-08-27 08:30:13 工使¶é¿: 0å°æ¶ 0åé 22ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:07:56 ç¨åºå ³é: 2025-08-27 22:08:12 工使¶é¿: 0å°æ¶ 0åé 15ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:09:24 ç¨åºå ³é: 2025-08-27 22:09:41 工使¶é¿: 0å°æ¶ 0åé 16ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:09:59 ç¨åºå ³é: 2025-08-27 22:10:10 工使¶é¿: 0å°æ¶ 0åé 10ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:10:34 ç¨åºå ³é: 2025-08-27 22:10:37 工使¶é¿: 0å°æ¶ 0åé 3ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:10:42 ç¨åºå ³é: 2025-08-27 22:10:53 工使¶é¿: 0å°æ¶ 0åé 10ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:11:22 ç¨åºå ³é: 2025-08-27 22:12:30 工使¶é¿: 0å°æ¶ 1åé 7ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:13:23 ç¨åºå ³é: 2025-08-27 22:13:56 工使¶é¿: 0å°æ¶ 0åé 32ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:15:06 ç¨åºå¯å¨: 2025-08-27 22:16:54 ç¨åºå ³é: 2025-08-27 22:17:02 工使¶é¿: 0å°æ¶ 0åé 8ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:18:07 ç¨åºå ³é: 2025-08-27 22:18:25 工使¶é¿: 0å°æ¶ 0åé 18ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:18:38 ç¨åºå ³é: 2025-08-27 22:19:08 工使¶é¿: 0å°æ¶ 0åé 30ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:19:33 ç¨åºå ³é: 2025-08-27 22:19:45 工使¶é¿: 0å°æ¶ 0åé 12ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:20:55 ç¨åºå ³é: 2025-08-27 22:21:18 工使¶é¿: 0å°æ¶ 0åé 22ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:22:15 ç¨åºå ³é: 2025-08-27 22:22:36 工使¶é¿: 0å°æ¶ 0åé 21ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:24:27 ç¨åºå¯å¨: 2025-08-27 22:36:01 ç¨åºå ³é: 2025-08-27 22:36:04 工使¶é¿: 0å°æ¶ 11åé 37ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:36:05 ç¨åºå ³é: 2025-08-27 22:36:07 工使¶é¿: 0å°æ¶ 0åé 1ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:36:59 ç¨åºå ³é: 2025-08-27 22:37:13 工使¶é¿: 0å°æ¶ 0åé 14ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:43:27 ç¨åºå¯å¨: 2025-08-27 22:45:39 ç¨åºå ³é: 2025-08-27 22:45:43 工使¶é¿: 0å°æ¶ 2åé 15ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:45:45 ç¨åºå ³é: 2025-08-27 22:45:54 工使¶é¿: 0å°æ¶ 0åé 9ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:48:06 ç¨åºå ³é: 2025-08-27 22:49:36 工使¶é¿: 0å°æ¶ 1åé 29ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:49:38 ç¨åºå ³é: 2025-08-27 22:49:43 工使¶é¿: 0å°æ¶ 0åé 5ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:50:11 ç¨åºå ³é: 2025-08-27 22:50:25 工使¶é¿: 0å°æ¶ 0åé 13ç§ ----------------------------------- ç¨åºå¯å¨: 2025-08-27 22:51:03 ç¨åºå ³é: 2025-08-27 22:51:23 工使¶é¿: 0å°æ¶ 0åé 20ç§ -----------------------------------