QSerialPort readyread() SIGNAL - c++

I have a problem when receiving bytes from RS232 in QByteArray. I connected readyread() signal to call my serialport method and inside it I am reading bytes with readAll() to an QByteArray. Whenever data is available it rewrites QByteArray, but I want to receive it all, and then use data, but now I cannot because it is in parts. What to do?

Simply append to the array. You'll also need some criterion to determine when you've received all the data you wished. This can be, e.g. a given number of bytes:
class Communicator {
int expect;
QSerialPort port;
QByteArray reply;
void processReply() {
...
}
public:
Communicator() {
QObject::connect(&port, &QIODevice::readyRead, [this]{
reply += port.readAll();
if (expect && reply.size() >= expect) {
processReply();
reply.clear();
expect = 0;
}
});
...
};

Related

Sending images over TCP from labVIEW to QT

I am trying to capture images taken from a camera connected to a myRIO and send them over a TCP/IP connection from labVIEW to a QT GUI application.
My problem is that QT keeps throwing a heap pointer exception and crashing when I read the data.
Expression: is_block_type_valid(header->_block_use)
I believe this could be because the data being sent is over 35k bytes, so I tried to read the data in separate chunks, but alas am still getting the error.
Below is my function that gets called on readyRead() being emitted:
void TCPHandler::onRead() {
QByteArray byteArray;
QByteArray buffer;
QByteArray dataSize = mainSocket->read(5); //read the expected amount of bytes incoming (about 35000)
while (buffer.size() < dataSize.toInt()) {
int bytesLeft = dataSize.toInt() - buffer.size();
if (bytesLeft < 1024) {
byteArray = mainSocket->read(bytesLeft);
}
else {
byteArray = mainSocket->read(1024);
}
buffer.append(byteArray);
}
QBuffer imageBuffer(&buffer);
imageBuffer.open(QIODevice::ReadOnly);
QImageReader reader(&imageBuffer, "JPEG");
QImage image;
if(reader.canRead())
image = reader.read();
else {
emit read("Cannot read image data");
}
if (!image.isNull())
{
image.save("C:/temp");
}
else
{
emit read(reader.errorString());
}}
In the LabVIEW code I send the size of the bytes being sent first, then the raw image data:
EDIT: Connect for the slot. Also should have mentioned this is running in a separate thread to the Main GUI.
TCPHandler::TCPHandler(QObject *parent)
: QObject(parent),
bytesExpected(0)
{
mainSocket = new QTcpSocket(this);
connect(mainSocket, SIGNAL(readyRead()), this, SLOT(onRead()));
connect(mainSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &TCPHandler::displayError);
}
You are sending your length as a decimal string. Then followed by the string.
I would expect that the length would be binary value. So instead of an 'I32 to String' function use a typecast with a string as the type.

readAll() from QSerialPort doesn't include the last response sent

I'm using Qt to control a serial device. If I send a command to my serial device, I do something like serial->write("command \r\n"). I made a push button which changes the text inside a plain text widget to the response of the serial port. To get the response of the serial port, I'm using serial->readAll(). The problem is it shows the 2nd to last response rather than the one I was expecting. Does Qt have some sort of buffer which is keeping hold of this response?
EDIT
I botched it by using recursion and compared the strings recieved
You might be calling readAll before the response is available. You should hook your code to the readyRead signal to be notified each time new chunk of data is ready to be read. Keep in mind that readyRead can be emitted with any number of bytes available to read - at a minimum, it'll be just one byte. You can't expect the data to be chunked/blocked in any particular way, since the serial port doesn't act as a message-based communication device. Your receiver code must be able to piece the data together from small chunks and act accordingly when it got all the data it needs.
For example, suppose that the device responses have a fixed, known length. You'd only want to react when a complete response has arrived. E.g.:
class Protocol : public QObject {
Q_OBJECT
QBasicTimer m_timer;
QPointer<QIODevice> m_port;
int m_responseLength = 0;
int m_read = 0;
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() != m_timer.timerId()) return;
m_timer.stop();
emit timedOut();
}
void onData() {
m_read += m_port->bytesAvailable();
if (m_read < m_responseLength)
return;
m_timer.stop();
emit gotResponse(m_port->read(m_responseLength));
m_read -= m_responseLength;
m_responseLength = 0;
}
public:
Q_SIGNAL void gotResponse(const QByteArray &);
Q_SIGNAL void timedOut();
Q_SLOT void sendCommand(const QByteArray & cmd, int responseLength, int cmdTimeout) {
m_responseLength = responseLength;
m_port->write(cmd);
m_timer.start(cmdTimeout, this);
}
explicit Protocol(QIODevice * port, QObject * parent = nullptr) :
QObject(parent), m_port(port) {
connect(m_port, &QIODevice::readyRead, this, &Protocol::onData);
}
};
...
Protocol protocol(0,0);
protocol.sendCommand({"foo"}, 10, 500);
QMetaObject::Connection cmd1;
cmd1 = QObject::connect(&protocol, &Protocol::gotResponse, [&]{
QObject::disconnect(cmd1);
qDebug() << "got response to foo";
});
QObject::connect(&protocol, &Protocol::timedOut, []{ qDebug() << "timed out :("; });

QSerialPort reads wrong count of data

here is what I want to do:
I have a measurement device that measures pressure. It's connected via COM1. By sending the "ASCII letter 9" data, respectively measurements are retrieved from this device.
These measurements should be shown in a QTableView-subclass in my GUI. I don't want the GUI to freeze while reading from the measurement device, so I guess this is called non-blocking.
In my code and for testing I want to retrieve 10 measurements in a for-loop. But I always just get 6, sometimes 7.
I have also subclassed QSerialPort.
The code is shown below. A hint what I am doing wrong or maybe even a correction of my code would be very appreciated. Also feel free to comment on the design of the code.
void MainWindow::startInspection()
{
SauterFH_S *sauterFH_S;
try
{
sauterFH_S = new SauterFH_S(new SerialPort(serialPort,
baudRate));
}
catch(QSerialPort::SerialPortError& e)
{
qDebug() << e;
}
connect(sauterFH_S, SIGNAL(measurandAvalaible(char*)),
measurandTableWidget, SLOT(insertMeasurand(char*)));
// Retrieve 10 measurements
for(int i=0; i<10; ++i)
sauterFH_S->getMeasurand();
delete sauterFH_S;
}
The constructor of the subclassed QSerialPort is as follows:
TASte::IO::SerialPort::SerialPort(const QString &portName, qint32
baudRate, DataBits dataBits, Parity parity, StopBits stopBits,
QIODevice::OpenMode openMode, QObject *parent)
:QSerialPort(parent)
{
setPort(QSerialPortInfo(portName));
setBaudRate(baudRate);
setDataBits(dataBits);
setParity(parity);
setStopBits(stopBits);
if( !open(openMode) ) throw error();
}
And here the rest of what should be important:
TASte::Gauge::SauterFH_S::SauterFH_S(IO::SerialPort *port)
:_port(port)
{
connect(_port, SIGNAL(readyRead()),this, SLOT(onReadyRead()));
}
TASte::Gauge::SauterFH_S::~SauterFH_S()
{
// delete _port;
}
void TASte::Gauge::SauterFH_S::getMeasurand()
{
// typedef QByteArray SerialCommand
IO::SerialCommand command("9");
_port->write(command);
}
void TASte::Gauge::SauterFH_S::onReadyRead()
{
// static const int DATA_LENGTH=8;
char data[DATA_LENGTH];
_port->read(data, DATA_LENGTH);
emit measurandAvalaible(data);
}
Thanks in advance!
Object QSerialPort works well if You send and recive data in other thread. In your case data it can be lost, and program sometimes freeze. I had this same problem. I show you something. I write code each using transmition in UDP, but in serialport is this same conception. So first you must create thread for your serial port. In my case I create therad but for UDP. And you must define your all connections each that be some Interafe beetwen Threads MainWindow and SerialPort.
thForUdp = new QThread();
udp->moveToThread(thForUdp);
thForUdp->start();
connect(this , SIGNAL(SIGNAL_RefreshStatus()) , udp , SLOT(SLOT_refreshStatus()) , Qt::QueuedConnection);
connect(udp , SIGNAL(SIGNAL_TransmitionFailed()) , this , SLOT(SLOT_TrasmitionFailed()) , Qt::QueuedConnection); //od
connect(udp , SIGNAL(SIGNAL_ActualStatus(QByteArray)) , schema , SLOT(SLOT_ActualStatus(QByteArray)) , Qt::QueuedConnection);
connect(udp , SIGNAL(SIGNAL_RefreshTimer()) , this , SLOT(SLOT_StartRefreshTimer()) , Qt::QueuedConnection ); //do
connect(this , SIGNAL(SIGNAL_GetAllName()) , udp , SLOT(SLOT_GetAllName()) , Qt::QueuedConnection );
connect(udp , SIGNAL(SIGNAL_AllName(QVector<QString>)) , schema , SLOT(SLOT_AllName(QVector<QString>)), Qt::QueuedConnection);
connect(udp , SIGNAL(SIGNAL_setEnableRefresh(bool)) , this , SLOT(SLOT_setEnableRefresh(bool)) , Qt::QueuedConnection);
Now you must create object inherited from QSerialPort. In my case I inhert from QUdpSocket
class Udp : public QUdpSocket , public Object
{
Q_OBJECT
public:
Udp(Mediator *medium);
private slots:
void SLOT_ReadyToReadStatus();
signals:
void SIGNAL_TransmitionFailed();
void SIGNAL_RefreshTimer();
void SIGNAL_ActualStatus(QByteArray stat);
void SIGNAL_AllName(QVector<QString> vec);
void SIGNAL_setEnableRefresh(bool state);
};
As you see Udp class have all SIGNAL then you see in first block code. Then you creat in your serial port class right signal and slot to send and recever data
In my case this is in construktor Udp
QObject::connect(this , SIGNAL(readyRead()) , this , SLOT(SLOT_ReadyToReadStatus()));`
Now your program will be worked in this rules.
MainWindow form tread A send signal (get data) --->> in object serialport in thread B data is send and in Thread B data is received then serialport send signal to thread A (send recived data to thread A) --->> MainWindow Received data
Very important is communicate between MainWindow and SerialPort via mechanism SIGNAL & SLOT becase the are two difrent thread. This is in QT rule.
This solution will that your program not freeze and data is be complet received, because another thread take care this.
Generaly I recommend use function waitForReadyRead() after you send data, and receive via waitForReadtRead
{
if(!this->waitForReadyRead(3000))
{
// here is wait for data maximum 3 second
// if recived your data find in slot SLOT_ReadyToReadStatus()
}
// if data is correct receive from this block you send to Thread A via SIGNAL!!
QByteArray array
SIGNAL_Here_Data_To_To_Thread_A(array)
}
Try this

How to make blocking tcp socket with Qt?

I work with QTcpSocket. I need any write/read calls to the socket to be synchronous (blocking).
I know there is waitForReadyRead() and waitForBytesWritten(), but those two methods are marked in Qt documentation as they can fail randomly under Windows. I cannot affort this.
The blocking read is the most important (as reading comes always after writting a command to the other peer, so I know that if data reaches the other peer, it will answer).
I have tried 2 approaches.
First:
QByteArray readBytes(qint64 count)
{
int sleepIterations = 0;
QByteArray resultBytes;
while (resultBytes.size() < count && sleepIterations < 100)
{
if (socket->bytesAvailable() == 0)
{
sleepIterations++;
QThread::msleep(100);
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
continue;
}
resultBytes += socket->read(qMin(count, socket->bytesAvailable()));
}
return resultBytes;
}
This should wait for bytes to be available for reading on the socket, processing the event loop in the mean time, so the socket is doing it's necessary internal stuff.
Unfortunately - for unknown to me reason - the bytesAvailable() sometimes returns correct number of bytes, but sometimes it never returns anything greater than 0.
I know in fact that there was data to be read, because it used to work with the second approach (but it has it's own problems).
Second:
I have a kind of signal "blocker", which blocks current context and processes event loop, until certain signal is emitted. This is the "blocker":
SignalWait.h:
class SignalWait : public QObject
{
Q_OBJECT
public:
SignalWait(QObject *object, const char *signal);
bool wait(int msTimeout);
private:
bool called = false;
private slots:
void handleSignal();
};
SignalWait.cpp:
SignalWait::SignalWait(QObject* object, const char* signal) :
QObject()
{
connect(object, signal, this, SLOT(handleSignal()));
}
bool SignalWait::wait(int msTimeout)
{
QTime timer(0, 0, 0, msTimeout);
timer.start();
while (!called && timer.elapsed() < msTimeout)
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
return called;
}
void SignalWait::handleSignal()
{
called = true;
}
and then I used it like this:
SignalWait signalWait(socket, SIGNAL(readyRead()));
// ...
// socket->write(...);
// ...
if (!signalWait.wait(30000))
{
// error
return;
}
bytes = socket->read(size);
This approach seems to be working better, but it also fails from time to time. I don't know why. It's like the readyRead() signal was never emitted and the SignalWait keeps waiting, until it times out.
I'm out of ideas. What is the proper way to deal with it?
I would suggest to use the asynchronous approach but if you really want to go with the synchronous way, then a better way is to use a local event loop:
QTimer timer;
timer.setSingleShot(true);
QEventLoop loop;
loop.connect(socket, SIGNAL(readyRead()), SLOT(quit()));
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
while (resultBytes.size() < count)
{
timer.start(msTimeout);
loop.exec();
if(timer.isActive())
resultBytes += socket->read(qMin(count, socket->bytesAvailable()));
else
break;
}
Here it waits until count bytes are read or the the timeout reaches.

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()));
}