167 lines
5.9 KiB
Python
167 lines
5.9 KiB
Python
#!/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) |