package publicway;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
import chuankou.SerialPortService;
|
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<FaultType> 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<FaultType> 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<FaultType> parseFaults(byte[] data) {
|
if (data.length < 14) {
|
throw new IllegalArgumentException("Êý¾Ý³¤¶È²»×㣬ÎÞ·¨½âÎö¹ÊÕÏÐÅÏ¢");
|
}
|
int faultByte = data[13] & 0xFF;
|
List<FaultType> 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<FaultType> 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<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.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<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.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<FaultType> getFaults() { return faults; }
|
public double getVoltage() { return voltage; }
|
public double getCurrent() { return current; }
|
public int getDataLength() { return dataLength; }
|
|
/**
|
* »ñÈ¡¹ÊÕϵÄÖÐÎÄÃèÊöÁбí
|
*/
|
public List<String> getFaultDescriptions() {
|
List<String> 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<ParseResult> 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)) {
|
// ³ØÒÑÂú£¬²»»ØÊÕ
|
}
|
}
|
}
|
}
|