Не получается правильно организовать передачу значений из слота QSerialport в функцию python QT5
Не получается собрать посылку полностью т.к. начало может быть в первых 32 байтах и конец на 5 или 7 посылке 32 байт и выходит постоянно из метода и обнуляет две необходимые мне переменные.
Необходимо собирать данные и для этого есть 2 переменные: одна включается когда сформировано начало посылки,а другая начинает плюсовать строки пока не встретит конец строки.
Как правильно это организовать и может использовать глобал? nonlocal пробовал и выдавало ошибки?
Ниже в коде есть описание попыток и какие ошибки были, где именно проблема. Передаю данные (32 байта максимум) из onReadyRead в DataReadCOM формирую переменные и передаю обратно в onReadyRead потом начинает заново все и переменные обнуляются т.к. выходит из метода onReadyRead.
import binascii
from PyQt5 import QtCore, QtGui, QtWidgets, QtSerialPort
import datetime
from datetime import timedelta
# пробую отдельную функцию для формирования послыки из буфера СОМ порта(работает нет вопросов)
def DataReadCOM(dataOnRR, NewMail_, strDataBuffer_):
countLenData = 0
count = len(dataOnRR)
for countLenData in range(0, count):
#print(dataOnRR[countLenData])
if dataOnRR[countLenData] == "[":
print("IN1")
if countLenData < len(dataOnRR):
print("IN2")
if dataOnRR[countLenData + 1] == "0":
print("IN3")
NewMail_ = True
strDataBuffer_ = strDataBuffer_ + dataOnRR[countLenData]
continue
if NewMail_ == True:
print("IN4")
strDataBuffer_ = strDataBuffer_ + dataOnRR[countLenData]
if dataOnRR[countLenData] == "[":
print("IN5")
if countLenData < len(dataOnRR):
print("IN6")
if dataOnRR[countLenData + 1] == "0":
print("IN7")
NewMail_ = False
strDataBuffer_ = strDataBuffer_ + dataOnRR[countLenData]
print(strDataBuffer_)
print(strDataBuffer_)
return NewMail_,strDataBuffer_
# Основной класс GUI + методы приема даннных из СОМ порта
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.label = QtWidgets.QLabel("Нажми кнопку для запуска потока")
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.btnConnect = QtWidgets.QPushButton("Connect")
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addWidget(self.label)
self.vbox.addWidget(self.btnConnect)
self.setLayout(self.vbox)
self.btnConnect.clicked.connect(self.slot_clicked_connect_button)
self.serial = QtSerialPort.QSerialPort(self)
### ВОПРОС НАЧИНАЕТСЯ ЗДЕСЬ###############################################################
NewMailglobal = False # переменная которую нужно запоминать и менять в функции DataReadCOM
strDataBufrglobal = " " # собираем строку из полученной информации чтобы потом записать в базу
self.serial.readyRead.connect(lambda: self.onReadyRead(NewMailglobal, str(strDataBufrglobal))) #работает, но не сохраняются 2 переменные
# ниже способ выдает ошибку line 55, in __init__ ... TypeError: cannot unpack non-iterable Connection object
#NewMailglobal, strDataBufrglobal = self.serial.readyRead.connect(lambda: self.onReadyRead(NewMailglobal, str(strDataBufrglobal)))
# ниже способ выдает ошибку line 58, in __init__ ... TypeError: argument 1 has unexpected type 'tuple'
#NewMailglobal, strDataBufrglobal = self.serial.readyRead.connect(self.onReadyRead(NewMailglobal, str(strDataBufrglobal)))
print("OUT1") # контроль выхода и вызова класса
def onReadyRead(self, NewMail, strDataBuffer):
i = 0
print("OUT2") # контроль выхода из цикла ожидания байтов
while self.serial.bytesAvailable() >= 1: # если хоть 1 байт есть в порту то выполнять
buffer = self.serial.read(32) # 32 байта макс. принимает с порта и обнуляет переменные выходя из метода
print(buffer) # фиксируем полученную информацию
NewMail, strDataBuffer = DataReadCOM(str(buffer), NewMail, strDataBuffer)
print(strDataBuffer) # фиксируем нормальный разбор строки из полученной информации
return NewMail, strDataBuffer # возвращаем переменные чтобы формировние послыки не пропало
#########################################################################################
### Дальше идут методы на прием данных по СОМ порту которые работают нет вопросов
def _open(self, port_name, baudrate=QtSerialPort.QSerialPort.Baud9600):
info = QtSerialPort.QSerialPortInfo(port_name)
self.serial.setPort(info)
self.serial.setBaudRate(baudrate)
return self.serial.open(QtCore.QIODevice.ReadWrite)
def connect_serial(self):
serial_info = {"port_name": "COM3"}
status = self._open(**serial_info)
return status
def disconnect_serial(self):
return self.serial.close()
@QtCore.pyqtSlot(name="clickedConnectButton")
def slot_clicked_connect_button(self):
if self.serial.isOpen():
self.disconnect_serial()
else:
self.connect_serial()
self.btnConnect.setText(
"Stop" if self.serial.isOpen() else "Connect"
)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MyWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
Ответы (1 шт):
Создайте класс обработки полученных данных из самого onReadyRead, который будет накапливать полученные данные и формировать из них нужные вам пакеты:
# Класс для формирования пакетов
class MailProcessor:
# Сигнал о том, что получен новый пакет
newMail = pyqtSignal()
# Объявление буфера для хранения данных
dataBuffer = QByteArray()
def process(self, data):
# добавление новых блоков данных к буферу,
# поиск начала/конца пакета
# Если в буфере сформировался пакет (получен конец данных),
# то блок ограниченный началом и концом вынимается и формируется посылка (newMail.emit()),
# остальное (начиная с признака начала пакета) сохраняется в буфере
# для последующей обработки
class MyWindow(QtWidgets.QWidget):
def __init__(self):
# ...
self.mailProcessor = MailProcessor()
# не надо лямбду
self.serial.readyRead.connect(self.onReadyRead)
def onReadyRead(self):
# ...
mailProcessor.process(self.readAll())