rnc_tuning/br_com_serial.py
2025-11-03 13:53:12 +08:00

183 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()