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. Qt - serial communication - receiving
Forum Updated to NodeBB v4.3 + New Features

Qt - serial communication - receiving

Scheduled Pinned Locked Moved Unsolved General and Desktop
15 Posts 4 Posters 2.3k 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
    Damian7546
    wrote on last edited by
    #1

    I am beginner in Qt. To first I would like to do application to communicate with serial device. This communication I did in thread. Sending work perfectly, but I have problem with receiving messages. The message should will be recive imediatelly after send frame. I think that problem is with m_Serial->waitForReadyRead(10)

    Below I paste my piece of code:

    void SerialWorker::doWork()
    {
    qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId();
    bool abort = false;
    quint8 inByte;
    quint8 checksum_temp;
    int numByte = 0;
    int receiverStatus = RCV_ST_IDLE;
    Frame *m_inFrame = nullptr;
    int dataLength = 0;
    
    QByteArray buffer_checksum;
    
    // Serial Port Initialization
    m_Serial = new QSerialPort();
    m_Serial->setPortName("COM6");
    m_Serial->setBaudRate(QSerialPort::Baud9600);
    m_Serial->setDataBits(QSerialPort::Data8);
    m_Serial->setParity(QSerialPort::NoParity);
    m_Serial->setStopBits(QSerialPort::OneStop);
    m_Serial->setFlowControl(QSerialPort::NoFlowControl);
    m_Serial->open(QIODevice::ReadWrite);
    qDebug() << "SerialPort Status: " << m_Serial->isOpen();
    
    while(!abort)
    {
        mutex.lock();
        abort = _abort;
        mutex.unlock();
    
        if(!m_outFrameQueue->isEmpty())
        {
            Frame *outFrame = m_outFrameQueue->dequeue();
            sendFrame(outFrame);
            delete outFrame;
    
        } else
    
        {
            if (m_Serial->waitForReadyRead(10))
            {
                QByteArray receivedData = m_Serial->readAll();
    
                while(receivedData.count() > 0)
                {
                    inByte = quint8(receivedData[0]);
                    receivedData.remove(0,1);
    
                        switch (receiverStatus)
                        {
                            case RCV_ST_IDLE:
                                {
                                    if(inByte == Frame::FRAME_ADDR_RFiD)
                                    {
                                        if (m_inFrame == nullptr)
                                            m_inFrame = new Frame();
    
                                        else
                                            m_inFrame->Clear();
    
                                        m_inFrame->AddByte(inByte);
                                        buffer_checksum.append(inByte);
                                        receiverStatus = RCV_ST_DATA_LENGTH;
                                    }
                                    else
                                    {
                                        buffer_checksum.clear();
                                    }
                                } break;
    
                            case RCV_ST_DATA_LENGTH:
                                {
    
                                    dataLength = inByte;      
                                    numByte = dataLength - 6; 
                                    m_inFrame->AddByte(inByte);
                                    buffer_checksum.append(inByte);
                                    receiverStatus = RCV_ST_CMD;
                                } break;
    
                            case RCV_ST_CMD:
                                {
                                    m_inFrame->AddByte(inByte);
                                    buffer_checksum.append(inByte);
                                    if(numByte > 0)
                                    receiverStatus = RCV_ST_DATA;
                                    else receiverStatus = RCV_ST_CODE;
    
                                } break;
    
                            case RCV_ST_DATA:
                                {
                                    m_inFrame->AddByte(inByte);
                                    buffer_checksum.append(inByte);
                                    if (--numByte == 0)
                                        receiverStatus = RCV_ST_CODE;
                                    else if (numByte < 0)
                                        receiverStatus = RCV_ST_IDLE;
                                } break;
    
                            case RCV_ST_CODE:
                                {
                                    m_inFrame->AddByte(inByte);
                                    buffer_checksum.append(inByte);
                                    receiverStatus = RCV_ST_CHECKSUM_HI;
                                } break;
    
                            case RCV_ST_CHECKSUM_HI:
                                {
                                    checksum_temp = (m_inFrame->CalculateCRC2_in(buffer_checksum) >> 8) & 0xFF;
                                    if (inByte == checksum_temp)
                                    {
    
                                        m_inFrame->AddByte(checksum_temp);
                                        receiverStatus = RCV_ST_CHECKSUM_LO;
                                    }
                                    else
                                    {
    
                                        receiverStatus = RCV_ST_IDLE;
                                        m_inFrame->Clear();
                                        delete m_inFrame;
                                    }
                                } break;
    
                            case RCV_ST_CHECKSUM_LO:
                                {
    
                                    checksum_temp = m_inFrame->CalculateCRC2_in(buffer_checksum) & 0xFF;
                                    if (inByte == checksum_temp)
                                    {
                                        receiverStatus = RCV_ST_IDLE;
                                        m_inFrame->AddByte(checksum_temp);
                                        emit this->frameReceived(m_inFrame);
                                        qDebug()<< "Frame:  " << Qt::hex << m_inFrame;
                                    }
                                    else
                                    {
    
                                        receiverStatus = RCV_ST_IDLE;
                                        m_inFrame->Clear();
                                        delete m_inFrame;
    
                                    }
                                } break;
                         }
    
                }
            } 
        }
    }
    }
    

    I checked whether the device definitely send frame, by this code

    void SerialWorker::doWork()
    {
    qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId();
    
    bool abort = false;
    quint8 inByte;
    quint8 checksum_temp;
    int numByte = 0;
    int receiverStatus = RCV_ST_IDLE;
    Frame *m_inFrame = nullptr;
    int dataLength = 0;
    
    QByteArray buffer_checksum;
    
    // Serial Port Initialization
    m_Serial = new QSerialPort();
    m_Serial->setPortName("COM6");
    m_Serial->setBaudRate(QSerialPort::Baud9600);
    m_Serial->setDataBits(QSerialPort::Data8);
    m_Serial->setParity(QSerialPort::NoParity);
    m_Serial->setStopBits(QSerialPort::OneStop);
    m_Serial->setFlowControl(QSerialPort::NoFlowControl);
    m_Serial->open(QIODevice::ReadWrite);
    qDebug() << "SerialPort Status: " << m_Serial->isOpen();
    
    while(!abort)
    {
        mutex.lock();
        abort = _abort;
        mutex.unlock();
       
        QByteArray receivedData = m_Serial->readAll();
    
    
        if(!m_outFrameQueue->isEmpty())
        {
            Frame *outFrame = m_outFrameQueue->dequeue();
            sendFrame(outFrame);
            delete outFrame;
    
        } else
    
        {
            if (receivedData.count() > 0) {
                qDebug() <<  "something came: "<< Qt::hex << receivedData.toHex() ;
                receivedData.clear();
            }
        }
    }
    }
    

    And it works. In receivedData.toHex() the receiving frame ic correct. So what is wrong with my fully soution pasted like first code ?

    JonBJ 1 Reply Last reply
    0
    • D Damian7546

      I am beginner in Qt. To first I would like to do application to communicate with serial device. This communication I did in thread. Sending work perfectly, but I have problem with receiving messages. The message should will be recive imediatelly after send frame. I think that problem is with m_Serial->waitForReadyRead(10)

      Below I paste my piece of code:

      void SerialWorker::doWork()
      {
      qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId();
      bool abort = false;
      quint8 inByte;
      quint8 checksum_temp;
      int numByte = 0;
      int receiverStatus = RCV_ST_IDLE;
      Frame *m_inFrame = nullptr;
      int dataLength = 0;
      
      QByteArray buffer_checksum;
      
      // Serial Port Initialization
      m_Serial = new QSerialPort();
      m_Serial->setPortName("COM6");
      m_Serial->setBaudRate(QSerialPort::Baud9600);
      m_Serial->setDataBits(QSerialPort::Data8);
      m_Serial->setParity(QSerialPort::NoParity);
      m_Serial->setStopBits(QSerialPort::OneStop);
      m_Serial->setFlowControl(QSerialPort::NoFlowControl);
      m_Serial->open(QIODevice::ReadWrite);
      qDebug() << "SerialPort Status: " << m_Serial->isOpen();
      
      while(!abort)
      {
          mutex.lock();
          abort = _abort;
          mutex.unlock();
      
          if(!m_outFrameQueue->isEmpty())
          {
              Frame *outFrame = m_outFrameQueue->dequeue();
              sendFrame(outFrame);
              delete outFrame;
      
          } else
      
          {
              if (m_Serial->waitForReadyRead(10))
              {
                  QByteArray receivedData = m_Serial->readAll();
      
                  while(receivedData.count() > 0)
                  {
                      inByte = quint8(receivedData[0]);
                      receivedData.remove(0,1);
      
                          switch (receiverStatus)
                          {
                              case RCV_ST_IDLE:
                                  {
                                      if(inByte == Frame::FRAME_ADDR_RFiD)
                                      {
                                          if (m_inFrame == nullptr)
                                              m_inFrame = new Frame();
      
                                          else
                                              m_inFrame->Clear();
      
                                          m_inFrame->AddByte(inByte);
                                          buffer_checksum.append(inByte);
                                          receiverStatus = RCV_ST_DATA_LENGTH;
                                      }
                                      else
                                      {
                                          buffer_checksum.clear();
                                      }
                                  } break;
      
                              case RCV_ST_DATA_LENGTH:
                                  {
      
                                      dataLength = inByte;      
                                      numByte = dataLength - 6; 
                                      m_inFrame->AddByte(inByte);
                                      buffer_checksum.append(inByte);
                                      receiverStatus = RCV_ST_CMD;
                                  } break;
      
                              case RCV_ST_CMD:
                                  {
                                      m_inFrame->AddByte(inByte);
                                      buffer_checksum.append(inByte);
                                      if(numByte > 0)
                                      receiverStatus = RCV_ST_DATA;
                                      else receiverStatus = RCV_ST_CODE;
      
                                  } break;
      
                              case RCV_ST_DATA:
                                  {
                                      m_inFrame->AddByte(inByte);
                                      buffer_checksum.append(inByte);
                                      if (--numByte == 0)
                                          receiverStatus = RCV_ST_CODE;
                                      else if (numByte < 0)
                                          receiverStatus = RCV_ST_IDLE;
                                  } break;
      
                              case RCV_ST_CODE:
                                  {
                                      m_inFrame->AddByte(inByte);
                                      buffer_checksum.append(inByte);
                                      receiverStatus = RCV_ST_CHECKSUM_HI;
                                  } break;
      
                              case RCV_ST_CHECKSUM_HI:
                                  {
                                      checksum_temp = (m_inFrame->CalculateCRC2_in(buffer_checksum) >> 8) & 0xFF;
                                      if (inByte == checksum_temp)
                                      {
      
                                          m_inFrame->AddByte(checksum_temp);
                                          receiverStatus = RCV_ST_CHECKSUM_LO;
                                      }
                                      else
                                      {
      
                                          receiverStatus = RCV_ST_IDLE;
                                          m_inFrame->Clear();
                                          delete m_inFrame;
                                      }
                                  } break;
      
                              case RCV_ST_CHECKSUM_LO:
                                  {
      
                                      checksum_temp = m_inFrame->CalculateCRC2_in(buffer_checksum) & 0xFF;
                                      if (inByte == checksum_temp)
                                      {
                                          receiverStatus = RCV_ST_IDLE;
                                          m_inFrame->AddByte(checksum_temp);
                                          emit this->frameReceived(m_inFrame);
                                          qDebug()<< "Frame:  " << Qt::hex << m_inFrame;
                                      }
                                      else
                                      {
      
                                          receiverStatus = RCV_ST_IDLE;
                                          m_inFrame->Clear();
                                          delete m_inFrame;
      
                                      }
                                  } break;
                           }
      
                  }
              } 
          }
      }
      }
      

      I checked whether the device definitely send frame, by this code

      void SerialWorker::doWork()
      {
      qDebug()<<"Starting worker process in Thread "<<thread()->currentThreadId();
      
      bool abort = false;
      quint8 inByte;
      quint8 checksum_temp;
      int numByte = 0;
      int receiverStatus = RCV_ST_IDLE;
      Frame *m_inFrame = nullptr;
      int dataLength = 0;
      
      QByteArray buffer_checksum;
      
      // Serial Port Initialization
      m_Serial = new QSerialPort();
      m_Serial->setPortName("COM6");
      m_Serial->setBaudRate(QSerialPort::Baud9600);
      m_Serial->setDataBits(QSerialPort::Data8);
      m_Serial->setParity(QSerialPort::NoParity);
      m_Serial->setStopBits(QSerialPort::OneStop);
      m_Serial->setFlowControl(QSerialPort::NoFlowControl);
      m_Serial->open(QIODevice::ReadWrite);
      qDebug() << "SerialPort Status: " << m_Serial->isOpen();
      
      while(!abort)
      {
          mutex.lock();
          abort = _abort;
          mutex.unlock();
         
          QByteArray receivedData = m_Serial->readAll();
      
      
          if(!m_outFrameQueue->isEmpty())
          {
              Frame *outFrame = m_outFrameQueue->dequeue();
              sendFrame(outFrame);
              delete outFrame;
      
          } else
      
          {
              if (receivedData.count() > 0) {
                  qDebug() <<  "something came: "<< Qt::hex << receivedData.toHex() ;
                  receivedData.clear();
              }
          }
      }
      }
      

      And it works. In receivedData.toHex() the receiving frame ic correct. So what is wrong with my fully soution pasted like first code ?

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @Damian7546
      In both cases, do not rely on readAll() to read all the data which has been sent. It reads whatever happens to be there at the instant it gets called. Could be anything from all the bytes down to just 1.

      1 Reply Last reply
      1
      • D Offline
        D Offline
        Damian7546
        wrote on last edited by
        #3

        I solved my problem by creating a slot for readyRead() signal. Solution/problem is described here:

        https://stackoverflow.com/a/44693193/11766659

        1 Reply Last reply
        0
        • D Offline
          D Offline
          Damian7546
          wrote on last edited by
          #4

          I have next problem. When I was very short cable RS485 the frame was received all in one shot . now in long cable the frame recive is byte by bytes, so my code doesn't works.
          Like I said I use slot "recive()" for readyRead() signal.

          void SerialWorker::recive()
          {
                  QByteArray buffer_checksum;
                  quint8 inByte;
                  quint8 checksum_temp;
                  int numByte = 0;
                  int receiverStatus = RCV_ST_IDLE;
                  Frame *m_inFrame = nullptr;
                  int dataLength = 0;
                  QByteArray receivedData = m_Serial->readAll();
          
          
          qDebug()<<receivedData;
          
                  while(receivedData.count() > 0)
                  {
          
                    ...................
                    .................
                 }
          }
          

          How I should wait for all bytes in frame in my slot ?

          Christian EhrlicherC 1 Reply Last reply
          0
          • D Damian7546

            I have next problem. When I was very short cable RS485 the frame was received all in one shot . now in long cable the frame recive is byte by bytes, so my code doesn't works.
            Like I said I use slot "recive()" for readyRead() signal.

            void SerialWorker::recive()
            {
                    QByteArray buffer_checksum;
                    quint8 inByte;
                    quint8 checksum_temp;
                    int numByte = 0;
                    int receiverStatus = RCV_ST_IDLE;
                    Frame *m_inFrame = nullptr;
                    int dataLength = 0;
                    QByteArray receivedData = m_Serial->readAll();
            
            
            qDebug()<<receivedData;
            
                    while(receivedData.count() > 0)
                    {
            
                      ...................
                      .................
                   }
            }
            

            How I should wait for all bytes in frame in my slot ?

            Christian EhrlicherC Online
            Christian EhrlicherC Online
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @Damian7546 said in Qt - serial communication - receiving:

            How I should wait for all bytes in frame in my slot ?

            You must not wait but read the data into a custom buffer (e.g. QByteArray) and parse the data later on.

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            1 Reply Last reply
            1
            • D Offline
              D Offline
              Damian7546
              wrote on last edited by Damian7546
              #6

              So, I changed my slot "recive()" in this way:

              void SerialWorker::recive()
              {
                      receivedData = receivedData + m_Serial->readAll();
                      if(!receivedData.isEmpty())
                      {
                          timeoutReciveData(this, SLOT(parseRecivedData()), 1000);
                      }
              }
              

              But something is wrong with singleshot , because doesn't work:

              void SerialWorker::parseRecivedData()
              {
                   qDebug() << receivedData ;
                       /* parse should be here */
              
              }
              void SerialWorker::timeoutReciveData(const QObject *obj, const char *signalOrSlot, int msDelay)
              {
                   QTimer::singleShot(msDelay, obj, signalOrSlot);
              }
              

              Any idea ?

              Christian EhrlicherC 1 Reply Last reply
              0
              • D Damian7546

                So, I changed my slot "recive()" in this way:

                void SerialWorker::recive()
                {
                        receivedData = receivedData + m_Serial->readAll();
                        if(!receivedData.isEmpty())
                        {
                            timeoutReciveData(this, SLOT(parseRecivedData()), 1000);
                        }
                }
                

                But something is wrong with singleshot , because doesn't work:

                void SerialWorker::parseRecivedData()
                {
                     qDebug() << receivedData ;
                         /* parse should be here */
                
                }
                void SerialWorker::timeoutReciveData(const QObject *obj, const char *signalOrSlot, int msDelay)
                {
                     QTimer::singleShot(msDelay, obj, signalOrSlot);
                }
                

                Any idea ?

                Christian EhrlicherC Online
                Christian EhrlicherC Online
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @Damian7546 said in Qt - serial communication - receiving:

                But something is wrong with singleshot , because doesn't work:

                does not work? What does this mean? Why do you not directly call parseRecivedData or QTimer::singleShot()?

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                D 1 Reply Last reply
                0
                • yinhao.qianY Offline
                  yinhao.qianY Offline
                  yinhao.qian
                  wrote on last edited by
                  #8
                  This post is deleted!
                  1 Reply Last reply
                  0
                  • Christian EhrlicherC Christian Ehrlicher

                    @Damian7546 said in Qt - serial communication - receiving:

                    But something is wrong with singleshot , because doesn't work:

                    does not work? What does this mean? Why do you not directly call parseRecivedData or QTimer::singleShot()?

                    D Offline
                    D Offline
                    Damian7546
                    wrote on last edited by
                    #9

                    @Christian-Ehrlicher said in Qt - serial communication - receiving:

                    Why do you not directly call parseRecivedData

                    Because I do not know when my frame will be completed, so I give the some time by timeoutReciveData and next go to parseRecivedData().
                    I expect such a frame:
                    DevAddres,LengthFrame,Command,Data1...n,CRCH,CRCL

                    @Christian-Ehrlicher said in Qt - serial communication - receiving:

                    does not work? What does this mean?

                    The parseRecivedData() slot does not start even though buffer "receivedData" are not empty .

                    Christian EhrlicherC 1 Reply Last reply
                    0
                    • D Damian7546

                      @Christian-Ehrlicher said in Qt - serial communication - receiving:

                      Why do you not directly call parseRecivedData

                      Because I do not know when my frame will be completed, so I give the some time by timeoutReciveData and next go to parseRecivedData().
                      I expect such a frame:
                      DevAddres,LengthFrame,Command,Data1...n,CRCH,CRCL

                      @Christian-Ehrlicher said in Qt - serial communication - receiving:

                      does not work? What does this mean?

                      The parseRecivedData() slot does not start even though buffer "receivedData" are not empty .

                      Christian EhrlicherC Online
                      Christian EhrlicherC Online
                      Christian Ehrlicher
                      Lifetime Qt Champion
                      wrote on last edited by
                      #10

                      @Damian7546 said in Qt - serial communication - receiving:

                      Because I do not know when my frame will be completed, so I give the some time by timeoutReciveData and next go to parseRecivedData().

                      And why should it be finished in 1000ms? It does not help at all.
                      Parse your buffer directly.

                      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                      Visit the Qt Academy at https://academy.qt.io/catalog

                      1 Reply Last reply
                      0
                      • D Offline
                        D Offline
                        Damian7546
                        wrote on last edited by
                        #11

                        Ok,
                        thank for your suggestion. I must rewrite my parseRecivedData() function.

                        1 Reply Last reply
                        0
                        • D Offline
                          D Offline
                          Damian7546
                          wrote on last edited by
                          #12

                          I wrote again my "recive()" function like you said, it works, but I have several doubt.

                          void SerialWorker::recive()
                          {
                                  QByteArray buff2CalcChecksum;
                                  Frame *m_inFrame = nullptr;
                                  receivedData_raw = receivedData_raw + m_Serial->readAll();
                                  if(!receivedData_raw.isEmpty())
                                  {
                                      for(int i=0; i <  receivedData_raw.count(); i++)
                                      {
                                          buff2CalcChecksum = buff2CalcChecksum + receivedData_raw[i];
                                          if ((((m_inFrame->CalculateCRC2_in(buff2CalcChecksum)) & 0xFF) == buff2CalcChecksum[i+2])  &&
                                              (((m_inFrame->CalculateCRC2_in(buff2CalcChecksum) >> 8) & 0xFF) == buff2CalcChecksum[i+1]))
                                          {
                                              qDebug() << "We have the correct frame";
                                              receivedData = receivedData_raw;
                                              receivedData_raw.clear();
                                              parseRecivedData();
                                          }
                          
                                          if (receivedData_raw.count() > 20 ) receivedData_raw.clear();  /// it is not a good idea...
                                       }
                                   }
                          }
                          
                          • How to protect code when too long no CRC sums ?

                          • It is a good idea that from first byte, calculate CRC sum to recognize my whole frame?

                          1 Reply Last reply
                          0
                          • Christian EhrlicherC Online
                            Christian EhrlicherC Online
                            Christian Ehrlicher
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            I don't think your code will ever work - the data comes in as a stream so you first have to figure out the start and end of your frame. For this a lot of protocols use a start and end-marker so you know when a frame starts and ends.

                            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                            Visit the Qt Academy at https://academy.qt.io/catalog

                            1 Reply Last reply
                            1
                            • D Offline
                              D Offline
                              Damian7546
                              wrote on last edited by Damian7546
                              #14

                              This protocol do not have marker start and end of frame. This is a frame:
                              zz.jpg

                              1 Reply Last reply
                              0
                              • Christian EhrlicherC Online
                                Christian EhrlicherC Online
                                Christian Ehrlicher
                                Lifetime Qt Champion
                                wrote on last edited by Christian Ehrlicher
                                #15

                                Then I don't know how you will ever find the start of a frame... they must have at least e.g. an end marker ('\r' or '\n' for example) where you can start from.

                                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                Visit the Qt Academy at https://academy.qt.io/catalog

                                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