Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.
Forum Updated to NodeBB v4.3 + New Features

QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.

Scheduled Pinned Locked Moved Unsolved General and Desktop
15 Posts 5 Posters 1.2k 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.
  • Christian EhrlicherC Offline
    Christian EhrlicherC Offline
    Christian Ehrlicher
    Lifetime Qt Champion
    wrote on last edited by
    #2

    Please provide a minimal, working example. You need to call the initial Qt event loop with QCoreApplication::exec() then all works fine. Please also take a look at the various examples.

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

      @Christian-Ehrlicher said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

      Please provide a minimal, working example. You need to call the initial Qt event loop with QCoreApplication::exec() then all works fine. Please also take a look at the various examples.

      Hello and thanks for your answer!
      Firstly for calling Qt event loop with QCoreApplication::exec() - I have tried it but it also blocks the thread and the client application. I have tried to move it to background thread, but then I got another warnings and errors (for example "QCoreApplication::exec: Must be called from the main thread"). I also get error: "QEventDispatcherWin32::registerTimer: timers cannot be started from another thread".

      Secondly, as you asked, a simplified code example. The implementations are included only for the necessary functions.

      
      class MLXCOMChannel : public QObject
      {
          Q_OBJECT
      
      protected:
          QSharedPointer<QIODevice> ch_communicationDevice;
      
          ErrorHandler ch_errorHandler;
          QMutex ch_mutex;
          bool ch_open;
          uint64_t ch_sentDataSize;
          QByteArray ch_dataBuffer;
      
      private:
      
      
      private slots:
          void                    handleMLXCOMError(MLXCOMErrorType errorType);
      
      protected slots:
          void                    readData() {
                                          if (ch_communicationDevice.data()) {
                                      
                                              QMutexLocker locker(&ch_mutex);
                                      
                                              ch_dataBuffer.append(ch_communicationDevice->readAll());
                                      
                                          } else {
                                      
                                              emit error(MLXCOMErrorType::FunctionalityNotImplemented);
                                      
                                          }                        };
          void                    dataWritten(qint64 bytes);
      
      public:
      
                                  MLXCOMChannel();
          virtual                 ~MLXCOMChannel();
      
          virtual void            open();
          virtual void            close();
          virtual void            sendData(const QByteArray &data);
          virtual QByteArray      receiveData(size_t dataSize);
          virtual bool            hasData();
          virtual qint32          availableDataSize();
      
      
          // Channels settings interaction
          t_ChannelType getChannelType();
          std::string getChannelTypeName();
      
          static qint32           createChannel(MLXCOMChannel **channel, const t_ChannelType channelType);
          static qint32           destroyChannel(MLXCOMChannel **channel);
      
      signals:
          void                    error(MLXCOMChannel::MLXCOMErrorType errorType) const;
      
      };
      
      
      // The one that works - TCP Channel
      class TCPChannel : public MLXCOMChannel
      {
          Q_OBJECT
      
      public:
          TCPChannel() {
                  ch_communicationDevice.reset(new QTcpSocket);
              
                  m_pSocket = reinterpret_cast<QTcpSocket*>(ch_communicationDevice.get());
              
              
              
                  connect(m_pSocket, &QTcpSocket::disconnected, this, [=](){ch_open = false;});
              
                  connect(m_pSocket, &QTcpSocket::connected, this, [=](){ch_open = true;});        
              
                  connect(m_pSocket, &QIODevice::readyRead, this, &TCPChannel::readData);
              
                  connect(m_pSocket, &QIODevice::bytesWritten, this, &TCPChannel::dataWritten);
              
                  connect(m_pSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &TCPChannel::handleSocketError);   ~TCPChannel() override;
      
          void open() override;
          void close() override;
          void sendData(const QByteArray &data) override;
      
      private:
      
          QTcpSocket *m_pSocket;
      
      
      private slots:
          void handleSocketError();
      };
      
      
      // The one that does not work - Serial Channel
      class SerialChannel : public MLXCOMChannel
      {
          Q_OBJECT
      
      public:
          SerialChannel() {
              ch_communicationDevice.reset(new QSerialPort);
          
              m_pSerialPort = reinterpret_cast<QSerialPort*>(ch_communicationDevice.get());
              
              connect(this, &SerialChannel::debugSignal, this, &SerialChannel::debugSlot);
          
              connect(m_pSerialPort, &QSerialPort::readyRead, this, &SerialChannel::readData);
          
              connect(m_pSerialPort, &QIODevice::bytesWritten, this, &SerialChannel::dataWritten);
          
              connect(m_pSerialPort, &QSerialPort::errorOccurred, this, &SerialChannel::handlePortError);;
          ~SerialChannel() override;
      
          // Overridden methods
          void open() override;
          void close() override;                              // To be moved to MLXCOMChannel
          void sendData(const QByteArray &data) override;     // To be moved to MLXCOMChannel
      
      
      private:
          QSerialPort *m_pSerialPort;
      
      
      private slots:
          void handlePortError();
          void debugSlot(QString &msg);
      signals:
          void debugSignal(QString &msg);
      
      };
      

      So, the TCPChannel works just fine. The debugSignal and debugSlot in SerialChannel work fine. Error handling signals work fine. Only the QSerialPort::readyRead doesn't.

      jsulmJ 1 Reply Last reply
      0
      • R Rufledore

        @Christian-Ehrlicher said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

        Please provide a minimal, working example. You need to call the initial Qt event loop with QCoreApplication::exec() then all works fine. Please also take a look at the various examples.

        Hello and thanks for your answer!
        Firstly for calling Qt event loop with QCoreApplication::exec() - I have tried it but it also blocks the thread and the client application. I have tried to move it to background thread, but then I got another warnings and errors (for example "QCoreApplication::exec: Must be called from the main thread"). I also get error: "QEventDispatcherWin32::registerTimer: timers cannot be started from another thread".

        Secondly, as you asked, a simplified code example. The implementations are included only for the necessary functions.

        
        class MLXCOMChannel : public QObject
        {
            Q_OBJECT
        
        protected:
            QSharedPointer<QIODevice> ch_communicationDevice;
        
            ErrorHandler ch_errorHandler;
            QMutex ch_mutex;
            bool ch_open;
            uint64_t ch_sentDataSize;
            QByteArray ch_dataBuffer;
        
        private:
        
        
        private slots:
            void                    handleMLXCOMError(MLXCOMErrorType errorType);
        
        protected slots:
            void                    readData() {
                                            if (ch_communicationDevice.data()) {
                                        
                                                QMutexLocker locker(&ch_mutex);
                                        
                                                ch_dataBuffer.append(ch_communicationDevice->readAll());
                                        
                                            } else {
                                        
                                                emit error(MLXCOMErrorType::FunctionalityNotImplemented);
                                        
                                            }                        };
            void                    dataWritten(qint64 bytes);
        
        public:
        
                                    MLXCOMChannel();
            virtual                 ~MLXCOMChannel();
        
            virtual void            open();
            virtual void            close();
            virtual void            sendData(const QByteArray &data);
            virtual QByteArray      receiveData(size_t dataSize);
            virtual bool            hasData();
            virtual qint32          availableDataSize();
        
        
            // Channels settings interaction
            t_ChannelType getChannelType();
            std::string getChannelTypeName();
        
            static qint32           createChannel(MLXCOMChannel **channel, const t_ChannelType channelType);
            static qint32           destroyChannel(MLXCOMChannel **channel);
        
        signals:
            void                    error(MLXCOMChannel::MLXCOMErrorType errorType) const;
        
        };
        
        
        // The one that works - TCP Channel
        class TCPChannel : public MLXCOMChannel
        {
            Q_OBJECT
        
        public:
            TCPChannel() {
                    ch_communicationDevice.reset(new QTcpSocket);
                
                    m_pSocket = reinterpret_cast<QTcpSocket*>(ch_communicationDevice.get());
                
                
                
                    connect(m_pSocket, &QTcpSocket::disconnected, this, [=](){ch_open = false;});
                
                    connect(m_pSocket, &QTcpSocket::connected, this, [=](){ch_open = true;});        
                
                    connect(m_pSocket, &QIODevice::readyRead, this, &TCPChannel::readData);
                
                    connect(m_pSocket, &QIODevice::bytesWritten, this, &TCPChannel::dataWritten);
                
                    connect(m_pSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &TCPChannel::handleSocketError);   ~TCPChannel() override;
        
            void open() override;
            void close() override;
            void sendData(const QByteArray &data) override;
        
        private:
        
            QTcpSocket *m_pSocket;
        
        
        private slots:
            void handleSocketError();
        };
        
        
        // The one that does not work - Serial Channel
        class SerialChannel : public MLXCOMChannel
        {
            Q_OBJECT
        
        public:
            SerialChannel() {
                ch_communicationDevice.reset(new QSerialPort);
            
                m_pSerialPort = reinterpret_cast<QSerialPort*>(ch_communicationDevice.get());
                
                connect(this, &SerialChannel::debugSignal, this, &SerialChannel::debugSlot);
            
                connect(m_pSerialPort, &QSerialPort::readyRead, this, &SerialChannel::readData);
            
                connect(m_pSerialPort, &QIODevice::bytesWritten, this, &SerialChannel::dataWritten);
            
                connect(m_pSerialPort, &QSerialPort::errorOccurred, this, &SerialChannel::handlePortError);;
            ~SerialChannel() override;
        
            // Overridden methods
            void open() override;
            void close() override;                              // To be moved to MLXCOMChannel
            void sendData(const QByteArray &data) override;     // To be moved to MLXCOMChannel
        
        
        private:
            QSerialPort *m_pSerialPort;
        
        
        private slots:
            void handlePortError();
            void debugSlot(QString &msg);
        signals:
            void debugSignal(QString &msg);
        
        };
        

        So, the TCPChannel works just fine. The debugSignal and debugSlot in SerialChannel work fine. Error handling signals work fine. Only the QSerialPort::readyRead doesn't.

        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #4

        @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

        I have tried it but it also blocks the thread and the client application

        Please show how you did it. I hope you did it in your main.cpp

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

        1 Reply Last reply
        1
        • R Offline
          R Offline
          Rufledore
          wrote on last edited by Rufledore
          #5

          @jsulm said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

          As I mentioned in the first post it is a part of a shared library that I develop. So, this library has export functions like these:

          MLXCOM_API int MLXCOM_CALL_CONV mlxcom_send_data(MLXCOM_CHANNEL mlxcomChannel, char* data, uint32_t dataSize) {
              MLXCOMChannel* channel = static_cast<MLXCOMChannel*>(mlxcomChannel);
              QByteArray dataForSend(data, dataSize);
          
              channel->prepareErrorHandler();
              channel->sendData(dataForSend);
              if (channel->hasNewError()) {
                  return channel->lastError().first;
              }
          
              return 0;
          }
          
          // add parameter - number of bytes.
          MLXCOM_API int MLXCOM_CALL_CONV mlxcom_receive_data(MLXCOM_CHANNEL mlxcomChannel, char* data, uint32_t data_size) {
              MLXCOMChannel* channel = static_cast<MLXCOMChannel*>(mlxcomChannel);
          
              channel->prepareErrorHandler();
              QByteArray msg = channel->receiveData(data_size);
              if (msg.size() > 0) {
                  std::memcpy(data, msg.data(), static_cast<size_t>(msg.size() + 1));
              }
              if (channel->hasNewError()) {
                  return channel->lastError().first;
              }
          
          
              return 0;
          }
          
          

          So I added a function init() where I did QCoreApplication::exec().

          I use the library in a test console application that is only a main(), but doesn't have QApplication or QCoreApplication in it. There I faced the issue. When I use the library in a test UI app that is simply a MainWindow started from main() and QApplication.exec() it works okay. However I am willing do make cross platform C-style library that could be used not only in Qt. TCP communication class works well also when I use it in visual studio.

          1 Reply Last reply
          0
          • R Offline
            R Offline
            Rufledore
            wrote on last edited by
            #6

            Okay, now I tried it and the static way QCoreApplication::exec() doesn't block but throw : QApplication::exec: Please instantiate the QApplication object first

            Christian EhrlicherC 1 Reply Last reply
            1
            • R Offline
              R Offline
              Rufledore
              wrote on last edited by
              #7

              I didn't mentioned also that it something actually turns the event loop sometimes and the signal is emitted, but not regularly. I think that it is waitForBytesWritten(). If I don't use waitForBytesWritten while writing to device nothing happens.

              1 Reply Last reply
              0
              • R Rufledore

                Okay, now I tried it and the static way QCoreApplication::exec() doesn't block but throw : QApplication::exec: Please instantiate the QApplication object first

                Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #8

                @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                QApplication::exec: Please instantiate the QApplication object first

                Then you should do this in our main() in the first line.

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

                R 1 Reply Last reply
                0
                • Christian EhrlicherC Christian Ehrlicher

                  @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                  QApplication::exec: Please instantiate the QApplication object first

                  Then you should do this in our main() in the first line.

                  R Offline
                  R Offline
                  Rufledore
                  wrote on last edited by
                  #9

                  @Christian-Ehrlicher said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                  @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                  QApplication::exec: Please instantiate the QApplication object first

                  Then you should do this in our main() in the first line.

                  In principle yes, but I don't want the user of the library to bother with Qt staff as QApplication. And the main question for me is how it works okay for TCPSocket but not for SerialPort?

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

                    You need a working QCoreApplication - everything else simply works by accident and may not work suddenly.

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

                      Then how to use Qt specific features as signals and slots in a library? QCoreApplication could be started only in main thread... If I start it on the background it doesn't work well. Could you give me an idea, how to proceed?

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

                        @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                        Could you give me an idea, how to proceed?

                        Quick answer - nohow, it makes not sense to use Qt stuff from the non-qt libraries.

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

                          @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                          could be started only in main thread

                          Q(Core|Gui)Application can also be started in another thread but then all gui operations must be done inside this thread too.

                          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
                          • R Rufledore

                            Then how to use Qt specific features as signals and slots in a library? QCoreApplication could be started only in main thread... If I start it on the background it doesn't work well. Could you give me an idea, how to proceed?

                            R Offline
                            R Offline
                            Rufledore
                            wrote on last edited by
                            #14

                            @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                            Then how to use Qt specific features as signals and slots in a library? QCoreApplication could be started only in main thread... If I start it on the background it doesn't work well. Could you give me an idea, how to proceed?

                            It is a Qt library but not for Qt application :)

                            JonBJ 1 Reply Last reply
                            0
                            • R Rufledore

                              @Rufledore said in QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.:

                              Then how to use Qt specific features as signals and slots in a library? QCoreApplication could be started only in main thread... If I start it on the background it doesn't work well. Could you give me an idea, how to proceed?

                              It is a Qt library but not for Qt application :)

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

                              @Rufledore
                              I don't think you can use Qt library calls for TCP/serial port without being in a Qt application. As in, they don't work properly, as you have discovered. They need parts of the Q(Core|Gui)Application-type architecture.,

                              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