The slot of readMessageFromTCPServer could not be triggered sometimes after receiving message - c++

I use Qt creator 5.5.1 in windows 7.
The compiler is VC 2010 32 bits.
I have written a socket client. It could connect well but sometimes its readyRead() signal could not be triggered after receiving message from server. So the readMessageFromTCPServer() slot could not be triggered and the thread could not run.
void MainWindow::on_pushBtn_LoadCfg_clicked()
{
if (tcpClient == NULL)
{
tcpClient = new QTcpSocket;
tcpClient->connectToHost(ui->txtIPServer->text(),ui->txtPortServer-
>text().toInt());
QObject::connect(tcpClient,SIGNAL(readyRead()),this,
SLOT(readMessageFromTCPServer()));
}
}
void MainWindow::readMessageFromTCPServer()
{
std::string r="start";
QByteArray qba;
qba= tcpClient->readAll();
if (qba.contains(r.c_str()))
{
cout<<"thread run";
}
}
When I tried to debug this program. I put a break point at this line: Sleep(800), but sometimes this slot could not be triggered after receiving message from socket server. And I have checked that the socket is still connected, why the slot could not be triggered?

There are some errors in your code. You will only have the slot triggered once.
Get rid of those Sleep commands. There is no good reason to use it if you are doing it in the main thread.
QByteArray qba= NULL; makes no sense. QByteArray qba; is ok.
while(1) means forever. You should break the loop at some point. Actually, you do not need this loop at all. Put the code inside this loop out of it and remove the loop. When the readyRead() signal is emitted, it means that there is some data to be read. You can readAll() that data chunk, do your stuff and return.
There is no guarantee that you will get your entire message in one round. So, in some circumstances, you may get "St" in one signal and "art" in another. So, you should implement your own buffering mechanism for such a situation. It may happen on big chunks of data. If you are sure that you are getting very short packages, then it's ok to rely on the internal buffer of QTCPSocket.

Related

Serial Communication Timeout in QT with Arduino

I want to implement a timeout mechanism such that if the arduino doesn't read the command within one second, it results in a timeout and the new command is discarded and the program runs fine.
But right now, the program hangs if any new command is sent during the execution of the old one.
This is the timeout section of my code:
QByteArray requestData = myRequest.toLocal8Bit();
serial.write(requestData);
if (serial.waitForBytesWritten(waitTime)) {
if (serial.waitForReadyRead(myWaitTimeout)) {
QByteArray responseData = serial.readAll();
while (serial.waitForReadyRead(10))
responseData += serial.readAll();
QString response(responseData);
emit this->response(response);
} else {
emit timeout(tr("Wait Read Request Timed Out %1")
.arg(QTime::currentTime().toString()));
}
} else {
emit timeout(tr("Wait Write Request Timed Out %1")
.arg(QTime::currentTime().toString()));
}
The timeout signal is connected to a slot that just prints the timeout message and does nothing.
How can I fix this so that I can achieve what I target?
You are using blocking approach to transmit data via serial port. Unless you are using threads I don't see possibility to send any additional data during execution of previous loop.
BTW: Your program, for example, will block indefinitely if Arduino manages to keep sending something within 10ms periods.
Add couple of QDebug() << "I'm here"; lines to check where your code gets stuck; it is possible that you are blocking somewhere outside code you pasted here. Alternative is to use debugger.
What if previous 'command' you tried to send is still in the buffer ? You'll end up filling output buffer. Check with QDebug how many bytes are in output buffer before writing more data to it. Buffer should be empty. (qint64 QIODevice::bytesToWrite() const).

How should QLocalSocket/QDataStream be read to avoid deadlocks?

How should QLocalSocket/QDataStream be read?
I have a program that communicates with another via named pipes using QLocalSocket and QDataStream. The recieveMessage() slot below is connected to the QLocalSocket's readyRead() signal.
void MySceneClient::receiveMessage()
{
qint32 msglength;
(*m_stream) >> msglength;
char* msgdata = new char[msglength];
int read = 0;
while (read < msglength) {
read += m_stream->readRawData(&msgdata[read], msglength - read);
}
...
}
I find that the application sometimes hangs on readRawData(). That is, it succesfully reads the 4 byte header, but then never returns from readRawData().
If I add...
if (m_socket->bytesAvailable() < 5)
return;
...to the start of this function, the application works fine (with the short test message).
I am guessing then (the documentation is very sparse) that there is some sort of deadlock occurring, and that I must use the bytesAvailable() signal to gradually build up the buffer rather than blocking.
Why is this? And what is the correct approach to reading from QLocalSocket?
Your loop blocks the event loop, so you will never get data if all did not arrive pn first read, is what causes your problem I think.
Correct approach is to use signals and slots, readyRead-signal here, and just read the available data in your slot, and if there's not enough, buffer it and return, and read more when you get the next signal.
Be careful with this alternative approach: If you are absolutely sure all the data you expect is going to arrive promptly (perhaps not unreasonable with a local socket where you control both client and server), or if the whole thing is in a thread which doesn nothing else, then it may be ok to use waitForReadyRead method. But the event loop will remain blocked until data arrives, freezing GUI for example (if in GUI thread), and generally troublesome.

Cannot write data to Serial Port

I am trying to write data to Serial Port. I use this way:
QBluetoothSocket *socket;
socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
socket->open(QIODevice::WriteOnly);
QByteArray byteArr;
QDataStream out(&byteArr, QIODevice::WriteOnly);
out << 1 << '\n'; //if plusbutton is pushedm then send zero
socket.write(byteArr);
qDebug()<<socket.write(byteArr)<<endl;
But I get in return:
W/libA_for_w8.so( 6443): (null):0 ((null)): qt.bluetooth.android:
Socket::writeData: QBluetoothSocket::ConnectingState false
W/libA_for_w8.so( 6443): (null):0 ((null)): qt.bluetooth.android:
Socket::writeData: QBluetoothSocket::ConnectingState false
D/libA_for_w8.so( 6443): ..\A_for_w8\widget.cpp:68 (void Widget::on_plus_clicked()): -1
D/libA_for_w8.so( 6443):
So, nothing is written to there.
It seems, that the code is ok, but it doesn't work.
Can you tell me what's wrong?
Thank you.
P.S.
I checked socket is open .
socket->isOpen return true and I get:
W/libA_for_w8.so( 9638): (null):0 ((null)): qt.bluetooth.android: Socket::writeData: QBluetoothSocket::UnconnectedState false
D/libA_for_w8.so( 9638): ..\A_for_w8\widget.cpp:70 (void Widget::on_plus_clicked()): -1
You need to connect the socket to an endpoint before you can successfully write anything. There must be a running Bluetooth service somewhere, to which you connect using connectToService(). After the connected() signal has been emitted, you can write data.
It doesn't appear that QBluetoothSocket has a waitForConnected() function, as QAbstractSocket and its subclasses do. This means you can use something like QSignalSpy to wait for the connected() signal, or, if you don't care so much about efficiency, just a busy-wait loop would do.
EDIT:
As pointed out in the comment, waiting for events to happen is the whole point of Qt's main event loop. Using the waitFor* methods or another event loop is pretty inefficient, and definitely goes against the spirit of Qt. So the best solution to writing data only after the socket is connected is to connect a writeData() slot to the connected() signal of QBluetoothSocket.

Qt creator - RS232 writing over serial to fast

for(int i = 0; i < receivedACLCommands.count(); i++ )
{
QByteArray s = receivedACLCommands[i].toLatin1();
serialport->write(s);
serialport->waitForBytesWritten(1000);
}
In my method I have a QStringList that contains all my commands. The commands will be send to a PID controller that needs to process the command before a new one I being send. I tried this with the waitForBytesWriten but this isnt working for me.
*the controller is an old SCORBOT controller-a.(works with ACL commands).
Yes, waitForBytesWritten() isn't going to solve that. Only other thing you can do is sleep for a while after the wait call, thus giving the device some time to process the command you have just written. Exactly how long to sleep is of course a blind guess, it is not necessarily a constant.
Do focus on enabling handshaking first, typically ignored too often. QSerialPort::setFlowControl() function. A decent device will use its RTS signal to turn off your CTS input (Clear to Send) when it isn't ready to receive anything. CTS/RTS handshaking is supported by Qt, you use QSerialPort::HardwareControl

How is my code Receiving Signals before the Qt Eventloop is Started

I'm trying to understand why putting the a.exec() call in the following Qt 4.8 code does not need to happen before my QProcess waitForFinished() and waitForStarted() calls can work. I understand that a.exec() starts the event loop, and in my mind the waitFor* slots need to receive a signal ( i.e 'started()' or 'finished()' ) before moving on with execution. How can this happen if the event loop has not been started?
Documentation for waitForStarted():
Blocks until the process has started and the started() signal has been emitted, or until msecs milliseconds have passed.
Code:
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Exec the i2c command to get the power button status
QProcess i2cprocess;
i2cprocess.start("/usr/bin/i2cget -f -y 1 0x4b 0x45");
// Wait for it to start
if(!i2cprocess.waitForStarted())
{
qDebug() << "Could not start QProcess to check power button status.";
exit(-1);
}
// Wait for it to finish
bool returnValue = i2cprocess.waitForFinished();
if ( returnValue )
{
QByteArray status = i2cprocess.readAllStandardOutput().trimmed();
bool ok;
quint16 hexValue = status.toUInt(&ok, 16);
qDebug() << "Power button status: " << status << hexValue << (hexValue & 0x01);
// We want LSB
exit(hexValue & 0x01);
}
else
{
qDebug() << "Error, process never completed to check power button status.";
exit(-1);
}
return a.exec();
}
Direct signal-slot connections are simply indirect function calls, they have nothing whatsoever to do with event loops.
What the waitForXxxx methods do, though, is to spin a local event loop until the signal fires. The signal is fired from some code that gets notified by the OS that the process state has changed. That code is executed, functionally, "by" the event loop.
Remember that in Qt you can create temporary event loops on a whim - it's a bad practice, and you should never write code that uses waitFor methods. It places requirements on your code that are not normally present - and thus introduces bugs!
The question is then: what is the use of an event loop when waiting for processes to change state? Internally, the process notifications require waiting for native events or callbacks, and those all get handled from an event loop. Even if no events are used, the event loop performs an interruptible sleep that's needed for the OS to deliver callbacks to the application.
The Qt documentation for QProcess states: -
QProcess provides a set of functions which allow it to be used without an event loop, by suspending the calling thread until certain signals are emitted:
waitForStarted() blocks until the process has started.
waitForReadyRead() blocks until new data is available for reading on the current read channel.
waitForBytesWritten() blocks until one payload of data has been written to the process.
waitForFinished() blocks until the process has finished.
Calling these functions from the main thread (the thread that calls QApplication::exec()) may cause your user interface to freeze.