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. QSerialPort not reading from Arduino
Forum Update on Monday, May 27th 2025

QSerialPort not reading from Arduino

Scheduled Pinned Locked Moved Unsolved General and Desktop
6 Posts 2 Posters 416 Views
  • 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.
  • D Offline
    D Offline
    Dummie1138
    wrote on 31 May 2023, 14:58 last edited by
    #1

    Question as posted on Arduino forum: https://forum.arduino.cc/t/serial-println-not-sent-to-qt-application/1133089

    Hi. I have the following code for a QSerialPort, meant to send and receive information from an Arduino.

    //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++;
            if(serialPort_Controller->open(QIODevice::ReadWrite))
            {
                qDebug() << "Connected";
                int i = serialPort_Controller->write("TOPIC_VALCN_00000000_48\r\n");    //"TOPIC_VALCN_00000000_48\r\n"
                qDebug() << i;
                qDebug() << "TOPIC_VALCN_00000000_48\r\n";
            }
            else
            {
                qDebug() << "Connection error";
            }
            if (!serialPort_Controller->isOpen())
            {
                qDebug() << "Cannot open controller serial port";
            }
        }
        else
        {
            currentPosInList = 0;
        } 
    }
    
    //received messages get processed here into the correct format
    void DeviceConnection::serialReady()
    {
        QString allReceived = QString(serialPort_Controller->readAll());
    
        //    if (SystemSettings::get()->getValue(PROTOCOL_DEBUG_MODE) == "1")
        //        backSerialPort->write(allReceived.toUtf8());
        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);
        }
    }
    

    The issue is simple: When I send a message through to the Arduino code from the Arduino serial monitor, the code does successfully process the message and return it on the Arduino serial monitor.

    However, when sending messages through via QSerialPort, the code no longer processes the message and returns it to the Qt application at baud rates higher than 9600.

    Things I've tried:

    Shortening the message written:

    serialPort_Controller->write("T\n");
    

    This did not work.

    Changing the data bits & parity, that did not work.

    Running the code in debug mode and adding a breakpoint at this line:

    serialPort_Controller->write("TOPIC_VALCN_00000000_48\r\n");
    

    This worked, somehow. I have yet to determine why.

    The part of the arduino code that directly reads and writes:

    void setup() {
      // put your setup code here, to run once:
      Serial.begin(115200); // usb port serial
      pinMode(LED_BUILTIN, OUTPUT);
    }
    
    void loop() {
      //Collect data.
      bool readyRead = true;
      int i = 0;
      //Serial.println("Serial available.");
      if (Serial.available() > 0) {
        //Serial.println("Serial available.");
        i = msgReceiver('\n', readyRead); //msgReceiver is for turning the input to a char array. '\n' is end char. The output of msgReceiver is the char array position, so need to ++.
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //This turns an LED on and off.
        messageArray[27] = '\0'; // terminate the string
    
        int msgLength = i + 1;
    
        for (i = msgLength; i > 22; i--) {  //messageArray[22] is the 2nd char of the checkSum. Should not be ablated.
          messageArray[i] = '\0';
        }
        bool canSend = true;
    
        char checkSumCharacters[2] = {messageArray[i - 1], messageArray[i]}; //Values are ascii code of the base16 numbers.
        int receivedCheckSum = strtoul(checkSumCharacters, NULL, 16);  //Converts the base16 characters to an int.
    
        int checkSum = checkSumGenerator(messageArray);
    
        for (i = 0; i < sizeof(cmdtarget); i++) { //Length of cmdtarget is 5.
          cmdtarget[i] = messageArray[i];
        }
        cmdtarget[5] = '\0';
        for (i = 0; i < sizeof(input_cmdtype) - 1; i++) { //Length of cmdtype is 5.
          input_cmdtype[i] = messageArray[i + 6];
        }
        input_cmdtype[5] = '\0';
        for (i = 0; i < sizeof(input_cmdparam) - 1; i++) { //Length of cmdparam is 8.
          input_cmdparam[i] = messageArray[i + 12];
        }
        input_cmdparam[8] = '\0';
        //An attempt at a function pointer to be called for rtnProtocols. Pointer used to decrease negative effects of conditionals.
        stringFunction *rtnpointer[] = {
          FIRMV_F, VALCN_F, RQSPC_F, CTFTC_F, LIDVM_F, LIDVC_F, PREVC_F, STPWM_F, CHPWM_F, STPER_F, CHPER_F, CHIGH_F, SHIGH_F, MOTST_F, MHIGH_F, MTRTT_F,
          RCTIC_F, RCTGM_F, RCTGC_F, SAVEA_F, PREST_F, PREND_F, RQPRE_F, CLPRE_F, RQDAT_F, CUPTC_F, LIDTC_F, CURPR_F, CUPTT_F, CDATE_F, CTIME_F, SDATE_F, RDTTM_F,
          SPROG_F, SLOAD_F, CUFAC_F, LIFAC_F, STFAC_F, MTFAC_F, PPFAC_F, PCOFF_F, CUPFM_F, CUPFC_F, LIDFM_F, LIDFC_F, PREFC_F, FCPWM_F, FCPER_F, FHIGH_F,
        };
    
        input in = convert(input_cmdtype);  //Using the char to enum converter.
        canSend = errorStack(cmdtarget, receivedCheckSum, checkSum, msgLength, in, canSend);
    
        if (canSend) {
          char verak[6] = "VERAK";
          rtnProtocols(verak, input_cmdparam);
    
          rtnpointer[in](input_cmdtype, input_cmdparam);
        }
      }
    }
    
    //Reads message.
    int msgReceiver(char endMarker, bool readyRead) {
      char rc;
      int ndx = 0;
      while (readyRead == true) {
        if (Serial.available() > 0) {
          rc = Serial.read();
          if (rc != endMarker) {
            messageArray[ndx] = rc;
            ndx++;
          }
          else if (rc == endMarker) {
            messageArray[ndx] = '\0'; // terminate the string
            //Serial.println("Received \n.");
            rc = 0;
            readyRead = false;
          }
          else {
            readyRead = true;
          }
        }
      }
      return ndx;
    }
    
    //Function write back to PC
    void rtnProtocols(char cmdtype[], char cmdparam[]) {
      char outputString[28] = "TOWST_";
      strcat (outputString, cmdtype);
      strcat (outputString, "_");
      strcat (outputString, cmdparam);
      strcat (outputString, "_");
    
      int outputCheckSum = checkSumGenerator(outputString);
      char outputCheckSumHex[3] = "00";
      itoa (outputCheckSum, outputCheckSumHex, 16);
      if (outputCheckSum < 16) { //Adds a 0 if CS has fewer than 2 numbers
        outputCheckSumHex[1] = outputCheckSumHex[0];
        outputCheckSumHex[0] = '0';
      }
      outputCheckSumHex[0] = toupper (outputCheckSumHex[0]);
      outputCheckSumHex[1] = toupper (outputCheckSumHex[1]);
      strcat (outputString, outputCheckSumHex); //Now displayed in base16
      outputString[23] = {'\r'}; //Not displayed in port. This should be happening, I think.
      outputString[24] = {'\n'};
    
      Serial.write(outputString);
    }
    

    Please let me know if more information is required.

    SGaistS 1 Reply Last reply 31 May 2023, 19:44
    0
    • D Dummie1138
      31 May 2023, 14:58

      Question as posted on Arduino forum: https://forum.arduino.cc/t/serial-println-not-sent-to-qt-application/1133089

      Hi. I have the following code for a QSerialPort, meant to send and receive information from an Arduino.

      //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++;
              if(serialPort_Controller->open(QIODevice::ReadWrite))
              {
                  qDebug() << "Connected";
                  int i = serialPort_Controller->write("TOPIC_VALCN_00000000_48\r\n");    //"TOPIC_VALCN_00000000_48\r\n"
                  qDebug() << i;
                  qDebug() << "TOPIC_VALCN_00000000_48\r\n";
              }
              else
              {
                  qDebug() << "Connection error";
              }
              if (!serialPort_Controller->isOpen())
              {
                  qDebug() << "Cannot open controller serial port";
              }
          }
          else
          {
              currentPosInList = 0;
          } 
      }
      
      //received messages get processed here into the correct format
      void DeviceConnection::serialReady()
      {
          QString allReceived = QString(serialPort_Controller->readAll());
      
          //    if (SystemSettings::get()->getValue(PROTOCOL_DEBUG_MODE) == "1")
          //        backSerialPort->write(allReceived.toUtf8());
          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);
          }
      }
      

      The issue is simple: When I send a message through to the Arduino code from the Arduino serial monitor, the code does successfully process the message and return it on the Arduino serial monitor.

      However, when sending messages through via QSerialPort, the code no longer processes the message and returns it to the Qt application at baud rates higher than 9600.

      Things I've tried:

      Shortening the message written:

      serialPort_Controller->write("T\n");
      

      This did not work.

      Changing the data bits & parity, that did not work.

      Running the code in debug mode and adding a breakpoint at this line:

      serialPort_Controller->write("TOPIC_VALCN_00000000_48\r\n");
      

      This worked, somehow. I have yet to determine why.

      The part of the arduino code that directly reads and writes:

      void setup() {
        // put your setup code here, to run once:
        Serial.begin(115200); // usb port serial
        pinMode(LED_BUILTIN, OUTPUT);
      }
      
      void loop() {
        //Collect data.
        bool readyRead = true;
        int i = 0;
        //Serial.println("Serial available.");
        if (Serial.available() > 0) {
          //Serial.println("Serial available.");
          i = msgReceiver('\n', readyRead); //msgReceiver is for turning the input to a char array. '\n' is end char. The output of msgReceiver is the char array position, so need to ++.
          digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); //This turns an LED on and off.
          messageArray[27] = '\0'; // terminate the string
      
          int msgLength = i + 1;
      
          for (i = msgLength; i > 22; i--) {  //messageArray[22] is the 2nd char of the checkSum. Should not be ablated.
            messageArray[i] = '\0';
          }
          bool canSend = true;
      
          char checkSumCharacters[2] = {messageArray[i - 1], messageArray[i]}; //Values are ascii code of the base16 numbers.
          int receivedCheckSum = strtoul(checkSumCharacters, NULL, 16);  //Converts the base16 characters to an int.
      
          int checkSum = checkSumGenerator(messageArray);
      
          for (i = 0; i < sizeof(cmdtarget); i++) { //Length of cmdtarget is 5.
            cmdtarget[i] = messageArray[i];
          }
          cmdtarget[5] = '\0';
          for (i = 0; i < sizeof(input_cmdtype) - 1; i++) { //Length of cmdtype is 5.
            input_cmdtype[i] = messageArray[i + 6];
          }
          input_cmdtype[5] = '\0';
          for (i = 0; i < sizeof(input_cmdparam) - 1; i++) { //Length of cmdparam is 8.
            input_cmdparam[i] = messageArray[i + 12];
          }
          input_cmdparam[8] = '\0';
          //An attempt at a function pointer to be called for rtnProtocols. Pointer used to decrease negative effects of conditionals.
          stringFunction *rtnpointer[] = {
            FIRMV_F, VALCN_F, RQSPC_F, CTFTC_F, LIDVM_F, LIDVC_F, PREVC_F, STPWM_F, CHPWM_F, STPER_F, CHPER_F, CHIGH_F, SHIGH_F, MOTST_F, MHIGH_F, MTRTT_F,
            RCTIC_F, RCTGM_F, RCTGC_F, SAVEA_F, PREST_F, PREND_F, RQPRE_F, CLPRE_F, RQDAT_F, CUPTC_F, LIDTC_F, CURPR_F, CUPTT_F, CDATE_F, CTIME_F, SDATE_F, RDTTM_F,
            SPROG_F, SLOAD_F, CUFAC_F, LIFAC_F, STFAC_F, MTFAC_F, PPFAC_F, PCOFF_F, CUPFM_F, CUPFC_F, LIDFM_F, LIDFC_F, PREFC_F, FCPWM_F, FCPER_F, FHIGH_F,
          };
      
          input in = convert(input_cmdtype);  //Using the char to enum converter.
          canSend = errorStack(cmdtarget, receivedCheckSum, checkSum, msgLength, in, canSend);
      
          if (canSend) {
            char verak[6] = "VERAK";
            rtnProtocols(verak, input_cmdparam);
      
            rtnpointer[in](input_cmdtype, input_cmdparam);
          }
        }
      }
      
      //Reads message.
      int msgReceiver(char endMarker, bool readyRead) {
        char rc;
        int ndx = 0;
        while (readyRead == true) {
          if (Serial.available() > 0) {
            rc = Serial.read();
            if (rc != endMarker) {
              messageArray[ndx] = rc;
              ndx++;
            }
            else if (rc == endMarker) {
              messageArray[ndx] = '\0'; // terminate the string
              //Serial.println("Received \n.");
              rc = 0;
              readyRead = false;
            }
            else {
              readyRead = true;
            }
          }
        }
        return ndx;
      }
      
      //Function write back to PC
      void rtnProtocols(char cmdtype[], char cmdparam[]) {
        char outputString[28] = "TOWST_";
        strcat (outputString, cmdtype);
        strcat (outputString, "_");
        strcat (outputString, cmdparam);
        strcat (outputString, "_");
      
        int outputCheckSum = checkSumGenerator(outputString);
        char outputCheckSumHex[3] = "00";
        itoa (outputCheckSum, outputCheckSumHex, 16);
        if (outputCheckSum < 16) { //Adds a 0 if CS has fewer than 2 numbers
          outputCheckSumHex[1] = outputCheckSumHex[0];
          outputCheckSumHex[0] = '0';
        }
        outputCheckSumHex[0] = toupper (outputCheckSumHex[0]);
        outputCheckSumHex[1] = toupper (outputCheckSumHex[1]);
        strcat (outputString, outputCheckSumHex); //Now displayed in base16
        outputString[23] = {'\r'}; //Not displayed in port. This should be happening, I think.
        outputString[24] = {'\n'};
      
        Serial.write(outputString);
      }
      

      Please let me know if more information is required.

      SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on 31 May 2023, 19:44 last edited by
      #2

      Hi,

      Are you sure about the flow control value as well ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      D 1 Reply Last reply 1 Jun 2023, 08:13
      0
      • SGaistS SGaist
        31 May 2023, 19:44

        Hi,

        Are you sure about the flow control value as well ?

        D Offline
        D Offline
        Dummie1138
        wrote on 1 Jun 2023, 08:13 last edited by
        #3

        @SGaist By flow control value, do you mean the XON/XOFF? My Arduino works on XON/XOFF. I have also tested changing, to no success.

        An additional predicament I have discovered is that the Arduino does receive, process, and return data from the Qt application the first time

        Recent suggestions on the Arduino forum have suggested that:

        When an application opens the Serial port to the Arduino, it causes the Arduino to reset so you need to wait for it to boot up and be ready to receive commands before you send them. For this reason, it is usually best to have your Arduino send a welcome string like "ready" inside of setup() that your application can detect before sending anything else.

        I have added a message to the setup function of the Arduino, which is able to be sent every time the Arduino is reconnected to the serial port. However, the original message (which is processed in the loop part) is still unable to be received.

        Addendum: the full code for the QSerialPort's file.

        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;
        
            QSerialPort* serialPort_Controller; //Need more research into this
        
            void addToQueue(QString message);
            void removeOneFromQueue();
            void closeConnection();
            bool isQueueEmpty();
            void emptyQueue();
        
        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();
        
        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
        
        private slots:
            void handleError(QSerialPort::SerialPortError error);
            void stopConnectAttempts(); //After current connection attempts finish, stop connecting
        private:
            bool alreadySetup;
        
            QString incomingRemainder;
            QStringList messagesList;
        
            QTimer* sendingTimer;
            QTimer* connectingTimer;
            QTimer* checkerTimer;
            QQueue<QString> toSendQueue;
            int waitingForResponse;
            int sendingAttempts;    //Lists the amount of attempts at sending a single message. Currently, tops out at 10
        
            QString calculateChecksum(QString message);
        
            Controller* controller;
        
        };
        
        #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(3000);
            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
                //This might need modification
                serialPort_Controller->setBaudRate(115200);
                serialPort_Controller->setDataBits(QSerialPort::Data8);
                serialPort_Controller->setParity(QSerialPort::NoParity);
                serialPort_Controller->setStopBits(QSerialPort::OneStop);
                serialPort_Controller->setFlowControl(QSerialPort::HardwareControl);
                currentPosInList++;
                if(serialPort_Controller->open(QIODevice::ReadWrite)){
                    qDebug() << "Connected";
                    QByteArray validationMessage = "TOARM_VALCN_00000000_4C";
                    validationMessage.append('\r');
                    validationMessage.append('\n');
                    serialPort_Controller->write(validationMessage);
                    qDebug() << "Sending message: " + validationMessage;
                    //FIXIT Arduino only returns information when in debug mode
                }
                else{
                    qDebug() << "Connection error";
                }
                if (!serialPort_Controller->isOpen()){
                    qDebug() << "Cannot open controller serial port";
                }
            }
            else{
                currentPosInList = 0;
            }
        }
        
        //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);
            portName = portsAvailable.at(currentPosInList - 1).portName();
            portInfo = portsAvailable.at(currentPosInList - 1);
            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
        void DeviceConnection::closeConnection()
        {
            serialPort_Controller->close();
        }
        
        //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 VERAK 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
        void DeviceConnection::sendFromQueue()  //this is tied to a qtimer that triggers once every 50ms
        {
        
            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)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        
        //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()
        {
            serialPort_Controller->close();
            qDebug() << "restartConnection";
            connectingTimer->start(3000);
            //qDebug() << "startedTimer";
            emit lostConnection();
        }
        
        //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";
                closeConnection();
                emptyQueue();
                connectingTimer->start(3000);
                emit lostConnection();
            }
        }
        
        SGaistS 1 Reply Last reply 1 Jun 2023, 19:39
        0
        • D Dummie1138
          1 Jun 2023, 08:13

          @SGaist By flow control value, do you mean the XON/XOFF? My Arduino works on XON/XOFF. I have also tested changing, to no success.

          An additional predicament I have discovered is that the Arduino does receive, process, and return data from the Qt application the first time

          Recent suggestions on the Arduino forum have suggested that:

          When an application opens the Serial port to the Arduino, it causes the Arduino to reset so you need to wait for it to boot up and be ready to receive commands before you send them. For this reason, it is usually best to have your Arduino send a welcome string like "ready" inside of setup() that your application can detect before sending anything else.

          I have added a message to the setup function of the Arduino, which is able to be sent every time the Arduino is reconnected to the serial port. However, the original message (which is processed in the loop part) is still unable to be received.

          Addendum: the full code for the QSerialPort's file.

          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;
          
              QSerialPort* serialPort_Controller; //Need more research into this
          
              void addToQueue(QString message);
              void removeOneFromQueue();
              void closeConnection();
              bool isQueueEmpty();
              void emptyQueue();
          
          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();
          
          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
          
          private slots:
              void handleError(QSerialPort::SerialPortError error);
              void stopConnectAttempts(); //After current connection attempts finish, stop connecting
          private:
              bool alreadySetup;
          
              QString incomingRemainder;
              QStringList messagesList;
          
              QTimer* sendingTimer;
              QTimer* connectingTimer;
              QTimer* checkerTimer;
              QQueue<QString> toSendQueue;
              int waitingForResponse;
              int sendingAttempts;    //Lists the amount of attempts at sending a single message. Currently, tops out at 10
          
              QString calculateChecksum(QString message);
          
              Controller* controller;
          
          };
          
          #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(3000);
              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
                  //This might need modification
                  serialPort_Controller->setBaudRate(115200);
                  serialPort_Controller->setDataBits(QSerialPort::Data8);
                  serialPort_Controller->setParity(QSerialPort::NoParity);
                  serialPort_Controller->setStopBits(QSerialPort::OneStop);
                  serialPort_Controller->setFlowControl(QSerialPort::HardwareControl);
                  currentPosInList++;
                  if(serialPort_Controller->open(QIODevice::ReadWrite)){
                      qDebug() << "Connected";
                      QByteArray validationMessage = "TOARM_VALCN_00000000_4C";
                      validationMessage.append('\r');
                      validationMessage.append('\n');
                      serialPort_Controller->write(validationMessage);
                      qDebug() << "Sending message: " + validationMessage;
                      //FIXIT Arduino only returns information when in debug mode
                  }
                  else{
                      qDebug() << "Connection error";
                  }
                  if (!serialPort_Controller->isOpen()){
                      qDebug() << "Cannot open controller serial port";
                  }
              }
              else{
                  currentPosInList = 0;
              }
          }
          
          //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);
              portName = portsAvailable.at(currentPosInList - 1).portName();
              portInfo = portsAvailable.at(currentPosInList - 1);
              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
          void DeviceConnection::closeConnection()
          {
              serialPort_Controller->close();
          }
          
          //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 VERAK 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
          void DeviceConnection::sendFromQueue()  //this is tied to a qtimer that triggers once every 50ms
          {
          
              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)
              {
                  return false;
              }
              else
              {
                  return true;
              }
          }
          
          //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()
          {
              serialPort_Controller->close();
              qDebug() << "restartConnection";
              connectingTimer->start(3000);
              //qDebug() << "startedTimer";
              emit lostConnection();
          }
          
          //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";
                  closeConnection();
                  emptyQueue();
                  connectingTimer->start(3000);
                  emit lostConnection();
              }
          }
          
          SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on 1 Jun 2023, 19:39 last edited by
          #4

          For debugging purposes, your class is really overly complicated.

          You should create something simpler that does not try to do so many stuff through timers.

          As a test helper, you could use the QSerialPort terminal. That way you can do tests manually.

          Interested in AI ? www.idiap.ch
          Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

          D 1 Reply Last reply 2 Jun 2023, 08:54
          0
          • SGaistS SGaist
            1 Jun 2023, 19:39

            For debugging purposes, your class is really overly complicated.

            You should create something simpler that does not try to do so many stuff through timers.

            As a test helper, you could use the QSerialPort terminal. That way you can do tests manually.

            D Offline
            D Offline
            Dummie1138
            wrote on 2 Jun 2023, 08:54 last edited by
            #5

            @SGaist What are some other ways I could approach reconnecting in regular intervals, as well as waiting for a connection to complete, other than timers?

            SGaistS 1 Reply Last reply 2 Jun 2023, 20:16
            0
            • D Dummie1138
              2 Jun 2023, 08:54

              @SGaist What are some other ways I could approach reconnecting in regular intervals, as well as waiting for a connection to complete, other than timers?

              SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on 2 Jun 2023, 20:16 last edited by
              #6

              A timer can be a possibility however I would rather first determine whether it's really needed.
              Also, if the reconnection happens, does the serial port name change ?

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              1 Reply Last reply
              0

              1/6

              31 May 2023, 14:58

              • Login

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