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