Revision control
Copy as Markdown
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*! \example modbus/custom
\title Modbus Custom Command
\ingroup qtserialbus-examples
\examplecategory Connectivity
\brief The example shows how to handle custom Modbus function codes.
The example acts as both Modbus client and server in a single application.
The connection between them is established via Modbus TCP. It is used to
send and receive custom Modbus requests and adjusts its internal states
based on the request and response.
The main purpose of the example is to provide some demo code on how to
implement a Modbus client or Modbus server handling custom Modbus function
codes.
\image ../images/custom.png
{Modbus Custom Command window with Server and Client register
tables, custom function codes 0x41 (Read) and 0x42 (Write)}
\section1 User-Defined Modbus Function Codes
The Modbus protocol supports function codes in the range \c {1 - 127
(0x01 - 0x7F HEX)}. Most of the function codes are well defined and publicly
documented. However, there are two ranges that can be used for user-defined
functions. Those are \c {65 - 72 (0x41 - 48 HEX)} and
\c {100 - 110 (0x64 - 0x6E HEX)}. The user can select function codes from
these ranges and handle them in some custom way.
This application uses function code \c {65 (0x41 HEX)} to implement
\c CustomRead command and function code \c {66 (0x42 HEX)} to implement
\c CustomWrite command. In this example the custom commands are used to
simply read and write the
\l {QModbusDataUnit::HoldingRegisters}{Holding Registers}.
\section1 Sending Custom Modbus Commands
The custom Modbus commands are sent using the
\l QModbusClient::sendRawRequest() method. This method requires to generate
a \l QModbusRequest object with the desired function code and a list of
arguments which will be encoded into a \l {QByteArray}:
\snippet modbus/custom/mainwindow.cpp generate_modbus_request
The \l QModbusClient::sendRawRequest() method returns a \l QModbusReply
object which can be used to check for errors as usual:
\snippet modbus/custom/mainwindow.cpp send_custom_command
\section1 Custom Modbus Server
The custom server is derived from the \l QModbusTcpServer class. It
overrides the \l QModbusServer::processPrivateRequest() method.
\snippet modbus/custom/modbusserver.h custom_server
The base server class calls the
\l {QModbusServer::}{processPrivateRequest()} method when a command with a
custom function code is received.
The custom implementation handles the \c CustomRead command by generating
a \l QModbusResponse with the values of requested registers:
\snippet modbus/custom/modbusserver.cpp handle_custom_read
Handling \c CustomWrite command includes extracting the new values from
the received \l QModbusPdu, doing the actual value update, and returning
a \l QModbusResponse with the registers that were actually updated:
\snippet modbus/custom/modbusserver.cpp handle_custom_write
\section1 Custom Modbus Client
The custom client is derived from the \l QModbusTcpClient class. It
overrides the \l QModbusClient::processPrivateResponse() method.
\snippet modbus/custom/modbusclient.h custom_client
The base client class calls the
\l {QModbusClient::}{processPrivateResponse()} method to process the server
responses with custom function codes.
The custom implementation handles the responses with \c CustomRead and
\c CustomWrite function codes:
\snippet modbus/custom/modbusclient.cpp private_response
The \c CustomRead response is handled by decoding the provided \l QModbusPdu
and extracting the values for requested registers:
\snippet modbus/custom/modbusclient.cpp process_custom_read
The \c CustomWrite response is handled by simply validating the response
parameters:
\snippet modbus/custom/modbusclient.cpp process_custom_write
\include examples-run.qdocinc
This example cannot be used in conjunction with other applications. Once the
example is started, it can only exchange custom Modbus commands within the
application itself. All interactions between the client and server use the
Modbus TCP protocol.
*/