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. Multiple serialport write in one call.
Forum Updated to NodeBB v4.3 + New Features

Multiple serialport write in one call.

Scheduled Pinned Locked Moved Solved General and Desktop
8 Posts 5 Posters 1.2k 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
    mondo
    wrote on last edited by aha_1980
    #1

    I'm writing strings to device through serial port. My function sends the same command twice with an interval of 3 seconds as following code.

    QSerialPort m_curSerial;
    //initializing process hidden
    m_curSerial.write(command);
    qDebug()<<"flush"<<m_curSerial.flush();
    qDebug()<<QDateTime::currentDateTime();
    
    QThread::sleep(3);
    m_curSerial.write(command);
    qDebug()<<"flush"<<m_curSerial.flush();
    qDebug()<<QDateTime::currentDateTime();
    

    Then I handle the byteWritten signal, only print a timestamp

    void SerialDevice::handleBytesWritten(){
        qDebug()<<"bytes written";
        qDebug()<<QDateTime::currentDateTime();
    }
    

    the output is somehow beyond expectation:

    flush true
    QDateTime(2018-11-26 16:52:55.051 
    flush true
    QDateTime(2018-11-26 16:52:58.052 
    bytes written
    QDateTime(2018-11-26 16:52:58.057 
    bytes written
    QDateTime(2018-11-26 16:52:58.057 
    read ready
    "@00FA00400000000102000040*\r"
    read ready
    "@00FA00400000000102000040*\r"
    

    Two commands are flushed at 52:55 and 52:58. But the bytesWritten signal are only emitted together after the second write finished, so are the readReay signals.

    I also tried sending more commands with longer interval , but the signals are still emitted after the last command flushes. There is a flash light on my R232 cable, it shows the commands are actually written to device at 3 second interval, It is the signals which are delayed.

    Is it just how the signals work or am I getting anything wrong? How can I catch the byteWritten and readReady signal after each succesful write?

    Any hint appreciated, Thanks

    J.HilkJ 1 Reply Last reply
    0
    • VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      1st If you need something like this you should really think about your design.

      The solution is replacing QThread::sleep(3); with

      QEventLoop waiter;
      QTimer::singleShot(3000,&waiter,&QEventLoop::quit);
      waiter.exec();
      

      The signals will be sent as soon as the control goes back to an event loop. QThread::sleep(3); blocks that loop

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      4
      • C Offline
        C Offline
        ChrisW67
        wrote on last edited by
        #3

        QSerialPort can only send when the Qt event loop is reached, which does not happen until after both write() calls are done. You will not receive bytesWritten() signals until that time.

        In general Qt QIODevice interfaces are intended to be driven in asynchronous fashion.  To get the synchronous behaviour you were expecting you probably need a waitForBytesWritten() call after each write(). Even then, it does not guarantee that the entire command has been written, just at least one byte.

        1 Reply Last reply
        4
        • M mondo

          I'm writing strings to device through serial port. My function sends the same command twice with an interval of 3 seconds as following code.

          QSerialPort m_curSerial;
          //initializing process hidden
          m_curSerial.write(command);
          qDebug()<<"flush"<<m_curSerial.flush();
          qDebug()<<QDateTime::currentDateTime();
          
          QThread::sleep(3);
          m_curSerial.write(command);
          qDebug()<<"flush"<<m_curSerial.flush();
          qDebug()<<QDateTime::currentDateTime();
          

          Then I handle the byteWritten signal, only print a timestamp

          void SerialDevice::handleBytesWritten(){
              qDebug()<<"bytes written";
              qDebug()<<QDateTime::currentDateTime();
          }
          

          the output is somehow beyond expectation:

          flush true
          QDateTime(2018-11-26 16:52:55.051 
          flush true
          QDateTime(2018-11-26 16:52:58.052 
          bytes written
          QDateTime(2018-11-26 16:52:58.057 
          bytes written
          QDateTime(2018-11-26 16:52:58.057 
          read ready
          "@00FA00400000000102000040*\r"
          read ready
          "@00FA00400000000102000040*\r"
          

          Two commands are flushed at 52:55 and 52:58. But the bytesWritten signal are only emitted together after the second write finished, so are the readReay signals.

          I also tried sending more commands with longer interval , but the signals are still emitted after the last command flushes. There is a flash light on my R232 cable, it shows the commands are actually written to device at 3 second interval, It is the signals which are delayed.

          Is it just how the signals work or am I getting anything wrong? How can I catch the byteWritten and readReady signal after each succesful write?

          Any hint appreciated, Thanks

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

          @mondo said in Mutiple serialport write in one call.:

          QSerialPort m_curSerial;
          //initializing process hidden
          m_curSerial.write(command);
          qDebug()<<"flush"<<m_curSerial.flush();
          qDebug()<<QDateTime::currentDateTime();

          QThread::sleep(3);
          m_curSerial.write(command);
          qDebug()<<"flush"<<m_curSerial.flush();
          qDebug()<<QDateTime::currentDateTime();

          For the love if ..
          Do NOT use QThread::sleep if you can avoid it!


          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.

          M 1 Reply Last reply
          4
          • J.HilkJ J.Hilk

            @mondo said in Mutiple serialport write in one call.:

            QSerialPort m_curSerial;
            //initializing process hidden
            m_curSerial.write(command);
            qDebug()<<"flush"<<m_curSerial.flush();
            qDebug()<<QDateTime::currentDateTime();

            QThread::sleep(3);
            m_curSerial.write(command);
            qDebug()<<"flush"<<m_curSerial.flush();
            qDebug()<<QDateTime::currentDateTime();

            For the love if ..
            Do NOT use QThread::sleep if you can avoid it!

            M Offline
            M Offline
            mondo
            wrote on last edited by
            #5

            @VRonin @ChrisW67 @J-Hilk

            Thanks for replying.
            So the key issue is the event loop. This code piece is a simplifed piece for finding the problem. The real stuff I needed was an independent thread which send the same command to my device all the time.

            void Scheduler::targetReadyCheck(){
                std::thread initThread(&Scheduler::targetReadyCycle, this);
                initThread.detach();
            }
            
            void Scheduler::targetReadyCycle(){
                bool isReady;
                while(true){
                    isReady = plc->checkTargetReady();
                    }
                }
            }
            

            The checkTargetReady() function contains the code I posted above which write to the serial port. I found the commands are written but no signal emitted. Then I came to the simplied code to locate the issue.

            Now I'm changing Qthread:sleep to QTimer, and trying methods to trigger the event loop.
            Will post the results later and close the question.
            Thanks again.

            aha_1980A 1 Reply Last reply
            0
            • VRoninV Offline
              VRoninV Offline
              VRonin
              wrote on last edited by
              #6

              Even worse. using a while(true) prevents ever reaching the event loop

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              2
              • M mondo

                @VRonin @ChrisW67 @J-Hilk

                Thanks for replying.
                So the key issue is the event loop. This code piece is a simplifed piece for finding the problem. The real stuff I needed was an independent thread which send the same command to my device all the time.

                void Scheduler::targetReadyCheck(){
                    std::thread initThread(&Scheduler::targetReadyCycle, this);
                    initThread.detach();
                }
                
                void Scheduler::targetReadyCycle(){
                    bool isReady;
                    while(true){
                        isReady = plc->checkTargetReady();
                        }
                    }
                }
                

                The checkTargetReady() function contains the code I posted above which write to the serial port. I found the commands are written but no signal emitted. Then I came to the simplied code to locate the issue.

                Now I'm changing Qthread:sleep to QTimer, and trying methods to trigger the event loop.
                Will post the results later and close the question.
                Thanks again.

                aha_1980A Offline
                aha_1980A Offline
                aha_1980
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @mondo

                You should probably have a look at the http://doc.qt.io/qt-5/qtserialport-cwriterasync-serialportwriter-cpp.html example

                Qt has to stay free or it will die.

                1 Reply Last reply
                3
                • M Offline
                  M Offline
                  mondo
                  wrote on last edited by mondo
                  #8

                  Alright.
                  Here is my conclusion:

                  First, "you should never ever block the event loop"

                  Second, use timer to call functions repeatively to replace an infinite loop

                  concluded from replies above and this post [https://stackoverflow.com/questions/17514890/qthread-event-loop-and-infinite-work-loop](link url)

                  For now Qtimer solves my problem.
                  Thanks all for replying

                  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