0

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • what version is it? There was bug they said fixed before 5.7.4 (?) that RTS wasn't set properly if flow control enabled. Also my work with mixing embedded ahrdware and notebooks without RS port revealed that RTS is kinda buggy with USB "virtual" RS-232. Some other RS may have issue too (422, 485?). It kind of depends which adapter it is, some cheap illegal knock-offs (apparently it's a patent, to have a serial-USB controller!) do have implementation issues, – Swift - Friday Pie Sep 03 '19 at 09:12
  • On Windows you will struggle with the timing to accurately turn on and off RTS, I know this from previous experience using the Modbus protocol on Windows and RS485. In the end we purchased a device from KK systems which automatically asserts RTS lines when it detects data. This was a much better solution. Windows is very poor at timeing. – SPlatten Sep 03 '19 at 11:25

1 Answers1

1

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621