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<StringBuilder> 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<FaultType> 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<FaultType> 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<FaultType> parseFaults(byte[] data, int offset) {
|
if (data.length < offset + 1) {
|
throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹ÊÕÏÐÅÏ¢");
|
}
|
int faultByte = data[offset] & 0xFF;
|
List<FaultType> 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<FaultType> faults;
|
private double voltage;
|
private double current;
|
private int dataLength;
|
|
// ÖØÓÃÁбí¶ÔÏó
|
private final List<FaultType> faultList = new ArrayList<>(5);
|
private final List<String> faultDescList = new ArrayList<>(5);
|
|
public ParseResult() {}
|
|
public void reset(int hostAddress, int slotNumber, WorkStatus workStatus,
|
DoorStatus doorStatus, CardStatus cardStatus, int cardStatusChange,
|
String cardNumber, List<FaultType> 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<FaultType> getFaults() { return faults; }
|
public double getVoltage() { return voltage; }
|
public double getCurrent() { return current; }
|
public int getDataLength() { return dataLength; }
|
|
/**
|
* »ñÈ¡¹ÊÕϵÄÖÐÎÄÃèÊöÁбí
|
*/
|
public List<String> 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<ParseResult> 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();
|
}
|
}
|
}
|