package publicway; import java.util.ArrayList; import java.util.List; import chushihua.SlotManager; public class ProtocolParser01 { // »º´æ³£ÓÃ×Ö·û´®¼õÉÙÖØ¸´´´½¨ private static final String[] WORK_STATUS_DESC = {"ÎÞЧ", "´ý»ú", "³äµç", "³äÂú", "¹ÊÕÏ", "ÊÚȨµ½ÆÚ", "ͨÐų¬Ê±", "δ֪״̬"}; private static final String[] DOOR_STATUS_DESC = {"δ֪״̬", "¿ªÃÅ״̬", "¹ØÃÅ״̬"}; private static final String[] CARD_STATUS_DESC = {"ÎÞ¿¨", "Óп¨", "¶Á¿¨´íÎó(¿¨·Ç·¨)", "δ֪״̬"}; // StringBuilder ¶ÔÏó³Ø private static final ThreadLocal stringBuilderPool = ThreadLocal.withInitial(() -> new StringBuilder(512)); /** * ÓÅ»¯ºóµÄ×Ö½ÚÊý×é½âÎö·½·¨ */ 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ЭÒéÊý¾Ý"); } ParseResult result = ParseResultPool.borrowObject(); try { // Ö±½ÓʹÓÃÔ­Êý×飬±ÜÃâ´´½¨ÐÂÊý×é if (packetData.length < 18) { // 2(°üÍ·) + 16(×îСÊý¾Ý³¤¶È) throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×ã"); } // ½âÎö¸÷¸ö×Ö¶Î int dataLength = parseDataLength(packetData, 2); int hostAddress = parseHostAddress(packetData, 4); int slotNumber = parseSlotNumber(packetData, 5); int functionCode = parseFunctionCode(packetData, 6); // ÑéÖ¤¹¦ÄÜÂë if (functionCode != 0x01) { throw new IllegalArgumentException("·Ç01¹¦ÄÜÂëÊý¾Ý"); } WorkStatus workStatus = parseWorkStatus(packetData, 7); DoorStatus doorStatus = parseDoorStatus(packetData, 8); CardStatus cardStatus = parseCardStatus(packetData, 9); int cardStatusChange = parseCardStatusChange(packetData, 10); String cardNumber = parseCardNumber(packetData, 13); List faults = parseFaults(packetData, 15); double voltage = parseVoltage(packetData, 16); double current = parseCurrent(packetData, 17); // ÖØÓà ParseResult ¶ÔÏó result.reset(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); return result; } catch (Exception e) { // ·¢ÉúÒ쳣ʱ¹é»¹¶ÔÏó ParseResultPool.returnObject(result); 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ЭÒéÊý¾Ý"); } ParseResult result = ParseResultPool.borrowObject(); 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, 0); int hostAddress = parseHostAddress(dataBytes, 2); int slotNumber = parseSlotNumber(dataBytes, 3); int functionCode = parseFunctionCode(dataBytes, 4); // 3. ÑéÖ¤¹¦ÄÜÂë if (functionCode != 0x01) { throw new IllegalArgumentException("·Ç01¹¦ÄÜÂëÊý¾Ý"); } WorkStatus workStatus = parseWorkStatus(dataBytes, 5); DoorStatus doorStatus = parseDoorStatus(dataBytes, 6); CardStatus cardStatus = parseCardStatus(dataBytes, 7); int cardStatusChange = parseCardStatusChange(dataBytes, 8); String cardNumber = parseCardNumber(dataBytes, 11); List faults = parseFaults(dataBytes, 13); double voltage = parseVoltage(dataBytes, 14); double current = parseCurrent(dataBytes, 15); result.reset(hostAddress, slotNumber, workStatus, doorStatus, cardStatus, cardStatusChange, cardNumber, faults, voltage, current, dataLength); return result; } catch (Exception e) { ParseResultPool.returnObject(result); throw new RuntimeException("½âÎöÊý¾Ýʱ·¢Éú´íÎó: " + e.getMessage(), e); } } /** * ½âÎöÊý¾Ý³¤¶È£¨2×Ö½Ú£© */ private static int parseDataLength(byte[] data, int offset) { if (data.length < offset + 2) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöÊý¾Ý³¤¶È"); } return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); } /** * ½âÎöÖ÷»úµØÖ·£¨1×Ö½Ú£© */ private static int parseHostAddress(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöÖ÷»úµØÖ·"); } return data[offset] & 0xFF; } /** * ½âÎö¿¨²Û±àºÅ£¨1×Ö½Ú£© */ private static int parseSlotNumber(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨²Û±àºÅ"); } return data[offset] & 0xFF; } /** * ½âÎö¹¦ÄÜÂ루1×Ö½Ú£© */ private static int parseFunctionCode(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹¦ÄÜÂë"); } return data[offset] & 0xFF; } /** * ½âÎö¹¤×÷״̬£¨1×Ö½Ú£© */ private static WorkStatus parseWorkStatus(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹¤×÷״̬"); } int statusValue = data[offset] & 0xFF; return WorkStatus.fromValue(statusValue); } /** * ½âÎöÔÚλ״̬/ÃÅ״̬£¨1×Ö½Ú£© */ private static DoorStatus parseDoorStatus(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöÔÚλ״̬"); } int statusValue = data[offset] & 0xFF; return DoorStatus.fromValue(statusValue); } /** * ½âÎö¿¨×´Ì¬£¨1×Ö½Ú£© */ private static CardStatus parseCardStatus(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨×´Ì¬"); } int statusValue = data[offset] & 0xFF; return CardStatus.fromValue(statusValue); } /** * ½âÎö¿¨×´Ì¬±ä¸ü£¨1×Ö½Ú£© */ private static int parseCardStatusChange(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨×´Ì¬±ä¸ü"); } return data[offset] & 0xFF; } /** * ½âÎö¿¨ºÅ£¨¿¨ºÅ3 + ¿¨ºÅ4£© */ private static String parseCardNumber(byte[] data, int offset) { if (data.length < offset + 2) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¿¨ºÅ"); } // Ö±½Ó·µ»Ø×Ö·û´®£¬±ÜÃâ´´½¨ÁÙʱ¶ÔÏó char[] hexChars = new char[4]; hexChars[0] = Character.forDigit((data[offset] >> 4) & 0xF, 16); hexChars[1] = Character.forDigit(data[offset] & 0xF, 16); hexChars[2] = Character.forDigit((data[offset + 1] >> 4) & 0xF, 16); hexChars[3] = Character.forDigit(data[offset + 1] & 0xF, 16); return new String(hexChars).toUpperCase(); } /** * ½âÎö¹ÊÕÏÐÅÏ¢£¨1×Ö½Ú£© */ private static List parseFaults(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹ÊÕÏÐÅÏ¢"); } int faultByte = data[offset] & 0xFF; List faults = new ArrayList<>(5); // Ô¤·ÖÅäÈÝÁ¿ for (FaultType fault : FaultType.values()) { if ((faultByte & fault.getBitMask()) != 0) { faults.add(fault); } } return faults; } /** * ½âÎöµçѹֵ£¨1×Ö½Ú£© */ private static double parseVoltage(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöµçѹ"); } int voltageValue = data[offset] & 0xFF; // 50mV/bit ת»»Îª·üÌØ return voltageValue * 0.05; } /** * ½âÎöµçÁ÷Öµ£¨1×Ö½Ú£© */ private static double parseCurrent(byte[] data, int offset) { if (data.length < offset + 1) { throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎöµçÁ÷"); } int currentValue = data[offset] & 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; // ÖØÓÃÁбí¶ÔÏó private final List faultList = new ArrayList<>(5); private final List faultDescList = new ArrayList<>(5); public ParseResult() {} 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.voltage = voltage; this.current = current; this.dataLength = dataLength; // ÖØÓùÊÕÏÁбí this.faultList.clear(); if (faults != null) { this.faultList.addAll(faults); } this.faults = this.faultList; } // 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() { faultDescList.clear(); for (FaultType fault : faults) { faultDescList.add(fault.getDescription()); } return faultDescList; } /** * »ñÈ¡¹ÊÕϵÄÖÐÎÄÃèÊö×Ö·û´® */ public String getFaultsString() { if (faults.isEmpty()) { return "ÎÞ¹ÊÕÏ"; } StringBuilder sb = stringBuilderPool.get(); sb.setLength(0); 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 = stringBuilderPool.get(); sb.setLength(0); sb.append("1.Ö÷»úµØÖ·:").append(String.format("%02X", hostAddress)); sb.append("2.¿¨²Û±àºÅ:").append(slotNumber); sb.append("3.¹¤×÷״̬:").append(workStatus.getDescription()) .append("(").append(workStatus.getValue()).append(")"); sb.append("4. ÃÅ״̬:").append(doorStatus.getDescription()) .append("(").append(doorStatus.getValue()).append(")"); sb.append("5.¿¨×´Ì¬:").append(cardStatus.getDescription()) .append("(").append(cardStatus.getValue()).append(")"); 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(" ×Ö½Ú"); return sb.toString(); } public void fuzhi() { SlotManager.gengxinshuxingzhi( slotNumber, // ¿¨²Û±àºÅ cardNumber, // ¿¨±àºÅ String.valueOf(cardStatus.getValue()), // ÊÇ·ñÓп¨0ÎÞ¿¨£¬1Óп¨£¬-1δ֪ String.valueOf(workStatus.getValue()), // ¹¤×÷״̬ String.format("%.2f", voltage), // µçѹ String.format("%.2f", current), // µçÁ÷ getFaultsString() // ¹ÊÕÏ ); } } /** * ¸Ä½øµÄ¶ÔÏó³ØÊµÏÖ */ public static class ParseResultPool { private static final int POOL_SIZE = 20; private static final java.util.concurrent.BlockingQueue pool = new java.util.concurrent.LinkedBlockingQueue<>(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) { // ÇåÀí״̬ result.reset(0, 0, WorkStatus.UNKNOWN, DoorStatus.UNKNOWN, CardStatus.UNKNOWN, 0, "", null, 0.0, 0.0, 0); // ·Ç×èÈûʽ¹é»¹ pool.offer(result); } } public static int getPoolSize() { return pool.size(); } } }