Unsolved QSerialPort::readyRead() is not emitted, but QTCPSocket::readyRead() works fine.
-
@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.
-
@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
-
@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.
-
Okay, now I tried it and the static way QCoreApplication::exec() doesn't block but throw : QApplication::exec: Please instantiate the QApplication object first
-
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.
-
@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.
-
@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?
-
You need a working QCoreApplication - everything else simply works by accident and may not work suddenly.
-
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?
-
@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.
-
@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.
-
@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 :)
-
@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 theQ(Core|Gui)Application
-type architecture.,