Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Reconnecting to another port in QSerialPort

Reconnecting to another port in QSerialPort

Scheduled Pinned Locked Moved Unsolved General and Desktop
1 Posts 1 Posters 515 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Dummie1138D Offline
    Dummie1138D Offline
    Dummie1138
    wrote on last edited by
    #1

    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_H
    
    

    deviceconnection.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();
    }
    
    
    1 Reply Last reply
    0

    • Login

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Get Qt Extensions
    • Unsolved