zouyu
9 天以前 bf95078dab81dcd0639fdb1a41e998b31c940fb1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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();
    }
 
}