来自 QSerialPort 的 readAll() 不包括最后发送的响应

2022-01-18 00:00:00 qt serial-port c++

我正在使用 Qt 来控制串行设备.如果我向串行设备发送命令,我会执行 serial->write("command ") 之类的操作.我做了一个按钮,它将纯文本小部件内的文本更改为串行端口的响应.为了得到串口的响应,我使用了serial->readAll().问题是它显示了倒数第二个响应,而不是我期望的响应.Qt 是否有某种缓冲区来保存此响应?

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 "). 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

推荐答案

您可能在响应可用之前调用了 readAll.您应该将代码挂接到 readyRead 信号,以便在每次准备好读取新数据块时收到通知.请记住,readyRead 可以发出任意数量的可供读取的字节 - 至少只有一个字节.您不能期望数据以任何特定方式被分块/阻塞,因为串行端口不充当基于消息的通信设备.您的接收器代码必须能够将数据从小块拼凑在一起,并在获得所需的所有数据时采取相应的行动.

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

相关文章