Не получается правильно организовать передачу значений из слота 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 шт):

Автор решения: Alexander Chernin

Создайте класс обработки полученных данных из самого 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())
→ Ссылка