Qt - serial communication - receiving
-
I am beginner in Qt. To first I would like to do application to communicate with serial device. This communication I did in thread. Sending work perfectly, but I have problem with receiving messages. The message should will be recive imediatelly after send frame. I think that problem is with m_Serial->waitForReadyRead(10)
Below I paste my piece of code:
void SerialWorker::doWork() { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); bool abort = false; quint8 inByte; quint8 checksum_temp; int numByte = 0; int receiverStatus = RCV_ST_IDLE; Frame *m_inFrame = nullptr; int dataLength = 0; QByteArray buffer_checksum; // Serial Port Initialization m_Serial = new QSerialPort(); m_Serial->setPortName("COM6"); m_Serial->setBaudRate(QSerialPort::Baud9600); m_Serial->setDataBits(QSerialPort::Data8); m_Serial->setParity(QSerialPort::NoParity); m_Serial->setStopBits(QSerialPort::OneStop); m_Serial->setFlowControl(QSerialPort::NoFlowControl); m_Serial->open(QIODevice::ReadWrite); qDebug() << "SerialPort Status: " << m_Serial->isOpen(); while(!abort) { mutex.lock(); abort = _abort; mutex.unlock(); if(!m_outFrameQueue->isEmpty()) { Frame *outFrame = m_outFrameQueue->dequeue(); sendFrame(outFrame); delete outFrame; } else { if (m_Serial->waitForReadyRead(10)) { QByteArray receivedData = m_Serial->readAll(); while(receivedData.count() > 0) { inByte = quint8(receivedData[0]); receivedData.remove(0,1); switch (receiverStatus) { case RCV_ST_IDLE: { if(inByte == Frame::FRAME_ADDR_RFiD) { if (m_inFrame == nullptr) m_inFrame = new Frame(); else m_inFrame->Clear(); m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); receiverStatus = RCV_ST_DATA_LENGTH; } else { buffer_checksum.clear(); } } break; case RCV_ST_DATA_LENGTH: { dataLength = inByte; numByte = dataLength - 6; m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); receiverStatus = RCV_ST_CMD; } break; case RCV_ST_CMD: { m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); if(numByte > 0) receiverStatus = RCV_ST_DATA; else receiverStatus = RCV_ST_CODE; } break; case RCV_ST_DATA: { m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); if (--numByte == 0) receiverStatus = RCV_ST_CODE; else if (numByte < 0) receiverStatus = RCV_ST_IDLE; } break; case RCV_ST_CODE: { m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); receiverStatus = RCV_ST_CHECKSUM_HI; } break; case RCV_ST_CHECKSUM_HI: { checksum_temp = (m_inFrame->CalculateCRC2_in(buffer_checksum) >> 8) & 0xFF; if (inByte == checksum_temp) { m_inFrame->AddByte(checksum_temp); receiverStatus = RCV_ST_CHECKSUM_LO; } else { receiverStatus = RCV_ST_IDLE; m_inFrame->Clear(); delete m_inFrame; } } break; case RCV_ST_CHECKSUM_LO: { checksum_temp = m_inFrame->CalculateCRC2_in(buffer_checksum) & 0xFF; if (inByte == checksum_temp) { receiverStatus = RCV_ST_IDLE; m_inFrame->AddByte(checksum_temp); emit this->frameReceived(m_inFrame); qDebug()<< "Frame: " << Qt::hex << m_inFrame; } else { receiverStatus = RCV_ST_IDLE; m_inFrame->Clear(); delete m_inFrame; } } break; } } } } } }
I checked whether the device definitely send frame, by this code
void SerialWorker::doWork() { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); bool abort = false; quint8 inByte; quint8 checksum_temp; int numByte = 0; int receiverStatus = RCV_ST_IDLE; Frame *m_inFrame = nullptr; int dataLength = 0; QByteArray buffer_checksum; // Serial Port Initialization m_Serial = new QSerialPort(); m_Serial->setPortName("COM6"); m_Serial->setBaudRate(QSerialPort::Baud9600); m_Serial->setDataBits(QSerialPort::Data8); m_Serial->setParity(QSerialPort::NoParity); m_Serial->setStopBits(QSerialPort::OneStop); m_Serial->setFlowControl(QSerialPort::NoFlowControl); m_Serial->open(QIODevice::ReadWrite); qDebug() << "SerialPort Status: " << m_Serial->isOpen(); while(!abort) { mutex.lock(); abort = _abort; mutex.unlock(); QByteArray receivedData = m_Serial->readAll(); if(!m_outFrameQueue->isEmpty()) { Frame *outFrame = m_outFrameQueue->dequeue(); sendFrame(outFrame); delete outFrame; } else { if (receivedData.count() > 0) { qDebug() << "something came: "<< Qt::hex << receivedData.toHex() ; receivedData.clear(); } } } }
And it works. In receivedData.toHex() the receiving frame ic correct. So what is wrong with my fully soution pasted like first code ?
-
I am beginner in Qt. To first I would like to do application to communicate with serial device. This communication I did in thread. Sending work perfectly, but I have problem with receiving messages. The message should will be recive imediatelly after send frame. I think that problem is with m_Serial->waitForReadyRead(10)
Below I paste my piece of code:
void SerialWorker::doWork() { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); bool abort = false; quint8 inByte; quint8 checksum_temp; int numByte = 0; int receiverStatus = RCV_ST_IDLE; Frame *m_inFrame = nullptr; int dataLength = 0; QByteArray buffer_checksum; // Serial Port Initialization m_Serial = new QSerialPort(); m_Serial->setPortName("COM6"); m_Serial->setBaudRate(QSerialPort::Baud9600); m_Serial->setDataBits(QSerialPort::Data8); m_Serial->setParity(QSerialPort::NoParity); m_Serial->setStopBits(QSerialPort::OneStop); m_Serial->setFlowControl(QSerialPort::NoFlowControl); m_Serial->open(QIODevice::ReadWrite); qDebug() << "SerialPort Status: " << m_Serial->isOpen(); while(!abort) { mutex.lock(); abort = _abort; mutex.unlock(); if(!m_outFrameQueue->isEmpty()) { Frame *outFrame = m_outFrameQueue->dequeue(); sendFrame(outFrame); delete outFrame; } else { if (m_Serial->waitForReadyRead(10)) { QByteArray receivedData = m_Serial->readAll(); while(receivedData.count() > 0) { inByte = quint8(receivedData[0]); receivedData.remove(0,1); switch (receiverStatus) { case RCV_ST_IDLE: { if(inByte == Frame::FRAME_ADDR_RFiD) { if (m_inFrame == nullptr) m_inFrame = new Frame(); else m_inFrame->Clear(); m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); receiverStatus = RCV_ST_DATA_LENGTH; } else { buffer_checksum.clear(); } } break; case RCV_ST_DATA_LENGTH: { dataLength = inByte; numByte = dataLength - 6; m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); receiverStatus = RCV_ST_CMD; } break; case RCV_ST_CMD: { m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); if(numByte > 0) receiverStatus = RCV_ST_DATA; else receiverStatus = RCV_ST_CODE; } break; case RCV_ST_DATA: { m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); if (--numByte == 0) receiverStatus = RCV_ST_CODE; else if (numByte < 0) receiverStatus = RCV_ST_IDLE; } break; case RCV_ST_CODE: { m_inFrame->AddByte(inByte); buffer_checksum.append(inByte); receiverStatus = RCV_ST_CHECKSUM_HI; } break; case RCV_ST_CHECKSUM_HI: { checksum_temp = (m_inFrame->CalculateCRC2_in(buffer_checksum) >> 8) & 0xFF; if (inByte == checksum_temp) { m_inFrame->AddByte(checksum_temp); receiverStatus = RCV_ST_CHECKSUM_LO; } else { receiverStatus = RCV_ST_IDLE; m_inFrame->Clear(); delete m_inFrame; } } break; case RCV_ST_CHECKSUM_LO: { checksum_temp = m_inFrame->CalculateCRC2_in(buffer_checksum) & 0xFF; if (inByte == checksum_temp) { receiverStatus = RCV_ST_IDLE; m_inFrame->AddByte(checksum_temp); emit this->frameReceived(m_inFrame); qDebug()<< "Frame: " << Qt::hex << m_inFrame; } else { receiverStatus = RCV_ST_IDLE; m_inFrame->Clear(); delete m_inFrame; } } break; } } } } } }
I checked whether the device definitely send frame, by this code
void SerialWorker::doWork() { qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId(); bool abort = false; quint8 inByte; quint8 checksum_temp; int numByte = 0; int receiverStatus = RCV_ST_IDLE; Frame *m_inFrame = nullptr; int dataLength = 0; QByteArray buffer_checksum; // Serial Port Initialization m_Serial = new QSerialPort(); m_Serial->setPortName("COM6"); m_Serial->setBaudRate(QSerialPort::Baud9600); m_Serial->setDataBits(QSerialPort::Data8); m_Serial->setParity(QSerialPort::NoParity); m_Serial->setStopBits(QSerialPort::OneStop); m_Serial->setFlowControl(QSerialPort::NoFlowControl); m_Serial->open(QIODevice::ReadWrite); qDebug() << "SerialPort Status: " << m_Serial->isOpen(); while(!abort) { mutex.lock(); abort = _abort; mutex.unlock(); QByteArray receivedData = m_Serial->readAll(); if(!m_outFrameQueue->isEmpty()) { Frame *outFrame = m_outFrameQueue->dequeue(); sendFrame(outFrame); delete outFrame; } else { if (receivedData.count() > 0) { qDebug() << "something came: "<< Qt::hex << receivedData.toHex() ; receivedData.clear(); } } } }
And it works. In receivedData.toHex() the receiving frame ic correct. So what is wrong with my fully soution pasted like first code ?
@Damian7546
In both cases, do not rely onreadAll()
to read all the data which has been sent. It reads whatever happens to be there at the instant it gets called. Could be anything from all the bytes down to just 1. -
I solved my problem by creating a slot for readyRead() signal. Solution/problem is described here:
-
I have next problem. When I was very short cable RS485 the frame was received all in one shot . now in long cable the frame recive is byte by bytes, so my code doesn't works.
Like I said I use slot "recive()" for readyRead() signal.void SerialWorker::recive() { QByteArray buffer_checksum; quint8 inByte; quint8 checksum_temp; int numByte = 0; int receiverStatus = RCV_ST_IDLE; Frame *m_inFrame = nullptr; int dataLength = 0; QByteArray receivedData = m_Serial->readAll(); qDebug()<<receivedData; while(receivedData.count() > 0) { ................... ................. } }
How I should wait for all bytes in frame in my slot ?
-
I have next problem. When I was very short cable RS485 the frame was received all in one shot . now in long cable the frame recive is byte by bytes, so my code doesn't works.
Like I said I use slot "recive()" for readyRead() signal.void SerialWorker::recive() { QByteArray buffer_checksum; quint8 inByte; quint8 checksum_temp; int numByte = 0; int receiverStatus = RCV_ST_IDLE; Frame *m_inFrame = nullptr; int dataLength = 0; QByteArray receivedData = m_Serial->readAll(); qDebug()<<receivedData; while(receivedData.count() > 0) { ................... ................. } }
How I should wait for all bytes in frame in my slot ?
@Damian7546 said in Qt - serial communication - receiving:
How I should wait for all bytes in frame in my slot ?
You must not wait but read the data into a custom buffer (e.g. QByteArray) and parse the data later on.
-
So, I changed my slot "recive()" in this way:
void SerialWorker::recive() { receivedData = receivedData + m_Serial->readAll(); if(!receivedData.isEmpty()) { timeoutReciveData(this, SLOT(parseRecivedData()), 1000); } }
But something is wrong with singleshot , because doesn't work:
void SerialWorker::parseRecivedData() { qDebug() << receivedData ; /* parse should be here */ } void SerialWorker::timeoutReciveData(const QObject *obj, const char *signalOrSlot, int msDelay) { QTimer::singleShot(msDelay, obj, signalOrSlot); }
Any idea ?
-
So, I changed my slot "recive()" in this way:
void SerialWorker::recive() { receivedData = receivedData + m_Serial->readAll(); if(!receivedData.isEmpty()) { timeoutReciveData(this, SLOT(parseRecivedData()), 1000); } }
But something is wrong with singleshot , because doesn't work:
void SerialWorker::parseRecivedData() { qDebug() << receivedData ; /* parse should be here */ } void SerialWorker::timeoutReciveData(const QObject *obj, const char *signalOrSlot, int msDelay) { QTimer::singleShot(msDelay, obj, signalOrSlot); }
Any idea ?
@Damian7546 said in Qt - serial communication - receiving:
But something is wrong with singleshot , because doesn't work:
does not work? What does this mean? Why do you not directly call parseRecivedData or QTimer::singleShot()?
-
This post is deleted!
-
@Damian7546 said in Qt - serial communication - receiving:
But something is wrong with singleshot , because doesn't work:
does not work? What does this mean? Why do you not directly call parseRecivedData or QTimer::singleShot()?
@Christian-Ehrlicher said in Qt - serial communication - receiving:
Why do you not directly call parseRecivedData
Because I do not know when my frame will be completed, so I give the some time by timeoutReciveData and next go to parseRecivedData().
I expect such a frame:
DevAddres,LengthFrame,Command,Data1...n,CRCH,CRCL@Christian-Ehrlicher said in Qt - serial communication - receiving:
does not work? What does this mean?
The parseRecivedData() slot does not start even though buffer "receivedData" are not empty .
-
@Christian-Ehrlicher said in Qt - serial communication - receiving:
Why do you not directly call parseRecivedData
Because I do not know when my frame will be completed, so I give the some time by timeoutReciveData and next go to parseRecivedData().
I expect such a frame:
DevAddres,LengthFrame,Command,Data1...n,CRCH,CRCL@Christian-Ehrlicher said in Qt - serial communication - receiving:
does not work? What does this mean?
The parseRecivedData() slot does not start even though buffer "receivedData" are not empty .
@Damian7546 said in Qt - serial communication - receiving:
Because I do not know when my frame will be completed, so I give the some time by timeoutReciveData and next go to parseRecivedData().
And why should it be finished in 1000ms? It does not help at all.
Parse your buffer directly. -
Ok,
thank for your suggestion. I must rewrite my parseRecivedData() function. -
I wrote again my "recive()" function like you said, it works, but I have several doubt.
void SerialWorker::recive() { QByteArray buff2CalcChecksum; Frame *m_inFrame = nullptr; receivedData_raw = receivedData_raw + m_Serial->readAll(); if(!receivedData_raw.isEmpty()) { for(int i=0; i < receivedData_raw.count(); i++) { buff2CalcChecksum = buff2CalcChecksum + receivedData_raw[i]; if ((((m_inFrame->CalculateCRC2_in(buff2CalcChecksum)) & 0xFF) == buff2CalcChecksum[i+2]) && (((m_inFrame->CalculateCRC2_in(buff2CalcChecksum) >> 8) & 0xFF) == buff2CalcChecksum[i+1])) { qDebug() << "We have the correct frame"; receivedData = receivedData_raw; receivedData_raw.clear(); parseRecivedData(); } if (receivedData_raw.count() > 20 ) receivedData_raw.clear(); /// it is not a good idea... } } }
-
How to protect code when too long no CRC sums ?
-
It is a good idea that from first byte, calculate CRC sum to recognize my whole frame?
-
-
I don't think your code will ever work - the data comes in as a stream so you first have to figure out the start and end of your frame. For this a lot of protocols use a start and end-marker so you know when a frame starts and ends.
-
This protocol do not have marker start and end of frame. This is a frame:
-
Then I don't know how you will ever find the start of a frame... they must have at least e.g. an end marker ('\r' or '\n' for example) where you can start from.