package com.mes.device; import com.fazecast.jSerialComm.SerialPort; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; /** * 继电器驱动(Modbus RTU串口通信) * 用于控制继电器开关 */ public class RelayDriver implements IDeviceDriver { private static final Logger log = LoggerFactory.getLogger(RelayDriver.class); private SerialPort serialPort; private String portName = "COM2"; private int baudrate = 38400; private String openCommand = "010600000000"; // 开继电器命令 private String closeCommand = "010600000001"; // 关继电器命令 private volatile boolean connected = false; public RelayDriver() { } public RelayDriver(String portName, int baudrate) { this.portName = portName; this.baudrate = baudrate; } @Override public void connect(Map config) { if (config != null) { if (config.containsKey("port")) { this.portName = config.get("port").toString(); } if (config.containsKey("baudrate")) { this.baudrate = ((Number) config.get("baudrate")).intValue(); } if (config.containsKey("open_command")) { this.openCommand = config.get("open_command").toString(); } if (config.containsKey("close_command")) { this.closeCommand = config.get("close_command").toString(); } } try { serialPort = SerialPort.getCommPort(portName); serialPort.setComPortParameters(baudrate, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0); if (serialPort.openPort()) { connected = true; log.info("继电器串口{}打开成功", portName); } else { connected = false; log.error("继电器串口{}打开失败", portName); } } catch (Exception e) { log.error("继电器连接失败: {}", e.getMessage()); connected = false; } } @Override public void disconnect() { if (serialPort != null && serialPort.isOpen()) { serialPort.closePort(); log.info("继电器串口已关闭"); } connected = false; } @Override public boolean isConnected() { return connected && serialPort != null && serialPort.isOpen(); } /** * 开继电器 */ public void open() { sendCommand(openCommand); log.info("继电器已开启"); } /** * 关继电器 */ public void close() { sendCommand(closeCommand); log.info("继电器已关闭"); } /** * 发送命令 */ private void sendCommand(String command) { if (!isConnected()) { reconnect(); } if (!isConnected()) { log.error("继电器未连接,无法发送命令"); return; } try { String crc = getCRC16ModbusStr(command); byte[] writeBuffer = hexStringToByteArray(command + crc); serialPort.writeBytes(writeBuffer, writeBuffer.length); // 读取响应 byte[] readBuffer = new byte[512]; int numRead = serialPort.readBytes(readBuffer, readBuffer.length); log.debug("继电器响应: {} bytes", numRead); } catch (Exception e) { log.error("发送继电器命令失败: {}", e.getMessage()); } } /** * 重新连接 */ private void reconnect() { disconnect(); Map config = new HashMap<>(); config.put("port", portName); config.put("baudrate", baudrate); connect(config); } /** * CRC16 Modbus校验 */ private String getCRC16ModbusStr(String data) { data = data.replace(" ", ""); int len = data.length(); if (len % 2 != 0) { return "0000"; } int num = len / 2; byte[] para = new byte[num]; for (int i = 0; i < num; i++) { int value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16); para[i] = (byte) value; } return getCRC(para); } private String getCRC(byte[] bytes) { int CRC = 0x0000ffff; int POLYNOMIAL = 0x0000a001; for (byte b : bytes) { CRC ^= ((int) b & 0x000000ff); for (int j = 0; j < 8; j++) { if ((CRC & 0x00000001) != 0) { CRC >>= 1; CRC ^= POLYNOMIAL; } else { CRC >>= 1; } } } String result = Integer.toHexString(CRC).toUpperCase(); if (result.length() != 4) { StringBuilder sb = new StringBuilder("0000"); result = sb.replace(4 - result.length(), 4, result).toString(); } return result.substring(2, 4) + result.substring(0, 2); } private byte[] hexStringToByteArray(String hexString) { hexString = hexString.trim(); if (hexString.length() % 2 != 0) { throw new IllegalArgumentException("Invalid hex string"); } BigInteger bigInt = new BigInteger(hexString, 16); byte[] byteArray = bigInt.toByteArray(); if (byteArray.length > hexString.length() / 2) { byte[] trimmedArray = new byte[hexString.length() / 2]; System.arraycopy(byteArray, 1, trimmedArray, 0, trimmedArray.length); return trimmedArray; } return byteArray; } // 以下方法继电器驱动不支持 @Override public void signalReady() { } @Override public void startHeartbeat() { } @Override public void stopHeartbeat() { } @Override public Map readStatus() { return new HashMap<>(); } @Override public boolean isWorkComplete() { return false; } @Override public int getPresetCount() { return 0; } @Override public int getFinishedCount() { return 0; } @Override public int getQualifiedCount() { return 0; } @Override public void setPresetCount(int count) { } @Override public void writeRegister(int address, int value) { } @Override public int readRegister(int address) { return 0; } @Override public String getDriverType() { return "relay"; } // Getters & Setters public String getPortName() { return portName; } public void setPortName(String portName) { this.portName = portName; } public int getBaudrate() { return baudrate; } public void setBaudrate(int baudrate) { this.baudrate = baudrate; } public String getOpenCommand() { return openCommand; } public void setOpenCommand(String openCommand) { this.openCommand = openCommand; } public String getCloseCommand() { return closeCommand; } public void setCloseCommand(String closeCommand) { this.closeCommand = closeCommand; } }