QT SERIAL PORT THREADING CRASH APP
-
This is the IO thread of my serial device which I override it. I can connect to the device and monitor it. But when I press the stop button which gives the stop hex code to the serial device, It suddenly crashes the app without error. Can anyone help me with it?
PS: For anyone who says why don't you use the readyread function? Basically, my serial device ( circuit ) sends every 2 ms and if there is no reading it deletes the data from its buffer. ready read function makes data leak from the buffer.
Kind regards.
#include "IOThread.h" IOThread::IOThread() { } void IOThread::setUpSerialPort(QString portName,int baudRate){ serialPort.setPortName(portName); serialPort.setDataBits(QSerialPort::Data8); serialPort.setParity(QSerialPort::NoParity); serialPort.setStopBits(QSerialPort::OneStop); serialPort.setFlowControl(QSerialPort::NoFlowControl); if(baudRate==1200){ serialPort.setBaudRate(QSerialPort::Baud1200); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==2400){ serialPort.setBaudRate(QSerialPort::Baud2400); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==4800){ serialPort.setBaudRate(QSerialPort::Baud4800); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==9600){ serialPort.setBaudRate(QSerialPort::Baud9600); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==19200){ serialPort.setBaudRate(QSerialPort::Baud19200); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==38400){ serialPort.setBaudRate(QSerialPort::Baud38400); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==57600){ serialPort.setBaudRate(QSerialPort::Baud57600); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==38400){ serialPort.setBaudRate(QSerialPort::Baud38400); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else{ qInfo()<<"Baud Rate is not valid!! It is connecting via 9600 baudrate"; emit sendMessageToSerialDevice("Baud Rate is not valid!! It is connecting via 9600 baudrate"); serialPort.setBaudRate(QSerialPort::Baud9600); } } void IOThread::run(){ qInfo()<<"Thread is started!"; qInfo()<<"This is array of the thread:"<<orderList; if(isOpen == true){ if(orderList.isEmpty()==false){ foreach (int data, orderList) { qInfo()<<"This is looper of the thread:"<<data<<orderList; executeOrder(data); } orderList.clear(); } while(monitoringStatus==true){ if(orderList.isEmpty()==false){ qInfo()<<"Order list status"<<orderList<<Qt::endl; foreach (int data, orderList) { executeOrder(data); } orderList.clear(); this->msleep(10); } this->msleep(10); QByteArray dataString; dataString = serialPort.readAll(); if(dataString.isEmpty()==false){ qInfo()<<"Reader loop has started!"<<dataString.toHex()<<Qt::endl; } this->msleep(1); } }else{ emit sendMessageToSerialDevice("Device is not open!! pls connect it first"); } } void IOThread::executeOrder(int order){ qInfo()<<"Order is executing:"<<order; if(order==0){ if(connectionStatus == false){ QByteArray b("0149"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); connectionStatus = true; emit sendConnectionStatus(true); qInfo()<<"Starting the device!"<<Qt::endl; }else{ emit sendMessageToSerialDevice("Device is already connected!"); } }else if(order == 1){ if(connectionStatus==true){ QByteArray b("0236"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); serialPort.close(); isOpen = false; connectionStatus = false; emit sendConnectionStatus(false); qInfo()<<"Stopping the device!"<<Qt::endl; }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); } }else if(order==2){ qInfo()<<"This is general monitor start"; if(connectionStatus == true){ if(monitoringStatus==false){ qInfo()<<"Order 3 is excuting if block in IOTHread"; QByteArray b("0919"); QByteArray bytes = QByteArray::fromHex(b); if(monitoringStatus == false){ serialPort.write(bytes); serialPort.waitForBytesWritten(); qInfo()<<"Starting the monitoring device!"<<Qt::endl; } monitoringStatus = true; emit sendMonitoringStatus(true); }else{ emit sendMessageToSerialDevice("Monitoring is already started!"); } }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); } }else if(order == 3){ qInfo()<<"This is general monitor stop"; // Kill all jedi masters :D if(connectionStatus == true){ if(monitoringStatus == true){ QByteArray b("0A53"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); qInfo()<<"Stopping the monitoring device!"<<Qt::endl; monitoringStatus = false; emit sendMonitoringStatus(false); }else{ emit sendMessageToSerialDevice("First start the monitoring device!"); } }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); } }else{ qInfo()<<"Order is not found!"; } } void IOThread::addDataCommandToQList(int order){ orderList.append(order); qInfo()<<"Data appending to commandList"<<order; }
-
This is the IO thread of my serial device which I override it. I can connect to the device and monitor it. But when I press the stop button which gives the stop hex code to the serial device, It suddenly crashes the app without error. Can anyone help me with it?
PS: For anyone who says why don't you use the readyread function? Basically, my serial device ( circuit ) sends every 2 ms and if there is no reading it deletes the data from its buffer. ready read function makes data leak from the buffer.
Kind regards.
#include "IOThread.h" IOThread::IOThread() { } void IOThread::setUpSerialPort(QString portName,int baudRate){ serialPort.setPortName(portName); serialPort.setDataBits(QSerialPort::Data8); serialPort.setParity(QSerialPort::NoParity); serialPort.setStopBits(QSerialPort::OneStop); serialPort.setFlowControl(QSerialPort::NoFlowControl); if(baudRate==1200){ serialPort.setBaudRate(QSerialPort::Baud1200); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==2400){ serialPort.setBaudRate(QSerialPort::Baud2400); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==4800){ serialPort.setBaudRate(QSerialPort::Baud4800); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==9600){ serialPort.setBaudRate(QSerialPort::Baud9600); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==19200){ serialPort.setBaudRate(QSerialPort::Baud19200); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==38400){ serialPort.setBaudRate(QSerialPort::Baud38400); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==57600){ serialPort.setBaudRate(QSerialPort::Baud57600); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else if(baudRate==38400){ serialPort.setBaudRate(QSerialPort::Baud38400); if(serialPort.open(QIODevice::ReadWrite)){ qInfo()<<"Device successfully connected"; isOpen = true; }else{ emit sendMessageToSerialDevice(serialPort.errorString()); } } else{ qInfo()<<"Baud Rate is not valid!! It is connecting via 9600 baudrate"; emit sendMessageToSerialDevice("Baud Rate is not valid!! It is connecting via 9600 baudrate"); serialPort.setBaudRate(QSerialPort::Baud9600); } } void IOThread::run(){ qInfo()<<"Thread is started!"; qInfo()<<"This is array of the thread:"<<orderList; if(isOpen == true){ if(orderList.isEmpty()==false){ foreach (int data, orderList) { qInfo()<<"This is looper of the thread:"<<data<<orderList; executeOrder(data); } orderList.clear(); } while(monitoringStatus==true){ if(orderList.isEmpty()==false){ qInfo()<<"Order list status"<<orderList<<Qt::endl; foreach (int data, orderList) { executeOrder(data); } orderList.clear(); this->msleep(10); } this->msleep(10); QByteArray dataString; dataString = serialPort.readAll(); if(dataString.isEmpty()==false){ qInfo()<<"Reader loop has started!"<<dataString.toHex()<<Qt::endl; } this->msleep(1); } }else{ emit sendMessageToSerialDevice("Device is not open!! pls connect it first"); } } void IOThread::executeOrder(int order){ qInfo()<<"Order is executing:"<<order; if(order==0){ if(connectionStatus == false){ QByteArray b("0149"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); connectionStatus = true; emit sendConnectionStatus(true); qInfo()<<"Starting the device!"<<Qt::endl; }else{ emit sendMessageToSerialDevice("Device is already connected!"); } }else if(order == 1){ if(connectionStatus==true){ QByteArray b("0236"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); serialPort.close(); isOpen = false; connectionStatus = false; emit sendConnectionStatus(false); qInfo()<<"Stopping the device!"<<Qt::endl; }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); } }else if(order==2){ qInfo()<<"This is general monitor start"; if(connectionStatus == true){ if(monitoringStatus==false){ qInfo()<<"Order 3 is excuting if block in IOTHread"; QByteArray b("0919"); QByteArray bytes = QByteArray::fromHex(b); if(monitoringStatus == false){ serialPort.write(bytes); serialPort.waitForBytesWritten(); qInfo()<<"Starting the monitoring device!"<<Qt::endl; } monitoringStatus = true; emit sendMonitoringStatus(true); }else{ emit sendMessageToSerialDevice("Monitoring is already started!"); } }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); } }else if(order == 3){ qInfo()<<"This is general monitor stop"; // Kill all jedi masters :D if(connectionStatus == true){ if(monitoringStatus == true){ QByteArray b("0A53"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); qInfo()<<"Stopping the monitoring device!"<<Qt::endl; monitoringStatus = false; emit sendMonitoringStatus(false); }else{ emit sendMessageToSerialDevice("First start the monitoring device!"); } }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); } }else{ qInfo()<<"Order is not found!"; } } void IOThread::addDataCommandToQList(int order){ orderList.append(order); qInfo()<<"Data appending to commandList"<<order; }
@canrollas said in QT SERIAL PORT THREADING CRASH APP:
It suddenly crashes the app without error.
Did you run your app through debugger to see what exactly happens?
Also, are you sure you need threads at all? Qt is an asynchronous framework.
-
@canrollas said in QT SERIAL PORT THREADING CRASH APP:
It suddenly crashes the app without error.
Did you run your app through debugger to see what exactly happens?
Also, are you sure you need threads at all? Qt is an asynchronous framework.
-
@jsulm Sir,look you have answered my other question same way. I need thread in my specific situation ( can not be explained ) .
@canrollas Then please run through debugger until it crashes and post the stack trace here. Debugging is the first thing to do in case of a crash.
-
@jsulm Sir,look you have answered my other question same way. I need thread in my specific situation ( can not be explained ) .
@canrollas Also, where do you call setUpSerialPort? You need to understand that you should create all needed variables (like serialPort) inside run() method, else they will live in the thread which starts your io thread.
-
@canrollas Then please run through debugger until it crashes and post the stack trace here. Debugging is the first thing to do in case of a crash.
-
@canrollas As you can see it crashes in executeOrder in file IOThread.cpp line 237 - what is in that line?
-
@canrollas Also, where do you call setUpSerialPort? You need to understand that you should create all needed variables (like serialPort) inside run() method, else they will live in the thread which starts your io thread.
this is execute function
else if(order == 3){ qInfo()<<"This is general monitor stop"; // Kill all jedi masters :D if(connectionStatus == true){ if(monitoringStatus == true){ QByteArray b("0A53"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); qInfo()<<"Stopping the monitoring device!"<<Qt::endl; monitoringStatus = false; emit sendMonitoringStatus(false); }else{ emit sendMessageToSerialDevice("First start the monitoring device!"); } }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); }
this is caller function
@jsulm void SerialDevice::connectToCanBus(){ QString portname ; foreach (auto looper, serialPortInfo->availablePorts()) { qInfo()<<"This is looping device on the machine:"<<looper.description()<<looper.portName(); if(looper.description()=="Makersan USB to CAN Converter" || looper.description()=="STMicroelectronics Virtual COM Port" && looper.portName().contains("tty")==true || looper.portName().contains("COM")==true){ qInfo()<<"The device has found in the loop:"<<looper.description(); portname = looper.portName(); thread->setUpSerialPort(looper.portName(),9600); thread->addDataCommandToQList(0); if(thread->isRunning()==false){ thread->start(); } } } if(portname.isEmpty()==true){ emit sendMessageToMainWindow("Device is not plugged or not detected"); } }
-
this is execute function
else if(order == 3){ qInfo()<<"This is general monitor stop"; // Kill all jedi masters :D if(connectionStatus == true){ if(monitoringStatus == true){ QByteArray b("0A53"); QByteArray bytes = QByteArray::fromHex(b); serialPort.write(bytes); serialPort.waitForBytesWritten(); qInfo()<<"Stopping the monitoring device!"<<Qt::endl; monitoringStatus = false; emit sendMonitoringStatus(false); }else{ emit sendMessageToSerialDevice("First start the monitoring device!"); } }else{ emit sendMessageToSerialDevice("First connect to the device via makcon!"); }
this is caller function
@jsulm void SerialDevice::connectToCanBus(){ QString portname ; foreach (auto looper, serialPortInfo->availablePorts()) { qInfo()<<"This is looping device on the machine:"<<looper.description()<<looper.portName(); if(looper.description()=="Makersan USB to CAN Converter" || looper.description()=="STMicroelectronics Virtual COM Port" && looper.portName().contains("tty")==true || looper.portName().contains("COM")==true){ qInfo()<<"The device has found in the loop:"<<looper.description(); portname = looper.portName(); thread->setUpSerialPort(looper.portName(),9600); thread->addDataCommandToQList(0); if(thread->isRunning()==false){ thread->start(); } } } if(portname.isEmpty()==true){ emit sendMessageToMainWindow("Device is not plugged or not detected"); } }
@canrollas Which line in that code is 237 please?
-
@canrollas Which line in that code is 237 please?
-
@canrollas Which line in that code is 237 please?
-
@jsulm @canrollas
I have the same issue both on Windows 10 and Ubuntu 20.04. Crash occurs on call towaitForBytesWritten()
+1 to solve this bug
-
@jsulm @canrollas
I have the same issue both on Windows 10 and Ubuntu 20.04. Crash occurs on call towaitForBytesWritten()
+1 to solve this bug
@Valentin49 said in QT SERIAL PORT THREADING CRASH APP:
I have the same issue
then please create a minimal compileable example which reproduces your crash and create a new thread instead hijacking an old one
-
Hi, I just stumbled acrros the same issue as yours when switching from Qt5.15.2 MinGW 32-bits to Qt6.3.2 MinGW 64-bits. My application was working fine with Qt5, but was constantly crashing when calling QSerialPort::waitForBytesWritten() when compiling using Qt6.
My original code:
// My QSerialPort object runs in its own thread QSerialPort *serial = new QSerialPort(this); // initializationn of serial object ... void MySerialClass::write( const QByteArray& bytes ) { serial->write(bytes); if(!serial->waitForBytesWritten()) { qWarning() << "Write timeout!"; } }
I found a fix by trial and error: I verify that there is indeed some bytes waiting to be written before calling the function:
void MySerialClass::write( const QByteArray& bytes ) { // write() returns the number of bytes that were actually written, or -1 if error quint64 bytes_written = serial->write(bytes); if(bytes_written != bytes.size() && !serial->waitForBytesWritten()) { qWarning() << "Write timeout!"; } }
Hope it works for you!