Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. 3rd Party Software
  4. [Solved] QtSerialPort and Threads
Forum Updated to NodeBB v4.3 + New Features

[Solved] QtSerialPort and Threads

Scheduled Pinned Locked Moved 3rd Party Software
18 Posts 3 Posters 15.3k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • R Offline
    R Offline
    RodriguesCunha
    wrote on last edited by
    #1

    Hi.

    I want to ask something which i don't know if it's possible.

    Is it possible to create a single qserialport object in guithread and then implement one separate thread for sending data and a different one to receive data?
    To receive data i need blocking approach because i need it to only send a signal when i receive a complete and valid data frame.

    Thanks

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      You don't need any additional threads for that. Just add a layer that handles your read/write operation and in that layer handle your special reading purpose and send a signal once you have what you want.

      Hope it helps

      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
      • R Offline
        R Offline
        RodriguesCunha
        wrote on last edited by
        #3

        [quote author="SGaist" date="1370891902"]Hi,

        You don't need any additional threads for that. Just add a layer that handles your read/write operation and in that layer handle your special reading purpose and send a signal once you have what you want.

        Hope it helps[/quote]

        Hi, Thanks for your input.

        I'm new to Qt so i don't understand what you mean by add a layer.

        Can you try to explain or give me an example?

        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          Warning it's just some quick coding to give you the basic idea, it has not been compiled.

          @
          class SerialPortHandlingLayer : public QObject
          {
          Q_OBJECT
          public:
          SerialPortHandlingLayer(QtSerialPort *serialPort) :
          _serialPort(serialPort)
          {
          connect(_serialPort, SIGNAL(readyRead()), SLOT(onReadyRead()));
          }

          signals:
          void mySignalForWhenAllDataHaveArrived(ParameterType parameterName);

          public slots:
          void write(const QByteArray& data) // Not mandatory but it will keep all serial port related
          // reading and writing in the same place
          {
          _serialPort->write(data);
          }

          private slots:
          void onReadyRead()
          {
          // read data from _serialPort
          // check if i have everything
          // emit mySignalForWhenAllDataHaveArrived(parameter);
          // if needed some cleanup
          }

          private:
          QtSerialPort *_serialPort;
          };
          @

          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
          • R Offline
            R Offline
            RodriguesCunha
            wrote on last edited by
            #5

            Thanks.
            Let´s see if i understood what you meant.

            In my:

            • mainwindow.h

            i declare:
            @QSerialPort *serial;@

            in:

            • mainwindow.cpp

            in the constructor i have:
            @ ui->setupUi(this);

            serial = new QSerialPort(this);
            
            openSerialPort("COM3");@
            
            • openSerialPort()

            @void MainWindow::openSerialPort(const QString &portName)
            {

            serial->setPortName(portName);
            if (serial->open(QIODevice::ReadWrite)) {
                if (serial->setBaudRate(QSerialPort::Baud19200)
                        && serial->setDataBits(QSerialPort::Data8)
                        && serial->setParity(QSerialPort::NoParity)
                        && serial->setStopBits(QSerialPort::OneStop)
                        && serial->setFlowControl(QSerialPort::NoFlowControl)) {
            
            
                    ui->statusBar->showMessage(tr("Connected to %1 : %2, %3, %4, %5, %6")
                                               .arg(serial->portName()).arg(serial->baudRate()).arg(serial->dataBits())
                                               .arg(serial->parity()).arg(serial->stopBits()).arg(serial->flowControl()));
            
                } else {
                    serial->close();
                    QMessageBox::critical(this, tr("Error"), serial->errorString());
            
                    ui->statusBar->showMessage(tr("Open error"));
                }
            } else {
                QMessageBox::critical(this, tr("Error"), serial->errorString());
            
                ui->statusBar->showMessage(tr("Configure error"));
            }
            

            }@

            and now i should create a new class like you told me to. Is this correct?

            Why do you have the implementation of write and onreadyread in the .h or this should be implemented in serialporthandlyinglayer.cpp?

            Also, i didn't understand what this does "SerialPortHandlingLayer(QtSerialPort *serialPort) :
            _serialPort(serialPort)"

            1 Reply Last reply
            0
            • SGaistS Offline
              SGaistS Offline
              SGaist
              Lifetime Qt Champion
              wrote on last edited by
              #6

              You can create the new class or do the handling in your MainWindow, personally I prefer to restrict the responsibilities of my classes to do one thing when possible.

              I've put all in the header because it was a quick way to show you the idea of the intermediate layer. Normally I would have put all the implementation in a cpp file.

              Then I strongly advise you to get a good C++ book. This is a constructor and the following line is initializing _serialPort with the content of serialPort.

              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
              • R Offline
                R Offline
                RodriguesCunha
                wrote on last edited by
                #7

                Hi,

                Now i understood your approach on the subject. What you are suggesting me is to use the asynchronous approach. I already modified the terminal example to do it. But because of my gui i can't use it, because using it, everytime i receive a byte i will get a signal. Thats why i decided to use threads, so that only when i get the complete valid message the signal is emmitted.
                I also experimented this, modifying the blocking slave example.
                But because i need to send data after doing some calculations, i was trying to create a thread for sending data.
                But if i have a thread for receiving and another to send (the send will be in a wait condition) i will need to initialize the qserialport on the guithread. But i don't know how to use it inside the worker threads. Is this possible? Same qserialport object will be created in guithread and used on receive and send thread. Can this be done?

                I need to receive a data array, from a PIC18F, for example: 0 | 1 | 3 | 121 | 50 | 99 other is 0 | 2 | 2 | 10 | 150

                to detect the start i use 0, then message identifier (1 or 2), next the number of data bytes and finally the data bytes (data will change). I receive a complete data message every 10ms. After receiving it i make some calculations and send back to pic the result.
                I thought of using separate threads for receiving and send because for receiving i'm using the blocking method. And also because Serial com is full duplex, it should be possible to read and write at the same time.

                1 Reply Last reply
                0
                • K Offline
                  K Offline
                  kuzulis
                  Qt Champions 2020
                  wrote on last edited by
                  #8

                  bq. And also because Serial com is full duplex, it should be possible to read and write at the same time.

                  Nobody forbids to do it to you in non-blocking (async) approach.

                  bq. But i don’t know how to use it inside the worker threads. Is this possible?

                  In your context of a question - No. It can't be done because QtSerialPort (as well as QAbstractSocket) to isn't thread safe.

                  bq. I also experimented this, modifying the blocking slave example.

                  Also available and simple Slave (non-blocking) example with async approach. You can look at it if your device has a slave role.

                  PS: To you already above Mr. SGaist responded that - is better to use asynchronous approach. In my opinion his explanation is exhaustive.

                  1 Reply Last reply
                  0
                  • R Offline
                    R Offline
                    RodriguesCunha
                    wrote on last edited by
                    #9

                    Hi, Thanks kuzulis.

                    I thought of using threads and blocking approach because if I'm processing received data i can't do anything else in my gui.

                    As i mentioned i need to receive data, update gui, do some calculations and write back to pic. And i think that if i use async approach in guithread my app will be most of the time processing reception. Also i will receive data from another serial device.

                    1 Reply Last reply
                    0
                    • K Offline
                      K Offline
                      kuzulis
                      Qt Champions 2020
                      wrote on last edited by
                      #10

                      UPD:

                      bq. I need to receive a data array, from a PIC18F, for example: 0 | 1 | 3 | 121 | 50 | 99 other is 0 | 2 | 2 | 10 | 150

                      bq. to detect the start i use 0, then message identifier (1 or 2), next the number of data bytes and finally the data bytes (data will change).

                      I don't understand that to you is unclear?

                      @

                      ...
                      enum ParserState { WaitForStart, WaitForMsgId, WaitForData, Done };

                      static ParserState currentParserState = WaitForStart; // start synchronization
                      ...

                      ...
                      connect(port, SIGNAL(readyRead()), this, SLOT(onParseInputStream()));
                      ...

                      SerialPortHandlingLayer::onParseInputStream()
                      {
                      while (port->bytesAvailable() > 0) {
                      switch (currentParserState) {
                      case WaitForStart:
                      char c = 0;
                      if (port->peek(&c, 1) > 0 && (c == 0)) {
                      currentParserState = WaitForMsgId;
                      } else {
                      // read wrong char to dummy, skip it
                      port->read(&c, 1);
                      // stay on WaitForStart
                      }
                      break;

                          case WaitForMsgId: 
                              QByteArray ba = port->peek(2);
                              if (ba.at(1) == 1 ||ba.at(1) == 2) {
                                  currentParserState = WaitForData;
                              } else {
                                  // read wrong char to dummy, skip it
                                  port->read(&c, 1);
                                  // transition to WaitForStart
                                  currentParserState = WaitForStart;
                              }
                              break;
                      
                          case WaitForData:
                              // parse next length field from data
                              QByteArray ba = port->peek(3);
                              int msgLength = ba.at(2);
                              if (msgLength <= port->bytesAvailable() - 2) {
                                  // all complete data is available
                                  // skip start, id, length field
                                  QByteArray dummy = port->read(3);
                                  // read complete data
                                  QByteArray data =  port->read(msgLength);
                      
                                  emit port->completeData(data);
                              } else {
                                  // not all data is available, wait for next readyRead()
                                  return;
                              }
                               break;
                          }
                      }
                      

                      }

                      @

                      1 Reply Last reply
                      0
                      • R Offline
                        R Offline
                        RodriguesCunha
                        wrote on last edited by
                        #11

                        This part i already have working.
                        The problem is that while i'm doing reception i can't do anything else.

                        1 Reply Last reply
                        0
                        • K Offline
                          K Offline
                          kuzulis
                          Qt Champions 2020
                          wrote on last edited by
                          #12

                          You can do the calculations (parse or something else) in a separate thread (e.g. using QtConcurrent) and pass the result of the calculations through the signal to the QtSerialPort back. So, I not see a problem.

                          1 Reply Last reply
                          0
                          • SGaistS Offline
                            SGaistS Offline
                            SGaist
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            Then don't block: read what is available on the port in a QByteArray and once the QByteArray has the correct size, do your computation.

                            Between two readyRead, your GUI will be responsive.

                            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
                            • R Offline
                              R Offline
                              RodriguesCunha
                              wrote on last edited by
                              #14

                              Hi, I will try your approach, but i will need to receive data from another serialport. How can i do this? Because if i'm processing the readyRead() of the first, my app can't process the readyRead() of the second...
                              That's why i first thought about threads..

                              1 Reply Last reply
                              0
                              • K Offline
                                K Offline
                                kuzulis
                                Qt Champions 2020
                                wrote on last edited by
                                #15

                                Sorry? You give us all new and new surprises? :)

                                bq. Hi, I will try your approach, but i will need to receive data from another serialport. How can i do this?

                                This:
                                @
                                QSerialPort *port1 = new QSerialPort;
                                QSerialPort *port2 = new QSerialPort;

                                connect(port1, SIGNAL(readyRead()),
                                this, SLOT(onReadyReadFromPort1()));

                                connect(port2, SIGNAL(readyRead()),
                                this, SLOT(onReadyReadFromPort2()));

                                port1->setPortName("COM1");
                                port2->setPortName("COM125");

                                ...
                                ...
                                ...
                                @

                                does not work? :)

                                1 Reply Last reply
                                0
                                • R Offline
                                  R Offline
                                  RodriguesCunha
                                  wrote on last edited by
                                  #16

                                  I already had mentioned it in a previous post.

                                  I thought of doing like you say, but my question is: if both signals happen at same time, won't my program freeze? It will only process one or the other, or so i think... Or can 2 slots be processed at the same time?

                                  1 Reply Last reply
                                  0
                                  • K Offline
                                    K Offline
                                    kuzulis
                                    Qt Champions 2020
                                    wrote on last edited by
                                    #17

                                    bq. if both signals happen at same time, won’t my program freeze?

                                    It depends on the code that you implement in the handler of each slot.

                                    bq. Or can 2 slots be processed at the same time?

                                    Any slot/signal is executed in turn in a context of the current thread. Only one slot it is possible to process at the same time. Signals can't come at the same time, all (signals and slots) is processing from Qt event-loop queue (as a whole).

                                    Please, read documentation on Qt as a whole...

                                    1 Reply Last reply
                                    0
                                    • R Offline
                                      R Offline
                                      RodriguesCunha
                                      wrote on last edited by
                                      #18

                                      Ok, like i thought.
                                      That's why i first thought on using Threads...
                                      So that each serialport could only deal with one port.

                                      1 Reply Last reply
                                      0

                                      • Login

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