0
votes

I try to programm a serial port using Qt and the QSerialPort class. I have a USB/Serial converter hooked up to my PC and an external device is connected to the serial port. The device can be queried (e.g. "ver?\n" or "meas?\n") and replies with strings; e.g. the reply to "ver?\n" could be "version 1.0" or the reply to "meas?\n" could be a comma seperated list of measurements, the length of the list being unknown in advance. The only thing I know is that each reply is terminated by a CR+LF.

When a button on my GUI is clicked, I want to send a specific request, wait for the full response and then process the data.

I have already implemented a slot for the readyRead signal, this works fine, but the problem is that this is fully asynchronous. How can I solve my problem?

I have already tried the following:

port->write(QString("meas?\n").toLocal8Bit().data());
port->flush();
port->waitForBytesWritten();
port->waitForReadyRead();
QString rxdata = port->readLine();

However, that does not work reliably because if my external device does not provide the answer fast enough, the timeout internal to QSerialPort expires, and no data is returned at all, or sometimes, I get only partial data (I think this is also due to an internal timeout).

Next, I tried to use a signal and slot approach. I connected the QSerialPort readyRead-signal to the following slot

void onReadyRead()
{
    static QString buffer;
    while(port->bytesAvailable())
    {
        buffer = buffer.append(port->readAll());
        if(buffer.endsWith("\n"))
        {
            // the reply is received completely
        }
    }
}

this does receive the full data correctly, but unfortunately, it is an asynchronous approach and the reply is stored in the buffer internal to onReadyRead. But I want to use the serial port as follows:

port->write("meas?\n"); QString reply = receive_reply(); //wait until \n is received or timeout occurs

2
It would be nice if you edited the question adding some code, to clarify the issue and show what you tried so far. Thanks.p-a-o-l-o

2 Answers

1
votes

I would try this:

port->write(QString("meas?\n").toLocal8Bit().data());
port->flush();
port->waitForBytesWritten();
port->waitForReadyRead();
QString rxdata;
while(!rxdata.endsWith("\n"))
{
    rxdata.append(port->readAll());
}
0
votes

I have expanded p-a-o-l-o answer a little bit:

QString buf;
QTime start = QTime::currentTime();
port->write("meas?\n");
port->flush();
port->waitForBytesWritten();
buf.clear();
while(!buf.endsWith("\n"))
{
    if(!port->waitForReadyRead(50))
        break;

    buf.append(port->readAll());
    QCoreApplication::processEvents(QEventLoop::AllEvents, 100);


   int elapsed = start.msecsTo(QTime::currentTime());
    qDebug() << elapsed;
    if(elapsed > 10000)
    {
        buf.clear();
        port->clear();
        break;
    }
}
return buf.trimmed();

I have also added the processEvents() call to prevent the GUI from freezing, and I also implemented a timeout.