QT 5.8.0 Serial Problems when reading and writing to a serial port connected to itself
-
Hello, I'm attempting to use QT to write a message to a serial port and read the message. I have a SBT-USC1M Usb to serial adapter, I've connected ports 2 and 3 such that sending information will just be read back in the same port.
I have a QT application which already opens a serial port with user specified information via QT gui. This works on a real hardware and I don't have any problems with it from that perspective, however I'm only reading data there.
I've added code after verifying that the port is open that looks like this with the marked output:
QString tstring = "AAAAAAA"; tstring.append("\0"); QByteArray ba = tstring.toLocal8Bit(); m_serial->write(ba); if (m_serial->waitForBytesWritten(1000)) { qDebug() << m_serial->bytesAvailable(); if (m_serial->waitForReadyRead(1000)) { QByteArray arr = m_serial->read(1); qDebug() << arr; //error handling afterwards... ---OUTPUT--- 0 ""
Device manager says my device has the following properties:
BPS 9600,
Databits 8,
Parity none,
stop bits 1,
flow control None,
port name COM4,Using the following code in Python pyserial,
#!/usr/bin/ import serial def main(): print('hello') serialport = serial.Serial('COM4', 19200, timeout=1) serialport.write(b'hello') s = serialport.read(6) print(s) serialport.close() pass if __name__ == "__main__": main()
results in:
hello b'hello'
So clearly this is not a hardware problem, Additionally its not like the port isn't getting the data, when iviewing m_serial d_ptr in debugmode, the following is shown after the timeout fails for waitReadyForRead()
>readChunkBuffer "AAAAAAA\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"... (512)
Am I missing something here? scouring google, SO, and even QT forums have not turned up relevant solutions, and turned up troubling information about QT's checkered past with regression bugs being introduced that stop this sort of thing from happening.
-
This problem does not appear to exist when the code provided exists as its own context not inside a thread. There must be a setting done to the port that makes it so it can't read properly, this lead me to look through the original source and find out if the normal read call for other functionality not even present was still being called on a hunch. It turns out that by adding a callback to readyRead() for the serial port, It would only call this other callback function, and reset the "readyRead()" flag even if nothing happened to read.
I'm marking this as solved now, to reiterate, because I attached the callback for readyRead() to another function, any other serialized functionality outside of readyRead() could no longer function as if the serial port was ready to be read from because the flag for readyRead() event inside the QSerialPort object is automatically set to false.
I'm not sure QT should be doing 'magic' things like that with out the users explicit invocation of such actions, reeks of bad code smell.
-
Hi and welcome to devnet,
Technically you main function has several flows. You don't create a QApplication or QCoreApplication for that matter thus the Qt internals are not setup like they should.
Then you don't use
waitForReadyRead
which is the way to do things if you have to wait for a while.Just calling
read(6)
like that doesn't guarantee that you get 6 bytes. -
what I posted was not full compilable code, merely a small piece that is called inside a much larger program, as such it does not have the issues you mentioned, a QAapplication is created in a main source file, where this isn't located (its inside the logic for a custom QT thread).
Also I do use waitForReadyRead? (or at least I did) or did you mean to not use it?
Just calling read(6) like that doesn't guarantee that you get 6 bytes.
that was not the issue, the issue was what I explained above, nothing was being read despite the readbuffer containing all the data I sent (hence why I put that in the original post) and this was because the flag in order to start a read was being overwritten after readyRead() was called. At this point I'm even having issues with that, I can now read it, but it seems to miss bytes, under normal conditions QT works fine and reads serial normally with this configuration, but the code I'm working with isn't something I made.
Is it normal practice to attach another function as a callback to readyRead() event?
-
@pitr said in QT 5.8.0 Serial Problems when reading and writing to a serial port connected to itself:
Is it normal practice to attach another function as a callback to readyRead() event?
Well its more normal to use a signal to say "DATA READY" for another thread to process the data.
A plain call back would not work across threads in same elegant way but if you are only using it
as a reset thing from same thread , it should be ok.Its funny/odd you have such issues in 5.8 as i actually tested Serial class in 5.6 using a bridged setup as u mentioned and i left to run on
linux box for 3 weeks transferring a little above 1.2 TB over the class with no data loss. ( using checksums)I wondering how you do the bridged setup ? I was using a real wire to loop it.
-
currently what is happening is that normal processing for data that would normally come from an external device (not the same port) is being handled in a single thread (but user defined) where the readyRead() event is linked to a callback function within the same thread within that thread. This callback appears to be causing data loss in software (since debugging, the python program, and normal usage of serial ports within QT itself does not actually show this issue).
I've since 'fixed' this issue by calling waitForReadyRead() when the number of bytes available is less than expected. I believe the callback causes a loss of readyRead() events some how when trying to process directly with out waiting for all the data.
Its funny/odd you have such issues in 5.8 as i actually tested Serial class in 5.6 using a bridged setup as u mentioned and i left to run on
linux box for 3 weeks transferring a little above 1.2 TB over the class with no data loss. ( using checksums)You misunderstand me, there is absolutely no hardware problem, as I've demonstrated time and time again, there is absolutely no known problem with following QT examples on how to accomplish serial communication, or using pyserial, or when looking inside the buffers in debugmode, the problem only occurs when using the readyRead() attached to a callback. In this configuration the string (now changed)
I am using a real wire to wire pins 2 and 3."ABCDEFG"
will come out as anything from:
"ABCF"
to
"ABEG"
and
"ABCFG"
the code now looks as follows:
connect(m_serial, &QSerialPort::readyRead, this, &MyThread::readyReadCallback); ... void MyThread::somefunction(...){ ... m_serial->write("ABCDEFG"); ... } void MyThread::readyReadCallback(){ if(m_serial->bytesAvailable() < num_bytes_needed){ m_serial->waitForReadyRead(10); } else{ ... read the data } }
this consistently gets me the correct results, but is an awkward solution for an awkward design decision the original author made.
-
Ah I see. Most of the time I just call other function from
readyRead slot so im not sure how that would be different from a callback, but I guess that
whatever this callback made happen it must be related to using multiple threads.
I cant however see why it should skip/miss some chars if the callback does as normally with buffer+=incoming until enough been read.