Read all input from QSerialPort - qt

I am receiving data in this shape:
Q1\n
9.70E-6\n
OK>
from an external device via QSerialPort, but with my reading routine
QString request = "Hello";
qDebug() << "TransAction started!";
QByteArray requestData = request.toLocal8Bit();
qDebug() << "Writing data: " << requestData;
serial->write(requestData);
qDebug() << "Data written";
if(serial->waitForBytesWritten(waitTimeout))
{
if(serial->waitForReadyRead(waitTimeout))
{
qDebug() << "Waiting for data!";
QByteArray responseData = serial->readAll();
while(serial->waitForReadyRead(100))
responseData += serial->readAll();
responseData.replace('\n', ' ');
QString response(responseData);
QByteArray response_arr = response.toLocal8Bit();
qDebug() << "Response is: " << response_arr.toHex();
emit this->response(response);
}
else
{
qDebug() << "Wait read response timeout";
emit this->timeout(tr("Wait read response timeout %1").arg(QTime::currentTime().toString()));
}
}
else
{
qDebug() << "Wait write request timeout!";
emit this->timeout(tr("Wait write request timeout %1").arg(QTime::currentTime().toString()));
}
I only get
Q1
as response. How can I modify my code such that I am able to read all input data?
Update:
When testing it with the serial port script described here: https://stackoverflow.com/a/7654527/2546099, everything works. Apparently the problem is that the qt-version stops reading after the first line break. This problem consists also if I add
char buffer[1000];
for(int i = 0; i < 1000; i++)
{
int tmp = serial->read(buffer, 1000);
if(tmp > 0)
qDebug() << buffer;
}
directly after the line
qDebug() << "Waiting for data!";
Then I still only get the first line (without the \n). Changing times does not change the received data.

The answer to my problem is (partly) described in this question: External vs internal declaration of QByteArray. My problem (why I did not receive any further data) was that I did not send a \x00D after the input line, thus the device just echoed my input, and was waiting for the Enter afterwards. After the input looks exactly as the first line, I misunderstood it for just getting the first line, and nothing else.

Related

QNetworkAccessManager send data incomplete

I have a trouble with QNetworkAccessManager in windows. I wrote the following code to submit request ,it works on ubuntu perfectly but on windows send just 16384 bytes!! It seems request execute just once and freeze.
QString concatenated = username + ":" + pass;
QByteArray hash = concatenated.toLocal8Bit().toBase64();
QString headerData = "Basic " + hash;
QNetworkRequest request = QNetworkRequest(QUrl(baseURL));
request.setRawHeader("Authorization", headerData.toLocal8Bit());
request.setRawHeader("Content-Type", "application/json");
QNetworkReply * reply = nam->post(request,data);
connect(reply,&QNetworkReply::uploadProgress,this,&myClass::uploadProgress);
in uploadProgress method:
qDebug() << sent << " " << total;
if(total && sent){
int result = (sent*100)/total;
emit uploaded(result);
}
output:
16384 632054 // AND EVERY THINGS STOP UNTIL I GET QNetworkReply::RemoteHostClosedError ERROR CODE
After two days finally, I found why it happened! It because I emit the signal in uploadProgress directly! I changed the uploadProgress code like below and it works perfectly now!
qDebug() << sent << " " << total;
if(total && sent){
int result = (sent*100)/total;
QTimer::singleShot(5,[this,result](){
emit uploaded(result);
}
}

How get raw answer data in QWebEngineView?

Next examples work on small html pages, but dont work if page return big html data or json
I try this after loadFinished signal
view->page()->toHtml([cc](const QString &result){
qDebug() << "result ready";
qDebug() << "result string ="<<result;
});
I see "result ready", but second string not print, also I try this:
v->page()->runJavaScript("function jsfun(){return document.getElementsByTagName('html')[0].outerHTML;};");
//v->page()->runJavaScript("alert(jsfun())"); //work correctly
v->page()->runJavaScript("jsfun();",[this](const QVariant &v) {
qDebug() << "result ready";
qDebug() << "result string ="<<v.toString();
});
but again dont see second string
All example work correctly, but if buffer very big qDebug dont print data, you can write data to file or print part of data
Example (call toHtml after loadFinished signal) :
view->page()->toHtml([cc](const QString &result){
QFile file("outerHTML.html");
if(!file.open(QFile::WriteOnly | QFile::Text)){
qDebug() << "Cannot create a file";
return;
}
QTextStream stream(&file);
stream << buff;
file.close();
}

Qmqtt QObject::connect: Cannot queue arguments of type 'ClientState' (Make sure 'ClientState' is registered using qRegisterMetaType().)

I am creating a thread and inside that thread :
m_client = new QMqttClient(this);
m_client->setHostname("ps01.xx.com");
m_client->setPort(1883);
m_client->setClientId("Sas-RASPi-001");
m_client->connectToHost();
connecting to the mqt broker.
any signal connecting attempt like :
QObject::connect(m_client, &QMqttClient::stateChanged, this, &Messenqt::updateLogStateChange);
produce an error like :
QObject::connect: Cannot queue arguments of type 'ClientState'
(Make sure 'ClientState' is registered using qRegisterMetaType().)
I added :
qRegisterMetaType<QMqttClient::ClientState>("QMqttClient::ClientState");
in the beginning of the code (above code)
still same problem.
What is the proper way to use mqt from different thread in QT signal/slot way ?
EDIT:
for (int i = 20 ; i < 20 ; i++){
QThread::sleep(1);
if(m_client->publish(topic_, QString("testing. . . ").toLocal8Bit() , 1 ,true) == -1;
qDebug() << " error" <<;
}
Hi,
I am using qmqtt in a for loop with sleep 1 second and then process waiting to send messages until all 20 messages published.
When the loop finishe all 20 messages send .
But . if we will not use QThread::sleep(1) . then each messages sending individually. why . ?
Is there any way to force send to each messages immediatelly when its published?
EDIT 2
Below example not sending the images to the broker. It is blocking some place somewhere. I need flush the messages :)
minimal example :
m_client = new QMqttClient(this);
m_client->setHostname("ps01.xxx.com");
m_client->setPort(1883);
m_client->setClientId("RASPBERRY-009");
m_client->setUsername("vv");
m_client->setPassword("vv");
m_client->setCleanSession(false);
m_client->connectToHost();
//yeni slot mekanizmasi. kendi icinde &Publisher örneği..
QObject::connect(m_client, &QMqttClient::stateChanged, this, &Publisher::updateStateChange);
QObject::connect(m_client, &QMqttClient::connected, this, &Publisher::sendMessages);
an the send message:
void Publisher::sendMessages()
{
QDir dir("/ram");
int count = 0;
QThread::sleep(5);
while (true){
QStringList images_metas = dir.entryList(QStringList() << "*.png" ,QDir::Files);
if (images_metas.size() > 0){
foreach(QString filename, images_metas) {
dataLoad *dl = new dataLoad;
QString img_path = "/ram/" + filename;
QImage img(img_path);
qDebug() << " : : : " << QImage("/ram/00-02-2018-04-05-2.png").size() << endl;
dl->image = img;
dl->text = "Deneme MEsajıdır . . ";
QByteArray byteArray_;
QDataStream stream(&byteArray_, QIODevice::WriteOnly);
stream.setVersion(QDataStream::Qt_5_10);
stream << dl->image << dl->text;
qDebug() << count++ << " sending : " << byteArray_.size() << " " << filename << endl;
qDebug() << testPublish(byteArray_)<< endl;
}
}
else {
qDebug() << " folder is empty waiting... " << endl;
}
//Check every 1 second
QThread::sleep(1);
}
}
and the publishing:
qint32 Publisher::testPublish(QByteArray &bytarray)
{
QMqttTopicName topic_ = QString("qtmqtt/topic1");
QString mesaj = ".x.x.x.x.x.x.x.";
auto id = m_client->publish(topic_, mesaj.toLocal8Bit() , 1 ,true);
return id;
}
Please try below code:
msg_timer = new QTimer(this);
//TODO big chip save timer.
connect(msg_timer, SIGNAL(timeout()) , this , SLOT(sendMessages()));
msg_timer->start(1000);
dont use while loop. It is blocking everything..
Best
I get a solution to the problem of "Qmqtt QObject::connect: Cannot queue arguments of type 'ClientState' (Make sure 'ClientState' is registered using qRegisterMetaType().)" caused by working in threads. Although I have not made clear the specific meaning, at least it can work well.
You can try it:
connect(m_client, &QMqttClient::stateChanged, [&](QMqttClient::ClientState state){
qDebug()<< state;
});

read and write to qtcpsocket using qdatastream

There are various methods of reading and writing from a QTcpSocket using a QDatastream as seen here
The difference is, I will be sending more than "one packet" or blocks.
A basic implementation on the server (sending) side and client (recieving) is seen below - only the actual sending and receiving snippets are shown
More Info, What I tried:
When writing to a QTcpSocket, I attempted to use the QTcpSocket::canReadLine() however this fails straightup after the QTcpSocket::waitForReadReady() signal fires.
I then tried QDataStream::atEnd() in a while loop which causes a system crash :(
The code below shows my latest attempt of going through the QDataStream docs, and utilzing the commitTransaction where it states
If no full packet is received, this code restores the stream to the initial position, after which you need to wait for more data to arrive.
Under the heading Using Read Transactions. But ofcourse, this just reads one block that is sent, i.e the first block.
Question:
When writing to a QTcpSocket multiple times, and flushing the socket each time to send that data, how can I read this from a QTcpSocket as it is send, keep the original "send structure"?
The example below only reads the first block and ends. I would like to read the block containing "Response 2" and "Response 3".
Code Implementations:
//server.h
//...
QTcpSocket *clientSocket = nullptr;
QDataStream in;
//...
//server.cpp
//...
in.setDevice(clientSocket);
in.setVersion(QDataStream::Qt_4_0);
in.startTransaction();
QString nextFortune;
in >> nextFortune;
if (in.commitTransaction())
ui->lblOut->setText(nextFortune);
if (clientSocket != nullptr) {
if (!clientSocket->isValid()) {
qDebug() << "tcp socket invalid";
return;
}
if (!clientSocket->isOpen()) {
qDebug() << "tcp socket not open";
return;
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << QString(QString("Response:") + nextFortune);
if (!clientSocket->write(block)){
QMessageBox::information(this, tr("Server"),tr("Could not send message"));
}
clientSocket->flush();
// block.clear();
out << QString("Response number 2");
if (!clientSocket->write(block)){
QMessageBox::information(this, tr("Server"),tr("Could not send message"));
}
clientSocket->flush();
// block.clear();
out << QString("Response number 3 here, and this is the end!");
if (!clientSocket->write(block)){
QMessageBox::information(this, tr("Server"),tr("Could not send message"));
}
clientSocket->flush();
clientSocket->disconnectFromHost();
}
//...
And the client side
//client.h
//...
QTcpSocket *tcp_con = nullptr;
QDataStream in;
//...
//client.cpp
//...
if(!tcp_con->waitForReadyRead()){
qDebug(log_lib_netman_err) << "tcp con timeout for reading";
tcp_con->disconnectFromHost();
return ReturnObject(ReturnCode::SocketError, QString());
}
in.setDevice(tcp_con);
in.setVersion(QDataStream::Qt_4_0);
in.startTransaction();
QList<QString> data_rcv = QList<QString>();
QString s;
// while (tcp_con->canReadLine()) {
// in >> s;
// data_rcv.push_back(s);
// }
// while (!in.read) {
in >> s;
data_rcv.push_back(s);
// }
while (!in.commitTransaction()){
qDebug(log_lib_netman_info) << "waiting for more data";
in >> s;
data_rcv.push_back(s);
// qDebug(log_lib_netman_err) << "Unable to send data to server";
// tcp_con->disconnectFromHost();
// return ReturnObject(ReturnCode::FailedReceiving, QString());
}
// if (s.isEmpty()) {
// qDebug(log_lib_netman_err) << "Empty response recieved";
// tcp_con->disconnectFromHost();
// return ReturnObject(ReturnCode::NoDataRecieved, QString());
// }
tcp_con->disconnectFromHost();
return ReturnObject(ReturnCode::ReceivedSuccess, data_rcv);
Help would be greatly appreciated!

Empty buffer when reading from a QTcpSocket

I am creating a simple threaded TCP server (based on the threaded Fortune server example). I have connected the readyRead signal to my readCommand slot, and I confirmed that the readCommand function fires after I've telnetted to my server and sent a string (followed by enter).
The function below outputs "In readCommand" once I send the string HELLO, then the output "new inBuffer" always shows empty ("").
void FortuneThread::readCommand()
{
qDebug() << "in readCommand" << endl;
QDataStream in(tcpSocketPtr);
in.setVersion(QDataStream::Qt_4_0);
in >> inBuffer;
qDebug() << "new inBuffer: " << inBuffer << endl;
...
}
If I print out tcpSocket->bytesAvailable(), then I see a growing count of characters as I send more via telnet. I'm just not getting them out of the socket...the code above is copied from the Fortune Client example so I assumed it would work. Am I using QDataStream wrong?
You should not initialize your QDataStream with QTcpSocket.
You should read the data from the socket io device with QByteArray QIODevice::readAll().
You should write the byte array of the previous operation into the data stream with the "<<" operator.
So, the code should look something like this:
void FortuneThread::readCommand()
{
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out << tcpSocketPtr->readAll();
...
}
The codes like these would work:
QByteArray res;
res.reserve(m_tcp_socket_ptr->bytesAvailable());
res = m_tcp_socket_ptr->readAll();
qDebug() << res;

Resources