// 声明包名 dell_system
|
package home;
|
|
// 导入串口通信库
|
import com.fazecast.jSerialComm.SerialPort;
|
// 导入 Java 函数式接口 Consumer,用于数据接收回调
|
import javax.swing.*;
|
import java.util.function.Consumer;
|
// 导入字节数组输出流
|
import java.io.ByteArrayOutputStream;
|
import java.io.InputStream;
|
import java.io.OutputStream;
|
|
/**
|
* 串口服务类
|
* 负责串口的打开、关闭、数据收发
|
*/
|
public class SerialPortService {
|
|
// 串口对象,用于与硬件通信
|
private SerialPort port;
|
|
// 标记是否正在捕获数据(线程运行中)
|
private volatile boolean capturing = false;
|
// 标记是否暂停接收数据
|
private volatile boolean paused = false;
|
|
// 数据读取线程
|
private Thread readerThread;
|
private Consumer<byte[]> responseConsumer;
|
|
|
// 优化:重用缓冲区,减少内存分配
|
private byte[] readBuffer = new byte[200];
|
private ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
|
private Consumer<byte[]> dataReceivedCallback;
|
|
|
public InputStream getInputStream() {
|
if (port != null && port.isOpen()) {
|
return port.getInputStream();
|
}
|
return null;
|
}
|
|
public OutputStream getOutputStream() {
|
if (port != null && port.isOpen()) {
|
return port.getOutputStream();
|
}
|
return null;
|
}
|
public void setComPortTimeouts(int timeoutMode, int readTimeout, int writeTimeout) {
|
if (port != null && port.isOpen()) {
|
port.setComPortTimeouts(timeoutMode, readTimeout, writeTimeout);
|
}
|
}
|
|
|
public void startCapture() {
|
if (dataReceivedCallback != null) {
|
startCapture(dataReceivedCallback);
|
} else {
|
System.err.println("No data received callback set. Please call startCapture(Consumer<byte[]> onReceived) first.");
|
}
|
}
|
|
/**
|
* 打开串口
|
* @param portName 串口名称(如 COM3)
|
* @param baud 波特率(如 9600)
|
* @return 是否成功打开
|
*/
|
public boolean open(String portName, int baud) {
|
// 如果串口已打开,直接返回成功
|
if (port != null && port.isOpen()) {
|
return true;
|
}
|
|
// 根据名称获取串口实例
|
port = SerialPort.getCommPort(portName);
|
// 设置串口参数:波特率、数据位8、停止位1、无校验位
|
port.setComPortParameters(baud, 8, 1, SerialPort.NO_PARITY);
|
// 修改为半阻塞模式,读超时1ms
|
port.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 1, 0);
|
|
// 打开串口并返回结果
|
return port.openPort();
|
}
|
|
public void setResponseConsumer(Consumer<byte[]> consumer) {
|
this.responseConsumer = consumer;
|
}
|
|
/**
|
* 关闭串口
|
*/
|
public void close() {
|
// 先停止数据接收线程
|
stopCapture();
|
// 如果串口已打开,关闭它
|
if (port != null && port.isOpen()) {
|
port.closePort();
|
}
|
// 释放串口引用
|
port = null;
|
}
|
|
/**
|
* 启动数据接收线程
|
* @param onReceived 数据接收回调函数,收到数据时调用
|
*/
|
public void startCapture(Consumer<byte[]> onReceived) {
|
this.dataReceivedCallback = onReceived;
|
if (capturing || port == null || !port.isOpen()) return;
|
capturing = true;
|
paused = false;
|
|
readerThread = new Thread(() -> {
|
buffer.reset();
|
long lastReceivedTime = 0;
|
|
while (capturing && port.isOpen()) {
|
if (paused) {
|
buffer.reset();
|
int len;
|
do {
|
len = port.readBytes(readBuffer, readBuffer.length);
|
} while (len > 0);
|
try { Thread.sleep(100); } catch (InterruptedException ignore) {}
|
continue;
|
}
|
|
long currentTime = System.currentTimeMillis();
|
if (buffer.size() > 0 && (currentTime - lastReceivedTime) >= 20) {
|
byte[] data = buffer.toByteArray();
|
onReceived.accept(data);
|
if (responseConsumer != null) {
|
responseConsumer.accept(data);
|
}
|
buffer.reset();
|
}
|
|
int len = port.readBytes(readBuffer, readBuffer.length);
|
currentTime = System.currentTimeMillis();
|
|
if (len > 0) {
|
buffer.write(readBuffer, 0, len);
|
lastReceivedTime = currentTime;
|
}
|
|
if (len <= 0 && buffer.size() == 0) {
|
try { Thread.sleep(1); } catch (InterruptedException ignore) {}
|
}
|
}
|
|
if (buffer.size() > 0) {
|
byte[] data = buffer.toByteArray();
|
onReceived.accept(data);
|
if (responseConsumer != null) {
|
responseConsumer.accept(data);
|
}
|
}
|
});
|
readerThread.setDaemon(true);
|
readerThread.start();
|
}
|
/**
|
* 停止数据接收线程
|
*/
|
public void stopCapture() {
|
// 设置捕获标志为 false,通知线程退出
|
capturing = false;
|
// 如果线程存在,等待最多500ms确保线程结束
|
if (readerThread != null) {
|
try { readerThread.join(500); } catch (InterruptedException ignore) {}
|
// 清空线程引用
|
readerThread = null;
|
}
|
}
|
|
// 设置暂停状态
|
public void setPaused(boolean paused) {
|
this.paused = paused;
|
}
|
|
// 获取当前是否暂停
|
public boolean isPaused() {
|
return paused;
|
}
|
|
// 判断串口是否已打开
|
public boolean isOpen() {
|
return port != null && port.isOpen();
|
}
|
|
/**
|
* 发送数据
|
* @param data 要发送的字节数组
|
* @return 是否成功发送
|
*/
|
public boolean send(byte[] data) {
|
if (!isOpen()) {
|
return false;
|
}
|
// 如果串口已初始化且已打开,发送数据并返回结果
|
return port != null && port.isOpen() && port.writeBytes(data, data.length) > 0;
|
}
|
}
|