hyOzd/serialplot

Receive buffer empty

MatejMozek opened this issue · 8 comments

Hi,

I've built serialplot 10.0.0 for Raspberry PI 3 using QtCreator 5.15.2. Builds fine, demo mode works as expected. However, I don't seem to get any data from tty/dev/acm0, when I connect my STM32F303 board (CDC class USB device). The STM32F303 board is sending some tab delimited integer values in format 1234\t2345\r\n. Port (tty/dev/acm0) works ok - if I set the same configuration on Putty, data is displayed is correct format. In both cases data transfer is ASCII, 8 bits, 1 stop, no parity, no flow control.

When I set the breakpoint on start of AsciiReader::ReadData, _device->canReadLine() always skips the while loop (as if it never read a \n terminator). If I add _device->bytesAvailable() before that call, it reports some non-zero number of bytes (differs, but larger than one line of received data). If I do peek/read/readall the QIODevice buffer, the buffer always reads zero. A call to
_device->isSequential() returns true.

In order to exclude any Qt environment related errors, I've also built the "Command Line Reader Async Example" (which uses ReadAll function on QSerialPort) and this works fine: Buffer stores and prints out values as expected.

Best regards,

Matej Možek

hyOzd commented

@MatejMozek thanks for creating a detailed ticket with debug information : )

We don't really have version 10.0.0. Latest version is 0.12.0. But I recommend just building the latest commit. Regardless the pieces of code that is related to your problem, probably didn't change recently.

Because I don't have a raspi at hand, I can only to guide you on how to debug the issue further.

First of all have you tried building the same code on PC (with same Qt version) and testing it there? This would quickly rule out a serialplot related issue and point to the platform support of Qt.

From your description I understand that unsigned AsciiReader::readData() is continuously being called, right?

So you are saying that bytesAvailable() displays a positive number but an immediate call after that returns empty array. Maybe we can see an error code from that. Can you dump error() and errorString() from _device when that happens? Note if you cast _device to QSerialPort* first, we might get better information as the error is overloaded by the QSerialPort class.

In order to exclude any Qt environment related errors, I've also built the "Command Line Reader Async Example" (which uses ReadAll function on QSerialPort) and this works fine: Buffer stores and prints out values as expected.

Considering the debug information you provided only thing that might cause a problem from SerialPort code is what we do when opening the port. This happens inside the PortControl class. But you should be able bypass the PortControl class, create another static QSerialPort instance, pass that as the read device to the reader class, inside the constructor of mainwindow only apply the settings you want and open the port. This means UI code won't have control on how the port is opened and what settings are applied.

This is the line of code that passes the 'serial port device' to the 'reader class' (it actually passes throught dataformatpanel which selects the 'reader' class to use): https://github.com/hyOzd/serialplot/blob/master/src/mainwindow.cpp#L73

Hi,

Ah yes, the version - I seem to have skipped a "little bit" in advance. My bad. :)

In the past days, I built the Windows 10 version using Qt_5_15_2_MinGW_64_bit and qwt 6.2.0. It has some warnings, but compiles ok. If I test this version using my ST-LINK CDC device, it works flawlessly. However - my target platform is RPI, because of its low power consumption and ability to extend SerialPlot IO capability to other communication protocols (e.g. USB-HID, I2C, SPI...).

As you suggested, I inserted debug probes into AsciiReader::readData() and on AbstractReader::onDataReady() signal. As you assumed correctly - the signal triggers instantly, number of received bytes seems correct (positive, increasing with each iteration), but there is no serial buffer contents (buffer reads as many zeros as reported by number of bytes). Weird is, that the errorString reports "Unknown error" always when reporting an empty buffer.

Afterwards I compiled the Qt asynchronous receiver example, which uses connect call to ReadyRead signal. This example works as expected (reads and displays data, however the errorString still persists at "Unknown error"). This indicates that the solution to empty buffer problem perhaps lies in instantiation of SerialPort device: If the device is forcibly created a QSerialPort instance (as in the Qt async. example), entire thing will work - but this is not my goal, since I want to use dynamic changing of reader type with AbstractReader class, as currently (and correctly) implemented in SerialPlot.

So far, if I tested port opening/closing/flushing ... everything seems to work - except for the empty receive buffer. I also checked if something else would use readAll/flush the data buffer before it reached currently selected Reader - but I could not find any such instance. And if I would have found such an instance - why would the number of bytes being reported as non-zero? Weird thing is: If I run Putty and it reads the data for some time and I terminate it and start debugging SerialPlot afterwards, the receive buffer is not empty (contains last characters which Putty left in the buffer). After these bytes are processed, the buffer always reads empty.

Best regards,

Matej Možek

hyOzd commented

I still suspect this is related to one of the settings we apply to the opened port.

but this is not my goal, since I want to use dynamic changing of reader type with AbstractReader class, as currently (and correctly) implemented in SerialPlot.

If you can do it as I described in my previous post you will retain the ability to choose different 'readers'.

Let me try to summarize it a little better. There is only one QSerialPort object instance in serialplot. It is statically instanced by MainWindow. Its pointer is passed to the PortControlPanel class which opens/closes the port and adjusts the settings. It is also passed to DataFormatPanel class which connects the output of serial port to the selected 'reader'. Here is what I'm suggesting to quickly isolate PortControlPanel class and see if issue is caused by it. Create another static instance of QSerialPort in the MainWindow class and pass that one to the DataFormatPanel instance.

Ideally we should figure out the root cause and solve it. But I'm guessing that this will be difficult because your experiment with x86 platform hints that this might be a problem specific issue. These kind of issues usually come from the Qt library.

hyOzd commented

If I run Putty and it reads the data for some time and I terminate it and start debugging SerialPlot afterwards, the receive buffer is not empty (contains last characters which Putty left in the buffer). After these bytes are processed, the buffer always reads empty.

This might also support my theory that one of the settings is causing an issue. I'm guessing that those bytes are read correctly, because they were received from the device using the settings putty applied to the port. They were already in the buffer so serialplot received them correctly. But because some settings are messing up the port anything new cannot be read correctly.

hyOzd commented

Here is an example:

--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright © 2021 Hasan Yavuz Özderya
+  Copyright © 2022 Hasan Yavuz Özderya
 
   This file is part of serialplot.
 
@@ -70,7 +70,7 @@
     secondaryPlot(NULL),
     snapshotMan(this, &stream),
     commandPanel(&serialPort),
-    dataFormatPanel(&serialPort),
+    dataFormatPanel(&serialPort2),
     recordPanel(&stream),
     textView(&stream),
     updateCheckDialog(this),
@@ -78,6 +78,11 @@
 {
     ui->setupUi(this);
 
+    serialPort2.setPortName("/dev/pts/1");
+
+    serialPort2.setBaudRate(QSerialPort::Baud9600);
+    serialPort2.open(QIODevice::ReadWrite);
+
     plotMan = new PlotManager(ui->plotArea, &plotMenu, &stream);
 
     ui->tabWidget->insertTab(0, &portControl, "Port");
diff --git a/src/mainwindow.h b/src/mainwindow.h
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -1,5 +1,5 @@
 /*
-  Copyright © 2019 Hasan Yavuz Özderya
+  Copyright © 2022 Hasan Yavuz Özderya
 
   This file is part of serialplot.
 
@@ -72,6 +72,7 @@
     void setupAboutDialog();
 
     QSerialPort serialPort;
+    QSerialPort serialPort2;
     PortControl portControl;
 
     unsigned int numOfSamples;

Hi,

I tried the amendments listed above: Now the AsciiReader::readData() reads zero bytes available, serial port error is still at "Unknown error" and the receive buffer is empty. Settings are 115200, 8 bits, no parity, 1 stop bit and no flow control.

Best regards,

Matej

I do owe you an update/apology - it was the port settings all the time, just as you predicted. It seems that I hastily misread the port settings: Namely, there are namely two very similar (115200 and 1152000) standard baud rate settings in QSerialPortInfo::standardBaudRates() reported on RPI3 for ttyacm0 serial port. Guess which one I used throughout entire process. :)

Thank you for all the suggestions.

Best regards,

Matej Možek

hyOzd commented

Aaah

Well it happens 🙃

Lets consider it good debugging experience 😂