Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QSerialPort - Cannot read more than 64 bytes - Windows - CP2102



  • Hi,

    I am developing a communication interface for an industrial device using Qt.

    I have following problem :

    • I send from my PC a request to my embedded device (no problem here)
    • When receiving the request, the embedded device sends to the PC 77 bytes that holds its configuration.
    • With Qt, I receive 64 bytes only instead of the 77 expected.
    • I made a Python script and with it, I do receive the 77 bytes so I believe the problem comes from my Qt code.

    Here is my Qt code :

    #include <QCoreApplication>
    #include <QSerialPort>
    #include <QDebug>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        //
        // Serial port object.
        //
        QSerialPort *port = new QSerialPort();
    
        //
        // Prepare the port.
        //
        port->setPortName("COM8");
        qDebug() << "setBaudRate   " << port->setBaudRate(921600);
        qDebug() << "setDataBits   " << port->setDataBits(QSerialPort::Data8);
        qDebug() << "setParity     " << port->setParity(QSerialPort::NoParity);
        qDebug() << "setStopBits   " << port->setStopBits(QSerialPort::OneStop);
        qDebug() << "setFlowControl" << port->setFlowControl(QSerialPort::NoFlowControl);
        qDebug() << "open          " << port->open(QIODevice::ReadWrite);
    
        //
        // Send the request.
        //
        const char request[4] = { 0x06, 0x00, 0x02, 0x10 };
        qDebug() << "";
        qDebug() << "write" << port->write(request, 4);
        qDebug() << "waitForBytesWritten" << port->waitForBytesWritten(1000); // milliseconds
    
        //
        // Read the port.
        //
        qDebug() << "";
        qDebug() << "waitForReadyRead" << port->waitForReadyRead(1000); // milliseconds
        char answer[77];
        qint64 bytesReceived = port->read(&answer[0], 77);
    
        //
        // Close the port.
        //
        port->close();
    
        //
        // Print data.
        //
        QList<quint8> quint8Array;
        for (quint16 i = 0; i < bytesReceived; ++i)
        {
            quint8Array.append((quint8)(answer[i]));
        }
    
        qDebug() << "";
        qDebug() << "Received" << bytesReceived << "bytes";
        qDebug() << quint8Array;
    
        return a.exec();
    }
    

    The result is :

    qt_result.png

    Now, here is the Python code that works well:

    # Imports
    import sys, serial
    
    # Serial object
    ser = serial.Serial()
    
    # Configuration
    ser.port     = "COM8"
    ser.baudrate = 921600
    ser.bytesize = serial.EIGHTBITS
    ser.parity   = serial.PARITY_NONE
    ser.stopbits = serial.STOPBITS_ONE
    ser.timeout  = 1.0 # seconds
    
    # Try to open the port
    try:
        ser.open()
        is_ser_open = True
    except Exception as e:
        print ("The COM Port \"" + COM_PORT + "\" cannot be opened!")
        print ("Fix the issue and try again.")
        sys.exit()
    
    # Write
    ser.write([0x06, 0x00, 0x02, 0x10])
    
    # Read
    data = ser.read(77)
    
    # Close the port
    ser.close()
    
    # Print
    txt = "["
    for i in range(0, len(data) - 1):
        txt += str(int(data[i])) + ", "
    txt = txt[:-2] + "]"
    
    print("Received " + str(len(data)) + " bytes.")
    print(txt)
    

    And the Python result:

    python_result.png

    My embedded device uses a MCU together with a USB Bridge from Silicon Lab :
    https://www.silabs.com/interface/usb-bridges/usbxpress/device.cp2102n-gqfn28

    I am using Qt Creator with the kit Desktop Qt 5.14.1 MinGW 32 bits on a Windows 10 PC.

    Can you help me with that?

    Thank in advance,

    Guillaume



  • @Guillaume-Girardot said in QSerialPort - Cannot read more than 64 bytes - Windows - CP2102:

    //
    // Read the port.
    //
    qDebug() << "";
    qDebug() << "waitForReadyRead" << port->waitForReadyRead(1000); // milliseconds
    char answer[77];
    qint64 bytesReceived = port->read(&answer[0], 77);
    

    If you want to do it in pooling mode, I would suggest you to change the code as follow:

        //
        // Read the port.
        //
        QElaspedTimer t;
        t.start();
        QByteArray reply;
        while(repy.size() < 77 && !t.hasExpired(2000)) {
            if(port->waitForReadyRead(100))
                reply.append(port->readAll());
        }
    
    

  • Qt Champions 2019

    Use signals / slots instead waitForReadyRead() - there is no guarantee that when waitForReadyRead() finishes all of your data is already there. It my work but must not.



  • Just guessing but it looks like those last 13 bytes are lost because you began reading too fast, so you only get the first USB packet of 64 bytes.

    So either do as @Christian-Ehrlicher says above (best solution), or as a test/short-term solution, try doing a 2nd waitForReadyRead(1000) after the first, i.e. after you've printed (qdebug()) out the first 64 bytes.



  • @Guillaume-Girardot said in QSerialPort - Cannot read more than 64 bytes - Windows - CP2102:

    //
    // Read the port.
    //
    qDebug() << "";
    qDebug() << "waitForReadyRead" << port->waitForReadyRead(1000); // milliseconds
    char answer[77];
    qint64 bytesReceived = port->read(&answer[0], 77);
    

    If you want to do it in pooling mode, I would suggest you to change the code as follow:

        //
        // Read the port.
        //
        QElaspedTimer t;
        t.start();
        QByteArray reply;
        while(repy.size() < 77 && !t.hasExpired(2000)) {
            if(port->waitForReadyRead(100))
                reply.append(port->readAll());
        }
    
    


  • @Christian-Ehrlicher thanks for the help!
    Which signal(s) do you recommend to use? From the IODevice class (on which is based QSerialPort) I can see the readyRead signal, and my understanding is that the waitForReadyRead function is actually waiting for that signal. Are they other signals?
    The readyRead is triggered once data is available, but we do not know how much (that was my problem actually).


  • Qt Champions 2019

    @Guillaume-Girardot said in QSerialPort - Cannot read more than 64 bytes - Windows - CP2102:

    The readyRead is triggered once data is available, but we do not know how much

    That's why you need to read every time readyRead is triggered and accumulate the data in a buffer, until you got everything.



  • @hskoglund thanks for the help! I did not try your solution, but I guess it should work because the solution from @KroMignon works and you have the same diagnostic.


Log in to reply