Problems with RTS management with QtSerialPort
-
Hi all.
I am implementing a communicatin protocol over RS485 and I am having problems with the RTS management.
I am QSerialPort class in Qt 5.6.1.I put UP the RTS when I am going to trasnmit a frame data and when the "bytesWritten" signal is received I put it DOWN in the connected slot.
If I have no answer to the above sent frame, I retransmit it. But in the retranmission (in the same slot as above) the RTS signal is put down before all the data have been retransmitted.The up and down of the signal is done with the method "setRequestToSend".
This is the code the mos relevant related code:
Port configuration
if(mSerialPort->open(QIODevice::ReadWrite)){
currentTxId = 0;
mSerialPort->setBaudRate(QSerialPort::Baud115200);
mSerialPort->setDataBits(QSerialPort::Data8);
mSerialPort->setFlowControl(QSerialPort::NoFlowControl);
mSerialPort->setStopBits(QSerialPort::OneStop);
mSerialPort->setParity(QSerialPort::NoParity);mSerialPort->setDataTerminalReady(true); bool rtsUP = mSerialPort->isRequestToSend(); mSerialPort->setRequestToSend(!rtsUP); connect(mSerialPort, SIGNAL(readyRead()), this, SLOT(onDataAvailable())); connect(mSerialPort, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
}
Send Data and RTS Up
bool AppProtocolHandler::sendFrameWithACK(const QByteArray frame)
{
QByteArray txframe = frame;
txframe.push_front(flag_STX);
txframe.push_front(flag_DLE);
txframe.push_back(flag_DEL);
txframe.push_back(flag_ETX);//Start frame retransmission Timer m_txTimer->start(FRAME_RETRANSMISION_TIME); bool rtsUP = mSerialPort->isRequestToSend(); if (rtsUP){ mSerialPort->setRequestToSend(false); } qint64 frameLenght = static_cast<qint64> (frame.at(0)); qint64 txlen = mSerialPort->write(txframe, frameLenght); if (mSerialPort->waitForBytesWritten(500)){ m_txframe = frame; m_pendingFrames.insert(static_cast<int>(txframe.at(5)), static_cast<t_prot_cmd>(txframe.at(6))); return true; } else { qDebug()<< "AppProtocolHandler::sendFrameWithACK waitForBytesWritten(500) = FALSE"; mSerialPort->setRequestToSend(true); return false; }
}
End Send Data and RTS Down
void AppProtocolHandler::onBytesWritten(qint64 nBytes)
{
qint64 frameLenght = static_cast<qint64> (m_txframe.at(0));if (nBytes == frameLenght) { bool rtsUP = mSerialPort->isRequestToSend(); if (!rtsUP){ mSerialPort->setRequestToSend(true); } }
}
Any help or experience would be appreciated.
Thanks!! -
Hi @iaguirre,
on which platform are you?
I guess your problem is most likely, that
onBytesWritten
is called when QSerialPort has written the data to the operating system (which has it's own buffers), but that does not mean the data is actually (completely) written on the serial line (and therefore not completely received from the other side).We had a problem like this some month ago, where a Linux
flush
call helped; I just don't find it now :(In any case, this will mean you have to block your program so it should preferable be done in a thread.
Edit: found it: https://forum.qt.io/topic/83399/qtserialport-blocking-write-in-raspberry-pi-raspbian-pixel
-
Hi @iaguirre,
We are running the program on Linux.
Good. The solution I have for you is not portable...
When you say Linux flush call, you mean QtSerialPort flush method?
The guy in the other thread cleared both the QtSerialPort (with flush) and Kernel buffers (with tcdrain) and it worked for him. Please see: https://forum.qt.io/topic/83399/qtserialport-blocking-write-in-raspberry-pi-raspbian-pixel/7
As said, keep in mind that it will block your program for the time it takes to write the bytes.
-
Hi again.
The best solution has been to enable RTS after open the port, following the instructions readed here:
https://github.com/torvalds/linux/blob/master/Documentation/serial/serial-rs485.txtYou should verify if your linux kernel driver supports it.
Regards