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.1k 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
    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 Online
              Christian EhrlicherC Online
              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 Online
                  Christian EhrlicherC Online
                  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 Online
                        Christian EhrlicherC Online
                        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