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 :
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:
My embedded device uses a MCU together with a USB Bridge from Silicon Lab :
https://www.silabs.com/interface/usb-bridges/usbxpress/device.cp2102n-gqfn28I 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()); }
-
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). -
@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.