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::waitForReadyRead() unusable for quick responses
Forum Updated to NodeBB v4.3 + New Features

QSerialPort::waitForReadyRead() unusable for quick responses

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 6 Posters 1.7k 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.
  • InTheBeningingI Offline
    InTheBeningingI Offline
    InTheBeninging
    wrote on last edited by InTheBeninging
    #1

    Re: [QSerialPort::waitForReadyRead() delays at least 5-10ms](how to make it respond faster?)

    Why at all does it delay reading? I don't even need time criticality. I just want to be able to read my sensors response... How come waitForReadyRead discards the response, but readyRead is able to capture it in parallel?
    I'm using a dedicated SerialPort thread to be able to write synchronized communication, which is much easier to read. You transmit something and block until you get the desired response in a single function instead of splitting it up across multiple signal/slots and trying to decipher which response belongs to which request.

    jsulmJ 1 Reply Last reply
    0
    • InTheBeningingI InTheBeninging

      Re: [QSerialPort::waitForReadyRead() delays at least 5-10ms](how to make it respond faster?)

      Why at all does it delay reading? I don't even need time criticality. I just want to be able to read my sensors response... How come waitForReadyRead discards the response, but readyRead is able to capture it in parallel?
      I'm using a dedicated SerialPort thread to be able to write synchronized communication, which is much easier to read. You transmit something and block until you get the desired response in a single function instead of splitting it up across multiple signal/slots and trying to decipher which response belongs to which request.

      jsulmJ Online
      jsulmJ Online
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:

      How come waitForReadyRead discards the response

      What do you mean? It should not discard any data.
      Can you show your code?

      From the documentation: "This function blocks until new data is available for reading and the readyRead() signal has been emitted". So, it will unblock after readyRead was emitted, but that should not cause any bigger slow down (unless you connect a slot to that signal and do something there).

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

      InTheBeningingI 1 Reply Last reply
      1
      • jsulmJ jsulm

        @InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:

        How come waitForReadyRead discards the response

        What do you mean? It should not discard any data.
        Can you show your code?

        From the documentation: "This function blocks until new data is available for reading and the readyRead() signal has been emitted". So, it will unblock after readyRead was emitted, but that should not cause any bigger slow down (unless you connect a slot to that signal and do something there).

        InTheBeningingI Offline
        InTheBeningingI Offline
        InTheBeninging
        wrote on last edited by InTheBeninging
        #3

        @jsulm

        MainWindow::MainWindow(QWidget *parent)
           : QMainWindow(parent)
           , ui(new Ui::MainWindow)
        {
           ui->setupUi(this);
        
           m_serialPort = new QSerialPort(this);
           m_serialPort->setPortName("COM5");
           m_serialPort->setBaudRate(QSerialPort::Baud38400);
           m_serialPort->setDataBits(QSerialPort::Data8);
           m_serialPort->setParity(QSerialPort::NoParity);
           m_serialPort->setStopBits(QSerialPort::OneStop);
           m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
           if (!m_serialPort->open(QIODevice::ReadWrite)) {
               qDebug() << "FAIL openSerialPort() can't open QSerialPort. Is the Device powered on?"
                                     << m_serialPort->errorString();
               return;
           }
           qDebug() << "OK openSerialPort()";
        
           QObject::connect(m_serialPort, &QSerialPort::readyRead, this, [&]{
               QByteArray requestData = m_serialPort->readAll();
               while (m_serialPort->waitForReadyRead(10))
                   requestData += m_serialPort->readAll();
        
               qDebug() << QString::fromStdString(requestData.toStdString()) << requestData;
           });
        
           QObject::connect(ui->pushButton_laserOff, &QPushButton::clicked, this, [&]{
               char command[] = "%01#WLR+0000055\r";
               int bytesWritten = m_serialPort->write(command, 16);
               bool portStatus = m_serialPort->waitForReadyRead(1000);
               if(!portStatus) {
                   qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString()
                                   << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command))
                                   << m_serialPort->error();
                   return;
               }
               QByteArray requestData = m_serialPort->readAll();
               while (m_serialPort->waitForReadyRead(10))
                   requestData += m_serialPort->readAll();
        
               qDebug() << requestData;
           });
        
           QObject::connect(ui->pushButton_laserOn, &QPushButton::clicked, this, [&]{
               // char command[] = "%01#WLR+0000154\r";
               char command[] = {'\x25','\x30','\x31','\x23','\x57','\x4C','\x52','\x2B','\x30','\x30','\x30','\x30','\x31','\x35','\x34','\x0D'};
               int bytesWritten = m_serialPort->write(command, 16);
               bool portStatus = m_serialPort->waitForReadyRead(1000);
               if(!portStatus) {
                   qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString()
                            << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command))
                            << m_serialPort->error();
                   return;
               }
               QByteArray requestData = m_serialPort->readAll();
               while (m_serialPort->waitForReadyRead(10))
                   requestData += m_serialPort->readAll();
        
               qDebug() << requestData;
           });
        }
        

        It always outputs whats written in the !portStatus, in other words waitForReadyRead always returns false, but the readyRead lambda is being run anyway...

        Ronel_qtmasterR jsulmJ 2 Replies Last reply
        0
        • InTheBeningingI InTheBeninging

          @jsulm

          MainWindow::MainWindow(QWidget *parent)
             : QMainWindow(parent)
             , ui(new Ui::MainWindow)
          {
             ui->setupUi(this);
          
             m_serialPort = new QSerialPort(this);
             m_serialPort->setPortName("COM5");
             m_serialPort->setBaudRate(QSerialPort::Baud38400);
             m_serialPort->setDataBits(QSerialPort::Data8);
             m_serialPort->setParity(QSerialPort::NoParity);
             m_serialPort->setStopBits(QSerialPort::OneStop);
             m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
             if (!m_serialPort->open(QIODevice::ReadWrite)) {
                 qDebug() << "FAIL openSerialPort() can't open QSerialPort. Is the Device powered on?"
                                       << m_serialPort->errorString();
                 return;
             }
             qDebug() << "OK openSerialPort()";
          
             QObject::connect(m_serialPort, &QSerialPort::readyRead, this, [&]{
                 QByteArray requestData = m_serialPort->readAll();
                 while (m_serialPort->waitForReadyRead(10))
                     requestData += m_serialPort->readAll();
          
                 qDebug() << QString::fromStdString(requestData.toStdString()) << requestData;
             });
          
             QObject::connect(ui->pushButton_laserOff, &QPushButton::clicked, this, [&]{
                 char command[] = "%01#WLR+0000055\r";
                 int bytesWritten = m_serialPort->write(command, 16);
                 bool portStatus = m_serialPort->waitForReadyRead(1000);
                 if(!portStatus) {
                     qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString()
                                     << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command))
                                     << m_serialPort->error();
                     return;
                 }
                 QByteArray requestData = m_serialPort->readAll();
                 while (m_serialPort->waitForReadyRead(10))
                     requestData += m_serialPort->readAll();
          
                 qDebug() << requestData;
             });
          
             QObject::connect(ui->pushButton_laserOn, &QPushButton::clicked, this, [&]{
                 // char command[] = "%01#WLR+0000154\r";
                 char command[] = {'\x25','\x30','\x31','\x23','\x57','\x4C','\x52','\x2B','\x30','\x30','\x30','\x30','\x31','\x35','\x34','\x0D'};
                 int bytesWritten = m_serialPort->write(command, 16);
                 bool portStatus = m_serialPort->waitForReadyRead(1000);
                 if(!portStatus) {
                     qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString()
                              << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command))
                              << m_serialPort->error();
                     return;
                 }
                 QByteArray requestData = m_serialPort->readAll();
                 while (m_serialPort->waitForReadyRead(10))
                     requestData += m_serialPort->readAll();
          
                 qDebug() << requestData;
             });
          }
          

          It always outputs whats written in the !portStatus, in other words waitForReadyRead always returns false, but the readyRead lambda is being run anyway...

          Ronel_qtmasterR Offline
          Ronel_qtmasterR Offline
          Ronel_qtmaster
          wrote on last edited by Ronel_qtmaster
          #4

          @InTheBeninging according to your code you don't even need these lines

          while (m_serialPort->waitForReadyRead(10))
          requestData += m_serialPort->readAll();

          You cannot connect ready read signal and directly after that call waitForReadyRead.It is bad coding

          InTheBeningingI 1 Reply Last reply
          0
          • Ronel_qtmasterR Ronel_qtmaster

            @InTheBeninging according to your code you don't even need these lines

            while (m_serialPort->waitForReadyRead(10))
            requestData += m_serialPort->readAll();

            You cannot connect ready read signal and directly after that call waitForReadyRead.It is bad coding

            InTheBeningingI Offline
            InTheBeningingI Offline
            InTheBeninging
            wrote on last edited by
            #5

            @Ronel_qtmaster Could you elaborate why?

            Christian EhrlicherC 1 Reply Last reply
            0
            • InTheBeningingI InTheBeninging

              @Ronel_qtmaster Could you elaborate why?

              Christian EhrlicherC Online
              Christian EhrlicherC Online
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on last edited by
              #6

              @InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:

              Could you elaborate why?

              Already written: "This function blocks until new data is available for reading and the readyRead() signal has been emitted"

              So you basically program a loop for no reason. Don't block, only use signals and slots.

              Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
              Visit the Qt Academy at https://academy.qt.io/catalog

              1 Reply Last reply
              1
              • InTheBeningingI InTheBeninging

                @jsulm

                MainWindow::MainWindow(QWidget *parent)
                   : QMainWindow(parent)
                   , ui(new Ui::MainWindow)
                {
                   ui->setupUi(this);
                
                   m_serialPort = new QSerialPort(this);
                   m_serialPort->setPortName("COM5");
                   m_serialPort->setBaudRate(QSerialPort::Baud38400);
                   m_serialPort->setDataBits(QSerialPort::Data8);
                   m_serialPort->setParity(QSerialPort::NoParity);
                   m_serialPort->setStopBits(QSerialPort::OneStop);
                   m_serialPort->setFlowControl(QSerialPort::NoFlowControl);
                   if (!m_serialPort->open(QIODevice::ReadWrite)) {
                       qDebug() << "FAIL openSerialPort() can't open QSerialPort. Is the Device powered on?"
                                             << m_serialPort->errorString();
                       return;
                   }
                   qDebug() << "OK openSerialPort()";
                
                   QObject::connect(m_serialPort, &QSerialPort::readyRead, this, [&]{
                       QByteArray requestData = m_serialPort->readAll();
                       while (m_serialPort->waitForReadyRead(10))
                           requestData += m_serialPort->readAll();
                
                       qDebug() << QString::fromStdString(requestData.toStdString()) << requestData;
                   });
                
                   QObject::connect(ui->pushButton_laserOff, &QPushButton::clicked, this, [&]{
                       char command[] = "%01#WLR+0000055\r";
                       int bytesWritten = m_serialPort->write(command, 16);
                       bool portStatus = m_serialPort->waitForReadyRead(1000);
                       if(!portStatus) {
                           qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString()
                                           << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command))
                                           << m_serialPort->error();
                           return;
                       }
                       QByteArray requestData = m_serialPort->readAll();
                       while (m_serialPort->waitForReadyRead(10))
                           requestData += m_serialPort->readAll();
                
                       qDebug() << requestData;
                   });
                
                   QObject::connect(ui->pushButton_laserOn, &QPushButton::clicked, this, [&]{
                       // char command[] = "%01#WLR+0000154\r";
                       char command[] = {'\x25','\x30','\x31','\x23','\x57','\x4C','\x52','\x2B','\x30','\x30','\x30','\x30','\x31','\x35','\x34','\x0D'};
                       int bytesWritten = m_serialPort->write(command, 16);
                       bool portStatus = m_serialPort->waitForReadyRead(1000);
                       if(!portStatus) {
                           qDebug() << "FAIL serialWriteRead() TIMEOUT device unresponsive. SerialPort Error:" << m_serialPort->errorString()
                                    << "Bytes Written: " << bytesWritten << "Command:" << QString::fromStdString(std::string(command))
                                    << m_serialPort->error();
                           return;
                       }
                       QByteArray requestData = m_serialPort->readAll();
                       while (m_serialPort->waitForReadyRead(10))
                           requestData += m_serialPort->readAll();
                
                       qDebug() << requestData;
                   });
                }
                

                It always outputs whats written in the !portStatus, in other words waitForReadyRead always returns false, but the readyRead lambda is being run anyway...

                jsulmJ Online
                jsulmJ Online
                jsulm
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @InTheBeninging I'm really confused by this code. I don't see any threads here ("I'm using a dedicated SerialPort thread" - where?). You're doing the serial communication inside GUI thread. So, what you wrote in your first post here and the code do not match.
                You're mixing readyRead with waitForReadyRead which you should not. And it is bad to wait for serial port in slots connected to buttons - this will block the UI until something arrives or timeout.

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

                J.HilkJ 1 Reply Last reply
                1
                • jsulmJ jsulm

                  @InTheBeninging I'm really confused by this code. I don't see any threads here ("I'm using a dedicated SerialPort thread" - where?). You're doing the serial communication inside GUI thread. So, what you wrote in your first post here and the code do not match.
                  You're mixing readyRead with waitForReadyRead which you should not. And it is bad to wait for serial port in slots connected to buttons - this will block the UI until something arrives or timeout.

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

                  @jsulm said in QSerialPort::waitForReadyRead() unusable for quick responses:

                  this will block the UI until something arrives

                  nothing will arrive:

                  QIODevice::readyRead()

                  readyRead() is not emitted recursively; if you reenter the event loop or call waitForReadyRead() inside a slot connected to the readyRead() signal, the signal will not be reemitted


                  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
                  • InTheBeningingI Offline
                    InTheBeningingI Offline
                    InTheBeninging
                    wrote on last edited by InTheBeninging
                    #9

                    @Christian-Ehrlicher @J-Hilk @jsulm
                    I'm sorry I didn't clear this up, the given code is just a demo stripped off of my codebase. These lambdas are actual slots in my Worker object living in another thread. I'm sending Command Objects to said Worker, whose execution functions contain the functionality of the demod lambdas.

                    It doesn't work either when i remove the use of the readyRead signal.

                    So you mean I can't use waitForReadyRead within a slot?
                    I have a couple other Serial Devices handled in the same manner and it works like intended. It's just that this particular sensor is responding too quick.

                    K 1 Reply Last reply
                    0
                    • InTheBeningingI InTheBeninging

                      @Christian-Ehrlicher @J-Hilk @jsulm
                      I'm sorry I didn't clear this up, the given code is just a demo stripped off of my codebase. These lambdas are actual slots in my Worker object living in another thread. I'm sending Command Objects to said Worker, whose execution functions contain the functionality of the demod lambdas.

                      It doesn't work either when i remove the use of the readyRead signal.

                      So you mean I can't use waitForReadyRead within a slot?
                      I have a couple other Serial Devices handled in the same manner and it works like intended. It's just that this particular sensor is responding too quick.

                      K Offline
                      K Offline
                      kuzulis
                      Qt Champions 2020
                      wrote on last edited by kuzulis
                      #10

                      @InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:

                      So you mean I can't use waitForReadyRead within a slot?

                      Yes. Don't use waitForReadyRead at all. I have not ideas why the Qt (which declares as an asynch framework) provides that blocking API at all.

                      PS: You are mixing a hedgehog and a snake - the result is known. )))

                      InTheBeningingI 1 Reply Last reply
                      1
                      • InTheBeningingI Offline
                        InTheBeningingI Offline
                        InTheBeninging
                        wrote on last edited by InTheBeninging
                        #11

                        Nevermind, it does work now. It was not even being too fast, as i found out my sensor has a delay parameter which i've set to 1 second and it still didn't work.

                        Turns out it was the hardware adapter I was using, that converted the RS485 Connection to a USB COM Port. It didn't work with the cheap one (ch340), but after switching to a more expensive one (ftdi) it magically worked. Seems to be depending on their drivers.

                        1 Reply Last reply
                        0
                        • InTheBeningingI InTheBeninging has marked this topic as solved on
                        • K kuzulis

                          @InTheBeninging said in QSerialPort::waitForReadyRead() unusable for quick responses:

                          So you mean I can't use waitForReadyRead within a slot?

                          Yes. Don't use waitForReadyRead at all. I have not ideas why the Qt (which declares as an asynch framework) provides that blocking API at all.

                          PS: You are mixing a hedgehog and a snake - the result is known. )))

                          InTheBeningingI Offline
                          InTheBeningingI Offline
                          InTheBeninging
                          wrote on last edited by
                          #12

                          @kuzulis
                          Because that's exactly what this virtual function is for. In QIODevice it says "This function can operate without an event loop. It is useful when writing non-GUI applications and when performing I/O operations in a non-GUI thread."
                          So the latter part sounds exactly like what i did... I don't see why that would be bad design? Telling one not to use a function which is clearly meant to be used in a thread and completely ignoring the constraint to have a synchronous snippet/ a single function is just misleading at best.

                          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