Search code examples
c++windowsqtqt5.6qtserialport

QSerialPort manual RTS on/off not synched to call


I'm trying to send to data over the serial port. For the control flow I need to manually set and clear the RTS line: Set it (RTS on) when I'm sending data, and clear it (RTS off) when I'm done sending and am ready to receive the reply.

The code I use is basically

serialPort->setRequestToSend(false);
serialPort->write(reinterpret_cast<char*>(package.data()), package.size());
serialPort->flush();
serialPort->setRequestToSend(true);

The variable package is a QVector<int8_t> but that's rather irrelevant for the problem. The above code is called in a timer every five second.

The problem is that RTS off doesn't happen until the next time I send a message, when I need it to happen immediately.

See the below sniffed log:

10:11:06 +00:06.301   Set RTS: on
10:11:06 +00:06.302 < 0000  01 01 00 01 00 01 ac 0a                          ........
10:11:11 +00:11.300   Set RTS: off
10:11:11 +00:11.300   Set RTS: on
10:11:11 +00:11.301 < 0000  01 01 00 01 00 01 ac 0a                          ........
10:11:16 +00:16.300   Set RTS: off
10:11:16 +00:16.301   Set RTS: on
10:11:16 +00:16.301 < 0000  01 01 00 01 00 01 ac 0a                          ........

As seen in the log, the RTS on happens correctly just when I send my message, but the RTS off doesn't happen until the next time I send.

The flush call doesn't matter, and adding another flush call after setRequestToSend(true) doesn't help either. Attempting to read after is also not helping.

Do I need to connect to a special signal to know when I can call setRequestToSend to set RTS off? Do I need to use the Windows native serial port functions to set/clear RTS? Or am I just doing something wrong, or have some misunderstanding in how the setRequestToSend function and QSerialPort work, or serial ports in general?

For reference, here's how I configure the serial port:

serialPort->setDataBits(QSerialPort::Data8);
serialPort->setBaudRate(QSerialPort::Baud115200);
serialPort->setParity(QSerialPort::NoParity);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);

And the port is opened okay as well.


A little background: I'm trying to replace an existing program which is getting rather old and also have problems being ported to Windows 10 (from Windows XP). It uses native Windows serial port functions to read and write, and also manual handling of RTS on/off. It communicates with Modbus devices, using a RS232-to-RS485 converter (made in-house). The old program can set and clear RTS without problems, but my replacement program using QSerialPort just can't. I would like to avoid getting the native Windows handle for the RTS problem, but will do that unless there's any other solution.

I'm using Qt 5.6.3 and VisualC++ 2017 (14.16.27023) in 32-bit mode, because I want the program to be compatible with the older Windows XP systems still being used.


Solution

  • It turns out that the data isn't actually written (including the RTS off flag) until the program returns to the event loop. Or if the waitForBytesWritten function is called.

    So the code now looks like

    serialPort->setRequestToSend(true);
    serialPort->write(reinterpret_cast<char*>(package.data()), package.size());
    serialPort->waitForBytesWritten(100);
    serialPort->setRequestToSend(false);
    

    The RTS on and RTS off now is "sent" when they should.