#!/opt/homebrew/bin/python3 # -*- coding:utf-8 -*- import sys import time from PyQt6 import * from PyQt6.QtCore import * import serial from interfaceSession.sessionAbstract import SessionAbstract from logs import log class SerialWorker(QObject): newDataArrive = pyqtSignal(bytearray) connectSuccess = pyqtSignal() connectClosed = pyqtSignal() connectFailed = pyqtSignal() closeSerial = pyqtSignal() def __init__(self): super().__init__() self.running = False self.serial = None self.autoReconnectChecked = False self.attrs = {} def start(self): try: # 校验端口是否存在于系统中(仅在端口已配置时检查) port = self.attrs.get('port', '') if port: from serial.tools import list_ports available = [p.device for p in list_ports.comports()] if port not in available and port.upper() not in [p.upper() for p in available]: log.warning(f"配置的端口 {port} 在系统中不存在,当前可用端口: {available}") parity_map = { '': 'N', # 默认值为 'N' 'None': 'N', # 无校验 'Odd': 'O', # 奇校验 'Even': 'E', # 偶校验 'Space': 'S' # 空格校验 } bytesize_value = self.attrs.get('bytesize', '8') # 默认值为 '8' if bytesize_value == '': bytesize_value = '8' # 设置为默认值 bytesize = int(bytesize_value) stopbits_value = self.attrs.get('stopbits', '1') # 默认值为 '1' if stopbits_value == '': stopbits_value = '1' # 设置为默认值 stopbits = float(stopbits_value) self.serial = serial.Serial(self.attrs['port'], self.attrs['baudrate'], parity=parity_map.get(self.attrs['parity']), bytesize=bytesize, stopbits=stopbits, timeout=1) if self.serial.is_open: self.connectSuccess.emit() self.running = True while self.running and self.serial.is_open: if self.serial.in_waiting: data = self.serial.read(self.serial.in_waiting) self.newDataArrive.emit(bytearray(data)) #延迟1ms time.sleep(0.001) if self.serial and self.serial.is_open: self.running = False self.serial.close() self.closeSerial.emit() except serial.SerialException as e: # log.info(f"Serial exception: {e}") if self.autoReconnectChecked: self.connectClosed.emit() else: self.connectFailed.emit() finally: if self.serial and self.serial.is_open: self.serial.close() self.running = False self.closeSerial.emit() def stop(self): self.running = False class SessionSerial(SessionAbstract): newDataArrive = pyqtSignal(bytearray) def __init__(self, id, name, attrs = {}): super().__init__(id, name, "serial", attrs) self.id = id self.worker = SerialWorker() self.worker.attrs = attrs self.thread = QThread() self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.start) self.worker.newDataArrive.connect(self.onNewDataArrive) self.worker.connectSuccess.connect(self.onConnectSuccess) self.worker.connectClosed.connect(self.onConnectClosed) self.worker.connectFailed.connect(self.onConnectFailed) self.worker.closeSerial.connect(self.close) self.reconnect_timer = QTimer(self) # 创建一个定时器 self.reconnect_timer.timeout.connect(self.timerout_reconnect) # 连接定时器信号到重连函数 self.reconnect_interval = 10 # 设置重连间隔时间(毫秒) def onNewDataArrive(self, data): self.newDataArrive.emit(data) def onConnectSuccess(self): self.connectSuccess.emit(self.id) def onConnectClosed(self): self.connectClosed.emit(self.id) def onConnectFailed(self): self.connectFailed.emit(self.id) self.close() def setAttrs(self, attrs): self._PROTECTED__attrs.update(attrs) self.worker.attrs.update(attrs) def timerout_reconnect(self): if self.worker.autoReconnectChecked: if self.worker.running: self.connectSuccess.emit(self.id) else: self.open() def stopAutoReconnect(self): self.worker.autoReconnectChecked = False self.reconnect_timer.stop() return True # 自动重连 def startAutoReconnect(self): self.worker.autoReconnectChecked = True self.reconnect_timer.start(self.reconnect_interval) return True def open(self): if not self.thread.isRunning(): self.thread.start() return self.worker.running def close(self): if self.thread.isRunning(): self.worker.stop() self.thread.quit() self.thread.wait() def isOpen(self): return self.thread.isRunning() def isConnect(self): return self.thread.isRunning() @pyqtSlot(bytes) def send(self, data): if self.thread.isRunning(): if self.worker.serial and self.worker.serial.is_open: self.worker.serial.write(data) @pyqtSlot(dict) def ioctrl(self, data: dict): if isinstance(data, dict): self.worker.attrs.update(data) self.worker.serial.baudrate = data.get('baudrate', 9600)