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

QSerialPort::waitForReadyRead() unusable for quick responses

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 6 Posters 689 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.
  • I Offline
    I Offline
    InTheBeninging
    wrote on 5 Apr 2024, 08:43 last edited by InTheBeninging 4 May 2024, 08:43
    #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.

    J 1 Reply Last reply 5 Apr 2024, 08:49
    0
    • I InTheBeninging
      5 Apr 2024, 08:43

      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.

      J Online
      J Online
      jsulm
      Lifetime Qt Champion
      wrote on 5 Apr 2024, 08:49 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

      I 1 Reply Last reply 5 Apr 2024, 09:03
      1
      • J jsulm
        5 Apr 2024, 08:49

        @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).

        I Offline
        I Offline
        InTheBeninging
        wrote on 5 Apr 2024, 09:03 last edited by InTheBeninging 4 May 2024, 09:06
        #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...

        R J 2 Replies Last reply 5 Apr 2024, 09:06
        0
        • I InTheBeninging
          5 Apr 2024, 09:03

          @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...

          R Offline
          R Offline
          Ronel_qtmaster
          wrote on 5 Apr 2024, 09:06 last edited by Ronel_qtmaster 4 May 2024, 09:18
          #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

          I 1 Reply Last reply 5 Apr 2024, 09:24
          0
          • R Ronel_qtmaster
            5 Apr 2024, 09:06

            @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

            I Offline
            I Offline
            InTheBeninging
            wrote on 5 Apr 2024, 09:24 last edited by
            #5

            @Ronel_qtmaster Could you elaborate why?

            C 1 Reply Last reply 5 Apr 2024, 09:27
            0
            • I InTheBeninging
              5 Apr 2024, 09:24

              @Ronel_qtmaster Could you elaborate why?

              C Offline
              C Offline
              Christian Ehrlicher
              Lifetime Qt Champion
              wrote on 5 Apr 2024, 09:27 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
              • I InTheBeninging
                5 Apr 2024, 09:03

                @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...

                J Online
                J Online
                jsulm
                Lifetime Qt Champion
                wrote on 5 Apr 2024, 09:29 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 1 Reply Last reply 5 Apr 2024, 09:33
                1
                • J jsulm
                  5 Apr 2024, 09:29

                  @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 Offline
                  J Offline
                  J.Hilk
                  Moderators
                  wrote on 5 Apr 2024, 09:33 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
                  • I Offline
                    I Offline
                    InTheBeninging
                    wrote on 5 Apr 2024, 09:41 last edited by InTheBeninging 4 May 2024, 09:46
                    #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 5 Apr 2024, 09:48
                    0
                    • I InTheBeninging
                      5 Apr 2024, 09:41

                      @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 5 Apr 2024, 09:48 last edited by kuzulis 4 May 2024, 09:51
                      #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. )))

                      I 1 Reply Last reply 5 Apr 2024, 13:24
                      1
                      • I Offline
                        I Offline
                        InTheBeninging
                        wrote on 5 Apr 2024, 12:54 last edited by InTheBeninging 4 May 2024, 13:34
                        #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
                        • I InTheBeninging has marked this topic as solved on 5 Apr 2024, 12:56
                        • K kuzulis
                          5 Apr 2024, 09:48

                          @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. )))

                          I Offline
                          I Offline
                          InTheBeninging
                          wrote on 5 Apr 2024, 13:24 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

                          5/12

                          5 Apr 2024, 09:24

                          • Login

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