why I receive some empty data received from the serialPort? - c++

I extracted the data from my sensor using these command lines:
QObject::connect(this->serialPort,SIGNAL(readyRead()),this,SLOT(pollSerialPort()));
QObject::connect(serialPort, &::QSerialPort::errorOccurred,this,&Imu::handleError);
QByteArray hexData = d.append(serialPort->readAll().toHex());
qDebug() << "Serial received " << hexData;
however, I do not receive the data every time
I have a lot of empty messages like this
Serial received "555541321e7ff3029f61da00000000ffff00d2fffa0cbe24b124b124b1007b13d00000f4d8"
Serial received ""
I used this command to receive the data every ms but it doesn't work
QObject::connect(this->serialPort, &QSerialPort::readyRead, this, this {QTimer::singleShot(5,this,&Imu::pollSerialPort);});
Any solution please ?

Instead of polling on a timer, connect QSerialPort::readyRead to a slot and inside the slot use QSerialPort::readAll() until QSerialPort::bytesAvailable() is 0.

Related

UART doesn't receive all sent values in Qt

I'm triying to send data from a PSoc via UART to my PC where a want to store data with Qt. The PSoc sends 3 bytes of data. Theses 3 bytes are repeatet with a frequency of 2.5Hz. When I check the signals with my oscilloscope everything is fine. When I receive the data with the software HTerm also everything is as expected. When I use my code written in c++ with Qt I get the problem that not all data are received in Qt, only one third is in the memory. I expected that the signal readyRead is emitted with every new byte? But it seems that the signal is only emitted at the begin of the package of the 3 bytes. Also my qDebug output doesn't react on changes from the PSoc. So when I change values at PSoc the output in qDebug doesn't change.
I already tried reading 3 Bytes (serial->read(3)) and then I first received some single bytes and after a few readings I get the 3 bytes I sended but this is not so reproducible.
connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
serial->setPortName(gui->ui->comboBox->currentData().toString());
serial->setBaudRate(QSerialPort::Baud115200);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
void uart::readData()
{
QByteArray data = serial->read(1);
qDebug() << data;
}
I expect an output like "0x01" "0x02" "0x03" 2.5 times a second, but I get only "0x01"
You are only reading a fixed size with read.
Could it be that you get readyRead signals with varying bytes available but you only read fixed size of them
In your readyRead slot try to read all available bytes.
qint64 available = serial->bytesAvailable();
if (available > 0)
{
QByteArray data = serial->read(available);
qDebug() << data;
}
You can also use readAll() function.
I just found the solution!
You have to set the read-buffer size to the right value.
So for reading a package of three bytes I must set:
serial->setReadBufferSize(3);

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 to loop a function till a new mqtt message arrives?

I'm writing a mqtt app in C++ with Paho. I'm using Paho.mqtt C library that can be found here.
When I receive a message in the callback function, it calls another function to print the message. I want to be able to loop that function until a new message arrives.
bool start = false;
void loopMessage(std::string message){
start = true;
while(start){
std::out << "message: " << message;
}
}
int messageArrivedCallback(mqtt message){
start = false;
loopMessage(message);
}
The code above is not working; I can receive one message and run the while loop in the loopMessage function. After that the client disconnects. I think this is because it is in blocking mode and the broker disconnects the client after the keep alive interval (I'm using MQTTClient). If I quickly send a new message before disconnection, the client doesn't receive it.
I tried to use the asynchronus client version (MQTTAsync) but it is giving me the same problem.
Any suggestions on how to do this?
The Paho client will start a thread to handle the network loop and collect new messages so just remove the loopMessage function and print the message in the messageArrivedCallback.
You should not make blocking calls (which is what this infinite loop does) in the messageArrivedCallback because it has to return to allow the client to continue to receive messages.
If you want to print the message content over and over agian until a new message arrives then you need to do it on a separate thread.

Qt Socket not waiting for bytes written

I wrote a chess client/server mobile application and have a remote server that has been tested on the West Coast, the East Coast, in between, etc. The program is this in a nutshell:
1. Log in to remote server with correct username/password via iOS/Android or Windows desktop.
2. Enter queue for a 1-minute, 5-minute or 30-minute game of chess.
3. Wait for another opponent to join queue.
4. Get matched and play game of chess.
5. When game is over, log out or play more chess.
I am getting the weirdest freaking error when I log in to the server via my school's internet, however. This is so weird because it the ONLY ISP that has problems out of the many ISP's I have connected from.
When I log into the server through my school's internet, I will get the following error and errorString from my socket.
QAbstractSocket::UnknownSocketError "Unknown error"
The steps to produce this in my application are:
1. Enter username and password, log into server. (Successfully completes this).
2. Click to join a queue for a game of chess. (Successfully writes to socket, but fails to wait for bytes written then emits the above error and error string.
I checked the server and readyRead() is not even called, so I know the client is not sending anything to the server.
The funny thing is, I found a workaround for getting past this error.
1. Click on Settings page.
2. Click Save. (Does the exact same thing as I try to do above. Write to socket, flush and wait for bytes written).
3. Join queue (Successfully joins queue).
The workaround MAKES NO SENSE since it does not do anything differently than what I tried to do above (write to socket, flush and wait for bytes written).
Does anyone have a clue on what might be going on?
Why is this error specific to ONE internet location? My school internet is slow as hell, but doesn't explain why the socket is disconnected immediately in the function below.
Why does my workaround work?
What can I do to learn more about my problem (i.e. stupid error message..."unknown error").
Not only this, but when I right-click on the function below, then click 'Find usages', the build folder appears. This is the only function in the program that does this. WTF???
Socket disconnects in this function.
void CG_serverConnection::sendQueueType(int timeControl)
{
//Create local JSON object
QJsonObject userInfo;
//Create object
userInfo["PacketHeader"] = QUEUE_REQUEST;
userInfo["TimeControl"] = timeControl;
//Create JSON document
QJsonDocument doc;
doc.setObject(userInfo);
qDebug() << "Send queue type called! ";
qDebug() << doc.toJson();
QByteArray byteArray = doc.toBinaryData();
//Send over socket
if(m_socket->write(byteArray))
{
qDebug() << "Wrote to socket";
}
else
m_socket->errorString();
if(m_socket->flush())
{
qDebug() << "Flushed";
}
else
qDebug() << m_socket->errorString();
if(m_socket->waitForBytesWritten(50000))
{
qDebug() << "Bytes were written.";
}
else
{
qDebug() << m_socket->error();
qDebug() << m_socket->errorString();
}
}
Where I call the function
Button
{
id: btn_oneMinuteGame
text: "One Minute"
style: cgButtonStyle
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: Lobby.getControlWidth()
Layout.preferredHeight: Lobby.getControlHeight()
onClicked:
{
ServerConnection.sendQueueType(1) // TODO : Magic numbers
root.startOneMinuteGame()
}
}
For some reason if I call this at the top of my function, everything works...
Makes no sense. If someone can explain why this works or you have another solution, please post it.
//Temporary bug fix
this->sendUpdatedUserInfo();
Function I call that somehow makes everything work
void CG_serverConnection::sendUpdatedUserInfo()
{
QJsonObject request;
request["PacketHeader"] = UPDATE_INFO;
request["loggedIn"] = m_player.loggedIn;
request["banned"] = m_player.banned;
request["username"] = m_player.username;
request["elo"] = m_player.elo;
request["countryFlag"] = m_player.countryFlag;
request["pieceSet"] = m_player.pieceSet;
request["language"] = m_player.language;
request["sound"] = m_player.sound;
request["coordinates"] = m_player.coordinates;
request["arrows"] = m_player.arrows;
request["autoPromote"] = m_player.autoPromote;
request["boardTheme"] = m_player.boardTheme;
QJsonDocument doc;
doc.setObject(request);
qDebug() << "Updated userInfo being sent: ";
qDebug() << doc.toJson();
m_socket->write(doc.toBinaryData());
m_socket->flush();
m_socket->waitForBytesWritten();
}

QTcpSocket - try to send bunch of requests

I am trying to send 2 request one by one at same time. My code is following (this is example code):
QTcpSocket client;
...
client->write(block);
client->write(block);
Problem is following. Server receives only first request. There is no second request. I sniffed using wireshark and see that there is no second request in tcp packets.
What must i do to send many requests via QTcpSocket one by one?
UPD: I inserted qDebug() << this->bytesAvailable() << "bytes"; to server in readyRead() and qDebug() << this->bytesToWrite(); after each client->write(block); in client. Also, I added this to client:
connect(this, SIGNAL(bytesWritten(qint64)), this, SLOT(bytesWritten(qint64)));
void Connection::bytesWritten(qint64 count)
{
qDebug() << count << "bytes written";
}
I send ORDER_STATUS_GET_LIST constant in first request and ORDER_GET_LIST in second. I added data output in server. I received first command.
There is output listing:
Client:
Sending ORDER_STATUS_GET_LIST
11 bytes to write
Sending ORDER_GET_LIST
68 bytes to write
68 bytes written
Server:
68 bytes
ORDER_STATUS_GET_LIST received
According to the documentation, you need to flush() the socket IF you don't return to the event loop between multiple writes.
The proper solution would be to buffer your blocks into, e.g., a QByteArray and send the buffer at once.
QTcpSocket client;
QByteArray buffer;
...
buffer << block;
buffer << block;
client->write(buffer);
I found solution myself. I think that somebody needs this too.
Solution is simple:
QTcpSocket client;
...
client->write(block);
client->flush();
client->write(block);
client->flush();
We need to flush qt socket buffer to net before fill it with another data.