wait for data arrive from serial port in Qt - c++

I use serial port connection in my qt application.
My problem- I cant get back the control (or the values comes from the comm port) after sending the command.
I have a class named serial.cpp which responsible to serial port connection.
This class contains 2 queues. one for save bytes from the comm port and second for the decoded messages. the class has the functions below:
void Serial::sendCommand(QString s)
{
QString sometext = s;
QByteArray ba = QByteArray::fromHex(sometext.toLatin1());
serial->write(ba);
}
void Serial::serialReceived()
{
QByteArray ba ;
serialArray = serial->readAll();
for (int i=0; i<sizeof(serialArray);i++)
{
queueBytes.enqueue(serialArray[i]); // queue for saving the bytes
}
QVector<int> vect = queueBytes.toVector();
packetSize = 6;
if (vect.size() >= packetSize)
{ // the whole packet arrived
for (int i =0 ;i<packetSize;i++)
{
item = queueBytes.dequeue();
ba.append(item);
}
}
if (ba.toHex() == "12ee02010176")
queueMsgs.enqueue("ACK");
// ... and so on
}
here is the call class:
void Engine::onNewMessageFromAppReceived(int msgId,QString args)
{
serial->sendCommand("ee1203190209005569");
while (serial->queueMsgs.size() == 0) // infinite loop-the queue is always empty
{
usleep(1);
}
QVector<QString> vect2 = serial->queueMsgs.toVector();
qDebug() << vect2 << "get ack---" ;
}
please your help

The QSerialPort class inherits from QIODevice which has waitFor... methods that may be what you're looking for. Take a look at these docs.
If you want to handle the serial port asynchronously, use the readyRead signal and perform reading in a function that you connected to that signal. If you don't mind that the operation is blocking, the waitForReadyRead function is what you're looking for.
The good way
Here's the proper way to do it using Qt's signals and slots mechanism. This will not block your GUI and lets your application respond to user actions even while you are waiting for the serial port.
Connect a function to the bytesWritten signal
The code you want to execute after you sent data through the serial port should be placed in this function.
Connect a function to the readyRead signal
The code you want to execute after you read some data from the serial port should be placed in this function.
Open the port
The bad way
In some cases you can do it like this, but it's blocking, meaning that your GUI will freeze while your app is waiting for the serial port. I don't recommend doing it like this.
Open the port
Send data
Call waitForBytesWritten
Call waitForReadyRead
Working example code
Qt has a vast amount of working example code. There are even examples about how to use QSerialPort, and they are well worth checking out. You might be most interested in the async writer example and the async reader example.

Related

edited: accessing a method in a running c++ program

I need to make a statistical printout of a socket program.
I am using method Listen(uint32_t port) in c++ thread to listen to clients on the specified port (more than one) and send/receive client's transactions to/from a server.
Now i need to write a log file of how many packet received/sent by this method.
my implementation is shown in the skeleton below:
hub.cpp
//set up necessary header
#include <iostream>
....
#include <vector>
//global variables
std::map<uint32_t,long> * received_pk;
std::map<uint32_t,long> * sent_pk;
void Listen(uint32_t port ); // method
int main (int argc, char **argv){
//set up client ports
vector<uint32_t> client_ports;
client_ports.push_back(50002);
client_ports.push_back(50003);
//initialize variables
received_pk = new std::map<uint32_t,uint32_t>();
sent_pk = new std::map<uint32_t,uint32_t>();
for(uint32_t i=0;i<client_ports.size();i++){
received_pk->insert(std::pair<uint32_t,uint32_t>(client_ports.at(i),0) );
sent_pk->insert(std::pair<uint32_t,uint32_t>(client_ports.at(i),0) );
}
//set up thread
vector<thread*> threads;
for(uint32_t i=0;i<client_ports.size();i++){
cout << "Create Listener in port " << client_ports.at(i) << endl;
threads.push_back(new thread(Listen,client_ports.at(i)));
}
//Wait for the threads to finish
for(uint32_t i=0;i<client_ports.size();i++){
threads.at(i)->join();
}
}
void Listen(uint32_t port){
...
set up struct sockaddr_in client, host;
listen on port: port
...
while(1){
receive packet from client;
received_pk->at(port)++;
check packet type
if(packet==status packet){
update the packet id number
}
if (packet==transaction){
send packet to Server
receive reply
send reply back to client
sent_pk->at(port)++;
}
}
}
Now i need to access received_pk and sent_pk while hub.cpp is still running (probably in the while loop)
I thought of two options:
Access received_pk and sent_pk from an external program: like define a method that can get the packet information while the thread is till running
problem: I don't know if i can access a variable/method while program is executing .
or print received_pk and sent_pk to a log file every 5 seconds.
problem: I don't know if it makes sense to have a timer in the multiple thread.
Please any advice will be appreciated.
Kehinde
Quite possibly, the easiest solution is to put the data in shared memory. The map x is a bit suspect - did you mean std::map<Key, Value>? That doesn't fit well in shared memory. Instead, use simple arrays. There are just 64K ports, and sizeof(long long[65536]) isn't excessive.

Qt QUdpSocket: readyRead() signal and corresponding slot not working as supposed

I have problems to find why my short QUdpSocket example is not working. I plan to use only one UDP socket to read and write to an embedded device at 192.168.2.66 on port 2007. The device will reply always on port 2007 to the sender. I tested the device with an UDP terminal software and works as I said. So, I designed a simple class to embed the functions needed to manage the device:
class QUdp : public QObject
{
// Q_OBJECT
public:
explicit QUdp(QObject *parent = 0, const char *szHost = 0, uint16_t wPort = 0);
~QUdp();
bool Open();
int64_t Write(QByteArray &data);
int64_t Write(QString strData);
private:
QString m_strHost;
uint16_t m_wPort;
QUdpSocket *OUdp;
private slots:
void received();
};
I suppose that the problem is in the Open method:
bool QUdp::Open()
{
QHostAddress OHost;
connect(OUdp, &QUdpSocket::readyRead, this, &QUdp::received);
bool zRet = OUdp->bind(QHostAddress::AnyIPv4, m_wPort, QUdpSocket::ShareAddress);
OHost.setAddress(m_strHost);
OUdp->connectToHost(OHost, m_wPort, QIODevice::ReadWrite);
return(zRet);
}
//------------------------------------------------------------------------
I used the Qt 5 syntax for the connect(), m_strHost value is "192.168.2.66" and m_wPort is 2007
my Write method is very simple (the part inside #if 0 was added to see if the socket received any data)
int64_t QUdp::Write(QString strData)
{
QByteArray data(strData.toStdString().c_str(), strData.length());
int64_t iCount = OUdp->write(data);
#if 0
bool zRecved = OUdp->waitForReadyRead(3000);
int64_t iRecvCount = OUdp->bytesAvailable();
#endif
return(iCount);
}
//------------------------------------------------------------------------
and this is my test received() method... I wrote it just to see if the signal-slot works or not:
void QUdp::received()
{
int64_t iRecvCount = OUdp->bytesAvailable();
}
//------------------------------------------------------------------------
I don't understand what is wrong.. I found some posts saying that is not possible read and write using only one UDP socket in Qt (Qt uses BSD sockets so it should be possible) but my example looks as the proposed solutions so I really don't understand what is not working.
You can read and write using just one UDP socket in Qt. I have this running in Qt5 on both windows and Linux, so no worries there :)
To establish Rx direct comms in QUdpSocket you should really use the bind() function, something like this:
// Rx connection: check we are not already bound
if (udpSocket->state() != udpSocket->BoundState)
{
// Rx not in bound state, attempt to bind
udpSocket->bind(address, port);
}
Once this has completed you will be able to check that udpSocket->state() == udpSocket->BoundState is true, then you are successfully "bound" to this ip/port. Now your listening can begin if your connection to readready() is correct. I have not used this connection syntax that you are using, so I can't say much about that, but here is the example of how I connect:
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(rxDataEvent()), Qt::QueuedConnection);
Where "this" is the class which contains my QUdpSocket and udpSocket is a QUdpSocket pointer. Then rxDataEvent is defined below:
void CIpComms::rxDataEvent(void)
{
QByteArray rxData;
QHostAddress sender;
quint16 senderPort;
while (udpSocket->hasPendingDatagrams())
{
// Resize and zero byte buffer so we can make way for the new data.
rxData.fill(0, udpSocket->pendingDatagramSize());
// Read data from the UDP buffer.
udpSocket->readDatagram(rxData.data(),
rxData.size(),
&sender,
&senderPort);
// Emit ipDataReceived Signal
emit ipDataReceived(rxData);
}
}
Here we continually check for datagrams until there are none pending (bit easier then doing the whole "bytesAvailable thing") and stick the data into a QByteArray and emit it off elsewhere (which you obviously don't have to do!).
That is all you need to do for connection. Then to send is very easy, you simply have to call writeDatagram(), well there are other options but this is by far the easier to use:
if (-1 == udpSocket->writeDatagram(txData, address, port))
{
// Data write failed, print out warning
qWarning() << "Unable to write data to " << address.toString() << ":" << port << endl;
return false;
}
I have pretty much cut and pasted this from my working code (with a few edits to keep it short-n-simple so it should give you a starting point. In summary where I believe you are going wrong is that you have not "bound" to the IP address/port and are therefore NOT listening to it and will not receive any readReady() events.

Qt C++ Console Server, Wait for socket connection & accept input at same time?

I am writing a server as a Qt console application. I have the server set up to wait for a socket connection, but I also need to allow a user to input commands into the server for managing it. Both are working independently. However, the problem I ran into is that when I'm in a while loop accepting and processing input commands, the server doesn't accept connections.
I have a Socket class, and in its constructor, I have:
connect(server,SIGNAL(newConnection()),this, SLOT(newConnection()));
Right under that in the constructor, I call a function that has a more in-depth version of this for getting commands from the user:
QTextStream qin(stdin, QIODevice::ReadOnly);
QString usrCmd;
while(usrCmd != "exit" && usrCmd != "EXIT") {
//Get command input and process here
}
Inside newConnection(), I just accept the next connection and then use the socket.
QTcpSocket *serverSocket = server->nextPendingConnection();
How can I make it so the socket can wait for connections and wait for user-inputed commands at the same time?
Problem with your code is because you are blocking event loop with your while loop. So, the solution to your problem is to read from stdin asynchronously. On Linux (and on Mac, I guess), you can use QSocketNotifier to notify when the data is arrived on stdin, and to read it manually), as per various internet sources.
As I am using Windows, I would suggest you to do it in this way (which should work on all platforms):
Open the thread for reading data from stdin
Once you get some data (perhaps line?) you can use Qt signal-slot mechanism to pass the data to main thread for processing without blocking the event loop.
So, this is the pseudocode. MainAppClass should your existing server class, just edit the constructor to create new thread, and add new slot for processing the data.
class Reader: public QThread
{
Q_OBJECT
public:
Reader(QObject * parent = 0 ): QThread(parent){}
void run(void)
{
forever{
std::string data;
std::getline (std::cin, data);
if(data == "exit")
{
emit exitServer();
return;
}
emit dataReady(QString::fromStdString(data));
}
}
signals:
void dataReady(QString data);
void exitServer();
};
class MainAppClass: public QObject
{
Q_OBJECT
public:
MainAppClass()
{
Reader * tr = new Reader(this);
connect(tr, SIGNAL(dataReady(QString)), this, SLOT(processData(QString)));
connect(tr, SIGNAL(exitServer()), this, SLOT(exitServer()));
tr->start();
}
public slots:
void processData(QString data)
{
std::cout << "Command: " << data.toStdString() << std::endl;
}
void exitServer()
{
std::cout << "Exiting..." << std::endl;
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainAppClass myapp; //your server
app.exec();
return 0;
}
Since I wrote simple guidelines how to use QTcpSocket, here is the brief
When you get client QTcpSocket, connect readyRead() signal to some slot, and read data from sender() object. You don't need to read anything in the constructor.
For reading you can use standard QIODevice functions.
Note: this is pseudo code, and you may need to change few things (check the state of the stream on reading, save pointer to sockets in some list, subscribe to disconnected() signal, call listen() in constructor, check if QTcpServer is listening, etc).
So, you need to have slot onReadyRead() in your class which will have the following code:
void Server::readyReadSlot()
{
QTcpSocket *client = (QTcpSocket*)sender(); // get socket which emited the signal
while(client->canReadLine()) // read all lines!
// If there is not any lines received (you may not always receive
// whole line as TCP is stream based protocol),
// you will not leave data in the buffer for later processing.
{
QString line = client->readLine();
processLine(line); // or emit new signal if you like
}
}
Inside newConnection() you need to connect readyRead() signal with your slot.
void Server::newConnection()
{
QTcpSocket *clientSocket = server->nextPendingConnection();
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
}

Authenticating users on a Qt Server

I am trying to implement an authentication system using C++/QtTcpSocket for a personal project (A Multiplayer Chess Game).
My friend suggested a method for verifying a user but I wanted to ask if there was an easier or better way. Coming from a Python background and mostly doing this project to develop a deeper understanding of C++.
I will post the method my friend suggested and ask for maybe a better solution.
He built it in a kind of pseudo code fashion. The server is mostly built, I am now hoping to implement Authentication
*cheers
void process_packet(PACKET *pkt)
{
switch(pkt->PacketID)
{
case 0: // let's say packet id 0 is the logon packet; packet contents are username and password
{
//let's say packet size is 101 bytes; packet id was already received, so get the other 100 bytes
unsigned char BUFFER[101] = {0}; // i always add an extra byte to the end of the buffer to allow for off-by-one errors ^_^
int result = recv_packet(pkt->cSocket, 100, BUFFER);
if(result <= 0)
return; // connection error; no packet data was received
unsigned char *UserName = BUFFER+0; //+0 is not neccessary, but the username starts at the beginning. just getting the point across.
unsigned char *PassWord = BUFFER+50;
//side note: if we did "unsigned long *blah = BUFFER+4" or something, we would have to make sure the byte order is right. network byte order is BIG ENDIAN
// WINDOWS byte order is LITTLE ENDIAN
result = QueryDatabase("SELECT username, password FROM chess_players WHERE username = '%s'", FILTER_INVALID_CHARS(UserName));
// check result
unsigned char ServerResponse[2] = {0};
if(result['password'] == PassWord)
{
ServerResponse[0] = 1; // packet id will be 1. the next byte can be 1 or 0 to indicate logon success or failure.
ServerResponse[1] = true; // so packet 0x0101 mean logon success, packet 0x0100 means logon failure
send_packet(pkt->cSocket, ServerResponse, 2);
} else {
ServerResponse[0] = 1;
ServerResponse[1] = false;
send_packet(pkt->cSocket, ServerResponse, 2);
}
}
break;
default:
{
// received an unknown packet id; send a packet to the client that indicates an error_status_t
unsigned char *ServerResponse[2] = {0};
ServerResponse[0] = 2; // packet id 2 means server error
ServerResponse[1] = 0; // error code 0 means 'unknown packet id'
send_packet(pkt_cSocket, ServerResponse, 2);
}
break;
}
delete pkt; // must delete pkt, was created with 'new' in get_client_packets()
}
This seems rather C-stylish and not like the Qt way of doing things.
There is no general answer to your question but my suggestions are the following:
Listen to the newConnection() signal of the QTcpServer. Your handler has to call the nextPendingConnection() to get the next client waiting in the queue. The first thing you will do is probably your user authentication.
Once authenticated, you keep the QTcpSocket in your list of active connections.
Take a look at e.g. the fortune client/server examples how to actually write/read packets.
You might also want to look into the stream operators << to serialize your objects. This is much easier and less error prone than the low-level method you posted. ALso, QDataStream will take care of host and network byte orders automatically.
If you have followed the fortune client/server examples, you should have a QTcpServer (Rfserver) with a QThread subclass (Rfdevice, its instance variable is called thread in the following code) that contains a QTcpSocket (listenSocket).
Having said that, in your server class, listen for incoming connections, my setup looks like this:
void Rfserver::incomingConnection(int socketDescriptor){
if(thread){ //if thread exists, there is probably still an open connection
if(thread->listenSocket){//if thread exists and the listenSocket is filled, there is definately an open connection
if(thread->listenSocket->state() == QAbstractSocket::UnconnectedState){
//but alas, it could just be in the unconnected state, if so kill it.
this->disconnect();
thread->terminate();
thread=0;
connected=false;
}//otherwise, do nothing, because the software is happily connected to a device
}
}
if(!thread){ //if no thread exists, we are by no means connected
thread = new rfdevice(socketDescriptor, this); //set up a new thread
//this first connection communicates the string from your socket to the server parent...use it if you want.
connect( thread, SIGNAL(RemoteButton(QString)),this,SLOT(remoteButton(QString)),Qt::BlockingQueuedConnection);
connect( thread, SIGNAL(error(QTcpSocket::SocketError)),this,SLOT(tcpError(QTcpSocket::SocketError)),Qt::AutoConnection);
connect( thread, SIGNAL(finished()), this, SLOT(threadZero())); //I have a threadZero function that deletes all the data then schedules the socket for deletion.
thread->start();
connected=true;
QString *welcome = new QString("Enter your password:\r\n");
echoCommand(welcome); //this is a function you will implement that sends the welcome message to the pending device.
}
}
Okay, so now, when a device tries to connect to the server the device is presented with "Enter your password:\r\n". Your device will respond to this with a password and username perhaps. But the Qt side of things would look like this:
/*
FUNCTION:read
this is a polling runloop that listens for data as long as the socket is connected or connecting. If a
write is ever scheduled, it will be called from this runloop..
*/
void Rfdevice::read(void){
while((listenSocket->state() == QAbstractSocket::ConnectedState) || (listenSocket->state() == QAbstractSocket::ConnectingState)){
//if there is data available to send write it to the socket
if(dataToSend) this->write();
if(listenSocket->waitForReadyRead(50)) readBytes();
//wait for 50ms for data from the device
//if there is ever data available to be read, read it.
}
}
Your device responds with a username/password in the format username---password\r\n. Then the socket does this:
/*
FUNCTION:readBytes
this is like a callback function because it only gets called when there is data available for read.
It basically converts the data to a string.
*/
void Rfdevice::readBytes(void){
QByteArray newData;
newData = listenSocket->readAll();
QString *recieved = new QString(newData);
QStringList userAndPass = recieved.split("---");//this is your delimiter
QString username = userAndPass.at(0);
QString password = userAndPass.at(1);
//NOW, check the username and password vs your SQL or wherever it's saved.
}
The pseudo-code is pretty complete on the particulars. Hopefully you can put it all together! Let me know if you need more code.

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
}
}