2016-07-03 2 views
1

Je travaille avec un périphérique série. QSerialPort se trouve dans un thread distinct. thread est créé de cette façon:QSerialPort - Wating pour l'ensemble des données de l'expéditeur

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

Lorsque les données sont disponibles ce signal dans mon travailleur de fil est emited:

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

Ceci est la fonction qui lit les données et vérifie si les données sont correctes - le second octet sur mon appareil de série indique depuis combien de temps le reste du paquet est ...

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; 
} 

mon problème est que le signal QSerialPort :: readyRead est emited avant la da ta à partir du périphérique série est terminée dans le tampon. Une idée de comment résoudre ce problème?

Répondre

3

Il est absolument NO garantir que vous obtiendrez des données entières à ONCE. Vous pouvez résoudre ce problème d'une certaine manière.

1) Si vous avez forfait de taille fixe que vous pouvez faire quelque chose comme ceci:

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) Si la taille de votre emballage peut varier. Ensuite, vous devez inclure "hader" dans votre paquet. Cet en-tête doit contenir au moins "start" octet et la taille des données (Son second octet dans votre cas). Et l'en-tête devrait être fixée en taille. Ensuite, vous pouvez faire quelque chose comme ceci:

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; 
} 

Et il n'y a absolument aucune raison de mettre votre QSerial pour thread différent.

UPD: Vous pouvez voir exemple plus complexe à mon GitHub https://github.com/YouDoItWrong/AltimeterTool (il est petit utilitaire de test pour sonar underwoter, qui fonctionne via RS-232.)

+0

i mettre m Qserial dans un fil differnt parce que je vouloir surveiller un ECU de voiture en temps réel. Je l'ai essayé dans le processus mainwindow et le GUI était très laggy –

+1

Je pense, il gèle parce que vous utilisez QSerialPort dans un "blocage" (non asynchrone). C'est pourquoi il gèle http://code.qt.io/cgit/qt/qtserialport.git/tree/src/serialport/qserialport.cpp#n201 – YouDoItWrong