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. Running just one slot in a different Thread
QtWS25 Last Chance

Running just one slot in a different Thread

Scheduled Pinned Locked Moved Solved General and Desktop
qserialportqthreadqobject
17 Posts 4 Posters 2.4k 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.
  • K Offline
    K Offline
    Kevin470
    wrote on 7 Sept 2022, 11:18 last edited by Kevin470 9 Jul 2022, 12:01
    #1

    I have a QSerialPort object QSerialPort m_serialPort which receives data with and without requests.
    Most of the time the answer I expect come in broken into multiple responses.

    I connected the QSerialPort [Signal] readyRead to a slot in my class SerialCommunication::readyRead()

    Is it possible to run just this slot SerialCommunication::readyRead() in a different thread so that this function runs without disruption?
    I tried to move this function to a different thread and start it. But if I run the SerialCommunication::setReadyReadToThread() method, the application crashes at start with no errors.

    I am still learning C++ and Qt. Sorry for any mistakes.

    My code is as follows:

    HEADER
    class SerialCommunication: public QObject
    {
        Q_OBJECT
    public:
        explicit SerialCommunication(QObject *parent = nullptr);
        ~SerialCommunication();
    
    signals:
        void newDataReceived(QByteArray &data);
    
    public slots:
        bool write(QByteArray &data);
        bool openPort();
        bool closePort();
        void setReadyReadToThread();
        void readyRead();
    
    private:
    
        QSerialPort m_serialPort;
        QByteArray m_buffer;
        
        QThread m_thread;
    };
    
    SOURCE
    SerialCommunication::SerialCommunication(QObject *parent)
        : QObject{parent}
    {
        m_serialPort.setBaudRate(QSerialPort::Baud57600,QSerialPort::AllDirections);
        m_serialPort.setDataBits(QSerialPort::Data8);
        m_serialPort.setParity(QSerialPort::NoParity);
        m_serialPort.setStopBits(QSerialPort::OneStop);
        m_serialPort.setPortName("COM5");
        
        connect(&m_serialPort,&QSerialPort::readyRead,this,&SerialCommunication::readyRead,Qt::QueuedConnection);
    
        setReadyReadToThread();
        openPort();
    }
    
    SerialCommunication::~SerialCommunication()
    {
        closePort();
    }
    
    bool SerialCommunication::openPort()
    {
        m_serialPort.open(QIODevice::ReadWrite);
    
        if (m_serialPort.isOpen())
        {
            qDebug() << "Serial port is open...";
            return true;
        }
        else
        {
            qDebug() << "OPEN ERROR: " << m_serialPort.errorString();
            return false;
        }
    }
    
    bool SerialCommunication::closePort()
    {
        if (m_serialPort.isOpen())
            {
                m_serialPort.close();
                qDebug() << "...serial port is closed!";
            }
        return true;
    }
    
    bool SerialCommunication::write(QByteArray &data)
    {
        if (m_serialPort.isWritable())
        {
            if(!m_serialPort.write(data))
            {
                qDebug() << "Serial Data Cannot be Written!";
                return false;
            }
            else
            {
                m_serialPort.flush();
                return true;
            }
          return true;
        }
        else
        {
            qDebug() << "Serial Data Cannot be Written!";
            return false;
        }
    }
    
    void SerialCommunication::setReadyReadToThread()
    {
        moveToThread(&m_thread);
        connect(&m_thread,&QThread::started,this,&SerialCommunication::readyRead);
        m_thread.start();
    }
    
    void SerialCommunication::readyRead()
    {
        QByteArray reception_buffer;
        while (running) 
        {
            if (m_serialPort.waitForReadyRead(1000)) {
                reception_buffer = m_serialPort.readAll();
                while (m_serialPort.waitForReadyRead(10)) {
                    reception_buffer += m_serialPort.readAll();
                }
                qDebug() << "reception_buffer ready";
                emit newDataReceived(reception_buffer);
            }
        }   
    }
    

    Thanks in advance :)

    J 1 Reply Last reply 7 Sept 2022, 12:11
    0
    • K Kevin470
      7 Sept 2022, 11:18

      I have a QSerialPort object QSerialPort m_serialPort which receives data with and without requests.
      Most of the time the answer I expect come in broken into multiple responses.

      I connected the QSerialPort [Signal] readyRead to a slot in my class SerialCommunication::readyRead()

      Is it possible to run just this slot SerialCommunication::readyRead() in a different thread so that this function runs without disruption?
      I tried to move this function to a different thread and start it. But if I run the SerialCommunication::setReadyReadToThread() method, the application crashes at start with no errors.

      I am still learning C++ and Qt. Sorry for any mistakes.

      My code is as follows:

      HEADER
      class SerialCommunication: public QObject
      {
          Q_OBJECT
      public:
          explicit SerialCommunication(QObject *parent = nullptr);
          ~SerialCommunication();
      
      signals:
          void newDataReceived(QByteArray &data);
      
      public slots:
          bool write(QByteArray &data);
          bool openPort();
          bool closePort();
          void setReadyReadToThread();
          void readyRead();
      
      private:
      
          QSerialPort m_serialPort;
          QByteArray m_buffer;
          
          QThread m_thread;
      };
      
      SOURCE
      SerialCommunication::SerialCommunication(QObject *parent)
          : QObject{parent}
      {
          m_serialPort.setBaudRate(QSerialPort::Baud57600,QSerialPort::AllDirections);
          m_serialPort.setDataBits(QSerialPort::Data8);
          m_serialPort.setParity(QSerialPort::NoParity);
          m_serialPort.setStopBits(QSerialPort::OneStop);
          m_serialPort.setPortName("COM5");
          
          connect(&m_serialPort,&QSerialPort::readyRead,this,&SerialCommunication::readyRead,Qt::QueuedConnection);
      
          setReadyReadToThread();
          openPort();
      }
      
      SerialCommunication::~SerialCommunication()
      {
          closePort();
      }
      
      bool SerialCommunication::openPort()
      {
          m_serialPort.open(QIODevice::ReadWrite);
      
          if (m_serialPort.isOpen())
          {
              qDebug() << "Serial port is open...";
              return true;
          }
          else
          {
              qDebug() << "OPEN ERROR: " << m_serialPort.errorString();
              return false;
          }
      }
      
      bool SerialCommunication::closePort()
      {
          if (m_serialPort.isOpen())
              {
                  m_serialPort.close();
                  qDebug() << "...serial port is closed!";
              }
          return true;
      }
      
      bool SerialCommunication::write(QByteArray &data)
      {
          if (m_serialPort.isWritable())
          {
              if(!m_serialPort.write(data))
              {
                  qDebug() << "Serial Data Cannot be Written!";
                  return false;
              }
              else
              {
                  m_serialPort.flush();
                  return true;
              }
            return true;
          }
          else
          {
              qDebug() << "Serial Data Cannot be Written!";
              return false;
          }
      }
      
      void SerialCommunication::setReadyReadToThread()
      {
          moveToThread(&m_thread);
          connect(&m_thread,&QThread::started,this,&SerialCommunication::readyRead);
          m_thread.start();
      }
      
      void SerialCommunication::readyRead()
      {
          QByteArray reception_buffer;
          while (running) 
          {
              if (m_serialPort.waitForReadyRead(1000)) {
                  reception_buffer = m_serialPort.readAll();
                  while (m_serialPort.waitForReadyRead(10)) {
                      reception_buffer += m_serialPort.readAll();
                  }
                  qDebug() << "reception_buffer ready";
                  emit newDataReceived(reception_buffer);
              }
          }   
      }
      

      Thanks in advance :)

      J Offline
      J Offline
      jsulm
      Lifetime Qt Champion
      wrote on 7 Sept 2022, 12:11 last edited by
      #2

      @Kevin470 said in Running just one slot in a different Thread:

      connect(&m_thread,&QThread::started,this,&SerialCommunication::readyRead);

      What are you trying to achieve with this connection?!
      You need to connect this slot to the readyRead signal from QSerialPort.

      SerialCommunication should not move itself into another thread. Do that where you create the SerialCommunication instance.
      Better follow worker approach as shown here: https://doc.qt.io/qt-6/qthread.html So, make SerialCommunication a worker.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      K 1 Reply Last reply 7 Sept 2022, 13:23
      3
      • J jsulm
        7 Sept 2022, 12:11

        @Kevin470 said in Running just one slot in a different Thread:

        connect(&m_thread,&QThread::started,this,&SerialCommunication::readyRead);

        What are you trying to achieve with this connection?!
        You need to connect this slot to the readyRead signal from QSerialPort.

        SerialCommunication should not move itself into another thread. Do that where you create the SerialCommunication instance.
        Better follow worker approach as shown here: https://doc.qt.io/qt-6/qthread.html So, make SerialCommunication a worker.

        K Offline
        K Offline
        Kevin470
        wrote on 7 Sept 2022, 13:23 last edited by
        #3

        @jsulm The problem with my Code is that my SerialCommunication::readyRead() method runs an infinite while loop.
        If I move the m_serialPort object to a different/new thread, the SerialCommunication::readyRead() method blocks any other function in that class.
        That is why I was thinking if it is possible to run only this method in a separate Thread so that any other function in this class is not blocked by it.
        Are there better options to run an Infinite loop in a different thread for Serial Read?

        JonBJ 1 Reply Last reply 7 Sept 2022, 13:29
        0
        • K Kevin470
          7 Sept 2022, 13:23

          @jsulm The problem with my Code is that my SerialCommunication::readyRead() method runs an infinite while loop.
          If I move the m_serialPort object to a different/new thread, the SerialCommunication::readyRead() method blocks any other function in that class.
          That is why I was thinking if it is possible to run only this method in a separate Thread so that any other function in this class is not blocked by it.
          Are there better options to run an Infinite loop in a different thread for Serial Read?

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on 7 Sept 2022, 13:29 last edited by JonB 9 Jul 2022, 13:30
          #4

          @Kevin470
          The simple(r) answer is precisely not to run an infinite loop for serial reading, not to use your waitForReadyRead(10) (which is a bit flaky anyway). Especially if that is why you are trying to do threading anyway. The Qt/event driven way is to accumulate input asynchronously into a buffer, then you probably wouldn't need any threading.

          K 1 Reply Last reply 7 Sept 2022, 13:50
          1
          • JonBJ JonB
            7 Sept 2022, 13:29

            @Kevin470
            The simple(r) answer is precisely not to run an infinite loop for serial reading, not to use your waitForReadyRead(10) (which is a bit flaky anyway). Especially if that is why you are trying to do threading anyway. The Qt/event driven way is to accumulate input asynchronously into a buffer, then you probably wouldn't need any threading.

            K Offline
            K Offline
            Kevin470
            wrote on 7 Sept 2022, 13:50 last edited by
            #5

            @JonB Thank you for your response.
            My initial Idea was to emit the data that I receive every time from the Serial Port and send (emit) it to another Class which parses the data. (Using connect(&m_serialPort,&QSerialPort::readyRead,this,&SerialCommunication::readyRead,Qt::QueuedConnection))

            But the device I connect to (which is ancient btw.) sends it extremely broken . I write a command and expect a response of 50 Bytes. I receive sometimes 1 response with all 50 bytes (and more sometimes) and sometimes 46 responses with single bytes and 2 responses with 2 bytes each.
            And sometimes it sends automatic error responses that I have to parse.
            That is why I thought of making this while loop because parsing so many broken responses is a lot more complex.
            If I could run this slot in another thread which emits me the data if there is a break of 10ms, I can parse it a lot easier.

            J 1 Reply Last reply 7 Sept 2022, 13:59
            0
            • K Kevin470
              7 Sept 2022, 13:50

              @JonB Thank you for your response.
              My initial Idea was to emit the data that I receive every time from the Serial Port and send (emit) it to another Class which parses the data. (Using connect(&m_serialPort,&QSerialPort::readyRead,this,&SerialCommunication::readyRead,Qt::QueuedConnection))

              But the device I connect to (which is ancient btw.) sends it extremely broken . I write a command and expect a response of 50 Bytes. I receive sometimes 1 response with all 50 bytes (and more sometimes) and sometimes 46 responses with single bytes and 2 responses with 2 bytes each.
              And sometimes it sends automatic error responses that I have to parse.
              That is why I thought of making this while loop because parsing so many broken responses is a lot more complex.
              If I could run this slot in another thread which emits me the data if there is a break of 10ms, I can parse it a lot easier.

              J Offline
              J Offline
              jsulm
              Lifetime Qt Champion
              wrote on 7 Sept 2022, 13:59 last edited by
              #6

              @Kevin470 You need to buffer the data you receive until you got a full package. So, connect a slot to readyRead (without any endless loops!), in that slot read the data and append to the buffer.

              https://forum.qt.io/topic/113070/qt-code-of-conduct

              K 1 Reply Last reply 8 Sept 2022, 06:33
              2
              • J jsulm
                7 Sept 2022, 13:59

                @Kevin470 You need to buffer the data you receive until you got a full package. So, connect a slot to readyRead (without any endless loops!), in that slot read the data and append to the buffer.

                K Offline
                K Offline
                Kevin470
                wrote on 8 Sept 2022, 06:33 last edited by
                #7

                @jsulm
                That was my initial plan. But since I expect different types of responses with varied byte sized I thought running this infinite loop would be the better idea. I will still try to use a buffer and solve this problem. Thank you all.

                JonBJ 1 Reply Last reply 8 Sept 2022, 07:39
                0
                • K Kevin470
                  8 Sept 2022, 06:33

                  @jsulm
                  That was my initial plan. But since I expect different types of responses with varied byte sized I thought running this infinite loop would be the better idea. I will still try to use a buffer and solve this problem. Thank you all.

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on 8 Sept 2022, 07:39 last edited by
                  #8

                  @Kevin470 said in Running just one slot in a different Thread:

                  But since I expect different types of responses with varied byte sized

                  You current implementation, with its while and waitForReadyRead(), effectively relies on timing of arrival to determine what constitutes a full "message" (emit newDataReceived(reception_buffer)). This is not an ideal way to arrange things. When you change over to buffering it will work much easier if your "messages" have some actual boundaries, e.g. a byte count at the beginning or a terminator at the end. Do they have such? If not you will have to do some work to deal with time passed in order to reconstruct separate messages.

                  K 1 Reply Last reply 8 Sept 2022, 08:34
                  2
                  • JonBJ JonB
                    8 Sept 2022, 07:39

                    @Kevin470 said in Running just one slot in a different Thread:

                    But since I expect different types of responses with varied byte sized

                    You current implementation, with its while and waitForReadyRead(), effectively relies on timing of arrival to determine what constitutes a full "message" (emit newDataReceived(reception_buffer)). This is not an ideal way to arrange things. When you change over to buffering it will work much easier if your "messages" have some actual boundaries, e.g. a byte count at the beginning or a terminator at the end. Do they have such? If not you will have to do some work to deal with time passed in order to reconstruct separate messages.

                    K Offline
                    K Offline
                    Kevin470
                    wrote on 8 Sept 2022, 08:34 last edited by
                    #9

                    @JonB Unfortunately they do not have any such boundaries.
                    Each command has a response of different size. And they do not have any terminators at the end or byte count in the response (like I mentioned earlier, it is a very old firmware). That is why I am finding it difficult to reconstruct every message individually if they are broken.

                    JonBJ 1 Reply Last reply 8 Sept 2022, 09:05
                    0
                    • K Kevin470
                      8 Sept 2022, 08:34

                      @JonB Unfortunately they do not have any such boundaries.
                      Each command has a response of different size. And they do not have any terminators at the end or byte count in the response (like I mentioned earlier, it is a very old firmware). That is why I am finding it difficult to reconstruct every message individually if they are broken.

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on 8 Sept 2022, 09:05 last edited by JonB 9 Aug 2022, 09:38
                      #10

                      @Kevin470
                      OK, then let's examine what you are going to have to do to behave the same as currently if you move off the blocking loop of while ... waitForReadyRead(1000).

                      Your current code receives some initial data and then keeps accumulating that into a single message while any new data arrives within 1 second. Once 1 second has passed without any further data arriving that marks the end of the "message" and you emit newDataReceived(reception_buffer).

                      To achieve that without the loop and the waiting, you are going to need a (single shot) QTimer::singleShot(). You want to keep accumulating into a buffer (class member variable). Each time new data arrives you want to restart the timer with a new 1 second from now. When finally the timer expires/times out that means 1 second has passed without any new data, and at that point your accumulated message data is "complete", you emit the signal and clear out the pending buffer.

                      So very vaguely I would expect something like:

                      // `SerialPort` has `reception_buffer` and `timer` as member variables
                      
                      reception_buffer.clear();
                      timer.setSingleShot(true);
                      timer.callOnTimeout(this, &SerialPort::onTimeout);
                      
                      void SerialPort::onReadyRead()
                      {
                          qDebug() << "reception_buffer appending new data";
                          reception_buffer.append(readAll());
                          timer.start(1000);
                      }
                      
                      void SerialPort::onTimeout()
                      {
                          qDebug() << "reception_buffer ready";
                          emit newDataReceived(reception_buffer);
                          reception_buffer.clear();
                      }
                      
                      K 1 Reply Last reply 8 Sept 2022, 10:24
                      1
                      • K Offline
                        K Offline
                        kuzulis
                        Qt Champions 2020
                        wrote on 8 Sept 2022, 09:41 last edited by kuzulis 9 Aug 2022, 09:43
                        #11
                        1. You don't need in a separate receiption buffer, like: reception_buffer.append(readAll()); because the QSP already so accumulates the data inside.

                        2. If a length of your response depends on a command, then you know that after a command A you expect e.g. a response with the 53 bytes, then it is simple to do like this:

                        SerialPort::SerialPort()
                        {
                            timer = new QTimer(this);
                        
                            connect(timer, &QTimer::timeout, this, &SerialPort::onTimeout);
                            timet->setSingleShot(true);
                        }
                        
                        void SerialPort::onReadyRead()
                        {
                            const auto bytesReceived = serial->byteaAvailable();
                            if (bytesReceived  < 53) { // 53 - expected length of response on a command `A`
                                timer->start(1000); // Or any other delay as you want.
                           } else {
                                const auto packet = serial->read(53);
                                emit packetReceived(packet);
                           }
                               
                        }
                        
                        void SerialPort::onTimeout()
                        {
                            qDebug() << "oops, something went wrong"
                        }
                        

                        But a better way is co create a some communication protocol with a <length><data><crc>.

                        K 1 Reply Last reply 8 Sept 2022, 12:32
                        3
                        • JonBJ JonB
                          8 Sept 2022, 09:05

                          @Kevin470
                          OK, then let's examine what you are going to have to do to behave the same as currently if you move off the blocking loop of while ... waitForReadyRead(1000).

                          Your current code receives some initial data and then keeps accumulating that into a single message while any new data arrives within 1 second. Once 1 second has passed without any further data arriving that marks the end of the "message" and you emit newDataReceived(reception_buffer).

                          To achieve that without the loop and the waiting, you are going to need a (single shot) QTimer::singleShot(). You want to keep accumulating into a buffer (class member variable). Each time new data arrives you want to restart the timer with a new 1 second from now. When finally the timer expires/times out that means 1 second has passed without any new data, and at that point your accumulated message data is "complete", you emit the signal and clear out the pending buffer.

                          So very vaguely I would expect something like:

                          // `SerialPort` has `reception_buffer` and `timer` as member variables
                          
                          reception_buffer.clear();
                          timer.setSingleShot(true);
                          timer.callOnTimeout(this, &SerialPort::onTimeout);
                          
                          void SerialPort::onReadyRead()
                          {
                              qDebug() << "reception_buffer appending new data";
                              reception_buffer.append(readAll());
                              timer.start(1000);
                          }
                          
                          void SerialPort::onTimeout()
                          {
                              qDebug() << "reception_buffer ready";
                              emit newDataReceived(reception_buffer);
                              reception_buffer.clear();
                          }
                          
                          K Offline
                          K Offline
                          Kevin470
                          wrote on 8 Sept 2022, 10:24 last edited by
                          #12

                          @JonB Thanks a lot for your response. I tried your program.

                          The buffer keeps appending and it gives out this error constantly without break.

                          reception_buffer appending new data
                          QObject::startTimer: Timers cannot be started from another thread
                          reception_buffer appending new data
                          QObject::killTimer: Timers cannot be stopped from another thread
                          QObject::startTimer: Timers cannot be started from another thread
                          reception_buffer appending new data
                          QObject::killTimer: Timers cannot be stopped from another thread
                          

                          I am not creating any Thread anywhere

                          JonBJ 1 Reply Last reply 8 Sept 2022, 11:23
                          0
                          • K Kevin470
                            8 Sept 2022, 10:24

                            @JonB Thanks a lot for your response. I tried your program.

                            The buffer keeps appending and it gives out this error constantly without break.

                            reception_buffer appending new data
                            QObject::startTimer: Timers cannot be started from another thread
                            reception_buffer appending new data
                            QObject::killTimer: Timers cannot be stopped from another thread
                            QObject::startTimer: Timers cannot be started from another thread
                            reception_buffer appending new data
                            QObject::killTimer: Timers cannot be stopped from another thread
                            

                            I am not creating any Thread anywhere

                            JonBJ Offline
                            JonBJ Offline
                            JonB
                            wrote on 8 Sept 2022, 11:23 last edited by JonB 9 Aug 2022, 11:25
                            #13

                            @Kevin470 said in Running just one slot in a different Thread:

                            I am not creating any Thread anywhere

                            I think you are, else you wouldn't get that message.... Since you can see I don't create threads it can't be me. The whole point of this was for you to get rid of your dedicated thread doing a blocking while loop, so you clearly have not done that.....

                            You:

                            If I move the m_serialPort object to a different/new thread

                            Me:

                            The Qt/event driven way is to accumulate input asynchronously into a buffer, then you probably wouldn't need any threading.

                            K 1 Reply Last reply 8 Sept 2022, 11:33
                            0
                            • JonBJ JonB
                              8 Sept 2022, 11:23

                              @Kevin470 said in Running just one slot in a different Thread:

                              I am not creating any Thread anywhere

                              I think you are, else you wouldn't get that message.... Since you can see I don't create threads it can't be me. The whole point of this was for you to get rid of your dedicated thread doing a blocking while loop, so you clearly have not done that.....

                              You:

                              If I move the m_serialPort object to a different/new thread

                              Me:

                              The Qt/event driven way is to accumulate input asynchronously into a buffer, then you probably wouldn't need any threading.

                              K Offline
                              K Offline
                              Kevin470
                              wrote on 8 Sept 2022, 11:33 last edited by
                              #14

                              @JonB I understand. But I am not running the moveToThread method at all.
                              This is my source currently.

                              There is no Threading involved except showing which function runs on which thread

                              SerialCommunication::SerialCommunication(QObject *parent)
                                  : QObject{parent}
                              {
                                  qInfo() << "SerialCommunication Constructor Thread: " << QThread::currentThread();
                              
                                  m_serialPort.setBaudRate(QSerialPort::Baud57600,QSerialPort::AllDirections);
                                  m_serialPort.setDataBits(QSerialPort::Data8);
                                  m_serialPort.setParity(QSerialPort::NoParity);
                                  m_serialPort.setStopBits(QSerialPort::OneStop);
                                  m_serialPort.setPortName("COM5");
                              
                                  connect(&m_serialPort,&QSerialPort::errorOccurred,this,&SerialCommunication::serialPortErrorOccured,Qt::QueuedConnection);
                                  connect(&m_serialPort,&QSerialPort::readyRead,this,&SerialCommunication::onReadyRead,Qt::QueuedConnection);
                              
                                  m_receptionBuffer.clear();
                                  m_receptionTimer.setSingleShot(true);
                                  m_receptionTimer.callOnTimeout(this, &SerialCommunication::onTimeout);
                              
                                  openPort();
                              }
                              
                              SerialCommunication::~SerialCommunication()
                              {
                                  closePort();
                              }
                              
                              bool SerialCommunication::openPort()
                              {
                                  m_serialPort.open(QIODevice::ReadWrite);
                              
                                  if (m_serialPort.isOpen())
                                  {
                                      qDebug() << "Serial port is open...";
                                      return true;
                              
                                  }
                                  else
                                  {
                                      qDebug() << "OPEN ERROR: " << m_serialPort.errorString();
                                      return false;
                                  }
                              }
                              
                              bool SerialCommunication::closePort()
                              {
                                  if (m_serialPort.isOpen())
                                      {
                                          m_serialPort.close();
                                          qDebug() << "...serial port is closed!";
                                      }
                                  return true;
                              }
                              
                              bool SerialCommunication::write(QByteArray &data)
                              {
                                  qInfo() << "SerialCommunication Write Function Thread: " << QThread::currentThread();
                                  if (m_serialPort.isWritable())
                                  {
                                      if(!m_serialPort.write(data))
                                      {
                                          qDebug() << "Serial Data Cannot be Written!";
                                          return false;
                                      }
                                      else
                                      {
                                          m_serialPort.flush();
                                          qInfo() << "Serial Data:" << data << "Written!";
                                          return true;
                                      }
                                    return true;
                                  }
                                  else
                                  {
                                      qDebug() << "Serial Data Cannot be Written!";
                                      return false;
                                  }
                              }
                              
                              void SerialCommunication::onReadyRead()
                              {
                                  qDebug() << "reception_buffer appending new data";
                                  m_receptionBuffer.append(m_serialPort.readAll());
                                  m_receptionTimer.start(1000);
                              }
                              
                              void SerialCommunication::onTimeout()
                              {
                                  qDebug() << "reception_buffer ready";
                                  emit newDataReceived(m_receptionBuffer);
                                  m_receptionBuffer.clear();
                              }
                              
                              void SerialCommunication::serialPortErrorOccured(QSerialPort::SerialPortError error)
                              {
                                  switch (error)
                                  {
                                  case (QSerialPort::NoError):
                                      break;
                                  case (QSerialPort::DeviceNotFoundError):
                                      qCritical() << "Serial Port not Found";
                                      break;
                                  case (QSerialPort::PermissionError):
                                      qCritical() << "Serial Port already in use or Permission required";
                                      break;
                                  case (QSerialPort::OpenError):
                                      qCritical() << "Serial Port Cannot be opened!";
                                      break;
                                  case (QSerialPort::NotOpenError):
                                      qCritical() << "Operation not Successful. Serial Port not Open";
                                      break;
                                  case (QSerialPort::WriteError):
                                      qCritical() << "Serial Port Error while writing Data!";
                                      break;
                                  case (QSerialPort::ReadError):
                                      qCritical() << "Serial Port Error while reading Data!";
                                      break;
                                  case (QSerialPort::ResourceError):
                                      qCritical() << "Serial Port Communication lost. Please try again!";
                                      break;
                                  case (QSerialPort::UnsupportedOperationError):
                                      qCritical() << "Serial Port Operation not Supported";
                                      break;
                                  case (QSerialPort::TimeoutError):
                                      qCritical() << "Serial Port Timeout";
                                      break;
                                  case (QSerialPort::UnknownError):
                                      qCritical() << "Unknown Serial Port Error!";
                                      break;
                              
                                  default:
                                      qCritical() << "Unknown Serial Port Error!";
                                      break;
                                  }
                              }
                              
                              JonBJ 1 Reply Last reply 8 Sept 2022, 11:37
                              0
                              • K Kevin470
                                8 Sept 2022, 11:33

                                @JonB I understand. But I am not running the moveToThread method at all.
                                This is my source currently.

                                There is no Threading involved except showing which function runs on which thread

                                SerialCommunication::SerialCommunication(QObject *parent)
                                    : QObject{parent}
                                {
                                    qInfo() << "SerialCommunication Constructor Thread: " << QThread::currentThread();
                                
                                    m_serialPort.setBaudRate(QSerialPort::Baud57600,QSerialPort::AllDirections);
                                    m_serialPort.setDataBits(QSerialPort::Data8);
                                    m_serialPort.setParity(QSerialPort::NoParity);
                                    m_serialPort.setStopBits(QSerialPort::OneStop);
                                    m_serialPort.setPortName("COM5");
                                
                                    connect(&m_serialPort,&QSerialPort::errorOccurred,this,&SerialCommunication::serialPortErrorOccured,Qt::QueuedConnection);
                                    connect(&m_serialPort,&QSerialPort::readyRead,this,&SerialCommunication::onReadyRead,Qt::QueuedConnection);
                                
                                    m_receptionBuffer.clear();
                                    m_receptionTimer.setSingleShot(true);
                                    m_receptionTimer.callOnTimeout(this, &SerialCommunication::onTimeout);
                                
                                    openPort();
                                }
                                
                                SerialCommunication::~SerialCommunication()
                                {
                                    closePort();
                                }
                                
                                bool SerialCommunication::openPort()
                                {
                                    m_serialPort.open(QIODevice::ReadWrite);
                                
                                    if (m_serialPort.isOpen())
                                    {
                                        qDebug() << "Serial port is open...";
                                        return true;
                                
                                    }
                                    else
                                    {
                                        qDebug() << "OPEN ERROR: " << m_serialPort.errorString();
                                        return false;
                                    }
                                }
                                
                                bool SerialCommunication::closePort()
                                {
                                    if (m_serialPort.isOpen())
                                        {
                                            m_serialPort.close();
                                            qDebug() << "...serial port is closed!";
                                        }
                                    return true;
                                }
                                
                                bool SerialCommunication::write(QByteArray &data)
                                {
                                    qInfo() << "SerialCommunication Write Function Thread: " << QThread::currentThread();
                                    if (m_serialPort.isWritable())
                                    {
                                        if(!m_serialPort.write(data))
                                        {
                                            qDebug() << "Serial Data Cannot be Written!";
                                            return false;
                                        }
                                        else
                                        {
                                            m_serialPort.flush();
                                            qInfo() << "Serial Data:" << data << "Written!";
                                            return true;
                                        }
                                      return true;
                                    }
                                    else
                                    {
                                        qDebug() << "Serial Data Cannot be Written!";
                                        return false;
                                    }
                                }
                                
                                void SerialCommunication::onReadyRead()
                                {
                                    qDebug() << "reception_buffer appending new data";
                                    m_receptionBuffer.append(m_serialPort.readAll());
                                    m_receptionTimer.start(1000);
                                }
                                
                                void SerialCommunication::onTimeout()
                                {
                                    qDebug() << "reception_buffer ready";
                                    emit newDataReceived(m_receptionBuffer);
                                    m_receptionBuffer.clear();
                                }
                                
                                void SerialCommunication::serialPortErrorOccured(QSerialPort::SerialPortError error)
                                {
                                    switch (error)
                                    {
                                    case (QSerialPort::NoError):
                                        break;
                                    case (QSerialPort::DeviceNotFoundError):
                                        qCritical() << "Serial Port not Found";
                                        break;
                                    case (QSerialPort::PermissionError):
                                        qCritical() << "Serial Port already in use or Permission required";
                                        break;
                                    case (QSerialPort::OpenError):
                                        qCritical() << "Serial Port Cannot be opened!";
                                        break;
                                    case (QSerialPort::NotOpenError):
                                        qCritical() << "Operation not Successful. Serial Port not Open";
                                        break;
                                    case (QSerialPort::WriteError):
                                        qCritical() << "Serial Port Error while writing Data!";
                                        break;
                                    case (QSerialPort::ReadError):
                                        qCritical() << "Serial Port Error while reading Data!";
                                        break;
                                    case (QSerialPort::ResourceError):
                                        qCritical() << "Serial Port Communication lost. Please try again!";
                                        break;
                                    case (QSerialPort::UnsupportedOperationError):
                                        qCritical() << "Serial Port Operation not Supported";
                                        break;
                                    case (QSerialPort::TimeoutError):
                                        qCritical() << "Serial Port Timeout";
                                        break;
                                    case (QSerialPort::UnknownError):
                                        qCritical() << "Unknown Serial Port Error!";
                                        break;
                                
                                    default:
                                        qCritical() << "Unknown Serial Port Error!";
                                        break;
                                    }
                                }
                                
                                JonBJ Offline
                                JonBJ Offline
                                JonB
                                wrote on 8 Sept 2022, 11:37 last edited by JonB 9 Aug 2022, 11:40
                                #15

                                @Kevin470 said in Running just one slot in a different Thread:

                                There is no Threading involved except showing which function runs on which thread

                                Then why do you think you get that error message? :) And why would you report which thread the function runs in if you don't have multiple threads somewhere? And how does that output compare to whatever is your main thread?

                                You only show your SerialCommunication class. You show nothing about where you create the instance, other parts of the program. Could you please search the whole of your project's code for thread case-insensitive and report back....

                                K 1 Reply Last reply 8 Sept 2022, 12:18
                                1
                                • JonBJ JonB
                                  8 Sept 2022, 11:37

                                  @Kevin470 said in Running just one slot in a different Thread:

                                  There is no Threading involved except showing which function runs on which thread

                                  Then why do you think you get that error message? :) And why would you report which thread the function runs in if you don't have multiple threads somewhere? And how does that output compare to whatever is your main thread?

                                  You only show your SerialCommunication class. You show nothing about where you create the instance, other parts of the program. Could you please search the whole of your project's code for thread case-insensitive and report back....

                                  K Offline
                                  K Offline
                                  Kevin470
                                  wrote on 8 Sept 2022, 12:18 last edited by
                                  #16

                                  @JonB Sorry about the inconvenience. I really did have moved it to a QThread in another class. I did not notice it earlier. I should have checked it properly.
                                  Thank you so much. And it works really well. 👍

                                  1 Reply Last reply
                                  1
                                  • K kuzulis
                                    8 Sept 2022, 09:41
                                    1. You don't need in a separate receiption buffer, like: reception_buffer.append(readAll()); because the QSP already so accumulates the data inside.

                                    2. If a length of your response depends on a command, then you know that after a command A you expect e.g. a response with the 53 bytes, then it is simple to do like this:

                                    SerialPort::SerialPort()
                                    {
                                        timer = new QTimer(this);
                                    
                                        connect(timer, &QTimer::timeout, this, &SerialPort::onTimeout);
                                        timet->setSingleShot(true);
                                    }
                                    
                                    void SerialPort::onReadyRead()
                                    {
                                        const auto bytesReceived = serial->byteaAvailable();
                                        if (bytesReceived  < 53) { // 53 - expected length of response on a command `A`
                                            timer->start(1000); // Or any other delay as you want.
                                       } else {
                                            const auto packet = serial->read(53);
                                            emit packetReceived(packet);
                                       }
                                           
                                    }
                                    
                                    void SerialPort::onTimeout()
                                    {
                                        qDebug() << "oops, something went wrong"
                                    }
                                    

                                    But a better way is co create a some communication protocol with a <length><data><crc>.

                                    K Offline
                                    K Offline
                                    Kevin470
                                    wrote on 8 Sept 2022, 12:32 last edited by
                                    #17

                                    @kuzulis Thank you so much for your response. That is a great idea.
                                    But you are right, the communication protocol would make a lot more sense if it followed the <length><data><crc> structure.

                                    @JonB 's Idea works well with my existing Program structure.

                                    1 Reply Last reply
                                    0

                                    1/17

                                    7 Sept 2022, 11:18

                                    • Login

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