Reconnecting to another port in QSerialPort
- 
Hi. I have two devices connected to my PC. In my code, I keep a connection open to only one of them. I have the following code, which is meant to change the port connection when called. //Function to change the connected port void DeviceConnection::changePort(QString name){ toSendQueue.clear(); qDebug() << "changing port to " << name; serialPort_Controller->close(); //This is triggering a handleError::ResourceError. Find out how the rest of the code overrides it. connectingTimer->stop(); emit lostConnection(Reconnect); setPort(name); sendConnectionVerification(); } //Configure port void DeviceConnection::setPort(QString port){ serialPort_Controller->setPortName(port); //My computer serialPort_Controller->setBaudRate(115200); serialPort_Controller->setDataBits(QSerialPort::Data8); serialPort_Controller->setParity(QSerialPort::NoParity); serialPort_Controller->setStopBits(QSerialPort::OneStop); serialPort_Controller->setFlowControl(QSerialPort::SoftwareControl); } //Send connection verification void DeviceConnection::sendConnectionVerification(){ qDebug() << serialPort_Controller->isDataTerminalReady(); if(serialPort_Controller->open(QIODevice::ReadWrite)){ qDebug() << "Connected"; QByteArray validationMessage = "TOARM_VALCN_00000000_4C"; validationMessage.append('\r'); validationMessage.append('\n'); serialPort_Controller->clear(QSerialPort::Output); serialPort_Controller->write(validationMessage); qDebug() << "Sending message: " + validationMessage; } else{ qDebug() << "Connection error"; } }My issues are: 
 1: When closing and reopening the port, I encounter a QSerialPort error. Specifically, a Resource Error. My understanding is that this is called when a device is unexpectedly removed from the system, which is why I'm confused why this would be called when I call close() on the port.2: It takes a bit of time for the port to fully switch. When changing to, say, COM Port 2, and sending a message through the QSerialPort (which is done pretty much instantly after the ports are switched), I receive a message back from COM Port 1 before I receive messages back from COM Port 2. Personally, I'm looking for something that can provide a signal back to Qt that the port has fully switched from COM Port 1 to COM Port 2 that isn't blocking if possible, but if there are better ways of implementing this, I am all ears. Please let me know if more information is required. The full code, if it helps: 
 deviceconnection.h#ifndef DEVICECONNECTION_H #define DEVICECONNECTION_H #include <QObject> #include <QQueue> #include <QElapsedTimer> #include <QThread> #include <QSerialPort> #include <QSerialPortInfo> class QTimer; class QSerialPort; class QSerialPortInfo; #include "controller.h" class DeviceConnection : public QObject { Q_OBJECT public: DeviceConnection(); ~DeviceConnection(); QString portName; //Internal holder of current port name QSerialPortInfo portInfo; struct PortList{ QString name; //holder of connectable ports QSerialPortInfo info; QList<QString> deviceSpec; }; QList<PortList> portList; QSerialPort* serialPort_Controller; //Need more research into this void addToQueue(QString message); void removeOneFromQueue(); void closeConnection(); bool isQueueEmpty(); void emptyQueue(); enum DisconMode{Disconnect, Reconnect}; //Reconnect is for reconnecting to another USB port signals: //message recieved, sent to get processed void receivedMessage(QString); //connection is lost, disable all relevant sections of the program and reset the info on main void lostConnection(int); public slots: void serialReady(); void sendFromQueue(); void connectDevice(); void restartConnection(); void finishConnectAttempts(); //upon a valid connecion occuring it waits to finish the current connection attempts void changePort(QString); //change the connected port private slots: void handleError(QSerialPort::SerialPortError error); void stopConnectAttempts(); //After current connection attempts finish, stop connecting private: bool alreadySetup; QString incomingRemainder; QStringList messagesList; void sendConnectionVerification(); //Sends VALCN QTimer* sendingTimer; QTimer* connectingTimer; QTimer* checkerTimer; QQueue<QString> toSendQueue; int waitingForResponse; void setPort(QString); //Configures port for sending int sendingAttempts; //Lists the amount of attempts at sending a single message. Currently, tops out at 10 QString calculateChecksum(QString message); }; #endif // DEVICECONNECTION_Hdeviceconnection.cpp #include "deviceconnection.h" #include <QtSerialPort/QSerialPort> #include <QtSerialPort/QSerialPortInfo> #include <QTimer> #include <QTime> #include <QFile> #include <QDebug> #include <QWidget> #include "statusbar.h" #include "controller.h" int numPortsAvailable; QList<QSerialPortInfo> portsAvailable = QSerialPortInfo::availablePorts(); int currentPosInList; //setting up the connections to start the device connection p1ocedures DeviceConnection::DeviceConnection(){ currentPosInList = 0; connectingTimer = new QTimer(this); connectingTimer->start(1000); serialPort_Controller = new QSerialPort(this); connectDevice(); connect(connectingTimer, SIGNAL(timeout()), this, SLOT(connectDevice())); connect(serialPort_Controller, SIGNAL(readyRead()), this, SLOT(serialReady())); sendingTimer = new QTimer(this); connect(sendingTimer, SIGNAL(timeout()), this, SLOT(sendFromQueue())); sendingTimer->start(50); connect(serialPort_Controller, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError))); //sendingAttempts = 0; } //attempts a connection with the next device in the list of available ports void DeviceConnection::connectDevice(){ serialPort_Controller->close(); portsAvailable = QSerialPortInfo::availablePorts(); qDebug() << "connecting"; qDebug() << portsAvailable.count(); QSerialPortInfo port; if (currentPosInList < portsAvailable.count()){ portName = portsAvailable.at(currentPosInList).portName(); qDebug() << portName; serialPort_Controller->setPortName(portName); //My computer serialPort_Controller->setBaudRate(115200); serialPort_Controller->setDataBits(QSerialPort::Data8); serialPort_Controller->setParity(QSerialPort::NoParity); serialPort_Controller->setStopBits(QSerialPort::OneStop); serialPort_Controller->setFlowControl(QSerialPort::SoftwareControl); currentPosInList++; //sendConnectionVerification(); if(serialPort_Controller->open(QIODevice::ReadWrite)){ qDebug() << "Connected"; QByteArray validationMessage = "TOARM_VALCN_00000000_4C"; validationMessage.append('\r'); validationMessage.append('\n'); serialPort_Controller->clear(QSerialPort::Output); serialPort_Controller->write(validationMessage); qDebug() << "Sending message: " + validationMessage; } else{ qDebug() << "Connection error"; } //FIXIT Arduino only returns information when in debug mode if (!serialPort_Controller->isOpen()){ qDebug() << "Cannot open controller serial port"; } } else{ currentPosInList = 0; } } //Configure port void DeviceConnection::setPort(QString port){ serialPort_Controller->setPortName(port); //My computer serialPort_Controller->setBaudRate(115200); serialPort_Controller->setDataBits(QSerialPort::Data8); serialPort_Controller->setParity(QSerialPort::NoParity); serialPort_Controller->setStopBits(QSerialPort::OneStop); serialPort_Controller->setFlowControl(QSerialPort::SoftwareControl); } //Send connection verification void DeviceConnection::sendConnectionVerification(){ qDebug() << serialPort_Controller->isDataTerminalReady(); if(serialPort_Controller->open(QIODevice::ReadWrite)){ qDebug() << "Connected"; QByteArray validationMessage = "TOARM_VALCN_00000000_4C"; validationMessage.append('\r'); validationMessage.append('\n'); serialPort_Controller->clear(QSerialPort::Output); serialPort_Controller->write(validationMessage); qDebug() << "Sending message: " + validationMessage; } else{ qDebug() << "Connection error"; } } //upon a valid connecion occuring it finishes up the connection attempts void DeviceConnection::finishConnectAttempts(){ int delayCount = portsAvailable.count() * connectingTimer->interval() + 500; //How much more time does the connectingTimer need to run before we turn it off //NOTE There is no significance to the +500, just as a buffer if (delayCount < 1){ delayCount = 1; } QTimer::singleShot(delayCount, this, &DeviceConnection::stopConnectAttempts); PortList portListBuf; portListBuf.name = portsAvailable.at(currentPosInList - 1).portName(); portListBuf.info = portsAvailable.at(currentPosInList - 1); portList.append(portListBuf); if(serialPort_Controller->open(QIODevice::ReadWrite)){ qDebug() << "connected with device"; } } //After current connection attempts finish, stop connecting void DeviceConnection::stopConnectAttempts(){ qDebug() << "stopping connect attempts"; connectingTimer->stop(); waitingForResponse = 0; } DeviceConnection::~DeviceConnection(){ serialPort_Controller->close(); delete serialPort_Controller; } //closes connection to device & purges records of ports void DeviceConnection::closeConnection(){ serialPort_Controller->close(); portList.clear(); } //received messages get processed here into the correct format void DeviceConnection::serialReady(){ QString allReceived = QString(serialPort_Controller->readAll()); qDebug() << "recieved messages: " << allReceived; allReceived = incomingRemainder + allReceived; QStringList fullMessages = allReceived.split("\r\n"); incomingRemainder = fullMessages.last(); fullMessages.removeLast(); foreach (QString message, fullMessages) { //qDebug() << message; For seeing the message on debugs. emit receivedMessage(message); } } //adds the massage to the back of the queue void DeviceConnection::addToQueue(QString message){ serialPort_Controller->thread(); qDebug() << "Pushing " + message + " back"; toSendQueue.push_back(message.toUtf8()); } //removes a message from the queue, triggered when a returning message is received. void DeviceConnection::removeOneFromQueue(){ //qDebug() << "removeOneFromQueue"; sendingAttempts = 0; waitingForResponse = 0; if (toSendQueue.count() != 0) { toSendQueue.pop_front(); } } //sends the message at the front of the queue to the device //this is tied to a qtimer that triggers once every 50ms void DeviceConnection::sendFromQueue(){ if (waitingForResponse) //waitingForResponse is a value decrementing from 20. waitingForResponse--; else { if (toSendQueue.count() > 0) { sendingAttempts++; qDebug() << "sending attempt: " << sendingAttempts; // don't continue sending if we are getting no response after sending more than 10 times if (sendingAttempts > 10) { // log the error qDebug() << "Attempting to send queued message to main board failed:" << toSendQueue.front(); removeOneFromQueue(); } else { // send the item at the top of the queue serialPort_Controller->write(toSendQueue.front().toUtf8()); qDebug() << "Sending message:" << toSendQueue.front(); waitingForResponse = 20; } } } } //returns true if the queue is empty, false if not bool DeviceConnection::isQueueEmpty(){ // if (toSendQueue.count() > 0){ //Purge by 08/06/2023. // return false; // } // else{ // return true; // } return toSendQueue.isEmpty(); } //empties the queue void DeviceConnection::emptyQueue(){ toSendQueue.clear(); } //ends the connection to the device and restarts the connection procedure with the next port void DeviceConnection::restartConnection(){ closeConnection(); qDebug() << "restartConnection"; connectingTimer->start(3000); emit lostConnection(Disconnect); } //informs the program that the connection was lost and restarts the connection procedure void DeviceConnection::handleError(QSerialPort::SerialPortError error){ if (error == QSerialPort::ResourceError) { qDebug() << "handleError"; //serialPort_Controller->clearError(); emptyQueue(); restartConnection(); } } //Function to change the connected port void DeviceConnection::changePort(QString name){ toSendQueue.clear(); qDebug() << "changing port to " << name; serialPort_Controller->close(); //This is triggering a handleError::ResourceError. Find out how the rest of the code overrides it. connectingTimer->stop(); emit lostConnection(Reconnect); setPort(name); sendConnectionVerification(); }
 
