Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Slot called twice by QModbusReply, why?



  • Hello,

    I am making my first steps with Modbus and it basically works.
    However, somehow the QModbusReply reply seems to emit the finished signal twice instead of once after calling readInputRegister(). Therfore the finishedReply() slot is invoked twice too.

    Has anyone a clue why this is happening?

    Thank you very much! :-)

    class.h:

    #ifndef MODBUS_CLIENT_H
    #define MODBUS_CLIENT_H
    
    #include "modbus_lib_global.h"
    #include <QObject>
    #include <QModbusTcpClient>
    #include <QDebug>
    
    class MODBUS_LIBSHARED_EXPORT Modbus_client : public QObject
    {
        Q_OBJECT
    
    public:
        explicit Modbus_client(QObject *parent = nullptr);
    
        void setConnectionParms(QString Ip, QString Port);
        void readInputRegister(int Registeraddress);
    
    signals:
        void queryResult(int);
    
    private slots:
        void onStateChanged();
        void onErrorOccurred();
        void finishedReply();
    
    private:
        bool debug = false;
        QModbusTcpClient *device;
        QModbusReply *reply;
        int registeraddress;
    
    };
    
    #endif // MODBUS_CLIENT_H
    

    class.cpp

    #include "modbus_client.h"
    
    Modbus_client::Modbus_client(QObject *parent) : QObject(parent)
    {
        device = new QModbusTcpClient();
        if(device != nullptr) {
            if(debug) qDebug() << "Created modbus device, state is:" << device->state();
            connect(device, &QModbusTcpClient::stateChanged, this, &Modbus_client::onStateChanged);
            connect(device, &QModbusTcpClient::errorOccurred, this, &Modbus_client::onErrorOccurred);
        } else qFatal("Unable to create Modbus TCP client device!");
    
    }
    
    void Modbus_client::setConnectionParms(QString Ip, QString Port)
    {
        device->setConnectionParameter(QModbusDevice::NetworkPortParameter, Port);
        device->setConnectionParameter(QModbusDevice::NetworkAddressParameter, Ip);
    }
    
    void Modbus_client::readInputRegister(int Registeraddress)
    {
        registeraddress = Registeraddress;
        // Connect modbus device
        if(!device->connectDevice()) {
            qDebug() << "Connect failed! Error is: " << device->errorString();
        }
    }
    
    void Modbus_client::onStateChanged()
    {
        if(device->state() == QModbusDevice::ConnectedState) {
            QVector<quint16> data(1); // One Byte
            QModbusDataUnit adu(QModbusDataUnit::InputRegisters, registeraddress, data); 
            reply = device->sendReadRequest(adu, 255);
            if(!reply->isFinished()) {
                connect(reply, &QModbusReply::finished, this, &Modbus_client::finishedReply, Qt::UniqueConnection); //Invoked only once (tested)
                qDebug() << "Invoked";
            } else finishedReply();
    
        }
        else if(device->state() == QModbusDevice::ClosingState) {
            if(debug) qDebug() << "Disconnected, state is: " << device->state();
        }
    }
    
    void Modbus_client::onErrorOccurred()
    {
        qDebug() << "Error occured!" << device->errorString();
    
    }
    
    void Modbus_client::finishedReply()
    {
        //This slot is called twice, after calling "readInputRegister()" once, but should be invoked once!
        qDebug() << "Called finishedReply()";
    
        if(reply != nullptr) {
            qDebug() << "triggered by: " <<sender();
    
            //emit queryResult(reply->result().value(0));
            reply->deleteLater();
    
        } else qDebug() << "Send of ready request failed! Error is: " << device->state();
    
    
        device->disconnectDevice();
    }
    

    Output:

    Invoked
    Called finishedReply()
    triggered by:  QModbusReply(0x27e13578770)
    Called finishedReply()
    triggered by:  QModbusReply(0x27e13578770)
    

  • Lifetime Qt Champion

    Hi,

    Check the number of times onStateChanged is called and whether you're passing twice in the part that connects that slot.



  • Thanks for the hint.

    I checked it.
    The condition if(device->state() == QModbusDevice::ConnectedState) is true only once.
    Still the reply slot is triggered twice.

    I do not find any mistake but I noticed that the second triggering comes late, after the device is disconnected:

    State changed QModbusDevice::ConnectingState
    State changed QModbusDevice::ConnectedState
    Invoked
    Called finishedReply()
    triggered by:  QModbusReply(0x20a102d9790)
    State changed QModbusDevice::ClosingState
    State changed QModbusDevice::UnconnectedState
    Called finishedReply()
    triggered by:  QModbusReply(0x20a102d9790)
    

    One solution to elliminate the second call of finishedReply() is to disconnect the signal in the finishedReply() function:

    disconnect(reply, &QModbusReply::finished, this, &Modbus_client::finishedReply);
    

    I know that this is dirty and therefore I still would like to figure out what happens.

    Do you have any other ideas?

    Thanks


  • Lifetime Qt Champion

    I'd say it's likely not the expected behaviour. What version of Qt are you using ?



  • @robro have you already run this client example? just to check if the double call happens there as well



  • Hi,

    thanks!

    I am using Qt. 5.12.2 MSVC2017 x64.
    I tried the example suggested and there everything works fine.

    Still I have no clue why with my codes the slot is called twice.

    I might try a newer Qt version or stay with my disconnect call in the slot.

    For the moment I mark this as solved.

    Again, thank you very much.


Log in to reply