QT 5.7 Serial port is very slow to read

I am very new to programming and I am teaching myself. I wrote an application to poll multiple requests from a control unit. I basically continuously send various read commands to the control unit and read the response. My program is working and I am successfully sending commands and getting responses. But reading is very slow (I have a 100ms timeout in my code so that I can get a complete answer) I have a program for the same control unit that was written by a professional C ++ coder, in his program it polls every 30 ms and I always get a complete answer during this time period. I have the same settings 57K baud 8 bits 1 stop bit and no parity. However, my QT code takes almost 100ms to get an answer. In my code, I read the first 2 bytes (the first byte is the message ID and the second is the rest of the message length),then I read in a loop until the total message length is equal to the message length +1 byte (+ 1 should include the first byte). I understand why my code is so slow in QT when I know it knows the hardware, which is the limiting factor. Requests are always 3 bytes and the response ranges from 3 to 61 bytes. Please help me point out my mistake. If I remove the timeout, I will always have short reads. So far I've tried reading (all) too, but with the same result. Below is an excerpt from my code where I read the answer. The complete code is inand the response ranges from 3 to 61 bytes. Please help me point out my mistake. If I remove the timeout, I will always have short reads. So far I've tried reading (all) too, but with the same result. Below is an excerpt from my code where I read the answer. The complete code is inand the response ranges from 3 to 61 bytes. Please help me point out my mistake. If I remove the timeout, I will always have short reads. So far I've tried reading (all) too, but with the same result. Below is an excerpt from my code where I read the answer. The complete code is inhttps://github.com/MarkusIppy/PowerTune

//Error handling 
QTime startTime = QTime::currentTime(); 
int timeOut = 100; // timeout in milisec. 
QByteArray recvData = m_serialport->read(2);  // reading first two bytes of received message to determine lenght of ecpected message 
int msgLen = recvData[1]; //Total message Lenght excluding the first byte 
while ( recvData.size() <= (msgLen+1) ) 
{ 
    if ( startTime.msecsTo(QTime::currentTime()) > timeOut ) break; 
    recvData += m_serialport->read(msgLen+1-recvData.size()); 
} 

if (msgLen +1 == recvData.length())  //if the received data lenght equals the message lenght from lenght byte + identifier byte (correct message lenght received ) 
{ 
    qDebug() << "Received data OK"<<msgLen +1; 
    if(requestIndex <= 61){requestIndex++;} 
    else{requestIndex = 58;} 
    readData(recvData); 
} 
else   //if the lenght of the received message does not correspond with the expected lenght repeat the request 
{ 
    qDebug() << "Received data lenght NIO"; 
    readData(recvData); 
    qDebug() << "Request Message again"<< requestIndex; 
}

      

+3


source to share


3 answers


Sorry I don't have time to go through your project and from the code you provided. I can't be 100% sure what the reason is. My best guess, however, is that the problem in this case is that you are not explicitly expecting data to be received, and event handling is somehow delayed or not happening at all.

Anyway, here you have a few suggestions:



  • Use QTimer for timeouts instead of QTime.
  • Learn about Qt5 signals and slots and use them to read asynchronously from a serial port.

I use QSerialPort, connecting its signals bytesWritten(qint64 bytes)

and readyRead()

to slots of my program, let's say on_bytesWritten(qint64 bytes)

, and on_readyRead()

. Then I send the request to the target device and in the slot I on_readyRead()

process the result. With each send command, I start QTimer with a signal timeout()

connected to a slot in on_timeout()

my application. Thus, I could control whether the device responds in time or not, and also receive data immediately after it appeared. You can also use the errorOccurred(QSerialPort::SerialPortError error)

QSerialPort signal to check if there is a transmission problem.

+2


source


This is what I have so far (just posting important parts of my cpp file) This code works almost perfectly with my message emulator. It polls now as expected, but the timeout always fires after 5 seconds (I need to change it so that it only fires when there is no message). I will only be able to test it at the actual hardware end of next week. This is what I have so far:



    void Serial::initSerialPort()
    {
    if (m_serialport)
        delete m_serialport;
    m_serialport = new SerialPort(this);
    connect(this->m_serialport,SIGNAL(readyRead()),this,SLOT(readyToRead()));
    connect(m_serialport, static_cast<void (QSerialPort::*)    (QSerialPort::SerialPortError)>(&QSerialPort::error),
            this, &Serial::handleError);
    connect(&m_timer, &QTimer::timeout, this, &Serial::handleTimeout);
     m_timer.start(5000);


    }

    void Serial::readyToRead() 
    {
    if(ecu == 0)
    {

        m_readData.append(m_serialport->readAll());
        Bytesexpected = m_readData[1]+1;
        if (Bytesexpected == m_readData.size())
        {
            if(requestIndex <= 62){requestIndex++;}
            else{requestIndex = 59;}
            readData(m_readData); // message for processing
            Serial::clear();
            m_readData.clear();
        }
    //Timeout
        if (!m_timer.isActive())
            m_timer.start(5000);

}
}

     void Serial::handleTimeout()
    {
    qDebug() << "Timeout";
    //request Data Again
    QString fileName = "Errors.txt";
    QFile mFile(fileName);
    if(!mFile.open(QFile::Append | QFile::Text)){
        qDebug() << "Could not open file for writing";
    }
    QTextStream out(&mFile);
    out << "Timeout Request Index " << int(requestIndex)<< " lenght received  "<< int(m_readData.length())<< " Bytes "<< " Expected Bytes "<< int(Bytesexpected)<< " bytes " <<" Message "<< QByteArray(m_readData.toHex()) <<endl;
    mFile.close();
    Serial::clear();
    m_readData.clear();
    Serial::sendRequest(requestIndex);
    }

    void Serial::handleError(QSerialPort::SerialPortError serialPortError)
    {
    if (serialPortError == QSerialPort::ReadError) {
        QString fileName = "Errors.txt";
        QFile mFile(fileName);
        if(!mFile.open(QFile::Append | QFile::Text)){
            qDebug() << "Could not open file for writing";
        }
        QTextStream out(&mFile);
        out << "Serial Error " << (m_serialport->errorString()) <<endl;
        mFile.close();
        qDebug() <<"Serialport Error" <<(m_serialport->errorString());
    }
    }

      

+1


source


Changed my code again and now it works fine on the hardware itself Below is my ready-to-read slot:

void Serial::readyToRead()
{
    qDebug() << "ready read";
    if(ecu == 0)
    {
        m_readData.append(m_serialport->readAll());
        Bytesexpected = m_readData[1]+1;
        qDebug() << "readdata current" <<m_readData.toHex();
        if (Bytesexpected == m_readData.size())
        {
            m_timer.stop();
            if(requestIndex <= 62){requestIndex++;}
            else{requestIndex = 59;}
            readData(m_readData);
            Serial::clear();
            m_readData.clear();
            Serial::sendRequest(requestIndex);
        }
        if (Bytesexpected != m_readData.size())
        {
            qDebug() << "starting timer";
            m_timer.start(5000);
        }
    }

      

+1


source







All Articles