Details
-
Bug
-
Resolution: Done
-
P2: Important
-
5.12.1
-
None
-
-
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.