2016-07-03 6 views
1

Ich arbeite mit einem seriellen Gerät. Der QSerialPort befindet sich in einem separaten Thread. Thema ist auf diese Weise erstellt:QSerialPort - wating für ganze Daten vom Absender

QThread* serialthread = new QThread; 
Serial* serial = new Serial(); 
serial->moveToThread(serialthread); 

Wenn Daten verfügbar dieses Signal in meinem Thread Arbeiter ist emited:

void Serial::process() 
    { 
     serialport = new QSerialPort(); 
     connect(this->serialport,SIGNAL(readyRead()),this,SLOT(readyToRead())); 
    } 
    void Serial::readyToRead() 
    { 
     emit SIG_dataAvailable(this->read()); 
    } 

Dies ist die Funktion, die die Daten und prüft, liest, wenn die Daten korrekt sind - das zweite Byte auf meinem seriellen Gerät sagt, wie lange der Rest des Pakets ist ...

QByteArray Serial::read() const 
{ 
    QByteArray receivedData; 
    int length; 
    receivedData = serialport->readAll(); 
    length = receivedData[1]; 
    if(length != receivedData.length() - 1) 
    { 
     qDebug() << "protocol error."; 
     return NULL; 
    } 
    return receivedData; 
} 

Mein Problem ist, dass das Signal QSerialPort :: readyread vor dem da emited ist ta vom seriellen Gerät ist im Puffer abgeschlossen. Irgendeine Idee, wie man dieses Problem löst?

Antwort

3

Es gibt absolut NO garantiert, dass Sie ganze Daten bei einmal erhalten werden. Sie können dieses Problem auf verschiedene Arten lösen.

1) Wenn Sie Größe Paket behoben haben, können Sie etwas tun:

void foo::onSerialRead() 
{ 
    //! Is there whole datagram appears? 
    if (m_serial->bytesAvailable() < ::package_size) { 
     //! If not, waiting for other bytes 
     return; 
    } 

    //! Read fixed size datagram. 
    QByteArray package = m_serial->read(::package_size); 
    //! And notify about it. 
    emit packageReady(package); 
} 

2) Wenn Ihr Paket Größe variieren. Dann müssen Sie "Hader" in Ihr Paket aufnehmen. Dieser Header sollte mindestens "Start" Byte und Datengröße (sein zweites Byte in Ihrem Fall) enthalten. Und der Header sollte eine feste Größe haben. Dann können Sie etwas tun:

void foo::onSerialRead() 
{ 
    static QByteArray package; 
    static bool isHeaderRead = false; 
    static quint8 startByte = 0; 
    static quint8 dataSize = 0; 

    //! Is there whole header appears? 
    if (m_serial->bytesAvailable() < ::header_size) { 
     //! If not, waiting for other bytes 
     return; 
    } 

    if (!isHeaderRead) { 
    //! Read fixed size header. 
     package.append(m_serial->read(::header_size)); 
     QDataStream out(&package); 

     out >> startByte; 

    //! Check is it actually beginning of our package? 
     if (Q_UNLIKELY(startByte != ::protocol_start_byte)) { 
      return; 
     } 
     out >> dataSize; 
     isHeaderRead = true; 
    } 

    //! Check is there whole package available? 
    if (Q_LIKELY(dataSize > m_serial->bytesAvailable())) { 
     //! If not, waiting for other bytes. 
     return; 
    } 
    //! Read rest. 
    package.append(m_serial->read(dataSize)); 
    //! And notify about it. 
    emit packageReady(package); 
    package.clear(); 
    isHeaderRead = false; 
} 

Und es gibt absolut keinen Sinn, Ihre QSerial bei der Umsetzung in unterschiedlichen Fäden.

UPD: Sie können etwas komplexeres Beispiel an meinem GitHub sehen https://github.com/YouDoItWrong/AltimeterTool (es ist klein Test-Utility für underwoter Sonar, die über RS-232 arbeitet.)

+0

i Qserial, weil ich in einem Differnt Gewinde M put möchte ein Auto-ECU in Echtzeit überwachen. Ich versuchte es im Hauptfenster process und die GUI war sehr laggy –

+1

Ich denke, es ist eiskalt, weil Sie QSerialPort in einer "blockierenden" (nicht asynchronen) Maner verwenden. Deshalb friert http://code.qt.io/cgit/qt/qtserialport.git/tree/src/serialport/qserialport.cpp#n201 ein – YouDoItWrong