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 troubles on Windows 10

QSerialPort troubles on Windows 10

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 4 Posters 3.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.
  • G gav007

    @aha_1980

    Ooops ! Right. The waitForBytesWritten call was originally not present. It has been added during the investigation phase.
    That's also the reason why I do not believe to have hit the mentionned bug (however, I will update my Qt environment and check again).
    The provided code is simplified. The error management has been removed for the presentation. And no error is raised.
    In Linux I also often used the QSerialPort class without any trouble. This is the 1st time I use it with the Windows 10 OS. By the way, I will check this code in Linux ...
    Could the MinGW development kit be incriminated ?

    Many thanks for the help !

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

    @gav007 said in QSerialPort troubles on Windows 10:

    This is the 1st time I use it with the Windows 10 OS. By the way, I will check this code in Linux ...

    Yes, please do to isolate the issue.

    Could the MinGW development kit be incriminated ?

    I think not ... but maybe @kuzulis has an idea?

    Qt has to stay free or it will die.

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

      @gav007 ,

      Try to do a simple loopback test at first (just connect the RX and TX pins).

      1 Reply Last reply
      1
      • G Offline
        G Offline
        gav007
        wrote on last edited by
        #6

        Unfortunately it did not work under Linux either (Ubuntu 18.04 + Qt 5.9.5). That's weird !
        Error and symptoms are identical.

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

          This means that an issue somewhere in your code or your HW.

          1 Reply Last reply
          0
          • G Offline
            G Offline
            gav007
            wrote on last edited by
            #8

            The trouble appears on 2 different HW. Hence the HW should not be at fault.
            I would rather point the SW. Here is the full class code :

            #ifndef OPLUSCOMM_H
            #define OPLUSCOMM_H
            
            #include <QObject>
            #include <QSerialPort>
            
            
            class OctoPlusComm : public QSerialPort
            {
            
                Q_OBJECT
            
            signals:
            
                void dataRead( const QByteArray & data );
                void dataSent( const QByteArray & data );
            
                void newCommunicationStep( const QString & step );
            
            public:
            
                struct Settings {
                    QString name;
                    qint32 baudRate;
                    QString stringBaudRate;
                    QSerialPort::DataBits dataBits;
                    QString stringDataBits;
                    QSerialPort::Parity parity;
                    QString stringParity;
                    QSerialPort::StopBits stopBits;
                    QString stringStopBits;
                    QSerialPort::FlowControl flowControl;
                    QString stringFlowControl;
                    bool localEchoEnabled;
                };
            
                enum CommunicationStep {
                    IdleStep,
                    StartCommandStep,
                    ROMVersionStep,
                    EEPROMSizeStep,
                    RAMSizeStep,
                    UploadStep
                };
            
                OctoPlusComm(QObject * parent = nullptr);
                virtual ~OctoPlusComm();
            
                bool openPort( const Settings & settings );
            
                static const QString stepText( const CommunicationStep step );
            
            private slots:
            
                void readAll();
            
            private:
            
                void nextStep();
                void setCommunicationStep( const CommunicationStep step );
                bool checkReception();
                bool checkStartCommand();
                bool checkRomVersion( QByteArray & frame );
                bool checkEepromSize( QByteArray & frame );
                bool checkRamSize( QByteArray & frame );
                bool uploadInProgress();
            
            private:
            
                CommunicationStep mCommStep;
            
                QByteArray mReceptionBuffer;
            
            };
            
            #endif // OPLUSCOMM_H
            

            With the implementation :

            OctoPlusComm::OctoPlusComm(QObject * parent) : QSerialPort(parent), mCommStep(IdleStep)
            {
                connect(this, &OctoPlusComm::readyRead, this, &OctoPlusComm::readAll);
            }
            
            OctoPlusComm::~OctoPlusComm() {}
            
            bool OctoPlusComm::openPort( const Settings & settings )
            {
                setPortName(settings.name);
                setBaudRate(settings.baudRate);
                setDataBits(settings.dataBits);
                setParity(settings.parity);
                setStopBits(settings.stopBits);
                setFlowControl(settings.flowControl);
                if ( !open(QIODevice::ReadWrite) ) {
                    setErrorString("Failed to open serial port");
                    emit errorOccurred(QSerialPort::OpenError);
                    return false;
                }
                mCommStep = IdleStep;
                mReceptionBuffer.clear();
                return true;
            }
            
            void OctoPlusComm::readAll()
            {
                qDebug() << "Ready to read";
            
                QByteArray newData = QSerialPort::readAll();
                mReceptionBuffer.append(newData);
            
                emit dataRead( newData );
            
                if ( checkReception() )
                {
                    nextStep();
                }
            }
            
            void OctoPlusComm::nextStep()
            {
                bool bOk = true;
                QByteArray nextFrame;
                nextFrame.clear();
                bOk = checkStartCommand() || checkRomVersion( nextFrame ) || checkEepromSize( nextFrame ) ||
                        checkRamSize( nextFrame ) || uploadInProgress();
                mReceptionBuffer.clear();
                if ( bOk )
                {
                    if ( nextFrame.isEmpty() )
                    {
                        nextFrame.append(COMM_RECEIVE_OK);
                        nextFrame.append(COMM_REC_OK_CHECKSUM);
                        nextFrame.append(COMM_FRAME_END);
                        qDebug() << "Ack reception";
                    }
                    write( nextFrame );
                    emit dataSent( nextFrame );
                }
                else
                {
                    QByteArray request;
                    request.append(mReceptionBuffer.at(1));
                    request.append(mReceptionBuffer.at(2));
                    setErrorString(tr("Unknown request : %1").arg(Utility::displayBuffer(request)));
                    emit errorOccurred(QSerialPort::UnknownError);
                }
            }
            
            void OctoPlusComm::setCommunicationStep( const CommunicationStep step )
            {
                mCommStep = step;
                emit newCommunicationStep( stepText( mCommStep ) );
            }
            
            bool OctoPlusComm::checkReception()
            {
                if (mReceptionBuffer.size() > 0)
                {
                    if ( mReceptionBuffer.endsWith(0x0D) )
                    {
                        qDebug() << "Reception complete";
                        int n = mReceptionBuffer.lastIndexOf('#');
                        if ( n > 0 )
                        {
                            mReceptionBuffer.remove(0, n);
                            qDebug() << "Reception cleaned (" << n << ") : " << Utility::displayBuffer(mReceptionBuffer);
                        }
                        return true;
                    }
            
                    qDebug() << "Reception incomplete";
                }
                else
                {
                    qDebug() << "Empty reception !";
                }
                return false;
            }
            
            bool OctoPlusComm::checkStartCommand()
            {
                if ( mReceptionBuffer.startsWith('#') &&
                     (mReceptionBuffer.indexOf(COMM_START_COMMAND, 1) == 1) )
                {
                    qDebug() << "Start command received";
                    setCommunicationStep( StartCommandStep );
                    return true;
                }
            //    setErrorString(tr("Expect start command, received %1").arg(Utility::displayBuffer(mReceptionBuffer)));
            //    emit errorOccurred(QSerialPort::UnknownError);
                return false;
            }
            
            bool OctoPlusComm::checkRomVersion( QByteArray & frame )
            {
                if ( mReceptionBuffer.startsWith('#') &&
                     (mReceptionBuffer.indexOf(COMM_ROM_VERSION_COMMAND, 1) == 1) )
                {
                    qDebug() << "ROM version request";
                    setCommunicationStep( ROMVersionStep );
            
                    frame.append(COMM_RECEIVE_OK);
                    frame.append(COMM_ROM_VERSION_RESPONSE);
                    frame.append(COMM_FRAME_END);
                    return true;
                }
                return false;
            }
            
            bool OctoPlusComm::checkEepromSize( QByteArray & frame )
            {
                if ( mReceptionBuffer.startsWith('#') &&
                     (mReceptionBuffer.indexOf(COMM_EEPROM_SIZE_COMMAND, 1) == 1) )
                {
                    qDebug() << "EEPROM size request";
                    setCommunicationStep( EEPROMSizeStep );
            
                    frame.append(COMM_RECEIVE_OK);
                    frame.append(COMM_EEPROM_SIZE_RESPONSE);
                    frame.append(COMM_FRAME_END);
                    return true;
                }
                return false;
            }
            
            bool OctoPlusComm::checkRamSize( QByteArray & frame )
            {
                if ( mReceptionBuffer.startsWith('#') &&
                     (mReceptionBuffer.indexOf(COMM_RAM_SIZE_COMMAND, 1) == 1) )
                {
                    qDebug() << "RAM size request";
            
                    setCommunicationStep( RAMSizeStep );
            
                    frame.append(COMM_RECEIVE_OK);
                    frame.append(COMM_RAM_SIZE_RESPONSE);
                    frame.append(COMM_FRAME_END);
                    return true;
                }
                return false;
            }
            
            bool OctoPlusComm::uploadInProgress()
            {
                if ( mReceptionBuffer.startsWith('#') &&
                     (mReceptionBuffer.indexOf(COMM_UPLOAD_COMMAND, 1) == 1) )
                {
                    qDebug() << "Upload data";
            
                    setCommunicationStep( UploadStep );
            
                    return true;
                }
                return false;
            }
            
            const QString OctoPlusComm::stepText( const CommunicationStep step )
            {
                switch ( step )
                {
                case IdleStep:          return tr("Idle");
                case StartCommandStep:  return tr("Start command");
                case ROMVersionStep:    return tr("ROM version check");
                case EEPROMSizeStep:    return tr("EEPROM size check");
                case RAMSizeStep:       return tr("RAM size check");
                case UploadStep:        return tr("Data upload");
                }
                return tr("???");
            }
            

            Does anyone see what I would do wrong ?
            Many thanks for any support.

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

              As I sad before, you should to create a simple loopback test at first, to make sure that all data transferred/received. Because nobody will be check your code.

              1 Reply Last reply
              0
              • G Offline
                G Offline
                gav007
                wrote on last edited by
                #10

                I wrote the loopback test. As expected it worked. The reported ticket is related to a timing issue. The loopback test has nothing to do with this. I lost my time.

                I added some delay measurements (OK, it's intrusive but at least, it gives some clues) and observe a delay of about 10 msec between the write operation and the reception of the bytesWritten signal and sometimes a delay of the same level between the readAll call and the write operation. Those delays are observed even if the signals are emitted after the read/write operations.
                If a remove all the emitted signals, those delays are no more observed. The communication is then successful.
                I then check what is done with the dataRead and the dataSent signals : these are only display operations in QPlainTextEdit widget :

                mTextConsole->insertPlainText( QString(data) );
                
                mHexConsole->insertPlainText( QString(data.toHex(' ')) );
                

                This should not justify 10 msec delays.

                So. Since I could not reach a good confidence level with QSerialPort, I abandoned the Qt framework for JAVA. Now I got my solution. In consequence this ticket can be closed for me.

                This is my first disappointing experience with Qt ! Too bad !

                Thanks for the support.
                Best regards.

                J.HilkJ 1 Reply Last reply
                0
                • G gav007

                  I wrote the loopback test. As expected it worked. The reported ticket is related to a timing issue. The loopback test has nothing to do with this. I lost my time.

                  I added some delay measurements (OK, it's intrusive but at least, it gives some clues) and observe a delay of about 10 msec between the write operation and the reception of the bytesWritten signal and sometimes a delay of the same level between the readAll call and the write operation. Those delays are observed even if the signals are emitted after the read/write operations.
                  If a remove all the emitted signals, those delays are no more observed. The communication is then successful.
                  I then check what is done with the dataRead and the dataSent signals : these are only display operations in QPlainTextEdit widget :

                  mTextConsole->insertPlainText( QString(data) );
                  
                  mHexConsole->insertPlainText( QString(data.toHex(' ')) );
                  

                  This should not justify 10 msec delays.

                  So. Since I could not reach a good confidence level with QSerialPort, I abandoned the Qt framework for JAVA. Now I got my solution. In consequence this ticket can be closed for me.

                  This is my first disappointing experience with Qt ! Too bad !

                  Thanks for the support.
                  Best regards.

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

                  @gav007
                  I don't think, that 20 ms to create a QString from raw data and than inserting it to a plain textview + (eventual) repaint of the the ui is totoally unreasonable. Especially, if you're using the old (qt4) styled syntax for QObject::connect. Those come with a noticeable overhead during execution.

                  This is the reason why I usually move my IO-communication in its own thread.
                  That said, giving your connects a 5th parameter Qt::QueuedConnection may already be enough to make your Qt-solution workable.


                  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
                  1
                  • K Offline
                    K Offline
                    kuzulis
                    Qt Champions 2020
                    wrote on last edited by
                    #12

                    @gav007 said in QSerialPort troubles on Windows 10:

                    observe a delay of about 10 msec between the write operation and the reception of the bytesWritten signal

                    Your words is empty without of a real example. In my case I got an expected delay in this example:

                    #include <QCoreApplication>
                    #include <QSerialPort>
                    #include <QElapsedTimer>
                    #include <QDebug>
                    
                    int main(int argc, char *argv[])
                    {
                        QCoreApplication a(argc, argv);
                    
                        QSerialPort sp("COM1");
                    
                        // it opens with 9600 bauds by default
                        if (!sp.open(QIODevice::ReadWrite))
                            return 0;
                    
                        QElapsedTimer et;
                    
                        auto write = [&]() {
                            et.start();
                            QByteArray ba(256, 0);
                            sp.write(ba);
                        };
                    
                        QObject::connect(&sp, &QSerialPort::bytesWritten, [&](qint64 bytes) {
                            qDebug() << et.elapsed();
                            write();
                        });
                    
                        write();
                    
                        return a.exec();
                    }
                    

                    It printed out:

                    265
                    265
                    266
                    266
                    265
                    

                    that is right, because according to this calculation, the expected delay should be:

                    baudrate = 9600 bits per second
                    bytes per second = 9600 / (1start bit + 8 data bits + 1 stop bit) = 960 bytes per second
                    256 bytes in seconds = 256 / 960 = 0.266(6)

                    • If I try to send ~10 bytes, then I got ~10 msecs. It is true.
                    • if I try to send ~1 byte, then I got ~0-1 msec. It is true.

                    So, I don't know what are you talking about.

                    1 Reply Last reply
                    1
                    • G Offline
                      G Offline
                      gav007
                      wrote on last edited by
                      #13

                      @kuzulis said in QSerialPort troubles on Windows 10:

                      Because nobody will be check your code.

                      @kuzulis said in QSerialPort troubles on Windows 10:

                      Your words is empty without of a real example

                      How surprising you can be !

                      Again, if you read my post, I'm more worried about the 10 msec for 2 insertions in QPlainTextEdit widget than the delay between the write operation and the bytesWritten signal.
                      Where you're right, I did not mention the size of the handled buffer : it varies between 4 and 12 bytes. Not enough to spend 10 msec for sending !

                      So @kuzulis, do not worry about my problem. I'm sure there will be people on this forum willing to help me. Thanks.

                      @J-Hilk ,
                      Thanks for this remark. I would not expect the QSerialPort signals to be managed in the same thread as the GUI elements. Hence using the default AutoConnection type should make the difference. However, I forced all the connections between the QSerialPort object and the GUI elements to be queued and unfortunately the behavior remains the same.

                      Best regards

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

                        @gav007 said in QSerialPort troubles on Windows 10:

                        it varies between 4 and 12 bytes. Not enough to spend 10 msec for sending !

                        Again, your words is empty. I already have provided the test above, you can try it with your HW, with your baudrate && data length.

                        @gav007 said in QSerialPort troubles on Windows 10:

                        do not worry about my problem

                        I'm do not worry, good luck!

                        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