package publicway; import java.util.ArrayList; import java.util.List; import chushihua.SlotManager; public class ProtocolParser01 { /** * ÐÂÔö£ºÖ±½ÓʹÓÃ×Ö½ÚÊý×é½âÎöµÄ·½·¨£¨±ÜÃâ×Ö·û´®×ª»»£© */ public static ParseResult parseDDCC01Data(byte[] packetData) { if (packetData == null || packetData.length < 18) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×ã"); } // ÑéÖ¤Æðʼ±ê¼Ç if (packetData[0] != (byte)0xDD || packetData[1] != (byte)0xCC) { throw new IllegalArgumentException("·ÇDDCCЭÒéÊý¾Ý"); } try { // Ìø¹ý°üÍ·DDCC (2×Ö½Ú)£¬Ö±½ÓʹÓÃÊ£ÓàÊý¾Ý byte[] dataBytes = new byte[packetData.length - 2]; System.arraycopy(packetData, 2, dataBytes, 0, dataBytes.length); if (dataBytes.length < 16) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×ã"); } // 2. ½âÎö¸÷¸ö×Ö¶Î int dataLength = parseDataLength(dataBytes); int hostAddress = parseHostAddress(dataBytes); int slotNumber = parseSlotNumber(dataBytes); int functionCode = parseFunctionCode(dataBytes); WorkStatus workStatus = parseWorkStatus(dataBytes); DoorStatus doorStatus = parseDoorStatus(dataBytes); CardStatus cardStatus = parseCardStatus(dataBytes); int cardStatusChange = parseCardStatusChange(dataBytes); String cardNumber = parseCardNumber(dataBytes); List faults = parseFaults(dataBytes); double voltage = parseVoltage(dataBytes); double current = parseCurrent(dataBytes); // 3. ÑéÖ¤¹¦ÄÜÂë if (functionCode != 0x01) { throw new IllegalArgumentException("·Ç01¹¦ÄÜÂëÊý¾Ý"); } return new ParseResult(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); } catch (Exception e) { throw new RuntimeException("½âÎöÊý¾Ýʱ·¢Éú´íÎó: " + e.getMessage(), e); } } /** * ±£ÁôÔ­Óз½·¨ÓÃÓÚ¼æÈÝÐÔ */ public static ParseResult parseDDCC01Data(String hexData) { if (hexData == null || hexData.isEmpty()) { throw new IllegalArgumentException("Êý¾ÝΪ¿Õ"); } // ÑéÖ¤Æðʼ±ê¼Ç if (!hexData.startsWith("DDCC")) { throw new IllegalArgumentException("·ÇDDCCЭÒéÊý¾Ý"); } try { // 1. ÒÆ³ý°üÍ·DDCC½øÐнâÎö String dataWithoutHeader = hexData.substring(4); byte[] dataBytes = HexUtil.hexStringToBytes(dataWithoutHeader); if (dataBytes == null || dataBytes.length < 16) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×ã"); } // 2. ½âÎö¸÷¸ö×Ö¶Î int dataLength = parseDataLength(dataBytes); int hostAddress = parseHostAddress(dataBytes); int slotNumber = parseSlotNumber(dataBytes); int functionCode = parseFunctionCode(dataBytes); WorkStatus workStatus = parseWorkStatus(dataBytes); DoorStatus doorStatus = parseDoorStatus(dataBytes); CardStatus cardStatus = parseCardStatus(dataBytes); int cardStatusChange = parseCardStatusChange(dataBytes); String cardNumber = parseCardNumber(dataBytes); List faults = parseFaults(dataBytes); double voltage = parseVoltage(dataBytes); double current = parseCurrent(dataBytes); // 3. ÑéÖ¤¹¦ÄÜÂë if (functionCode != 0x01) { throw new IllegalArgumentException("·Ç01¹¦ÄÜÂëÊý¾Ý"); } return new ParseResult(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); } catch (Exception e) { throw new RuntimeException("½âÎöÊý¾Ýʱ·¢Éú´íÎó: " + e.getMessage(), e); } } /** * CRCУÑé * ¸ù¾ÝЭÒ飺CRC16УÑé´Ó¹¦ÄÜÂëÖ®ºóÒ»Ö±µ½CRC16֮ǰµÄÊý¾Ý */ private static boolean validateCRC(String hexData) { try { // CRCÔÚ×îºó4¸ö×Ö·û String receivedCRC = hexData.substring(hexData.length() - 6); byte[] cmdBytes = HexUtil.hexStringToBytes(hexData.replace(receivedCRC,"")); String crc = HexUtil.calculate(cmdBytes)+"00"; System.out.println("ÊÕµ½µÄÍêÕûÊý¾ÝÊÇ£º"+hexData); System.out.println("ÊÕµ½Êý¾ÝУÑéÂëÊÇ£º"+receivedCRC); System.out.println("УÑéÂëÊÇ£º"+crc); return receivedCRC.equalsIgnoreCase(crc); } catch (Exception e) { System.err.println("CRCУÑéÒì³£: " + e.getMessage()); return false; } } /** * ½âÎöÊý¾Ý³¤¶È£¨2×Ö½Ú£© * Êý¾Ý³¤¶ÈÊÇ´Ó¸Ã×Ö½ÚÖ®ºó¿ªÊ¼µ½CRC16֮ǰÊý¾Ý×Ö½ÚÊý */ private static int parseDataLength(byte[] data) { if (data.length < 2) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöÊý¾Ý³¤¶È"); } return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF); } /** * ½âÎöÖ÷»úµØÖ·£¨1×Ö½Ú£© */ private static int parseHostAddress(byte[] data) { if (data.length < 3) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöÖ÷»úµØÖ·"); } return data[2] & 0xFF; } /** * ½âÎö¿¨²Û±àºÅ£¨1×Ö½Ú£© */ private static int parseSlotNumber(byte[] data) { if (data.length < 4) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨²Û±àºÅ"); } return data[3] & 0xFF; } /** * ½âÎö¹¦ÄÜÂ루1×Ö½Ú£© */ private static int parseFunctionCode(byte[] data) { if (data.length < 5) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹¦ÄÜÂë"); } return data[4] & 0xFF; } /** * ½âÎö¹¤×÷״̬£¨1×Ö½Ú£© */ private static WorkStatus parseWorkStatus(byte[] data) { if (data.length < 6) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹¤×÷״̬"); } int statusValue = data[5] & 0xFF; return WorkStatus.fromValue(statusValue); } /** * ½âÎöÔÚλ״̬/ÃÅ״̬£¨1×Ö½Ú£© */ private static DoorStatus parseDoorStatus(byte[] data) { if (data.length < 7) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöÔÚλ״̬"); } int statusValue = data[6] & 0xFF; return DoorStatus.fromValue(statusValue); } /** * ½âÎö¿¨×´Ì¬£¨1×Ö½Ú£© */ private static CardStatus parseCardStatus(byte[] data) { if (data.length < 8) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨×´Ì¬"); } int statusValue = data[7] & 0xFF; return CardStatus.fromValue(statusValue); } /** * ½âÎö¿¨×´Ì¬±ä¸ü£¨1×Ö½Ú£© */ private static int parseCardStatusChange(byte[] data) { if (data.length < 9) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨×´Ì¬±ä¸ü"); } return data[8] & 0xFF; } /** * ½âÎö¿¨ºÅ£¨¿¨ºÅ3 + ¿¨ºÅ4£© */ private static String parseCardNumber(byte[] data) { if (data.length < 13) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨ºÅ"); } // Ë÷Òý11£º¿¨ºÅ3£¬Ë÷Òý12£º¿¨ºÅ4 byte cardNumber3 = data[11]; byte cardNumber4 = data[12]; return String.format("%02X%02X", cardNumber3 & 0xFF, cardNumber4 & 0xFF); } /** * ½âÎö¹ÊÕÏÐÅÏ¢£¨1×Ö½Ú£© */ private static List parseFaults(byte[] data) { if (data.length < 14) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹ÊÕÏÐÅÏ¢"); } int faultByte = data[13] & 0xFF; List faults = new ArrayList<>(); for (FaultType fault : FaultType.values()) { if ((faultByte & fault.getBitMask()) != 0) { faults.add(fault); } } return faults; } /** * ½âÎöµçѹֵ£¨1×Ö½Ú£© */ private static double parseVoltage(byte[] data) { if (data.length < 15) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöµçѹ"); } int voltageValue = data[14] & 0xFF; // 50mV/bit ת»»Îª·üÌØ return voltageValue * 0.05; } /** * ½âÎöµçÁ÷Öµ£¨1×Ö½Ú£© */ private static double parseCurrent(byte[] data) { if (data.length < 16) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöµçÁ÷"); } int currentValue = data[15] & 0xFF; // 10mA/bit ת»»Îª°²Åà return currentValue * 0.01; } /** * ¹¤×÷״̬ö¾Ù */ public enum WorkStatus { INVALID(0, "ÎÞЧ"), STANDBY(1, "´ý»ú"), CHARGING(2, "³äµç"), FULL(3, "³äÂú"), FAULT(4, "¹ÊÕÏ"), AUTHORIZATION_EXPIRED(5, "ÊÚȨµ½ÆÚ"), COMMUNICATION_TIMEOUT(6, "ͨÐų¬Ê±"), UNKNOWN(-1, "δ֪״̬"); private final int value; private final String description; WorkStatus(int value, String description) { this.value = value; this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } public static WorkStatus fromValue(int value) { for (WorkStatus status : values()) { if (status.value == value) { return status; } } return UNKNOWN; } } /** * ÃÅ״̬ö¾Ù */ public enum DoorStatus { UNKNOWN(0, "δ֪״̬"), DOOR_OPEN(1, "¿ªÃÅ״̬"), DOOR_CLOSE(2, "¹ØÃÅ״̬"); private final int value; private final String description; DoorStatus(int value, String description) { this.value = value; this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } public static DoorStatus fromValue(int value) { for (DoorStatus status : values()) { if (status.value == value) { return status; } } return UNKNOWN; } } /** * ¿¨×´Ì¬Ã¶¾Ù */ public enum CardStatus { NO_CARD(0, "ÎÞ¿¨"), HAS_CARD(1, "Óп¨"), READ_ERROR(2, "¶Á¿¨´íÎó(¿¨·Ç·¨)"), UNKNOWN(-1, "δ֪״̬"); private final int value; private final String description; CardStatus(int value, String description) { this.value = value; this.description = description; } public int getValue() { return value; } public String getDescription() { return description; } public static CardStatus fromValue(int value) { for (CardStatus status : values()) { if (status.value == value) { return status; } } return UNKNOWN; } } /** * ¹ÊÕÏÀàÐÍö¾Ù */ public enum FaultType { INSERT_ERROR(0x01, "²å¿¨´íÎó"), OVER_CURRENT(0x02, "¹ýÁ÷"), DOOR_CONTROL_FAULT(0x04, "ÃſعÊÕÏ"), OVER_VOLTAGE(0x08, "¹ýѹ"), UNDER_VOLTAGE(0x10, "Ƿѹ"); private final int bitMask; private final String description; FaultType(int bitMask, String description) { this.bitMask = bitMask; this.description = description; } public int getBitMask() { return bitMask; } public String getDescription() { return description; } } /** * ½âÎö½á¹ûÀà - Ìí¼Ó¶ÔÏó³ØÖ§³Ö */ public static class ParseResult { private int hostAddress; private int slotNumber; private WorkStatus workStatus; private DoorStatus doorStatus; private CardStatus cardStatus; private int cardStatusChange; private String cardNumber; private List faults; private double voltage; private double current; private int dataLength; // ĬÈϹ¹ÔìÆ÷ÓÃÓÚ¶ÔÏó³Ø public ParseResult() {} public ParseResult(int hostAddress, int slotNumber, WorkStatus workStatus, DoorStatus doorStatus, CardStatus cardStatus, int cardStatusChange, String cardNumber, List faults, double voltage, double current, int dataLength) { this.hostAddress = hostAddress; this.slotNumber = slotNumber; this.workStatus = workStatus; this.doorStatus = doorStatus; this.cardStatus = cardStatus; this.cardStatusChange = cardStatusChange; this.cardNumber = cardNumber; this.faults = faults; this.voltage = voltage; this.current = current; this.dataLength = dataLength; } /** * ÖØÖ÷½·¨£¬ÓÃÓÚ¶ÔÏóÖØÓà */ public void reset(int hostAddress, int slotNumber, WorkStatus workStatus, DoorStatus doorStatus, CardStatus cardStatus, int cardStatusChange, String cardNumber, List faults, double voltage, double current, int dataLength) { this.hostAddress = hostAddress; this.slotNumber = slotNumber; this.workStatus = workStatus; this.doorStatus = doorStatus; this.cardStatus = cardStatus; this.cardStatusChange = cardStatusChange; this.cardNumber = cardNumber; this.faults = faults; this.voltage = voltage; this.current = current; this.dataLength = dataLength; } // Getter·½·¨ public int getHostAddress() { return hostAddress; } public int getSlotNumber() { return slotNumber; } public WorkStatus getWorkStatus() { return workStatus; } public DoorStatus getDoorStatus() { return doorStatus; } public CardStatus getCardStatus() { return cardStatus; } public int getCardStatusChange() { return cardStatusChange; } public String getCardNumber() { return cardNumber; } public List getFaults() { return faults; } public double getVoltage() { return voltage; } public double getCurrent() { return current; } public int getDataLength() { return dataLength; } /** * »ñÈ¡¹ÊÕϵÄÖÐÎÄÃèÊöÁбí */ public List getFaultDescriptions() { List descriptions = new ArrayList<>(); for (FaultType fault : faults) { descriptions.add(fault.getDescription()); } return descriptions; } /** * »ñÈ¡¹ÊÕϵÄÖÐÎÄÃèÊö×Ö·û´® */ public String getFaultsString() { if (faults == null || faults.isEmpty()) { return "ÎÞ¹ÊÕÏ"; } StringBuilder sb = new StringBuilder(); for (int i = 0; i < faults.size(); i++) { if (i > 0) sb.append(", "); sb.append(faults.get(i).getDescription()); } return sb.toString(); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("=== DDCCЭÒéÊý¾Ý½âÎö½á¹û ===\n"); sb.append("1. Ö÷»úµØÖ·: ").append(String.format("%02X", hostAddress)); sb.append("2. ¿¨²Û±àºÅ: ").append(slotNumber); sb.append("3. ¹¤×÷״̬: ").append(workStatus.getDescription()) .append(" (").append(workStatus.getValue()); sb.append("4. ÃÅ״̬: ").append(doorStatus.getDescription()) .append(" (").append(doorStatus.getValue()); sb.append("5. ¿¨×´Ì¬: ").append(cardStatus.getDescription()) .append(" (").append(cardStatus.getValue()); sb.append("6. ¿¨×´Ì¬±ä¸ü: ").append(cardStatusChange); sb.append("7. ¿¨ºÅ: ").append(cardNumber); sb.append("8. ¹ÊÕÏ: ").append(getFaultsString()); sb.append("9. µçѹ: ").append(String.format("%.2f", voltage)); sb.append("10. µçÁ÷: ").append(String.format("%.2f", current)); sb.append("Êý¾Ý³¤¶È: ").append(dataLength).append(" ×Ö½Ú"); // System.out.println(sb.toString()); return sb.toString(); } public void fuzhi() { SlotManager.gengxinshuxingzhi( slotNumber, // ¿¨²Û±àºÅ cardNumber, // ¿¨±àºÅ String.valueOf(cardStatus.getValue()), // ÊÇ·ñÓп¨0ÎÞ¿¨£¬1Óп¨£¬-1δ֪ String.valueOf(workStatus.getValue()), // ¹¤×÷״̬0.ÎÞЧ1.´ý»ú£»2.³äµç£»3.³äÂú£»4.¹ÊÕÏ£»5.ÊÚȨµ½ÆÚ£»6.ͨÐų¬Ê± String.format("%.2f", voltage), // µçѹ String.format("%.2f", current), // µçÁ÷ getFaultsString() // ¹ÊÕÏ1²å¿¨´íÎó£»2¹ýÁ÷£»3,ÃſعÊÕÏ£»4¹ýѹ£»5Ƿѹ£» ); } } /** * ¼òµ¥µÄ¶ÔÏó³ØÊµÏÖ */ public static class ParseResultPool { private static final int POOL_SIZE = 10; private static final java.util.concurrent.BlockingQueue pool = new java.util.concurrent.ArrayBlockingQueue<>(POOL_SIZE); static { // Ô¤´´½¨¶ÔÏó for (int i = 0; i < POOL_SIZE; i++) { pool.offer(new ParseResult()); } } public static ParseResult borrowObject() { ParseResult result = pool.poll(); return result != null ? result : new ParseResult(); } public static void returnObject(ParseResult result) { if (result != null && !pool.offer(result)) { // ³ØÒÑÂú£¬²»»ØÊÕ } } } }