2016-06-29 26 views
0

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

编辑 我把事情弄糟了通过使用递归和比较字符串收到

回答

3

你可能会调用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 :("; }); 
+0

感谢这是一个非常有帮助的回应! – jxb458