// Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include "modbusclient.h" // The read response must contain the start address (quint16), the byte count // (quint8) and at least one register value (quint16). static constexpr int ReadHeaderSize {3}; static constexpr int MinimumReadResponseSize {ReadHeaderSize + 2}; // 2 payload bytes // The response must contain the start address (quint16) and the number of // registers written (quint16). static constexpr int WriteResponseSize {4}; ModbusClient::ModbusClient(QObject *parent) : QModbusTcpClient(parent) { QModbusResponse::registerDataSizeCalculator(CustomRead, [](const QModbusResponse &response) { if (!response.isValid()) return -1; if (response.dataSize() < MinimumReadResponseSize) return -1; return ReadHeaderSize + quint8(response.data().at(ReadHeaderSize - 1)); }); QModbusResponse::registerDataSizeCalculator(CustomWrite, [](const QModbusResponse &response) { if (!response.isValid()) return -1; return (response.dataSize() != WriteResponseSize ? -1 : WriteResponseSize); }); } //! [process_custom_read] static bool collateBytes(const QModbusPdu &response, QModbusDataUnit *data) { if (response.dataSize() < MinimumReadResponseSize) return false; quint16 address; quint8 byteCount; response.decodeData(&address, &byteCount); if (byteCount % 2 != 0) return false; if (data) { QDataStream stream(response.data().remove(0, 3)); QList values; const quint8 itemCount = byteCount / 2; for (int i = 0; i < itemCount; i++) { quint16 tmp; stream >> tmp; values.append(tmp); } *data = {QModbusDataUnit::HoldingRegisters, address, values}; } return true; } //! [process_custom_read] //! [process_custom_write] static bool collateMultipleValues(const QModbusPdu &response, QModbusDataUnit *data) { if (response.dataSize() != WriteResponseSize) return false; quint16 address, count; response.decodeData(&address, &count); if (count < 1 || count > 10) return false; if (data) *data = {QModbusDataUnit::HoldingRegisters, address, count}; return true; } //! [process_custom_write] //! [private_response] bool ModbusClient::processPrivateResponse(const QModbusResponse &response, QModbusDataUnit *data) { if (!response.isValid()) return QModbusClient::processPrivateResponse(response, data); if (CustomRead == response.functionCode()) return collateBytes(response, data); if (CustomWrite == response.functionCode()) return collateMultipleValues(response, data); return QModbusClient::processPrivateResponse(response, data); } //! [private_response]