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

时间:2016-06-29 15:03:15

标签: c++ qt serial-port

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

修改 我通过使用递归对其进行了拙劣,并比较了收到的字符串

1 个答案:

答案 0 :(得分:3)

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

例如,假设设备响应具有固定的已知长度。您只想在完成响应时做出反应。 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 :("; });