Serial connection does not work correctly with QPushbuttons - c++

void CSerialController::sl_executeCommand(const QString s_command,QString&s_result){
QMutexLocker locker(mpo_mutex);
KT_Error t_error = ERROR_NONE;
QByteArray o_serialOutput;
QString s_serialAnswer = "";
char c_serialLetter = ' ';
// Port is already open
mpo_serial->clearBuffer(); // Flush and ReadAll
t_error = mpo_serial->sendStr(s_command); //
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
while ((t_error == ERROR_NONE) && (c_serialLetter != '\n')) // Reads Serial till newline is found
{
t_error = mpo_serial->getChar(c_serialLetter); // -> checks BytesAvailable -> if no bytes available -> waitForReadyRead(1) <- This is in a Loop while given time is over(Timeouttime)
o_serialOutput.append(c_serialLetter);
}
}
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
s_serialAnswer = o_serialOutput;
s_serialAnswer.remove("\r\n");
}
s_result = s_serialAnswer; }
Im working with C++ and Qt 5.5 and i cant get the serial connection to work correctly. Im using signals to connect a QPushButton with a slot in the CSerialController class which calls this function in the same class. I tried this function with a endless while-loop and it works correctly all the time. Its just not working when i use the buttons. First time i use a button it works correctly but the second time i press a button which calls this slot, the serialport only sometimes returns a value. (Writing works just not reading) I even tried changing the Thread of this class but that didnt help aswell. If you want i can post the sendStr and getChar functions aswell but like i said they work without a problem(allready used in a lot of projects)
UPDATE: I tried using the Windows API for the serial connection = problem is gone. Seems like a problem with QSerialPort usage on an old CPU (I7-870)

Related

Why does QDialog::exec() blocks QTcpSocket work

I make a Bomberman (or DynaBlast) game clone with multiplayer. Server game and client game communicate through messages using QTcpSocket. Typical workflow for playing network game is following:
Server player execs NetworkGame dialog, among other things this dialog creates NetworkGame object
Client player execs ClientGame dialog, among other things this dialog creates ClientGame object
Client chooses IP of server and clicks "Connect"
Server accepts connections, server and clients are now able to send messages each other
Client sends "ready"-message, server start game
When game over, the game object emits GameStatusChanged(GameStatus newStatus) signal. This signal connected to MainWindow, which execs GameOverDialog. If player chooses "Play again" at GameOverDialog, MainWindow execs NetworkGame or ClientGame dialogs again and we are at the first points.
So, after first game is over, second exec of ClientGameDialog blocks QTcpSocket work in the way it cann't read data or emit QTcpSocket::readyRead signal (I don't know which one point exactly). ClientGameDialog's GUI is responsive, it can send messages to server, but it cann't read messages. At the same time NetworkGame and NetworkGameDialog work properly - they are able to send and receive messages. I checked all my classes several times and don't see any significant difference.
I think full code is to huge to post it here, so I gave UML a try. This is a chart for most important classes. Green arrow designates Qt's child-parent relations, starting at a child QObject it points to a parent.
When Socket class receives new message through QTcpSocket interface, it emits messageReceived(const Message& message) signal; other classes can connect to this signal via slots and handle messages. I don't see what Client, ServerWorker, Server classes can do with event loop, the just help to process raw data from QTcpSocket and deliver messages to other classes, particulary to Game and Dialog classes.
Here is some code (I have some code duplications, I leave them until better times). Creating game:
// Server game
void MainWindow::startNetworkGame() // User clicked "Start network game" button
{
const auto& player = mainMenuWidget_->selectedPlayer();
gameDialogs_ = createGameDialogs(this, GameType::Server, player);
auto answer = gameDialogs_.creationDialog->exec();
if (answer == QDialog::Accepted) {
auto initializationData = gameDialogs_.creationDialog->initializationData();
initializeGame(initializationData);
startGame(initializationData);
}
}
// Client game
void MainWindow::connectToServer() // User clicked "Connect to server" button
{
const auto& player = mainMenuWidget_->selectedPlayer();
gameDialogs_ = createGameDialogs(this, GameType::Client, player);
auto answer = gameDialogs_.creationDialog->exec(); // At first time it works fine
if (answer == QDialog::Accepted) {
auto initializationData = gameDialogs_.creationDialog->initializationData();
initializeGame(initializationData);
startGame(initializationData);
}
}
Next snippet is code for processing GameStatusChanged signal when game was over:
void MainWindow::gameStatusChanged(GameStatus newStatus)
{
if (newStatus == GameStatus::GameOver) {
auto* gameOverDialog = gameDialogs_.gameOverDialog;
gameOverDialog->setGameResult(gameData_.game->gameResult());
auto gameOverDialogAnswer = gameOverDialog->exec();
if (gameOverDialogAnswer == QDialog::Accepted) {
gameDialogs_.creationDialog->reset();
auto answer = gameDialogs_.creationDialog->exec(); // At this point client cann't receive messages, but server can.
if (answer == QDialog::Accepted) {
auto initializationData = gameDialogs_.creationDialog->initializationData();
initializeGame(initializationData);
startGame(initializationData);
} else {
showMainMenu();
}
} else {
showMainMenu();
}
}
}
I suspect that ClientGameDialog's event loop (is it indeed has it's own event loop) doesn't processes QTcpSocket's events. I tried to replace exec() with open methods for client dialog:
void MainWindow::gameStatusChanged(GameStatus newStatus)
{
if (newStatus == GameStatus::GameOver) {
auto* gameOverDialog = gameDialogs_.gameOverDialog;
gameOverDialog->setGameResult(gameData_.game->gameResult());
auto gameOverDialogAnswer = gameOverDialog->exec();
if (gameOverDialogAnswer == QDialog::Accepted) {
gameDialogs_.creationDialog->reset();
auto d = qobject_cast<ClientGameDialog*>(gameDialogs_.creationDialog);
if (d) {
gameDialogs_.creationDialog->open();
} else {
auto answer = gameDialogs_.creationDialog->exec();
if (answer == QDialog::Accepted) {
auto initializationData = gameDialogs_.creationDialog->initializationData();
initializeGame(initializationData);
startGame(initializationData);
} else {
showMainMenu();
}
}
} else {
showMainMenu();
}
}
}
It works, but I want to find where was the problem. Maybe someone can prompt, where to search a solution. Main questions are: where the difference between Server and Client code flows and why Client code works fine at the first time and breaks at the second.
This is because QDialog::exec is a synchronous blocking operation that will stop the event loop of the main thread and start a new event loop for this dialog. This most of the time is not a problem unless you are doing some continuous work on the main thread such as processing QTCPSocket
Instead of using QDialog::exec use QDialog::open which is asynchronous and does not start a new event loop, you can simply connect signals from the dialog to read the results once the user will accept/close the dialog.
If you require blocking dialogs then you also can simply offload QTcpSocket to another thread and do whole processing asynchronously and only emit required updates to the main GUI thread.

Sleep inside QTConcurrent run method

I'm using QtConcurrent::run to execute some functions in background and not hang the GUI thread. In one function, I read logs from local SQlite database and send them to server by TCP socket.
Now I want to delay the execution after each log so the server has time to save it (TCP response is read in different thread). I'm stuck with Qt4.8 due to implementation limitations (many embeded devices - no chance to upgrade QT on them) and I can't use QThread::sleep(2) because it is protected in 4.8.
Is it possible to somehow pause the execution of thread inside QtConcurrent::run method or should I redesign it to implement my own class inheriting QThread?
void MainWindow::ReportFinishedHUs(bool asyncWork)
{
if(asyncWork == false)
{
QMutexLocker locker(&localDBmutex);
QList<QSqlRecord> HUsToReport = localDB->getHUsForBook();
qDebug() << "HUs to report" << HUsToReport.count();
if(!HUsToReport.isEmpty())
{
Cls_log::WriteDebugLog("HUs to report: " + QString::number(HUsToReport.count()));
foreach (QSqlRecord record, HUsToReport)
{
int _hu = record.indexOf("hu");
int _logTime = record.indexOf("logTime");
QString logTimeString = record.value(_logTime).toString();
QString hu = record.value(_hu).toString();
qDebug() << hu << logTimeString;
// creating message here ...
qDebug() << message;
emit sig_SendTCPMessage(message);
// this is where I need to wait for 2 seconds
QThread::sleep(2);
}
}
}
else
{
QtConcurrent::run(this, &MainWindow::ReportFinishedHUs, false);
}
}
EDIT:
Solved by usleep(2000000) which I somehow discarded for being platform specific... but hey, half of my aplication is platform specific and I only use it in embeded device with constant OS.
Keeping the question open if anyone can suggest more elegand solution using Qt methods. I like to get inspired.

qt waitforreadyread() inconsistent?

Under Qt 4.7.1, OS X 10.6.8
(have to use this -- later versions
of Qt and/or OS X introduce severe
incompatibilities for my users)
The following works. Sometimes. Then sometimes not.
When it doesn't work, it returns "Unknown Error"
hst is good in all cases, qDebug returns same correct
data for hst every time.
The idea is, use ->get to pull a CGI URL; the CGI
returns some data, which I can ignore in this case.
Then I'm done.
hst is a well formed URL,
http://yadda.com/cgi-bin/whatever.py
QString hst;
QNetworkReply *qnr;
QNetworkAccessManager *qqnap = NULL;
qqnap = new(std::nothrow) QNetworkAccessManager(tmw);
if (qqnap != NULL)
{
hst = loaduphst(); // get qstring to send
qnr = qqnap->get(QNetworkRequest(QUrl(hst))); // report in and fetch update info
if (qnr->waitForReadyRead(3000) == FALSE)
{
qDebug() << "waitForReadyRead() returned FALSE -- error or timeout:" << qnr->errorString();
}
}
else
{
qDebug() << "qqnap is NULL";
}
yadda.com is up; the target script is dead simple
and works fine from browser or cmd line every time.
This is running within the context of
MainWindow::closeEvent(QCloseEvent *ce)
before I emit ce->accept() GUI is still up,
etc.
Hints? Tips? Abuse? Thanks!
waitForReadyRead is not implemented in QNetworkReply. The default implementation does nothing:
bool QIODevice::waitForReadyRead(int msecs)
{
Q_UNUSED(msecs);
return false;
}
Use the readyRead signal to find out when there is data available to be read.
More-or-less synchronous use of async networking is very problematic in the context of the main GUI loop. Signals that don't appear (finished OR readyRead), URLs that sometimes send and sometimes don't... and of course, as the kind person above pointed out, unimplemented functions. Zebras!
What we can do, though, is fire up an event loop and a timer on our own, and this will in a more-or-less friendly way act synchronous.
Perhaps some poor soul will need to poke a website CGI as I do; here's the code. It works. At least under Qt 4.7.1 it does!
So anyway, here it is:
QNetworkReply *qnr;
QNetworkAccessManager *qqnap;
QNetworkRequest qnwr;
QEventLoop w;
QTimer arf;
if ((qqnap = new(std::nothrow) QNetworkAccessManager(this)))
{
qnwr.setUrl(myUrl()); // Build web goodness
qnwr.setRawHeader("User-Agent", myUserAgent());
arf.setSingleShot(true);
if (connect(&arf, SIGNAL(timeout()), // timer firing blows...
&w, SLOT(quit()) // ...out event loop
) == FALSE)
{ return(BAD_CONNECT_TOUT); }
if (connect(qqnap, SIGNAL(finished(QNetworkReply*)), // notify we finished...
this, SLOT(qqnapReplyQ(QNetworkReply*)) // ...cuz I need to know
) == FALSE)
{ return(BAD_CONNECT_FINISHED_NOTIFY); }
if (connect(qqnap, SIGNAL(finished(QNetworkReply*)), // finishing blows out...
&w, SLOT(quit()) // ...event loop
) == FALSE)
{ return(BAD_CONNECT_FINISHED_ELOOP); }
if ((qnr = qqnap->get(qnwr))) // Go if qnr is good
{
arf.start(6000); // timeout in ms // Watchdog timer on
w.exec(); // handle all that
if (arf.isActive()) { arf.stop(); } // kill timer if needed
}
else { return(BAD_WWWGET); } // FAIL
}
else
{
return(BAD_NWAM); // FAIL
}
return(ZEN_NETWORKING);

Unable to read correctly from socket

I have a server application which sends some xor encrypted strings. I am reading them from my QT client application. Sometimes, the server is slower and I am not able to receive the entire string. I have tried something like below but it gets stuck ( see the comment below). How can I wait until I have the entire data. I tried bytesAviable() but then again i get stuck (infinite loop)
QTcpSocket * sock = static_cast<QTcpSocket*>(this->sender());
if (key == 0)
{
QString recv(sock->readLine());
key = recv.toInt();
qDebug() << "Cheia este " << key;
char * response = enc_dec("#AUTH|admin|admin",strlen("#AUTH|admin|admin"),key);
sock->write(response);
}
else
{
busy = true;
while (sock->bytesAvailable() > 0)
{
unsigned short word;
sock->read((char*)(&word),2);
qDebug()<<word;
//Sleep(100); if i do this than it works great!
QByteArray bts = sock->read(word);
while (bts.length() < word)
{
char bit; //here get's stuck
if (sock->read(&bit,1) > 0)
bts.append(bit);
sock->flush();
}
char * decodat = enc_dec((char*)bts.data(),bts.length() - 2,key);
qDebug() << decodat;
}
}
I don't know what the meaning of key == 0 is, but you are almost certainly misusing available(), like almost everybody else who has ever called it, including me. It tells you how much data can be read without blocking. It has nothing to do with how much data may eventually be delivered down the connection, and the reason is that there are TCP APIs that can tell you the former, but not the latter. Indeed the latter doesn't have any real meaning, considering that the peer could keep writing from now until Doomsday. You should just block and loop until you have read the amount of data you need for the next piece of work.
I offer you to do the following:
QObject::connect(this->m_TCPSocket, SIGNAL(readyRead()), this, SLOT(processRecivedDatagrams()));
Some explanation:
It is convinient to create a class instance of which will manage network;
One has the member which is pointer on TCPSocket;
In constructor implement connection of signal from socket readyRead() which is emmited when needed data was delivered with SLOT(processRecivedDatagrams()). which is responsible for processing recived datagrams/ in this case it is processRecivedDatagrams(), also implement this slot
Mind that class which manages network has to inherit from QObject and also in its declaration include macrosQ_OBject` for MOC.
update:
i also offer you to store recived data in container like stack or queue this will allow you to synhronize sender and reciver (container in this case acts like buffer)
// SLOT:
void Network::processRecivedDatagrams(void)
{
if (!this->m_flagLocked) // use analog of mutex
{
this->m_flagLocked = true; // lock resource
QByteArray datagram;
do
{
datagram.resize(m_TCPSocket->pendingDatagramSize());
m_TCPSocket->readDatagram(datagram.data(), datagram.size());
}
Qt::String YourString; // actualy I don`t remember how to declare Qt string
while (m_TCPSocket->hasPendingDatagrams());
QDataStream in (&datagram, QIODevice::ReadOnly);
in >> YourString
--numberOfDatagrams;
}
this->m_flagLocked = false; // unlock resource
}
}

My qhttp get() call does not work on Windows but does on Linux

I have written a program that uses qhttp to get a webpage. This works fine on Linux, but does not work on my Windows box (Vista). It appears that the qhttp done signal is never received.
The relevant code is:
Window::Window()
{
http = new QHttp(this);
connect(http, SIGNAL(done(bool)), this, SLOT(httpDone(bool)));
url = new QUrl("http://something.com/status.xml");
http->setHost(url->host(), url->port() != -1 ? url->port() : 80);
if (!url->userName().isEmpty()) http->setUser(url->userName(), url->password());
}
void Window::retrievePage()
{
byteArray = new QByteArray;
result = new QBuffer(byteArray);
result->open(QIODevice::WriteOnly);
httpRequestAborted = false;
httpGetId = http->get(url->path(), result);
}
void Window::httpDone(bool error)
{
//Never gets here!
}
Any help would be appriecated.
Matt
This should not happen at all, i.e. QHttp works reliably both on Windows and Unix.
My advice is to check whether the serves gives proper response. This can be done e.g. by verifying that data transfer is fine. You can trace the status from QHttp's signal, e.g. dataReadProgress, requestStarted, requestFinished, and other related signals.
On the other hand, instead of using old QHttp, why not using the recommended QNetworkAccessManager instead? To get your feet wet quickly, check an example I posted to Qt Labs some time ago: image viewer with remote URL drag-and-drop support. It uses the said QNetworkAccessManager to grab the image from the dropped URL. Check the source-code, it is only 150 lines.
Rewritten as suggested by Ariya to use QNetworkAccessManager and looking at this example
This now works on Windows and Linux.
Window::Window()
{
connect(&manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(retrieveData(QNetworkReply*)));
}
void Window::retrieveMessage()
{
manager.get(QNetworkRequest(QUrl("http://...")));
}
void Window::retrieveData(QNetworkReply *reply)
{
QVariant statusCodeV =
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
// "200 OK" received?
if (statusCodeV.toInt()==200)
{
QByteArray bytes = reply->readAll(); // bytes
}
reply->deleteLater();
}