|
|
|
package com.zhonglai.luhui.smart.spare.feeder.service;
|
|
|
|
|
|
|
|
import com.fazecast.jSerialComm.SerialPort;
|
|
|
|
import com.fazecast.jSerialComm.SerialPortEvent;
|
|
|
|
import com.ruoyi.common.utils.ByteUtil;
|
|
|
|
import com.zhonglai.luhui.smart.feeder.config.OperatingData;
|
|
|
|
import com.zhonglai.luhui.smart.feeder.dto.ModbusDto;
|
|
|
|
import com.zhonglai.luhui.smart.feeder.dto.SerialPortConfig;
|
|
|
|
import com.zhonglai.luhui.smart.feeder.dto.commd.FeederCommdDto;
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
|
|
import java.util.concurrent.BlockingQueue;
|
|
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 端口服务
|
|
|
|
*/
|
|
|
|
public class SerialPortService implements com.fazecast.jSerialComm.SerialPortDataListener {
|
|
|
|
private static final Logger logger = LoggerFactory.getLogger(SerialPortService.class);
|
|
|
|
private SerialPort serialPort;
|
|
|
|
private boolean isConnected = false;
|
|
|
|
private final Object lock = new Object();
|
|
|
|
|
|
|
|
private BlockingQueue<ModbusDto> dataQueue = new LinkedBlockingQueue<>();
|
|
|
|
|
|
|
|
public void connect(String portName) {
|
|
|
|
serialPort = findSerialPort(portName);
|
|
|
|
// 尝试打开串口
|
|
|
|
logger.info("尝试打开串口:"+portName);
|
|
|
|
// serialPort = SerialPort.getCommPort(portName);
|
|
|
|
if (serialPort == null) {
|
|
|
|
logger.error("无法找到串口: " + portName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
logger.info("串口尝试打开成功,准备连接:"+portName);
|
|
|
|
|
|
|
|
try {
|
|
|
|
SerialPortConfig serialPortConfig = OperatingData.feederConfig.getSerialPortConfig();
|
|
|
|
|
|
|
|
// 配置串口参数
|
|
|
|
serialPort.setBaudRate(serialPortConfig.getBaudrate());
|
|
|
|
serialPort.setNumDataBits(serialPortConfig.getDataBits());
|
|
|
|
serialPort.setNumStopBits(serialPortConfig.getStopBits());
|
|
|
|
serialPort.setParity(serialPortConfig.getParity());
|
|
|
|
|
|
|
|
// 打开串口
|
|
|
|
serialPort.openPort();
|
|
|
|
serialPort.addDataListener(this);
|
|
|
|
|
|
|
|
// 设置串口为非阻塞模式,以便可以异步接收数据
|
|
|
|
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);
|
|
|
|
|
|
|
|
isConnected = true;
|
|
|
|
logger.info("串口已连接: " + portName);
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
logger.error("串口连接失败: " , e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getListeningEvents() {
|
|
|
|
// 监听数据到达事件
|
|
|
|
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;//返回要监听的事件类型,以供回调函数使用。可发回的事件包括:SerialPort.LISTENING_EVENT_DATA_AVAILABLE,SerialPort.LISTENING_EVENT_DATA_WRITTEN,SerialPort.LISTENING_EVENT_DATA_RECEIVED。分别对应有数据在串口(不论是读的还是写的),有数据写入串口,从串口读取数据。如果AVAILABLE和RECEIVED同时被监听,优先触发RECEIVED
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void serialEvent(SerialPortEvent event) {
|
|
|
|
if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
|
|
|
|
try {
|
|
|
|
// 读取串口数据
|
|
|
|
byte[] newData = new byte[serialPort.bytesAvailable()];
|
|
|
|
int numRead = serialPort.readBytes(newData, newData.length);
|
|
|
|
|
|
|
|
logger.info("串口返回{}字节数据:{}",numRead, ByteUtil.toHexString(newData));
|
|
|
|
FeederCommdDto commdDto = new FeederCommdDto(newData);
|
|
|
|
dataQueue.offer(commdDto); // 将数据添加到队列中// 处理串口返回的数据
|
|
|
|
} catch (Exception e) {
|
|
|
|
logger.error("读取串口数据时出错: " , e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void disconnect() {
|
|
|
|
if (isConnected) {
|
|
|
|
try {
|
|
|
|
serialPort.removeDataListener();
|
|
|
|
serialPort.closePort();
|
|
|
|
isConnected = false;
|
|
|
|
logger.info("串口已断开连接");
|
|
|
|
} catch (Exception e) {
|
|
|
|
logger.error("串口断开失败: " , e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isConnected() {
|
|
|
|
return isConnected;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 实现掉线重连逻辑
|
|
|
|
public void reconnect(String portName, int reconnectIntervalMillis) {
|
|
|
|
while (!isConnected) {
|
|
|
|
try {
|
|
|
|
Thread.sleep(reconnectIntervalMillis);
|
|
|
|
connect(portName);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
logger.error("重连线程被中断: " , e);
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public ModbusDto sendByte(byte[] bytes)
|
|
|
|
{
|
|
|
|
synchronized (lock)
|
|
|
|
{
|
|
|
|
if(isConnected)
|
|
|
|
{
|
|
|
|
serialPort.writeBytes(bytes,bytes.length);
|
|
|
|
try {
|
|
|
|
ModbusDto reStr = dataQueue.poll(15, TimeUnit.SECONDS);
|
|
|
|
logger.info("接串口通知数据:{}",reStr);
|
|
|
|
return reStr;
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
logger.error("等待串口返回数据异常!" + e);
|
|
|
|
disconnect();
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
logger.error("串口未打开!" );
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private SerialPort findSerialPort(String portName)
|
|
|
|
{
|
|
|
|
SerialPort[] serialPorts = SerialPort.getCommPorts();//查找所有串口
|
|
|
|
logger.info("总串口数"+serialPorts.length);
|
|
|
|
for(SerialPort port:serialPorts){
|
|
|
|
logger.info("Port:{},PortDesc:{},PortDesc:{}",port.getSystemPortName(),port.getPortDescription(),port.getDescriptivePortName());//打印串口名称,如COM4;打印串口类型,如USB Serial;打印串口的完整类型,如USB-SERIAL CH340(COM4)
|
|
|
|
if(port.getSystemPortName().equals(portName))
|
|
|
|
{
|
|
|
|
return port;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
public ModbusDto sendHexData(String hexStr) {
|
|
|
|
logger.info("串口写入:{}",hexStr);
|
|
|
|
byte[] bytes = ByteUtil.hexStringToByte(hexStr.replace(" ","").trim().toUpperCase());
|
|
|
|
return sendByte(bytes);
|
|
|
|
}
|
|
|
|
} |
...
|
...
|
|