C++ QSerialPort中的readAll()不';不包括最后发送的响应

C++ QSerialPort中的readAll()不';不包括最后发送的响应,c++,qt,serial-port,C++,Qt,Serial Port,我用Qt控制一个串行设备。如果我向串行设备发送命令,我会执行类似于serial->write(“command\r\n”)的操作。我制作了一个按钮,它将纯文本小部件中的文本更改为串行端口的响应。要获得串行端口的响应,我使用serial->readAll()。问题是它显示的是倒数第二个响应,而不是我期望的响应。Qt是否有某种缓冲区来保存此响应 编辑 我使用递归将它搞糟了,并比较了接收到的字符串。在响应可用之前,您可能正在调用readAll。您应该将代码挂接到readyRead信号,以便在每次准备读

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

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

例如,假设设备响应具有固定的已知长度。您只希望在收到完整的响应后才做出反应。例如:

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 :("; });
类协议:公共QObject{
Q_对象
基本定时器;
QPointer m_端口;
int m_responseLength=0;
int m_read=0;
无效timerEvent(QTimerEvent*ev)覆盖{
如果(ev->timerId()!=m_timer.timerId())返回;
m_timer.stop();
emit timedOut();
}
void onData(){
m_read+=m_端口->字节可用();
如果(m_读取读取(m_responseLength));
m_read-=m_响应长度;
m_响应长度=0;
}
公众:
Q_信号无效响应(常数QByteArray&);
Q_信号无效时间dout();
Q_插槽无效发送命令(const QByteArray&cmd、int responseLength、int cmdTimeout){
m_responseLength=responseLength;
m_端口->写入(cmd);
m_timer.start(cmdTimeout,this);
}
显式协议(QIODevice*端口,QObject*父级=nullptr):
QObject(父对象),m_端口(端口){
连接(m_端口和QIODevice::readyRead、this和Protocol::onData);
}
};
...
协议(0,0);
sendCommand({“foo”},10500);
QMetaObject::Connection cmd1;
cmd1=QObject::connect(&protocol,&protocol::gotResponse,[&]{
QObject::disconnect(cmd1);

qDebug()在响应可用之前,您可能正在调用
readAll
。您应该将代码挂接到
readyRead
信号,以便在每次准备读取新数据块时收到通知。请记住,
readyRead
可以读取任意数量的字节-至少只有一个字节。您可以由于串行端口不作为基于消息的通信设备,因此不能期望以任何特定方式对数据进行分块/阻塞。接收器代码必须能够将数据从小块分割到一起,并在获得所需的所有数据时采取相应措施

例如,假设设备响应具有固定的已知长度。您只希望在完整响应到达时进行响应。例如:

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 :("; });
类协议:公共QObject{
Q_对象
基本定时器;
QPointer m_端口;
int m_responseLength=0;
int m_read=0;
无效timerEvent(QTimerEvent*ev)覆盖{
如果(ev->timerId()!=m_timer.timerId())返回;
m_timer.stop();
emit timedOut();
}
void onData(){
m_read+=m_端口->字节可用();
如果(m_读取读取(m_responseLength));
m_read-=m_响应长度;
m_响应长度=0;
}
公众:
Q_信号无效响应(常数QByteArray&);
Q_信号无效时间dout();
Q_插槽无效发送命令(const QByteArray&cmd、int responseLength、int cmdTimeout){
m_responseLength=responseLength;
m_端口->写入(cmd);
m_timer.start(cmdTimeout,this);
}
显式协议(QIODevice*端口,QObject*父级=nullptr):
QObject(父对象),m_端口(端口){
连接(m_端口和QIODevice::readyRead、this和Protocol::onData);
}
};
...
协议(0,0);
sendCommand({“foo”},10500);
QMetaObject::Connection cmd1;
cmd1=QObject::connect(&protocol,&protocol::gotResponse,[&]{
QObject::disconnect(cmd1);

谢谢这是一个非常有用的回答!谢谢这是一个非常有用的回答!