rnc_tuning/br_com_serial.py

183 lines
7.7 KiB
Python
Raw Normal View History

2025-11-03 13:53:12 +08:00
from PySide6.QtCore import QObject, Signal, Slot, QThread, QMutex, QWaitCondition
from PySide6.QtSerialPort import QSerialPort, QSerialPortInfo
from br_com_message import BrComMessage
import time
import queue
class SerialReaderThread(QThread):
"""串口数据读取线程"""
def __init__(self, serial_port, buffer_queue):
super().__init__()
self.serial_port = serial_port
self.buffer_queue = buffer_queue
self.running = True
self.buffer = bytearray()
self.max_buffer_size = 50 * 1024 * 1024 # 50MB
self.buffer_mutex = QMutex()
def run(self):
while self.running:
if not self.serial_port.isOpen():
time.sleep(0.1)
continue
if self.serial_port.waitForReadyRead(100): # 等待100ms
data = self.serial_port.readAll()
if data:
self.buffer_mutex.lock()
try:
# 检查缓冲区大小
if len(self.buffer) >= self.max_buffer_size:
print("Warning: Buffer overflow, clearing buffer")
self.buffer.clear()
# 将数据添加到缓冲区
self.buffer.extend(data.data())
# 将完整的数据块放入队列
self.buffer_queue.put(self.buffer)
# 清空缓冲区,准备接收下一块数据
self.buffer = bytearray()
finally:
self.buffer_mutex.unlock()
else:
# 如果没有数据,短暂休眠
time.sleep(0.01)
def stop(self):
self.running = False
class MessageProcessorThread(QThread):
"""消息处理线程"""
def __init__(self, buffer_queue, message_queue):
super().__init__()
self.buffer_queue = buffer_queue
self.message_queue = message_queue
self.running = True
self.accumulated_data = bytearray()
self.max_accumulated_size = 50 * 1024 * 1024 # 50MB
self.data_mutex = QMutex()
def run(self):
while self.running:
try:
# 从缓冲区队列获取数据,设置超时
data = self.buffer_queue.get(timeout=0.1)
if data:
self.data_mutex.lock()
try:
# 检查累积数据大小
if len(self.accumulated_data) >= self.max_accumulated_size:
print("Warning: Accumulated data overflow, clearing data")
self.accumulated_data.clear()
# 将新数据添加到累积数据中
self.accumulated_data.extend(data)
# 处理累积的数据,查找完整的消息
while len(self.accumulated_data) > 0:
# 查找消息头假设消息头是0xAA
start_index = self.accumulated_data.find(0xAA)
if start_index == -1:
# 没有找到消息头,清空数据
self.accumulated_data.clear()
break
# 移除消息头之前的数据
self.accumulated_data = self.accumulated_data[start_index:]
# 检查是否有足够的数据来获取消息长度
if len(self.accumulated_data) < 4: # 假设消息头+长度至少4字节
break
# 获取消息长度假设长度字段在消息头后的2个字节
message_length = (self.accumulated_data[1] << 8) | self.accumulated_data[2]
# 检查消息长度是否合理
if message_length > self.max_accumulated_size:
print(f"Warning: Invalid message length {message_length}, skipping")
self.accumulated_data = self.accumulated_data[1:] # 跳过当前字节
continue
# 检查是否有完整的消息
if len(self.accumulated_data) < message_length:
break
# 提取完整的消息
message_data = self.accumulated_data[:message_length]
self.accumulated_data = self.accumulated_data[message_length:]
# 将消息放入消息队列
self.message_queue.put(message_data)
finally:
self.data_mutex.unlock()
except queue.Empty:
# 队列超时,继续循环
continue
def stop(self):
self.running = False
class BrComSerial(QObject):
signal_connected = Signal()
signal_disconnected = Signal()
signal_error = Signal(str)
signal_message = Signal(BrComMessage)
def __init__(self, parent=None):
super().__init__(parent)
self.serial_port = QSerialPort()
self.serial_port.errorOccurred.connect(self.on_error)
# 创建数据缓冲队列和消息队列,设置最大大小
self.buffer_queue = queue.Queue(maxsize=1000) # 限制队列大小
self.message_queue = queue.Queue(maxsize=1000) # 限制队列大小
# 创建并启动数据读取线程
self.reader_thread = SerialReaderThread(self.serial_port, self.buffer_queue)
self.reader_thread.start()
# 创建并启动消息处理线程
self.processor_thread = MessageProcessorThread(self.buffer_queue, self.message_queue)
self.processor_thread.start()
# 启动消息处理定时器
self.timer = QTimer()
self.timer.timeout.connect(self.process_messages)
self.timer.start(10) # 每10ms检查一次消息队列
def process_messages(self):
"""处理消息队列中的消息"""
while not self.message_queue.empty():
try:
message_data = self.message_queue.get_nowait()
# 处理消息(这里可以添加具体的消息处理逻辑)
msg = BrComMessage.from_bytes(message_data)
if msg:
self.signal_message.emit(msg)
except queue.Empty:
break
except Exception as e:
print(f"Error processing message: {e}")
def on_error(self, error):
"""处理串口错误"""
if error == QSerialPort.NoError:
return
error_str = f"Serial port error: {error}"
print(error_str)
self.signal_error.emit(error_str)
if self.serial_port.isOpen():
self.serial_port.close()
self.signal_disconnected.emit()
def close(self):
"""关闭串口和线程"""
self.reader_thread.stop()
self.processor_thread.stop()
self.reader_thread.wait()
self.processor_thread.wait()
if self.serial_port.isOpen():
self.serial_port.close()