Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-74466

Can't get PDUResponse from RawRequest (QModbusTcpClient)

    XMLWordPrintable

Details

    • Bug
    • Resolution: Done
    • P2: Important
    • 5.15, 6.2
    • 5.12.1
    • SerialBus: MOD Bus
    • None
    • All
    • 8
    • Qt6_Foundation_Sprint 30

    Description

      I think I’ve found an error when getting a response from client.sendRawRequest

      This error is only in QModbusTcpClient!

      Test code for QModbusRtuSerialMaster (everything works correctly!)

       

      QModbusRtuSerialMaster master;
      QModbusRequest unit;
      master.setConnectionParameter(QModbusDevice::SerialPortNameParameter, "/dev/ttyUSB0");
      master.setConnectionParameter(QModbusDevice::SerialParityParameter,
       QSerialPort::NoParity);
      master.setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
       QSerialPort::Baud57600);
      master.setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
       QSerialPort::Data8);
      master.setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
       QSerialPort::OneStop);
      master.setTimeout(200);
      QObject::connect(&master, &QModbusClient::stateChanged, this, [this]() {
       qDebug() << master.state();
      if (master.state() == QModbusDevice::UnconnectedState)
       QTimer::singleShot(100, [this]{ master.connectDevice();});
      if (master.state() == QModbusDevice::ConnectedState)
       send();
      });
      
      QTimer::singleShot(100, [this]{ master.connectDevice();});
       
      bool send()
      {
       QModbusResponse::registerDataSizeCalculator(QModbusPdu::FunctionCode(0x64),
       [](const QModbusResponse &rsp)-> int {
       return 132;
       });
      QByteArray raw_pdu = QByteArray::fromHex("000000");
      unit.setFunctionCode(QModbusPdu::FunctionCode(0x64));
       unit.setData(raw_pdu);
      auto *reply = master.sendRawRequest(unit, 0x01);
      if( !reply )
       {
       qDebug() << "cant get replay";
       return false;
       }
      if(!reply->isFinished())
       QObject::connect(reply, &QModbusReply::finished, this, [this, reply]() {
      qDebug() << " Result -------:" << reply->rawResult().data().toHex();
      if(reply->error() != QModbusDevice::NoError)
       {
       qDebug() << "reply->error: " << reply->error();
       } else
       {
       //qDebug() << " Result -------:" << reply->rawResult().data().toHex();
       }
      reply->deleteLater();
       });
       else
       {
       qDebug() << "reply fast";
       reply->deleteLater(); // broadcast replies return immediately
       }
      return true;
      }
      

       

      What I get:

       

      
      QModbusDevice::ConnectingState
      QModbusDevice::ConnectedState
      qt.modbus: (RTU client) Sent Serial PDU: 0x64000000
      qt.modbus.lowlevel: (RTU client) Sent Serial ADU: 0x016400000006f0
      qt.modbus: (RTU client) Send successful (quick): 0x64000000
      qt.modbus.lowlevel: (RTU client) Response buffer: "01"
      qt.modbus: (RTU client) Modbus ADU not complete
      qt.modbus.lowlevel: (RTU client) Response buffer: "0164"
      cnt: 128
      qt.modbus: (RTU client) Incomplete ADU received, ignoring
      qt.modbus.lowlevel: (RTU client) Response buffer: "016400"
      cnt: 128
      qt.modbus: (RTU client) Incomplete ADU received, ignoring
      qt.modbus.lowlevel: (RTU client) Response buffer: "01640000"
      //a lot of ignoring (waiting for the whole ADU)
      qt.modbus.lowlevel: (RTU client) Response buffer: "016400000080000001840000056bc3d07f5dfd2f65cf2edcd3f911f56d4116480ee463de76a636e4b831d4b0f1aa78daad54e18e82300c7e15b2dfe6d20d8678afe299cb90c1912818363c8de1dd6f1d0ae582779a1892d17e745fdb6f2beb0bdbebaa65ef01fbd24d75566c11307b3e6844f250785715cee3c299fbb2f2e61ba0a34ede09bd2460"
      qt.modbus: (RTU client) Received ADU: "016400000080000001840000056bc3d07f5dfd2f65cf2edcd3f911f56d4116480ee463de76a636e4b831d4b0f1aa78daad54e18e82300c7e15b2dfe6d20d8678afe299cb90c1912818363c8de1dd6f1d0ae582779a1892d17e745fdb6f2beb0bdbebaa65ef01fbd24d75566c11307b3e6844f250785715cee3c299fbb2f2e61ba0a34ede09bd2460"
       Result -------: "00000080000001840000056bc3d07f5dfd2f65cf2edcd3f911f56d4116480ee463de76a636e4b831d4b0f1aa78daad54e18e82300c7e15b2dfe6d20d8678afe299cb90c1912818363c8de1dd6f1d0ae582779a1892d17e745fdb6f2beb0bdbebaa65ef01fbd24d75566c11307b3e6844f250785715cee3c299fbb2f2e61ba0a34ede09bd"
      QModbusDevice::ClosingState
      QModbusDevice::UnconnectedState
      

       

       

      What I get when working with TCP: (not correctly, I guess that there is an error!)

       

      QModbusRequest unit;
      QModbusTcpClient client;
      
      QUrl device_url = QUrl::fromUserInput("192.168.10.1:502");
      client.setConnectionParameter(QModbusDevice::NetworkPortParameter, device_url.port());
      client.setConnectionParameter(QModbusDevice::NetworkAddressParameter, device_url.host());
      
      QObject::connect(&client, &QModbusClient::stateChanged, this, [this]() {
       qDebug() << client.state();
      if (client.state() == QModbusDevice::UnconnectedState)
       QTimer::singleShot(500, [this]{ client.connectDevice();});
      if (client.state() == QModbusDevice::ConnectedState)
       send();
      });
      
      QTimer::singleShot(1000, [this]{ client.connectDevice();});
      
      bool send()
      {
       QModbusResponse::registerDataSizeCalculator(QModbusPdu::FunctionCode(0x64),
       [](const QModbusResponse &rsp)-> int {
       return 132;
       });
      
       QByteArray raw_pdu = QByteArray::fromHex("000000");
      unit.setFunctionCode(QModbusPdu::FunctionCode(0x64));
       unit.setData(raw_pdu);
      
       auto *reply = client.sendRawRequest(unit, 0x01);
      if( !reply )
       {
       qDebug() << "cant get replay";
       return false;
       }
      if(!reply->isFinished())
       QObject::connect(reply, &QModbusReply::finished, this, [this, reply]() {
      qDebug() << " Result -------:" << reply->rawResult().data().toHex();
      if(reply->error() != QModbusDevice::NoError)
       {
       qDebug() << "reply->error: " << reply->error();
       } else
       {
       //qDebug() << " Result -------:" << reply->rawResult().data().toHex();
       }
      reply->deleteLater();
       });
       else
       {
       qDebug() << "reply fast";
        reply->deleteLater(); // broadcast replies return immediately
       }
       return true;
      }
       
      

      What I get:

       

      QModbusDevice::ConnectingState
      qt.modbus: (TCP client) Connected to QHostAddress("192.168.10.1") on port 502
      QModbusDevice::ConnectedState
      qt.modbus.lowlevel: (TCP client) Sent TCP ADU: "0000000000050164000000"
      qt.modbus: (TCP client) Sent TCP PDU: 0x64000000 with tId: 0
      qt.modbus.lowlevel: (TCP client) Response buffer: "000000000086016400000080000001840000056bc3d07f5dfd2f65cf2edcd3f911f56d4116480ee463de76a636e4b831d4b0f1aa78daad54e18e82300c7e15b2dfe6d20d8678afe299cb90c1912818363c8de1dd6f1d0ae582779a1892d17e745fdb6f2beb0bdbebaa65ef01fbd24d75566c11307b3e6844f250785715cee3c299fbb2f2e61ba0a34ede09bd"
      qt.modbus: (TCP client) tid: 0 size: 86 server address: 1
      qt.modbus: (TCP client) Received PDU: 0 ""
       Result -------: ""
      qt.modbus: (TCP client) Connection closed.
      QModbusDevice::UnconnectedState
      

      As you can see, the PDU is received, and it is received correctly, but Qt did not return it to me. I was returned InvalidPDU (FC == 0)

      I assume that the error is in line 138 of the qmodbustcpclient_p.h code:

      QModbusResponse responsePdu;
      input >> responsePdu; // row 138
      qCDebug(QT_MODBUS) << "(TCP client) Received PDU:" << responsePdu.functionCode()
       << responsePdu.data().toHex();

      in file: qmodbuspdu.cpp in function:

      static QDataStream & pduFromStream(QDataStream &stream, QModbusPdu &pdu, Type type)

      streaming is parsed there and when checking QModbusResponse::minimumDataSize(pdu)
      we returned -1 (us FunctionCode is not standard) and we didn’t even get to the function call: QModbusResponse::calculateDataSize(pdu)

      As a result there wasn't copying of the data in the PDU, which should be returned as an response.

      IMHO: It's no sense to use input >> responsePdu because it's just ModBusTCP and we already know the size of the PDU. it is contained in mbpaHeader.
      Maybe it need to add a simple validation in qmodbustcpclient_p.h for checking and just use memcpy.

      Attachments

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            heimrich Karsten Heimrich
            koynovstas Stas Koynov
            Maurice Kalinowski Maurice Kalinowski
            Alex Blasche Alex Blasche
            Votes:
            2 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Gerrit Reviews

                There are no open Gerrit changes