Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSerialPort and QThread

QSerialPort and QThread

Scheduled Pinned Locked Moved Unsolved General and Desktop
10 Posts 6 Posters 3.1k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    maratk1n
    wrote on last edited by maratk1n
    #1

    Hi all!

    I have a small project:

    mainwindow.cpp

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
     
        ComPort::get().open();
     
        thread = new QThread(this);
        connect(this, SIGNAL(destroyed(QObject*)), thread, SLOT(quit()));
     
        valve = new Valve(7);
        connect(valve, SIGNAL(remoteStatus(bool)), this, SLOT(remoteStatus(bool)));
     
        valve->moveToThread(thread);
     
     
        QTimer *valvesReadTimer = new QTimer(this);     
        connect(valvesReadTimer, SIGNAL(timeout()), valve, SLOT(getAllStates()));
        valvesReadTimer->start(1000);                   
     
        connect(passform, SIGNAL(manualModeEmit(bool)), 
                this, SLOT(manualMode(bool)));
     
     
        emergency = new EmergencyResetOfPressure();
        connect(emergency, SIGNAL(openValveSignal(int)), this, SLOT(openValve(int)));
        connect(emergency, SIGNAL(closeValveSignal(int)), this, SLOT(closeValve(int)));
        //emergency->start();
        emergency->moveToThread(emergency);
        emergency->start();
        thread->start();
     
        initActionConnection();
     
    }
     
    MainWindow::~MainWindow()
    {
        delete ui;
    }
     
    void MainWindow::valveSwitch(int id)    //переключатель клапанов
    {
        if (valve->getState(id))
            closeValve(id);
        else
            openValve(id);
    }
     
    void MainWindow::openValve(int id)
    {
        QString str = "Клапан №" + QString::number(id+1);
        valveButton[id]->setEnabled(false);
        if (valve->open(id)) {
            if (manualModeState)
                valveButton[id]->setEnabled(true);
            //valveButton[id]->setPalette(QPalette(Qt::green));
            //valveButton[id]->setStyleSheet(VALVE_OPEN_COLOR);
            QString style = QString(DEFAULT_STYLE_BUTTON) + QString(DEFAULT_BACKGROUND_BUTTON);
            valveButton[id]->setStyleSheet(style);
            ui->mainLabel->setText(str + " открыл! :)");
        }
        else {
            if (manualModeState)
                valveButton[id]->setEnabled(true);
            ui->mainLabel->setText("Не могу открыть " + str);
            remoteStatus(0);
        }
    }
    void MainWindow::closeValve(int id)
    {
        QString str = "Клапан №" + QString::number(id+1);
        valveButton[id]->setEnabled(false);
        if (valve->close(id)) {
            if (manualModeState)
                valveButton[id]->setEnabled(true);
            //valveButton[id]->setPalette(style()->standardPalette());
            valveButton[id]->setStyleSheet("");
            ui->mainLabel->setText(str + " закрыл! :)");
        }
        else {
            if (manualModeState)
                valveButton[id]->setEnabled(true);
            ui->mainLabel->setText("Не могу закрыть " + str);
            remoteStatus(0);
        }
    }
     
    void MainWindow::pressureDrop() //Испытание по методу "Спад давления"
    {
        emergency->begin();
     
        ui->mainLabel->setText("Испытание по методу \n Спад давления");
    }
     
     
    void MainWindow::initActionConnection()
    {
        //обработка нажатий на кнопки клапанов
        QSignalMapper* signalMapper = new QSignalMapper (this);     //чтобы можно было обработать ф-ю с аргументом в Слоте
        for(int i = 0; i < 7; i++)
            signalMapper->setMapping(valveButton[i], i);
        for(int i = 0; i < 7; i++)
            connect(valveButton[i], SIGNAL(clicked()), signalMapper, SLOT(map()));
        connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(valveSwitch(int)));
     
     
        connect(ui->pressureTestButton, SIGNAL(clicked(bool)), this, SLOT(pressureDrop()));     //опрессовка и испытание на прочность
     
    }
     
     
    EmergencyResetOfPressure::EmergencyResetOfPressure(QObject *parent) : QThread(parent)
    {
     
    }
     
    EmergencyResetOfPressure::~EmergencyResetOfPressure()
    {
     
    }
     
    void EmergencyResetOfPressure::begin()
    {
        for (int i = 0; i<7; i++)
        {
            //sleep(1);
            emit openValveSignal(i);
        }
        for (int i = 0; i<7; i++)
        {
            //sleep(1);
            emit closeValveSignal(i);
        }
    }
    

    File for working with valves and port (singleton class)

    class ComPort : public QObject {    //класс синглтон
        Q_OBJECT
    private:
        QString portName;
        QSerialPort *serial;
        explicit ComPort(QObject *parent = 0);
        ~ComPort();
     
        //защита от копирования
        ComPort(ComPort const&) = delete;
        ComPort& operator= (ComPort const&) = delete;
     
        int timeoutCount = 0;
        int responseCount = 0;
     
    public:
        QByteArray buffer;
        static ComPort& get()
        {
            static ComPort instance;
            return instance;
        }
     
        void open();
        void close();
        QByteArray requestResponse(const QByteArray &data);
        void write(const QByteArray &data);
        bool crcCheck(const QByteArray &data);
    private slots:
        void readData();
        void handleError(QSerialPort::SerialPortError error);
    };
    

    .cpp

    Valve::Valve(int size, QObject *parent) : QObject(parent) //конструктор
    {
        valveState.resize(size);
        for(int i = 0; i < size; i++)
        {
            valveState[i] = false;
        }
    }
     
    Valve::~Valve() //деструктор
    {
     
    }
     
    bool Valve::open(int id)
    {
        QByteArray arr;
        arr.resize(7);
        arr[0] = 0xAB;
        arr[1] = 0x01;
        arr[2] = 0x02;
        arr[3] = 0x02;
        arr[4] = id+1;
        arr[5] = 0xFF;
        arr[6] = 0x00 - arr[1] - arr[2] - arr[3] - arr[4] - arr[5];
     
        QByteArray response = ComPort::get().requestResponse(arr);
        if(response[0] == arr[0])
        {
            qDebug() << "клапан №: " << id+1 << " открыт!";
            valveState[id] = true;
     
            emit remoteStatus(1);
            return 1;
        }
     
        emit remoteStatus(0);
        return 0;
    }
     
    bool Valve::close(int id)
    {
        QByteArray arr;
        arr.resize(7);
        arr[0] = 0xAB;
        arr[1] = 0x01;
        arr[2] = 0x02;
        arr[3] = 0x02;
        arr[4] = id+1;
        arr[5] = 0x00;
        arr[6] = 0x00 - arr[1] - arr[2] - arr[3] - arr[4] - arr[5];
     
        QByteArray response = ComPort::get().requestResponse(arr);
        if(response[0] == arr[0])
        {
            qDebug() << "клапан №: " << id+1 << " закрыт!";
            valveState[id] = false;
     
            emit remoteStatus(1);
            return 1;
        }
     
        emit remoteStatus(0);
        return 0;
    }
     
    /*****************************************
     *          Класс для работы с COM портом
     * **************************************/
     
    ComPort::ComPort(QObject *parent) : QObject(parent)
    {
        buffer = "";
        serial = new QSerialPort();
        connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
    }
    ComPort::~ComPort()
    {
     
    }
     
    void ComPort::open()
    {
        if(serial->isOpen())
            close();
        if(portName != Config::get().getValue("COM/name").toString())
        {
            qDebug() << "Порт " << portName << "сменился на " << Config::get().getValue("COM/name").toString();
            portName = Config::get().getValue("COM/name").toString();
        }
        serial->setPortName(portName);
        if (serial->open(QIODevice::ReadWrite)) {
            if (serial->setBaudRate(QSerialPort::Baud115200)
                    && serial->setFlowControl(QSerialPort::NoFlowControl)) {
     
            qDebug() << "Порт открыт";
     
            } else {
                //QMessageBox::critical(this, "Error", serial->errorString());
                qDebug() << QString(serial->errorString());
                serial->close();
     
            }
        } else {
            //QMessageBox::critical(this, QObject::tr("Error"), serial->errorString());
     
        }
    }
    QByteArray ComPort::requestResponse(const QByteArray &data)
    {
        QByteArray readBuf;
        qDebug() << "-------------------------";
        int attempts = 1;
        while (attempts <= REQATTEMPTS) {      //3 попытки
            if (serial->isWritable())
            {
                serial->write(data);
                qDebug() << "Попытка № " << attempts;
                qDebug() << "Запрос: " << data.toHex();
                while (serial->waitForReadyRead(WAITFORREADY)) {
                    readBuf += serial->readAll();
                    if (crcCheck(readBuf) && data[2] == readBuf[2] ){  //если CRC и команда сошлись -- успех!
                        qDebug() << "Ответ: " << readBuf.toHex();
                        responseCount++;
                        qDebug() << "Кол-во запросов:  " << responseCount;
                        qDebug() << "Кол-во таймаутов: " << timeoutCount;
                        float percent = timeoutCount * 100;
                        percent = percent / responseCount;
                        qDebug() << "Процент косяков:  " << QString::number(percent, 'f', 3) << "%";
                        close();
                        open();
                        return readBuf;
                    }
                }
                readBuf.clear();
                qDebug() << "Таймаут...";
                timeoutCount++;
                close();
                open();
                attempts++;
            }
            else
            {
                qDebug() << "Порт " << portName << " не пишется!";
                return 0;
            }
     
        }
    //    close();
    //    open();
        return 0;
    }
     
    void ComPort::close()
    {
        serial->close();
        qDebug() << "Порт закрыт";
    }
    void ComPort::write(const QByteArray &data)
    {
        serial->write(data);
        qDebug() << "Запрос:        " << data.toHex();
    }
    void ComPort::readData()
    {
        buffer = serial->readAll();
        if (ComPort::get().crcCheck(buffer))
        {
            qDebug() << "Ответ:         " << buffer.toHex();
            qDebug() << "---------------------------";
        }
    }
    void ComPort::handleError(QSerialPort::SerialPortError error)
    {
        if (error == QSerialPort::ResourceError) {
            ComPort::get().close();
            qDebug() << "что-то не так!";
        }
    }
    

    While working, I get an error:

    QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QSerialPort(0x197b7f8), parent's thread is QThread(0xc16e50), current thread is QThread(0x197c620)
    

    How can I get rid of this error?
    I hope for any help. Thanks!

    J.HilkJ 1 Reply Last reply
    1
    • dheerendraD Offline
      dheerendraD Offline
      dheerendra
      Qt Champions 2022
      wrote on last edited by
      #2

      Which function is supposed to be executed in thread ?. For me code looked as if no function is executed in thread. Also with error I feel it is coming from getallstates. Can you paste getallstates code ? U must be passing object created in one thread as parent to another object created another thread. Just for testing purpose can avoid passing parent while creating object ?

      Dheerendra
      @Community Service
      Certified Qt Specialist
      http://www.pthinks.com

      1 Reply Last reply
      0
      • M Offline
        M Offline
        maratk1n
        wrote on last edited by maratk1n
        #3

        In the class of the main window, I create instances of classes of sensors, valves, etc. They are interrogated with a certain frequency by the timer. I want them to work in a separate thread so that the GUI does not hang.

        getAllStates:

        bool Valve::getAllStates()
        {
            QByteArray arr;
            arr.resize(5);
            arr[0] = 0xAB;
            arr[1] = 0x01;
            arr[2] = 0x00;
            arr[3] = 0x00;
            arr[4] = 0x00 - arr[1] - arr[2] - arr[3];
        
            QByteArray response = ComPort::get().requestResponse(arr);
            if(response[0] == arr[0])
            {
                QBitArray bitStates(16);    //8 на клапана, 8 на фиттинги
        
                for (int i = 4; i<6; i++)   // конвертируем 4й и 5й байты (HEX) в биты (BIN)
                    for (int b = 0; b<8; b++)
                        bitStates.setBit((i-4)*8+b, response.at(i)&(1<<b));
        
                //qDebug() << bitStates;
        
                for (int i = 0; i < valveState.size(); i++)     //обновляем состояния клапанов
                    valveState[i] = bitStates[i];
                for (uint i = 0; i < sizeof(fittingState); i++)  //обновляем состояния фиттингов
                    fittingState[i] = bitStates[i+8];
        
                emit remoteStatus(1);
                return 1;
            }
        
            emit remoteStatus(0);
            return 0;
        }
        

        getAllStates is executed, for example, once per second. In the same thread, another function is executed with a frequency of three times per second:

        bool PressureSensors::readSensors()
        {
            QByteArray arr;
            arr.resize(5);
            arr[0] = 0xAB;
            arr[1] = 0x01;
            arr[2] = 0x03;
            arr[3] = 0x00;
            arr[4] = 0x00 - arr[1] - arr[2] - arr[3];
        
            QByteArray response = ComPort::get().requestResponse(arr);
            if(response[0] == arr[0])
            {
                QByteArray dd1 = response.mid(4, 2);
                QByteArray dd2 = response.mid(6, 2);
                QByteArray dd3 = response.mid(8, 2);
                QByteArray dd4 = response.mid(10, 4);
                pressureArray[3] = hexToFloat(reverseHex(dd4));
                float Pmax = 160.0;
                pressureArray[2] = hexToDec(reverseHex(dd3)) * Pmax / maxADC;
                pressureArray[1] = hexToDec(reverseHex(dd2)) * Pmax / maxADC;
                pressureArray[0] = hexToDec(reverseHex(dd1)) * Pmax / maxADC;
        
                emit remoteStatus(1);
                return 1;
            }
        
            emit remoteStatus(0);
            return 0;
        }
        
        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Hi,

          Can you show the code where you do your thread handling ?

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          0
          • K Offline
            K Offline
            kuzulis
            Qt Champions 2020
            wrote on last edited by kuzulis
            #5

            serial = new QSerialPort(this);

            you have missed this, Luke!

            PS: Don't use threads at all (if you don't know how to do it right)!

            M 1 Reply Last reply
            0
            • M maratk1n

              Hi all!

              I have a small project:

              mainwindow.cpp

              MainWindow::MainWindow(QWidget *parent) :
                  QMainWindow(parent),
                  ui(new Ui::MainWindow)
              {
                  ui->setupUi(this);
               
                  ComPort::get().open();
               
                  thread = new QThread(this);
                  connect(this, SIGNAL(destroyed(QObject*)), thread, SLOT(quit()));
               
                  valve = new Valve(7);
                  connect(valve, SIGNAL(remoteStatus(bool)), this, SLOT(remoteStatus(bool)));
               
                  valve->moveToThread(thread);
               
               
                  QTimer *valvesReadTimer = new QTimer(this);     
                  connect(valvesReadTimer, SIGNAL(timeout()), valve, SLOT(getAllStates()));
                  valvesReadTimer->start(1000);                   
               
                  connect(passform, SIGNAL(manualModeEmit(bool)), 
                          this, SLOT(manualMode(bool)));
               
               
                  emergency = new EmergencyResetOfPressure();
                  connect(emergency, SIGNAL(openValveSignal(int)), this, SLOT(openValve(int)));
                  connect(emergency, SIGNAL(closeValveSignal(int)), this, SLOT(closeValve(int)));
                  //emergency->start();
                  emergency->moveToThread(emergency);
                  emergency->start();
                  thread->start();
               
                  initActionConnection();
               
              }
               
              MainWindow::~MainWindow()
              {
                  delete ui;
              }
               
              void MainWindow::valveSwitch(int id)    //переключатель клапанов
              {
                  if (valve->getState(id))
                      closeValve(id);
                  else
                      openValve(id);
              }
               
              void MainWindow::openValve(int id)
              {
                  QString str = "Клапан №" + QString::number(id+1);
                  valveButton[id]->setEnabled(false);
                  if (valve->open(id)) {
                      if (manualModeState)
                          valveButton[id]->setEnabled(true);
                      //valveButton[id]->setPalette(QPalette(Qt::green));
                      //valveButton[id]->setStyleSheet(VALVE_OPEN_COLOR);
                      QString style = QString(DEFAULT_STYLE_BUTTON) + QString(DEFAULT_BACKGROUND_BUTTON);
                      valveButton[id]->setStyleSheet(style);
                      ui->mainLabel->setText(str + " открыл! :)");
                  }
                  else {
                      if (manualModeState)
                          valveButton[id]->setEnabled(true);
                      ui->mainLabel->setText("Не могу открыть " + str);
                      remoteStatus(0);
                  }
              }
              void MainWindow::closeValve(int id)
              {
                  QString str = "Клапан №" + QString::number(id+1);
                  valveButton[id]->setEnabled(false);
                  if (valve->close(id)) {
                      if (manualModeState)
                          valveButton[id]->setEnabled(true);
                      //valveButton[id]->setPalette(style()->standardPalette());
                      valveButton[id]->setStyleSheet("");
                      ui->mainLabel->setText(str + " закрыл! :)");
                  }
                  else {
                      if (manualModeState)
                          valveButton[id]->setEnabled(true);
                      ui->mainLabel->setText("Не могу закрыть " + str);
                      remoteStatus(0);
                  }
              }
               
              void MainWindow::pressureDrop() //Испытание по методу "Спад давления"
              {
                  emergency->begin();
               
                  ui->mainLabel->setText("Испытание по методу \n Спад давления");
              }
               
               
              void MainWindow::initActionConnection()
              {
                  //обработка нажатий на кнопки клапанов
                  QSignalMapper* signalMapper = new QSignalMapper (this);     //чтобы можно было обработать ф-ю с аргументом в Слоте
                  for(int i = 0; i < 7; i++)
                      signalMapper->setMapping(valveButton[i], i);
                  for(int i = 0; i < 7; i++)
                      connect(valveButton[i], SIGNAL(clicked()), signalMapper, SLOT(map()));
                  connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(valveSwitch(int)));
               
               
                  connect(ui->pressureTestButton, SIGNAL(clicked(bool)), this, SLOT(pressureDrop()));     //опрессовка и испытание на прочность
               
              }
               
               
              EmergencyResetOfPressure::EmergencyResetOfPressure(QObject *parent) : QThread(parent)
              {
               
              }
               
              EmergencyResetOfPressure::~EmergencyResetOfPressure()
              {
               
              }
               
              void EmergencyResetOfPressure::begin()
              {
                  for (int i = 0; i<7; i++)
                  {
                      //sleep(1);
                      emit openValveSignal(i);
                  }
                  for (int i = 0; i<7; i++)
                  {
                      //sleep(1);
                      emit closeValveSignal(i);
                  }
              }
              

              File for working with valves and port (singleton class)

              class ComPort : public QObject {    //класс синглтон
                  Q_OBJECT
              private:
                  QString portName;
                  QSerialPort *serial;
                  explicit ComPort(QObject *parent = 0);
                  ~ComPort();
               
                  //защита от копирования
                  ComPort(ComPort const&) = delete;
                  ComPort& operator= (ComPort const&) = delete;
               
                  int timeoutCount = 0;
                  int responseCount = 0;
               
              public:
                  QByteArray buffer;
                  static ComPort& get()
                  {
                      static ComPort instance;
                      return instance;
                  }
               
                  void open();
                  void close();
                  QByteArray requestResponse(const QByteArray &data);
                  void write(const QByteArray &data);
                  bool crcCheck(const QByteArray &data);
              private slots:
                  void readData();
                  void handleError(QSerialPort::SerialPortError error);
              };
              

              .cpp

              Valve::Valve(int size, QObject *parent) : QObject(parent) //конструктор
              {
                  valveState.resize(size);
                  for(int i = 0; i < size; i++)
                  {
                      valveState[i] = false;
                  }
              }
               
              Valve::~Valve() //деструктор
              {
               
              }
               
              bool Valve::open(int id)
              {
                  QByteArray arr;
                  arr.resize(7);
                  arr[0] = 0xAB;
                  arr[1] = 0x01;
                  arr[2] = 0x02;
                  arr[3] = 0x02;
                  arr[4] = id+1;
                  arr[5] = 0xFF;
                  arr[6] = 0x00 - arr[1] - arr[2] - arr[3] - arr[4] - arr[5];
               
                  QByteArray response = ComPort::get().requestResponse(arr);
                  if(response[0] == arr[0])
                  {
                      qDebug() << "клапан №: " << id+1 << " открыт!";
                      valveState[id] = true;
               
                      emit remoteStatus(1);
                      return 1;
                  }
               
                  emit remoteStatus(0);
                  return 0;
              }
               
              bool Valve::close(int id)
              {
                  QByteArray arr;
                  arr.resize(7);
                  arr[0] = 0xAB;
                  arr[1] = 0x01;
                  arr[2] = 0x02;
                  arr[3] = 0x02;
                  arr[4] = id+1;
                  arr[5] = 0x00;
                  arr[6] = 0x00 - arr[1] - arr[2] - arr[3] - arr[4] - arr[5];
               
                  QByteArray response = ComPort::get().requestResponse(arr);
                  if(response[0] == arr[0])
                  {
                      qDebug() << "клапан №: " << id+1 << " закрыт!";
                      valveState[id] = false;
               
                      emit remoteStatus(1);
                      return 1;
                  }
               
                  emit remoteStatus(0);
                  return 0;
              }
               
              /*****************************************
               *          Класс для работы с COM портом
               * **************************************/
               
              ComPort::ComPort(QObject *parent) : QObject(parent)
              {
                  buffer = "";
                  serial = new QSerialPort();
                  connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
              }
              ComPort::~ComPort()
              {
               
              }
               
              void ComPort::open()
              {
                  if(serial->isOpen())
                      close();
                  if(portName != Config::get().getValue("COM/name").toString())
                  {
                      qDebug() << "Порт " << portName << "сменился на " << Config::get().getValue("COM/name").toString();
                      portName = Config::get().getValue("COM/name").toString();
                  }
                  serial->setPortName(portName);
                  if (serial->open(QIODevice::ReadWrite)) {
                      if (serial->setBaudRate(QSerialPort::Baud115200)
                              && serial->setFlowControl(QSerialPort::NoFlowControl)) {
               
                      qDebug() << "Порт открыт";
               
                      } else {
                          //QMessageBox::critical(this, "Error", serial->errorString());
                          qDebug() << QString(serial->errorString());
                          serial->close();
               
                      }
                  } else {
                      //QMessageBox::critical(this, QObject::tr("Error"), serial->errorString());
               
                  }
              }
              QByteArray ComPort::requestResponse(const QByteArray &data)
              {
                  QByteArray readBuf;
                  qDebug() << "-------------------------";
                  int attempts = 1;
                  while (attempts <= REQATTEMPTS) {      //3 попытки
                      if (serial->isWritable())
                      {
                          serial->write(data);
                          qDebug() << "Попытка № " << attempts;
                          qDebug() << "Запрос: " << data.toHex();
                          while (serial->waitForReadyRead(WAITFORREADY)) {
                              readBuf += serial->readAll();
                              if (crcCheck(readBuf) && data[2] == readBuf[2] ){  //если CRC и команда сошлись -- успех!
                                  qDebug() << "Ответ: " << readBuf.toHex();
                                  responseCount++;
                                  qDebug() << "Кол-во запросов:  " << responseCount;
                                  qDebug() << "Кол-во таймаутов: " << timeoutCount;
                                  float percent = timeoutCount * 100;
                                  percent = percent / responseCount;
                                  qDebug() << "Процент косяков:  " << QString::number(percent, 'f', 3) << "%";
                                  close();
                                  open();
                                  return readBuf;
                              }
                          }
                          readBuf.clear();
                          qDebug() << "Таймаут...";
                          timeoutCount++;
                          close();
                          open();
                          attempts++;
                      }
                      else
                      {
                          qDebug() << "Порт " << portName << " не пишется!";
                          return 0;
                      }
               
                  }
              //    close();
              //    open();
                  return 0;
              }
               
              void ComPort::close()
              {
                  serial->close();
                  qDebug() << "Порт закрыт";
              }
              void ComPort::write(const QByteArray &data)
              {
                  serial->write(data);
                  qDebug() << "Запрос:        " << data.toHex();
              }
              void ComPort::readData()
              {
                  buffer = serial->readAll();
                  if (ComPort::get().crcCheck(buffer))
                  {
                      qDebug() << "Ответ:         " << buffer.toHex();
                      qDebug() << "---------------------------";
                  }
              }
              void ComPort::handleError(QSerialPort::SerialPortError error)
              {
                  if (error == QSerialPort::ResourceError) {
                      ComPort::get().close();
                      qDebug() << "что-то не так!";
                  }
              }
              

              While working, I get an error:

              QObject: Cannot create children for a parent that is in a different thread.
              (Parent is QSerialPort(0x197b7f8), parent's thread is QThread(0xc16e50), current thread is QThread(0x197c620)
              

              How can I get rid of this error?
              I hope for any help. Thanks!

              J.HilkJ Offline
              J.HilkJ Offline
              J.Hilk
              Moderators
              wrote on last edited by
              #6

              There are some crucial parts of your valve-class missing to be sure, but I believe valve tries to access ther SerialPort created in your main thread ComPort::get().open(); form a different thread valve->moveToThread(thread);

              @maratk1n said in QSerialPort and QThread:

              ComPort::get().open();

              thread = new QThread(this);
              connect(this, SIGNAL(destroyed(QObject*)), thread, SLOT(quit()));
              
              valve = new Valve(7);
              

              connect(valve, SIGNAL(remoteStatus(bool)), this, SLOT(remoteStatus(bool)));

              valve->moveToThread(thread);

              That won't work, you'll need to create the port in the same thread it is accessed from or handle that via SIGNAL/SLOTS at all times.


              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


              Q: What's that?
              A: It's blue light.
              Q: What does it do?
              A: It turns blue.

              1 Reply Last reply
              0
              • K kuzulis

                serial = new QSerialPort(this);

                you have missed this, Luke!

                PS: Don't use threads at all (if you don't know how to do it right)!

                M Offline
                M Offline
                maratk1n
                wrote on last edited by
                #7

                @kuzulis said in QSerialPort and QThread:

                serial = new QSerialPort(this);
                you have missed this, Luke!

                Tried it. Does not help.

                @SGaist said in QSerialPort and QThread:

                Can you show the code where you do your thread handling ?

                What do you mean?..

                @J.Hilk said in QSerialPort and QThread:

                That won't work, you'll need to create the port in the same thread it is accessed from or handle that via SIGNAL/SLOTS at all times.

                Redo the class methods in slots? But in fact the instance of the class QSerialPort will still be created in the main thread.

                jsulmJ 1 Reply Last reply
                0
                • M maratk1n

                  @kuzulis said in QSerialPort and QThread:

                  serial = new QSerialPort(this);
                  you have missed this, Luke!

                  Tried it. Does not help.

                  @SGaist said in QSerialPort and QThread:

                  Can you show the code where you do your thread handling ?

                  What do you mean?..

                  @J.Hilk said in QSerialPort and QThread:

                  That won't work, you'll need to create the port in the same thread it is accessed from or handle that via SIGNAL/SLOTS at all times.

                  Redo the class methods in slots? But in fact the instance of the class QSerialPort will still be created in the main thread.

                  jsulmJ Offline
                  jsulmJ Offline
                  jsulm
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @maratk1n said in QSerialPort and QThread:

                  What do you mean?..

                  The code where you create and start your threads.

                  "Redo the class methods in slots?" - do not create instance variables in the constructor of QThread derived classes! Such a class is created in the main thread - that means constructor is executed in the main thread and this means - everything created in the constructor is created in main thread. Create everything your thread needs in run() - run() is executed in that new thread.
                  See "It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run()." in http://doc.qt.io/qt-5.8/qthread.html
                  And take a look at https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

                  https://forum.qt.io/topic/113070/qt-code-of-conduct

                  M 1 Reply Last reply
                  2
                  • jsulmJ jsulm

                    @maratk1n said in QSerialPort and QThread:

                    What do you mean?..

                    The code where you create and start your threads.

                    "Redo the class methods in slots?" - do not create instance variables in the constructor of QThread derived classes! Such a class is created in the main thread - that means constructor is executed in the main thread and this means - everything created in the constructor is created in main thread. Create everything your thread needs in run() - run() is executed in that new thread.
                    See "It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run()." in http://doc.qt.io/qt-5.8/qthread.html
                    And take a look at https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

                    M Offline
                    M Offline
                    maratk1n
                    wrote on last edited by
                    #9

                    @jsulm said in QSerialPort and QThread:

                    The code where you create and start your threads.

                    This is written at the very beginning of the post, if I understood correctly

                    MainWindow::MainWindow(QWidget *parent) :
                        QMainWindow(parent),
                        ui(new Ui::MainWindow)
                    {
                        ui->setupUi(this);
                     
                        ComPort::get().open();
                     
                        thread = new QThread(this);
                        connect(this, SIGNAL(destroyed(QObject*)), thread, SLOT(quit()));
                     
                        valve = new Valve(7);
                        connect(valve, SIGNAL(remoteStatus(bool)), this, SLOT(remoteStatus(bool)));
                     
                        valve->moveToThread(thread);
                     
                     
                        QTimer *valvesReadTimer = new QTimer(this);     
                        connect(valvesReadTimer, SIGNAL(timeout()), valve, SLOT(getAllStates()));
                        valvesReadTimer->start(1000);                   
                     
                        connect(passform, SIGNAL(manualModeEmit(bool)), 
                                this, SLOT(manualMode(bool)));
                     
                     
                        emergency = new EmergencyResetOfPressure();
                        connect(emergency, SIGNAL(openValveSignal(int)), this, SLOT(openValve(int)));
                        connect(emergency, SIGNAL(closeValveSignal(int)), this, SLOT(closeValve(int)));
                        //emergency->start();
                        emergency->moveToThread(emergency);
                        emergency->start();
                        thread->start();
                     
                        initActionConnection();
                     
                    }
                    
                    1 Reply Last reply
                    0
                    • M Offline
                      M Offline
                      maratk1n
                      wrote on last edited by
                      #10

                      Has a little changed work with port:

                      bool Valve::getAllStates()
                      {
                          QByteArray arr;
                          arr.resize(5);
                          arr[0] = 0xAB;
                          arr[1] = 0x01;
                          arr[2] = 0x00;
                          arr[3] = 0x00;
                          arr[4] = 0x00 - arr[1] - arr[2] - arr[3];
                      
                          emit requestResponse(arr);
                      //    QByteArray response = ComPort::get().requestResponse(arr);
                      //    if(response[0] == arr[0])
                      //    {
                      //        QBitArray bitStates(16);    //8 на клапана, 8 на фиттинги
                      
                      //        for (int i = 4; i<6; i++)   // конвертируем 4й и 5й байты (HEX) в биты (BIN)
                      //            for (int b = 0; b<8; b++)
                      //                bitStates.setBit((i-4)*8+b, response.at(i)&(1<<b));
                      
                      //        //qDebug() << bitStates;
                      
                      //        for (int i = 0; i < valveState.size(); i++)     //обновляем состояния клапанов
                      //            valveState[i] = bitStates[i];
                      //        for (uint i = 0; i < sizeof(fittingState); i++)  //обновляем состояния фиттингов
                      //            fittingState[i] = bitStates[i+8];
                      
                      //        emit remoteStatus(1);
                      //        return 1;
                      //    }
                      
                      //    emit remoteStatus(0);
                      //    return 0;
                      }
                      

                      And I configured the connection in the designer of the valve class:

                      connect(this, SIGNAL(requestResponse(QByteArray)), &ComPort::get(), SLOT(requestResponse(QByteArray)));
                      

                      The error has disappeared

                      QObject: Cannot create children for a parent that is in a different thread.
                      (Parent is QSerialPort(0x197b7f8), parent's thread is QThread(0xc16e50), current thread is QThread(0x197c620)
                      

                      But there were other problems:

                      1. The GUI is terribly slow.
                      2. The port class function is used by a variety of classes, so it is not clear to me how to determine which of them came the answer.
                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved