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
Forum Updated to NodeBB v4.3 + New Features

QSerialPort troubles on Windows 10

Scheduled Pinned Locked Moved Unsolved General and Desktop
14 Posts 4 Posters 3.5k Views 1 Watching
  • 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