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. Modbus RTU: readyRead() not called
Forum Updated to NodeBB v4.3 + New Features

Modbus RTU: readyRead() not called

Scheduled Pinned Locked Moved Unsolved General and Desktop
20 Posts 5 Posters 3.6k Views 2 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.
  • M Mark81

    I'm trying to "port" the example of Modbus master to my application.
    Here some relevant code:

    QModbusClient *_modbus;
    
    bool ModbusMaster::open(QString port)
    {
        _modbus = new QModbusRtuSerialMaster(this);
    
        _modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, port);
        _modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::NoParity);
        _modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, QSerialPort::Baud57600);
        _modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
        _modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
    
        _modbus->setTimeout(2000);
        _modbus->setNumberOfRetries(3);
    
        return _modbus->connectDevice();
    }
    
    bool ModbusMaster::read(QModbusDataUnit::RegisterType type, int startAddress, quint16 count)
    {
        if (!_modbus) return false;
        if (_modbus->state() != QModbusDevice::ConnectedState) return false;
    
        qDebug() << "Read" << startAddress;
    
        QModbusDataUnit req(type, startAddress, count);    
        if (auto *reply = _modbus->sendReadRequest(req, 1))
        {
            qDebug() << reply->isFinished();
            if (!reply->isFinished()) connect(reply, &QModbusReply::finished, this, &ModbusMaster::readyRead);
            else readReady();
            return true;
        }
        return false;
    }
    
    void ModbusMaster::readyRead ()
    {
        qDebug() << "readyRead executed!";
        auto reply = qobject_cast<QModbusReply *>(sender());
        if (!reply) return;
        reply->deleteLater();
    
        if (reply->error() == QModbusDevice::NoError)
        {
            const QModbusDataUnit unit = reply->result();
            // do something
        }
        else if (reply->error() == QModbusDevice::ProtocolError)  qDebug() << reply->errorString();
        else qDebug() << reply->errorString();
    
        // call next reading
        emit readFinished();
    }
    

    but it seems even if received data readyRead() is not called, example:

    Debug: read 495
    Debug: false 
    Debug: (RTU client) Sent Serial PDU: 0x0301ef0001
    Debug: (RTU client) Sent Serial ADU: 0x010301ef0001b403 
    Debug: (RTU client) Response buffer: "0103020000b844" 
    Debug: (RTU client) Received ADU: "0103020000b844" 
    Debug: (RTU client) Send successful: 0x0301ef0001 
    

    after few seconds I got a timeout from my timer. As far as I understand the response is actually received, but the readyRead() slot is not called.

    Is there something obvious I'm missing?

    J.HilkJ Online
    J.HilkJ Online
    J.Hilk
    Moderators
    wrote on last edited by
    #10

    @Mark81

    the QModbusRtuSerialMaster has also errors that can be emitted. And those differ from the reply, check those also.

    connect(_modbus, & QModbusRtuSerialMaster::errorOccurred, this, [](QModbusDevice::Error error)->void{ qDebug() << error;});
    

    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


    Q: What's that?
    A: It's blue light.
    Q: What does it do?
    A: It turns blue.

    M 1 Reply Last reply
    2
    • J.HilkJ J.Hilk

      @Mark81

      the QModbusRtuSerialMaster has also errors that can be emitted. And those differ from the reply, check those also.

      connect(_modbus, & QModbusRtuSerialMaster::errorOccurred, this, [](QModbusDevice::Error error)->void{ qDebug() << error;});
      
      M Offline
      M Offline
      Mark81
      wrote on last edited by
      #11

      @J.Hilk You're right. Added and tried. Whenever the "hang" happens also this slot shows nothing, unfortunately.

      J.HilkJ 1 Reply Last reply
      0
      • M Mark81

        @J.Hilk You're right. Added and tried. Whenever the "hang" happens also this slot shows nothing, unfortunately.

        J.HilkJ Online
        J.HilkJ Online
        J.Hilk
        Moderators
        wrote on last edited by
        #12

        @Mark81 how much time passes between open and the first read request ?

        I noticed, on Windows, that when I call immediately after opening the device the first data , then most of the time nothing happens at all.


        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


        Q: What's that?
        A: It's blue light.
        Q: What does it do?
        A: It turns blue.

        M 1 Reply Last reply
        2
        • J.HilkJ J.Hilk

          @Mark81 how much time passes between open and the first read request ?

          I noticed, on Windows, that when I call immediately after opening the device the first data , then most of the time nothing happens at all.

          M Offline
          M Offline
          Mark81
          wrote on last edited by
          #13

          @J.Hilk adding a small delay seems to drastically improve the situation. Occasionally it still happens that the debug messages show a received answer but the slot is not called. That's weird because I can understand if some reasons the answer cannot be received, but this is not the case...

          1 Reply Last reply
          0
          • M Offline
            M Offline
            Mark81
            wrote on last edited by Mark81
            #14

            UPDATE

            I think (not sure, though) I noticed something interesting.
            When it works, the debug output from qt.modbus is like this:

            qt.modbus: (RTU client) Sent Serial PDU: 0x0304270001
            qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x0103042700013531
            qt.modbus: (RTU client) Send successful: 0x0304270001
            qt.modbus.lowlevel: (RTU client) Response buffer: "01030200017984"
            qt.modbus: (RTU client) Received ADU: "01030200017984"
            

            and my slot is correctly called. Instead, when the problem arises the output is like the one reported in the first post or even this one:

            qt.modbus: (RTU client) Sent Serial PDU: 0x0304180002
            qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x010304180002453c
            qt.modbus.lowlevel: (RTU client) Response buffer: "01030400004080ca53"
            qt.modbus: (RTU client) Received ADU: "01030400004080ca53"
            qt.modbus: (RTU client) Send successful: 0x0304180002
            qt.modbus: (RTU client) Receive timeout: 0x0304180002
            qt.modbus: (RTU client) Sent Serial PDU: 0x0304180002
            qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x010304180002453c
            qt.modbus.lowlevel: (RTU client) Response buffer: "01030400004080ca53"
            qt.modbus: (RTU client) Received ADU: "01030400004080ca53"
            qt.modbus: (RTU client) Send successful: 0x0304180002
            qt.modbus: (RTU client) Receive timeout: 0x0304180002
            

            Here my slot is not called.

            I see that every time this happens the "Response buffer" line comes before the "Send successful" one.
            I'm looking at the code but I don't understand if this might be a problem.

            (Sorry for the outdated link but I have difficult to find the actual source code of Qt5 - btw I'm using Qt5.11.1)

            aha_1980A 1 Reply Last reply
            0
            • M Offline
              M Offline
              Mark81
              wrote on last edited by
              #15

              Perhaps I found it here https://code.woboq.org/qt5/qtserialbus/src/serialbus/qmodbusrtuserialmaster_p.h.html#154:

              if (m_state != State::Receive) {
                  qCDebug(QT_MODBUS) << "(RTU server) Ignoring response due to non receive state";
                  return;
              }
              

              but https://code.woboq.org/qt5/qtserialbus/src/serialbus/qmodbusrtuserialmaster_p.h.html#351:

              qCDebug(QT_MODBUS) << "(RTU client) Send successful:" << m_current.requestPdu;
              m_state = Receive;
              

              So if the state is not set to Receive it discard the response. Anyway I didn't see the debug output "Ignoring response...".

              1 Reply Last reply
              0
              • M Mark81

                UPDATE

                I think (not sure, though) I noticed something interesting.
                When it works, the debug output from qt.modbus is like this:

                qt.modbus: (RTU client) Sent Serial PDU: 0x0304270001
                qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x0103042700013531
                qt.modbus: (RTU client) Send successful: 0x0304270001
                qt.modbus.lowlevel: (RTU client) Response buffer: "01030200017984"
                qt.modbus: (RTU client) Received ADU: "01030200017984"
                

                and my slot is correctly called. Instead, when the problem arises the output is like the one reported in the first post or even this one:

                qt.modbus: (RTU client) Sent Serial PDU: 0x0304180002
                qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x010304180002453c
                qt.modbus.lowlevel: (RTU client) Response buffer: "01030400004080ca53"
                qt.modbus: (RTU client) Received ADU: "01030400004080ca53"
                qt.modbus: (RTU client) Send successful: 0x0304180002
                qt.modbus: (RTU client) Receive timeout: 0x0304180002
                qt.modbus: (RTU client) Sent Serial PDU: 0x0304180002
                qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x010304180002453c
                qt.modbus.lowlevel: (RTU client) Response buffer: "01030400004080ca53"
                qt.modbus: (RTU client) Received ADU: "01030400004080ca53"
                qt.modbus: (RTU client) Send successful: 0x0304180002
                qt.modbus: (RTU client) Receive timeout: 0x0304180002
                

                Here my slot is not called.

                I see that every time this happens the "Response buffer" line comes before the "Send successful" one.
                I'm looking at the code but I don't understand if this might be a problem.

                (Sorry for the outdated link but I have difficult to find the actual source code of Qt5 - btw I'm using Qt5.11.1)

                aha_1980A Offline
                aha_1980A Offline
                aha_1980
                Lifetime Qt Champion
                wrote on last edited by
                #16

                @Mark81 said in Modbus RTU: readyRead() not called:

                (Sorry for the outdated link but I have difficult to find the actual source code of Qt5 - btw I'm using Qt5.11.1)

                Then you should really test with a recent version 5.12.x. There has been quite some fixes last year.

                Qt has to stay free or it will die.

                1 Reply Last reply
                0
                • M Offline
                  M Offline
                  Mark81
                  wrote on last edited by
                  #17

                  Update to Qt5.12.2. Now with the very same code and data after a while it crashes with this error:

                  ASSERT failure in processQueue: "response timer active", file qmodbusrtuserialmaster_p.h, line 302

                  What should one do in such a case?

                  J.HilkJ 1 Reply Last reply
                  0
                  • M Mark81

                    Update to Qt5.12.2. Now with the very same code and data after a while it crashes with this error:

                    ASSERT failure in processQueue: "response timer active", file qmodbusrtuserialmaster_p.h, line 302

                    What should one do in such a case?

                    J.HilkJ Online
                    J.HilkJ Online
                    J.Hilk
                    Moderators
                    wrote on last edited by J.Hilk
                    #18

                    @Mark81 vote for the issue and pray, like I did

                    https://bugreports.qt.io/browse/QTBUG-73965

                    also leave a comment, it helps when people state that they have the same issue.


                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    M 1 Reply Last reply
                    3
                    • J.HilkJ J.Hilk

                      @Mark81 vote for the issue and pray, like I did

                      https://bugreports.qt.io/browse/QTBUG-73965

                      also leave a comment, it helps when people state that they have the same issue.

                      M Offline
                      M Offline
                      Mark81
                      wrote on last edited by
                      #19

                      @J.Hilk said in Modbus RTU: readyRead() not called:

                      @Mark81 vote for the issue and pray, like I did

                      I'll try to suggest to my customer to pray and wait a fix too.

                      J.HilkJ 1 Reply Last reply
                      0
                      • M Mark81

                        @J.Hilk said in Modbus RTU: readyRead() not called:

                        @Mark81 vote for the issue and pray, like I did

                        I'll try to suggest to my customer to pray and wait a fix too.

                        J.HilkJ Online
                        J.HilkJ Online
                        J.Hilk
                        Moderators
                        wrote on last edited by
                        #20

                        @Mark81
                        you can download the source code and in qmodbusrtumaster comment that line

                        QObject::connect(m_serialPort, &QSerialPort;::bytesWritten, q,
                        [this](qint64 bytes) {
                        m_current.bytesWritten += bytes;
                        if (m_state == Send && (m_current.bytesWritten ==m_current.adu.size()) && !m_current.reply.isNull()) {
                               // the if conditions above are copied from processQueue()
                                qCDebug(QT_MODBUS) << "(RTU client) Send successful(quick):" << m_current.requestPdu;
                                m_state = Receive;
                                m_sendTimer.stop();
                        //        m_responseTimer.start(m_responseTimeoutDuration); comment this line
                        }
                        });
                        

                        thats the quick and dirty fix I made, fixes the unexpected state issue


                        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                        Q: What's that?
                        A: It's blue light.
                        Q: What does it do?
                        A: It turns blue.

                        1 Reply Last reply
                        3

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved