PDA

View Full Version : No readyRead() signal from SerialPort, but (seemingly) same code works in another app



davethomaspilot
24th September 2013, 16:24
I've been using the QtSerialPort add-on with no issues for about 9 months in one application. But, when I use what I think is the same code in another application, I don't get the readyRead() signal when bytes have been sent to the serial port.

I'm stuck on how to debug why it's not firing.

No message is issued when the connect statement is executed. When I have a typo in a signal or slot name, I've seen error messages. So, I think that means the connect was ok.

The open on the port succeeds along with configuration of the communication parameters, but a breakpoint on the first line of readData is never hit. Here's the relevant code:

in main.h:


class MainWindow : public QMainWindow, public Ui_MainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent=0);
SerialPort *serial;
...
private slots:
void writeData(const QByteArray &data);
void readData();
...
}


in main.cpp:


MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);

....
serial = new SerialPort(this);


if (serial_port_settings->setCurrentPort("COM47"))
openSerialPort();

QObject::connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));

}
void MainWindow::openSerialPort()
{

SettingsDialog::Settings p = serial_port_settings->settings();

serial->setPort(p.name);
if (serial->open(QIODevice::ReadWrite)) {
if (serial->setRate(p.rate)
&& serial->setDataBits(p.dataBits)
&& serial->setParity(p.parity)
&& serial->setStopBits(p.stopBits)
&& serial->setFlowControl(p.flowControl)) {


statusbar->showMessage(tr("Connected to %1 : %2, %3, %4, %5, %6")
.arg(p.name).arg(p.stringRate).arg(p.stringDataBit s)
.arg(p.stringParity).arg(p.stringStopBits).arg(p.s tringFlowControl));

} else {
serial->close();
QMessageBox::critical(this, tr("Error"),
tr("Can't configure the serial port: %1,\n"
"error code: %2")
.arg(p.name).arg(serial->error()));

statusbar->showMessage(tr("Open error"));
}
} else {
QMessageBox::critical(this, tr("Error"),
tr("Can't opened the serial port: %1,\n"
"error code: %2")
.arg(p.name).arg(serial->error()));

statusbar->showMessage(tr("Configure error"));
}
}


void MainWindow::readData()
{
...
}




I can run the old application that has the same code fragments and use the same method to send characters to the serial port. It still works fine.

More info--

The new application uses openCv with a Qt enhancement. cvWaitKey() is called periodically instead of entering an event loop using exec().

This has worked fine. The GUI is still responsive when the serial port should have received characters, yet no readyRead signal is generated. Is the fact that the GUI is still responsive (and my widget to widget signal/slots are working) sufficient to conclude the event loop isn't "broken", or is the mechanism somehow different for SerialPort?

Any suggestions would be greatly appreciated!

Windows 7

Thanks,

Dave Thomas

Added after 21 minutes:

I did a hack to my code and inserted a call to exec() before the main thread executed the loop with the cvWaitKey(10) command in it. The readyRead signal is issued!

So, it's definitely has something to do with the eventLoop processing.

Eventually, I need to rewrite the application to not use the Qt bolt-on that's and "experimental" bolt-on to openCv, but that's a big effort. Meanwhile, I'd like to get the SerialPort stuff working while using cvWaitKey().

So, I guess the question becomes what's magic about exec() that's not under cvWaitKey(). I'll try finding source for both.

Dave Thomas

davethomaspilot
24th September 2013, 16:55
Added a call to QApplication::processEvents() right after the cvWaitKey(10) and everything works fine!

I thought that's what the cvWaitKey did (among other things). And I don't understand why all my widgets were working fine, if the cvWaitkey wasn't calling processEvents or doing something equivalent.

It works, but I want to understand better. So, I need to find the cvWaitKey source (with the Qt bolt experimental stuff), I guess unless someone smarter than me has a clue.

Dave Thomas

ChrisW67
24th September 2013, 21:54
cvWaitKey() does exactly that, it waits for up to x milliseconds for a keypress, then continues. cvWaitKey is part of OpenCV, it has nothing to do with Qt's event processing (or Qt at all). If you want the source for cvWaitKey() OpenCV is where you need to look.

If Qt's event processing code is never executed then nothing is checking for bytes received, timers expired, and other events before translating these things into Qt events and signals. You can probably dispense with cvWaitKey() altogether using the Qt key press events on approrpiate widgets.

davethomaspilot
25th September 2013, 13:30
it has nothing to do with Qt's event processing (or Qt at all).

I don't think that's true, when you build OpenCv with Qt support ( the symbolic HAVE_QT is defined) to get this function:

http://docs.opencv.org/modules/highgui/doc/qt_new_functions.html

Before I really got "on board" with Qt, I was using openCv with their simple Gui functionality. This was a big enhancement, so I used it. I needed a much better Gui, and this enhancement got me looking at Qt. Later, I got better at Qt and have done many widgets and dialogs. All work fine--I think the only way events could get processed are calls to the cvWaitKey() function, since QApplication::exec() never gets called.

I think I read that when you build OpenCv with Qt support, cvWaitKey() causes the event processing to occur. I'm still looking for where I read that, but certainly all the widgets work just fine without running an exec and only calling the cvWaitKey. And the gui becomes non-responsive if cvWaitKey is not executed periodically. Also, still trying to find the source for cvWaitKey() in openCv. I'll update the thread when I find it, for the benefit of anyone else who's gone down this path. But the trhead probably belongs on the OpenCv forum, not here, because if my guess is correct, cvWaitKey() at least sometimes doesn't seem to cause Qt events to be processed.

Dave Thomas

Added after 11 minutes:

Here's the source for cvWaitKey in the openCV tree (higui/src/window_Qt.cpp) Note the call to processEvents()





CV_IMPL int cvWaitKey(int delay)
{
int result = -1;

if (!guiMainThread)
return result;

unsigned long delayms = delay <= 0 ? ULONG_MAX : delay; //in milliseconds

if (multiThreads)
{
mutexKey.lock();
if (key_pressed.wait(&mutexKey, delayms)) //false if timeout
{
result = last_key;
}
last_key = -1;
mutexKey.unlock();
}
else
{
//cannot use wait here because events will not be distributed before processEvents (the main eventLoop is broken)
//so I create a Thread for the QTimer

if (delay > 0)
guiMainThread->timer->start(delay);

//QMutex dummy;

while (!guiMainThread->bTimeOut)
{
qApp->processEvents(QEventLoop::AllEvents);

if (!guiMainThread)//when all the windows are deleted
return result;

mutexKey.lock();
if (last_key != -1)
{
result = last_key;
last_key = -1;
guiMainThread->timer->stop();
//printf("keypressed\n");
}
mutexKey.unlock();

if (result!=-1)
{
break;
}
else
{
/*
* //will not work, I broke the event loop !!!!
dummy.lock();
QWaitCondition waitCondition;
waitCondition.wait(&dummy, 2);
*/

//to decrease CPU usage
//sleep 1 millisecond
#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
Sleep(1);
#else
usleep(1000);
#endif
}
}

guiMainThread->bTimeOut = false;
}

return result;
}




I'll have to figure out how to step into the cvWaitKey function while under the debugger to see if the processEvents() method gets called.

ChrisW67
25th September 2013, 22:52
Well it certainly won't be called if the global "multiThreads" is true. Perhaps that is easier to check?

davethomaspilot
26th September 2013, 07:54
Good suggestion, but the debugger doesn't know about multiThreads:

multiThreads CXX0017: Error: symbol "multiThreads" not found

Unfortunately, VS2010 can't find the .pdb it needs for source line debugging:

"Loaded 'C:\OpenCV\builds\install\bin\opencv_highgui240d.d ll', Cannot find or open the PDB file"

I guess it needs that file for globals too. I found the pdb and copied it to the same directory as the dll, but VS still couldn't find it. So, I'll need to figure out where it needs to be or how to tell VS to look in the right directory.

It is a multi-threaded application. However, all GUI interaction is on the main thread. There are separate threads for each of two cameras and windows thread sync mechanisms like WaitForMultipleObjects, ReleaseSemaphore, and ReleaseMutex are used to keep everything thread safe (I didn't know enough Qt to use the framework supplied threading objects when I wrote the code).

But, I think processEvents must be getting called at least some of the time, since everything but the SerialPort signal/slot worked and still works fine without the the added processEvents call. The Qt widgets and dialog remain responsive if and only if cvWaitKey is called periodically. Adding the "extra" processEvents() makes the SerialPort code work too.

That's why I'm so confused.

Dave Thomas

Added after 53 minutes:

VS doesn' thing my pdb file matches the dll:

Under Modules Symbol load information:
C:\OpenCV\builds\bin\Debug\opencv_highgui240d.pdb: PDB does not match image.

No clue why. I see the timestamp is about 5 hours later on 5/23 2012 for the pdb. That's way too long ago to remember the bizillion steps it took to build openCv.

I think I'll have to rebuild to step into the OpenCV code and/or see its symbols. I want to do that, since where there's smoke...

I just don't have time to do right now--need to get more code done.

Thanks for the replies.

Dave THomas