package com.chinaztt.mes.docx.handler;
|
|
import com.fazecast.jSerialComm.SerialPort;
|
import com.fazecast.jSerialComm.SerialPortDataListener;
|
import com.fazecast.jSerialComm.SerialPortEvent;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Component;
|
|
import javax.annotation.PostConstruct;
|
import javax.annotation.PreDestroy;
|
import java.io.InputStream;
|
import java.nio.charset.StandardCharsets;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
@Slf4j
|
@Component
|
public class SerialPortListener {
|
|
// 串口核心对象
|
private static SerialPort serialPort;
|
|
// 定义缓冲区,暂存零散数据
|
private static final StringBuilder dataBuffer = new StringBuilder();
|
|
// 定义数据结束标志
|
private static final String END_MARK = "g";
|
|
public List<Double> dataList = new ArrayList<>(6);
|
|
private static final int MAX_COUNT = 6;
|
|
@Value("${serialPort.listenName}")
|
public String listenName;
|
|
// 标记监听是否运行
|
private volatile boolean isListening = false;
|
|
public void serialPortDataListener(){
|
// 双重校验锁,避免重复启动
|
if (isListening) {
|
log.warn("串口 {} 监听已启动,无需重复执行", listenName);
|
return;
|
}
|
|
synchronized (this) {
|
if (isListening) {
|
return;
|
}
|
isListening = true;
|
}
|
|
// 2. 选择目标串口
|
String targetPortName = listenName;
|
serialPort = SerialPort.getCommPort(targetPortName);
|
|
// 3. 配置串口参数(需与设备端一致)
|
serialPort.setBaudRate(9600); // 波特率
|
serialPort.setNumDataBits(8); // 数据位
|
serialPort.setNumStopBits(1); // 停止位
|
serialPort.setParity(SerialPort.NO_PARITY); // 校验位(无校验)
|
serialPort.setFlowControl(SerialPort.NO_PARITY); // 关闭流控
|
serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1000, 0); // 读取超时
|
|
// 4. 打开串口
|
if (serialPort.openPort()) {
|
log.info("串口打开成功:{}",targetPortName);
|
} else {
|
log.error("串口打开失败!请检查串口是否被占用或名称是否正确");
|
isListening = false;
|
return;
|
}
|
|
// 5. 注册串口数据监听器(异步读取,避免阻塞主线程)
|
try {
|
serialPort.addDataListener(new SerialPortDataListener() {
|
// 指定监听的事件类型:数据可用时触发
|
@Override
|
public int getListeningEvents() {
|
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
|
}
|
|
// 数据可用时的处理逻辑
|
@Override
|
public void serialEvent(SerialPortEvent event) {
|
if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_AVAILABLE) {
|
// 读取缓冲区中的所有字节
|
byte[] buffer = new byte[serialPort.bytesAvailable()];
|
int readBytes = serialPort.readBytes(buffer, buffer.length);
|
|
if (readBytes > 0) {
|
// 把本次收到的零散数据转成字符串,追加到缓冲区
|
String received = new String(buffer, 0, readBytes, StandardCharsets.UTF_8);
|
dataBuffer.append(received);
|
|
// 检查缓冲区是否包含“结束标志”,循环处理所有完整数据
|
int endIndex = dataBuffer.indexOf(END_MARK);
|
while (endIndex != -1) {
|
// 提取“开头到结束标志”的完整数据
|
String completeData = dataBuffer.substring(0, endIndex).replace(" ", "").replace("\n","");
|
// 打印/处理合并后的完整数据
|
double parseDouble = Double.parseDouble(completeData);
|
log.info("接收到的数据-->{}",parseDouble);
|
if(dataList.size()<MAX_COUNT){
|
dataList.add(parseDouble);
|
}
|
// 移除缓冲区中已处理的部分(保留剩余未完成的内容)
|
dataBuffer.delete(0, endIndex + END_MARK.length());
|
// 继续检查缓冲区是否还有其他完整数据
|
endIndex = dataBuffer.indexOf(END_MARK);
|
}
|
}
|
}
|
}
|
});
|
} catch (Exception e) {
|
log.warn("串口监听子线程被中断", e);
|
Thread.currentThread().interrupt();
|
}
|
}
|
|
/**
|
* 关闭串口
|
*/
|
private void closeSerialPort() {
|
if (serialPort != null && serialPort.isOpen()) {
|
serialPort.removeDataListener(); // 移除监听
|
serialPort.closePort(); // 关闭串口
|
log.info("串口 {} 已关闭", listenName);
|
}
|
isListening = false;
|
}
|
|
/**
|
* 项目停止时关闭串口
|
*/
|
@PreDestroy
|
public void destroy() {
|
log.info("项目停止,关闭串口 {} 监听", listenName);
|
isListening = false; // 终止子线程循环
|
closeSerialPort();
|
}
|
|
}
|