API Reference๏ƒ

This section provides comprehensive API documentation for all libmodbus classes, functions, and data types. The documentation is automatically generated from the source code comments using Doxygen and Breathe.

๐Ÿ“š Core Components๏ƒ

Main Library Header๏ƒ

Main include file for the libmodbus C++ library.

Author

libmodbus Project

Version

1.0

Date

2024

namespace libmodbus๏ƒ

Main namespace for all libmodbus functionality.

All libmodbus classes, functions, and constants are contained within this namespace to avoid naming conflicts with other libraries.

struct Version๏ƒ
#include <libmodbus.hpp>

Library version information.

Public Static Functions

static inline const char *getString()๏ƒ

Get version string.

Returns:

Version string in format โ€œMAJOR.MINOR.PATCHโ€

Public Static Attributes

static constexpr int MAJOR = 1๏ƒ

Major version number.

static constexpr int MINOR = 0๏ƒ

Minor version number.

static constexpr int PATCH = 0๏ƒ

Patch version number.

๐Ÿ“Š Data Model๏ƒ

Modbus data model implementation with configurable limits.

This file implements the Modbus data model that stores all four types of Modbus data: coils, discrete inputs, holding registers, and input registers. The implementation supports configurable limits and provides both modern vector-based storage and legacy compatibility.

Author

libmodbus Project

Version

1.0

Date

2024

Typedefs

using DiscreteInputType = bool๏ƒ

Type alias for discrete input values.

Discrete inputs are read-only boolean values that typically represent the state of physical inputs to the device.

using CoilType = bool๏ƒ

Type alias for coil values.

Coils are read/write boolean values that typically control physical outputs of the device.

using InputRegisterType = uint16_t๏ƒ

Type alias for input register values.

Input registers are read-only 16-bit values that typically contain analog input values or other measured data.

using HoldingRegisterType = uint16_t๏ƒ

Type alias for holding register values.

Holding registers are read/write 16-bit values that can store configuration parameters, setpoints, or other control data.

class ModbusDataModel
#include <ModbusDataModel.hpp>

Configurable Modbus data model with support for all four data types.

This class implements a complete Modbus data model that stores:

  • Coils (read/write discrete outputs)

  • Discrete Inputs (read-only discrete inputs)

  • Holding Registers (read/write 16-bit registers)

  • Input Registers (read-only 16-bit registers)

The implementation uses vectors for dynamic sizing and supports both default limits that comply with Modbus specifications and custom limits for specialized applications.

See also

ModbusFunctionCode for supported operations

Note

All data addresses are 0-based internally, following common programming conventions, even though Modbus addresses are traditionally 1-based.

Public Functions

inline ModbusDataModel()

Default constructor with standard Modbus limits.

Creates a data model with the default limits as specified in the Modbus application protocol specification:

  • 2000 discrete inputs

  • 2000 coils

  • 125 input registers

  • 125 holding registers

All values are initialized to false/0.

inline ModbusDataModel(size_t maxDiscreteInputs, size_t maxCoils, size_t maxInputRegisters, size_t maxHoldingRegisters)

Custom constructor with user-defined limits.

Creates a data model with custom limits for specialized applications that may need different capacity than the standard Modbus limits.

Note

All values are initialized to false/0.

Parameters:
  • maxDiscreteInputs โ€“ Maximum number of discrete inputs

  • maxCoils โ€“ Maximum number of coils

  • maxInputRegisters โ€“ Maximum number of input registers

  • maxHoldingRegisters โ€“ Maximum number of holding registers

inline size_t getMaxDiscreteInputs() const

Get the maximum number of discrete inputs.

Returns:

Maximum number of discrete inputs this data model can store

inline size_t getMaxCoils() const

Get the maximum number of coils.

Returns:

Maximum number of coils this data model can store

inline size_t getMaxInputRegisters() const

Get the maximum number of input registers.

Returns:

Maximum number of input registers this data model can store

inline size_t getMaxHoldingRegisters() const

Get the maximum number of holding registers.

Returns:

Maximum number of holding registers this data model can store

DiscreteInputType readDiscreteInput(uint16_t index) const

Read a discrete input value.

Note

This function performs bounds checking and returns false for invalid indices

Parameters:

index โ€“ 0-based index of the discrete input to read

Returns:

Value of the discrete input (true/false), or false if index is out of range

CoilType readCoil(uint16_t index) const

Read a coil value.

Note

This function performs bounds checking and returns false for invalid indices

Parameters:

index โ€“ 0-based index of the coil to read

Returns:

Value of the coil (true/false), or false if index is out of range

InputRegisterType readInputRegister(uint16_t index) const

Read an input register value.

Note

This function performs bounds checking and returns 0 for invalid indices

Parameters:

index โ€“ 0-based index of the input register to read

Returns:

Value of the input register (0-65535), or 0 if index is out of range

HoldingRegisterType readHoldingRegister(uint16_t index) const

Read a holding register value.

Note

This function performs bounds checking and returns 0 for invalid indices

Parameters:

index โ€“ 0-based index of the holding register to read

Returns:

Value of the holding register (0-65535), or 0 if index is out of range

void writeCoil(uint16_t index, CoilType value)

Write a single coil value.

Note

This function performs bounds checking and ignores writes to invalid indices

Parameters:
  • index โ€“ 0-based index of the coil to write

  • value โ€“ New value for the coil (true/false)

void writeHoldingRegister(uint16_t index, HoldingRegisterType value)

Write a single holding register value.

Note

This function performs bounds checking and ignores writes to invalid indices

Parameters:
  • index โ€“ 0-based index of the holding register to write

  • value โ€“ New value for the holding register (0-65535)

void writeMultipleCoils(uint16_t start_index, const CoilType values[], size_t num_values)

Write multiple coil values starting at a specified address.

Note

This function performs bounds checking and only writes values that fit within the valid address range. Partial writes may occur if the range extends beyond the maximum address.

Parameters:
  • start_index โ€“ 0-based starting index for the write operation

  • values โ€“ Array of coil values to write

  • num_values โ€“ Number of values to write from the array

void writeMultipleHoldingRegisters(uint16_t start_index, const HoldingRegisterType values[], size_t num_values)

Write multiple holding register values starting at a specified address.

Note

This function performs bounds checking and only writes values that fit within the valid address range. Partial writes may occur if the range extends beyond the maximum address.

Parameters:
  • start_index โ€“ 0-based starting index for the write operation

  • values โ€“ Array of holding register values to write

  • num_values โ€“ Number of values to write from the array

void setDiscreteInput(uint16_t index, DiscreteInputType value)

Set a discrete input value (for testing/initialization)

Note

This function is primarily intended for testing and initialization. In a real Modbus device, discrete inputs would typically be updated by hardware or other system components, not by Modbus commands.

Note

This function performs bounds checking and ignores writes to invalid indices

Parameters:
  • index โ€“ 0-based index of the discrete input to set

  • value โ€“ New value for the discrete input (true/false)

void setInputRegister(uint16_t index, InputRegisterType value)

Set an input register value (for testing/initialization)

Note

This function is primarily intended for testing and initialization. In a real Modbus device, input registers would typically be updated by hardware or other system components, not by Modbus commands.

Note

This function performs bounds checking and ignores writes to invalid indices

Parameters:
  • index โ€“ 0-based index of the input register to set

  • value โ€“ New value for the input register (0-65535)

inline std::vector<DiscreteInputType> &getDiscreteInputs()

Get direct access to discrete inputs vector.

Deprecated:

This method is deprecated. Use the read/write methods instead.

Warning

Direct access bypasses bounds checking and may lead to undefined behavior

Returns:

Reference to the internal discrete inputs vector

inline std::vector<CoilType> &getCoils()

Get direct access to coils vector.

Deprecated:

This method is deprecated. Use the read/write methods instead.

Warning

Direct access bypasses bounds checking and may lead to undefined behavior

Returns:

Reference to the internal coils vector

inline std::vector<InputRegisterType> &getInputRegisters()

Get direct access to input registers vector.

Deprecated:

This method is deprecated. Use the read/write methods instead.

Warning

Direct access bypasses bounds checking and may lead to undefined behavior

Returns:

Reference to the internal input registers vector

inline std::vector<HoldingRegisterType> &getHoldingRegisters()

Get direct access to holding registers vector.

Deprecated:

This method is deprecated. Use the read/write methods instead.

Warning

Direct access bypasses bounds checking and may lead to undefined behavior

Returns:

Reference to the internal holding registers vector

Public Static Attributes

static constexpr size_t DEFAULT_MAX_DISCRETE_INPUTS = 2000

Default maximum number of discrete inputs (2000 per Modbus spec)

static constexpr size_t DEFAULT_MAX_COILS = 2000

Default maximum number of coils (2000 per Modbus spec)

static constexpr size_t DEFAULT_MAX_INPUT_REGISTERS = 125

Default maximum number of input registers (125 per Modbus spec)

static constexpr size_t DEFAULT_MAX_HOLDING_REGISTERS = 125

Default maximum number of holding registers (125 per Modbus spec)

static constexpr size_t MAX_DISCREET_INPUT = DEFAULT_MAX_DISCRETE_INPUTS

Legacy constant for maximum discrete inputs.

Deprecated:

Use DEFAULT_MAX_DISCRETE_INPUTS

static constexpr size_t MAX_COILS = DEFAULT_MAX_COILS

Legacy constant for maximum coils.

Deprecated:

Use DEFAULT_MAX_COILS

static constexpr size_t MAX_INPUT_REGISTERS = DEFAULT_MAX_INPUT_REGISTERS

Legacy constant for maximum input registers.

Deprecated:

Use DEFAULT_MAX_INPUT_REGISTERS

static constexpr size_t MAX_HOLDING_REGISTERS = DEFAULT_MAX_HOLDING_REGISTERS

Legacy constant for maximum holding registers.

Deprecated:

Use DEFAULT_MAX_HOLDING_REGISTERS

Private Members

std::vector<DiscreteInputType> discreteInputs๏ƒ

Storage for discrete input values.

std::vector<CoilType> coils๏ƒ

Storage for coil values.

std::vector<InputRegisterType> inputRegisters๏ƒ

Storage for input register values.

std::vector<HoldingRegisterType> holdingRegisters๏ƒ

Storage for holding register values.

๐Ÿ—‚๏ธ Protocol Definitions๏ƒ

Core Modbus protocol definitions and enumerations.

This file contains the fundamental Modbus protocol definitions including function codes, exception codes, and diagnostic sub-function codes as specified in the Modbus Application Protocol Specification V1.1b3.

Author

libmodbus Project

Version

1.0

Date

2024

Enums

enum class ModbusFunctionCode : uint8_t

Modbus function codes as defined in the Modbus specification.

This enumeration contains all the standard Modbus function codes supported by this library. Each function code corresponds to a specific operation that can be performed on Modbus data.

Values:

enumerator NONE

No function code (invalid/uninitialized)

enumerator READ_COILS

Read coils (discrete outputs) - FC 01.

enumerator READ_DISCRETE_INPUTS

Read discrete inputs - FC 02.

enumerator READ_HOLDING_REGISTERS

Read holding registers - FC 03.

enumerator READ_INPUT_REGISTERS

Read input registers - FC 04.

enumerator WRITE_SINGLE_COIL

Write single coil - FC 05.

enumerator WRITE_SINGLE_REGISTER

Write single register - FC 06.

enumerator READ_EXCEPTION_STATUS

Read exception status - FC 07.

enumerator DIAGNOSTICS

Diagnostics - FC 08.

enumerator WRITE_MULTIPLE_COILS

Write multiple coils - FC 15 (0x0F)

enumerator WRITE_MULTIPLE_REGISTERS

Write multiple registers - FC 16 (0x10)

enum class ModbusExceptionCode : uint8_t

Modbus exception codes returned in error responses.

When a Modbus request cannot be processed successfully, the server responds with an exception frame containing one of these exception codes to indicate the specific error condition.

Values:

enumerator NONE

No exception (success)

enumerator ILLEGAL_FUNCTION

Function code not supported.

enumerator ILLEGAL_DATA_ADDRESS

Data address not valid.

enumerator ILLEGAL_DATA_VALUE

Data value not valid.

enumerator SLAVE_DEVICE_FAILURE

Unrecoverable error in slave device.

enumerator ACKNOWLEDGE

Request accepted, processing.

enumerator SLAVE_DEVICE_BUSY

Slave device busy.

enumerator NEGATIVE_ACKNOWLEDGMENT

Request cannot be performed.

enumerator MEMORY_PARITY_ERROR

Memory parity error.

enumerator GATEWAY_PATH_UNAVAILABLE

Gateway path unavailable.

enumerator GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND

Gateway target device failed to respond.

enum class ModbusDiagnosticsCode : uint16_t

Diagnostic sub-function codes for function code 08 (Diagnostics)

The diagnostics function (FC 08) supports various sub-functions for testing communication and retrieving diagnostic information from Modbus devices. This enumeration defines the standard sub-function codes.

Values:

enumerator RETURN_QUERY_DATA

Echo back query data.

enumerator RESTART_COMMUNICATIONS_OPTION

Restart communications option.

enumerator RETURN_DIAGNOSTIC_REGISTER

Return diagnostic register.

enumerator CHANGE_ASCII_INPUT_DELIMITER

Change ASCII input delimiter.

enumerator FORCE_LISTEN_ONLY_MODE

Force listen only mode.

enumerator CLEAR_COUNTERS_AND_DIAGNOSTIC_REGISTER

Clear counters and diagnostic register.

enumerator RETURN_BUS_MESSAGE_COUNT

Return bus message count.

enumerator RETURN_BUS_COMMUNICATION_ERROR_COUNT

Return bus communication error count.

enumerator RETURN_BUS_EXCEPTION_ERROR_COUNT

Return bus exception error count.

enumerator RETURN_SLAVE_MESSAGE_COUNT

Return slave message count.

enumerator RETURN_SLAVE_NO_RESPONSE_COUNT

Return slave no response count.

enumerator RETURN_SLAVE_NAK_COUNT

Return slave NAK count.

enumerator RETURN_SLAVE_BUSY_COUNT

Return slave busy count.

enumerator RETURN_BUS_CHARACTER_OVERRUN_COUNT

Return bus character overrun count.

๐Ÿ–ผ๏ธ Frame Processing๏ƒ

Modbus frame implementations for RTU, ASCII, and TCP protocols.

This file contains the implementation of Modbus frame structures for all three main Modbus variants: RTU (serial), ASCII (serial), and TCP (Ethernet). Each frame type handles the specific formatting, serialization, and deserialization requirements of its respective protocol.

Author

libmodbus Project

Version

1.0

Date

2024

Enums

enum class ModbusFrameType

Enumeration of Modbus frame types.

This enumeration identifies the type of Modbus frame being processed, which determines how the frame should be interpreted and what response should be generated.

Values:

enumerator NONE

Uninitialized or invalid frame.

enumerator REQUEST

Request frame from client to server.

enumerator RESPONSE

Normal response frame from server to client.

enumerator EXCEPTION

Exception response frame indicating an error.

class ModbusFrame
#include <ModbusFrame.hpp>

Core Modbus Protocol Data Unit (PDU) implementation.

This class represents the core Modbus PDU that is common to all Modbus variants (RTU, ASCII, TCP). It contains the function code, frame data, and exception information. The PDU is embedded within the various transport-specific frame formats.

The frame structure is:

  • Function Code (1 byte)

  • Data (0-252 bytes)

  • Exception Code (1 byte, only for exception frames)

Public Functions

inline ModbusFrame()

Default constructor.

Creates an uninitialized frame with NONE type, NONE function code, and no exception code.

inline ModbusFrame(ModbusFrameType type, ModbusFunctionCode func)

Constructor with frame type and function code.

Parameters:
  • type โ€“ The type of frame (REQUEST, RESPONSE, or EXCEPTION)

  • func โ€“ The Modbus function code

Public Members

ModbusFrameType frameType

Type of frame (request/response/exception)

ModbusFunctionCode functionCode

Modbus function code.

std::vector<uint8_t> frameData

Frame data payload.

ModbusExceptionCode exceptionCode

Exception code (only used for exception frames)

class ModbusRtuFrame
#include <ModbusFrame.hpp>

Modbus RTU (Remote Terminal Unit) frame implementation.

Implements the Modbus RTU frame format used for serial communication. RTU frames use binary encoding and CRC-16 checksums for error detection.

Normal frame structure: | Slave Address (1 byte) | Function Code (1 byte) | Data (n bytes) | CRC (2 bytes) |

Exception frame structure: | Slave Address (1 byte) | Function Code + 0x80 (1 byte) | Exception Code (1 byte) | CRC (2 bytes) |

Note

The CRC is calculated using the Modbus CRC-16 algorithm over all bytes except the CRC itself, with low byte transmitted first.

Public Functions

inline ModbusRtuFrame()

Default constructor.

Creates an RTU frame with slave address 0 and checksum 0.

inline ModbusRtuFrame(uint8_t addr)

Constructor with slave address.

Parameters:

addr โ€“ Slave address (1-247, 0 for broadcast)

std::vector<uint8_t> serialize()

Serialize the RTU frame to a byte vector.

Converts the RTU frame to its binary representation suitable for transmission over a serial link. The function automatically calculates and appends the CRC-16 checksum.

Note

The CRC is calculated using the Modbus CRC-16 algorithm

Returns:

Vector of bytes representing the serialized frame

void deserialize(ModbusFrameType frameType, const std::vector<uint8_t> &data)

Deserialize a byte vector into an RTU frame.

Parses a received byte vector and populates the RTU frame fields. The function extracts the slave address, function code, data, and CRC.

Note

This function does not validate the CRC - that should be done by the caller before calling this function.

Parameters:
  • frameType โ€“ Expected frame type (REQUEST, RESPONSE, or EXCEPTION)

  • data โ€“ Byte vector containing the raw frame data

Public Members

uint8_t slaveaddr

Slave address (1-247, 0 for broadcast)

ModbusFrame pdu

Protocol Data Unit.

uint16_t checksum

CRC-16 checksum.

class ModbusAsciiFrame
#include <ModbusFrame.hpp>

Modbus ASCII frame implementation.

Implements the Modbus ASCII frame format used for serial communication. ASCII frames use hexadecimal character encoding and LRC checksums.

Frame structure: | Start โ€˜:โ€™ | Address (2 hex chars) | Function (2 hex chars) | Data (hex chars) | LRC (2 hex chars) | End CRLF |

Note

ASCII frames are longer than RTU frames but are human-readable and less susceptible to transmission errors.

Warning

ASCII implementation is currently incomplete (TODO)

Public Functions

std::vector<uint8_t> serialize()

Serialize the ASCII frame to a byte vector.

Todo:

This method is not yet implemented

Returns:

Vector of bytes representing the serialized frame

void deserialize(const std::vector<uint8_t> &data)

Deserialize a byte vector into an ASCII frame.

Todo:

This method is not yet implemented

Parameters:

data โ€“ Byte vector containing the raw frame data

Public Members

uint8_t start

Start character (always โ€˜:โ€™)

uint8_t address

Slave address.

ModbusFrame pdu

Protocol Data Unit.

uint16_t checksum

LRC checksum.

uint16_t end

End characters (CR LF)

class MbapHeader
#include <ModbusFrame.hpp>

Modbus Application Protocol (MBAP) header for TCP frames.

The MBAP header is used in Modbus TCP to provide transaction identification, protocol identification, length information, and unit identification.

Header structure (7 bytes): | Transaction ID (2 bytes) | Protocol ID (2 bytes) | Length (2 bytes) | Unit ID (1 byte) |

Public Functions

inline MbapHeader()

Default constructor.

Creates an MBAP header with all fields set to 0.

inline MbapHeader(uint16_t transactionId, uint16_t protocolId, uint16_t length, uint8_t unitId)

Constructor with all header fields.

Parameters:
  • transactionId โ€“ Transaction identifier

  • protocolId โ€“ Protocol identifier (should be 0 for Modbus)

  • length โ€“ Length of following bytes

  • unitId โ€“ Unit identifier

Public Members

uint16_t transactionId

Transaction identifier for matching requests/responses.

uint16_t protocolId

Protocol identifier (always 0 for Modbus)

uint16_t length

Number of following bytes (PDU length + 1)

uint8_t unitId

Unit identifier (slave address equivalent)

class ModbusTcpFrame
#include <ModbusFrame.hpp>

Modbus TCP frame implementation.

Implements the Modbus TCP frame format used for Ethernet communication. TCP frames include an MBAP header followed by the PDU. No checksum is needed as TCP provides reliable delivery.

Frame structure: | MBAP Header (7 bytes) | PDU (1-253 bytes) |

Warning

TCP implementation is currently incomplete (TODO)

Public Functions

std::vector<uint8_t> serialize()

Serialize the TCP frame to a byte vector.

Todo:

This method is not yet implemented

Returns:

Vector of bytes representing the serialized frame

void deserialize(const std::vector<uint8_t> &data)

Deserialize a byte vector into a TCP frame.

Todo:

This method is not yet implemented

Parameters:

data โ€“ Byte vector containing the raw frame data

Public Members

MbapHeader mbapHeader

MBAP header.

ModbusFrame pdu

Protocol Data Unit.

๐ŸŽฎ Command Processing๏ƒ

Modbus command implementations for all supported function codes.

This file contains the command pattern implementation for all supported Modbus function codes. Each command class handles the specific logic for processing requests and generating appropriate responses or exceptions.

Author

libmodbus Project

Version

1.0

Date

2024

class ModbusCommand
#include <ModbusCommand.hpp>

Abstract base class for all Modbus command implementations.

This class defines the interface for Modbus command processing using the Command pattern. Each specific function code has its own derived command class that implements the execute() method.

The class also provides common validation methods that are used by multiple command implementations to ensure consistent error handling and compliance with Modbus specifications.

Subclassed by DiagnosticsCommand, ReadCoilCommand, ReadDiscreteInputCommand, ReadHoldingRegisterCommand, ReadInputRegisterCommand, WriteCoilCommand, WriteHoldingRegisterCommand, WriteMultipleCoilsCommand, WriteMultipleRegistersCommand

Public Functions

virtual ~ModbusCommand() = default

Virtual destructor for proper polymorphic destruction.

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request) = 0

Execute the command with given data model and request.

This is the main entry point for command execution. Each derived class implements this method to handle its specific function code.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming Modbus request frame

Returns:

Response frame (normal response or exception)

Protected Functions

bool validateQuantity(const ModbusFrame &request, uint16_t minQuantity, uint16_t maxQuantity, ModbusFrame &response)

Generic quantity validation for Modbus requests.

Validates that the quantity field in a Modbus request falls within the specified minimum and maximum values.

Note

This method assumes the quantity is in bytes 2-3 of the frame data

Parameters:
  • request โ€“ The incoming request frame

  • minQuantity โ€“ Minimum allowed quantity

  • maxQuantity โ€“ Maximum allowed quantity

  • response โ€“ Reference to response frame (populated with exception if validation fails)

Returns:

true if validation passes, false if exception was generated

bool validateAddress(const ModbusFrame &request, uint16_t maxValidAddress, ModbusFrame &response)

Address range validation for Modbus requests.

Validates that the starting address and quantity combination is within the valid address range for the data type.

Note

This method assumes address is in bytes 0-1 and quantity in bytes 2-3

Parameters:
  • request โ€“ The incoming request frame

  • maxValidAddress โ€“ Maximum valid address for this data type

  • response โ€“ Reference to response frame (populated with exception if validation fails)

Returns:

true if validation passes, false if exception was generated

bool validateReadCoilsQuantity(const ModbusFrame &request, ModbusFrame &response)

Validate quantity for Read Coils function (FC 01)

Validates quantity range for coil reading operations (1-2000 coils).

Parameters:
  • request โ€“ The incoming request frame

  • response โ€“ Reference to response frame (populated with exception if validation fails)

Returns:

true if validation passes, false if exception was generated

bool validateReadRegistersQuantity(const ModbusFrame &request, ModbusFrame &response)

Validate quantity for Read Registers functions (FC 03, 04)

Validates quantity range for register reading operations (1-125 registers).

Parameters:
  • request โ€“ The incoming request frame

  • response โ€“ Reference to response frame (populated with exception if validation fails)

Returns:

true if validation passes, false if exception was generated

bool validateWriteMultipleCoilsQuantity(const ModbusFrame &request, ModbusFrame &response)

Validate quantity for Write Multiple Coils function (FC 15)

Validates quantity range for multiple coil writing operations (1-1968 coils).

Parameters:
  • request โ€“ The incoming request frame

  • response โ€“ Reference to response frame (populated with exception if validation fails)

Returns:

true if validation passes, false if exception was generated

bool validateWriteMultipleRegistersQuantity(const ModbusFrame &request, ModbusFrame &response)

Validate quantity for Write Multiple Registers function (FC 16)

Validates quantity range for multiple register writing operations (1-123 registers).

Parameters:
  • request โ€“ The incoming request frame

  • response โ€“ Reference to response frame (populated with exception if validation fails)

Returns:

true if validation passes, false if exception was generated

class ReadCoilCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Read Coils function (FC 01)

Reads the status of coils (discrete outputs) from the data model. Returns a bit-packed response where each bit represents one coil state.

Request format:

  • Starting Address (2 bytes)

  • Quantity of Coils (2 bytes)

Response format:

  • Byte Count (1 byte)

  • Coil Status (n bytes, bit-packed)

Note

Coils are packed 8 per byte, LSB first

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Read Coils command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame containing coil status or exception

class ReadDiscreteInputCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Read Discrete Inputs function (FC 02)

Reads the status of discrete inputs from the data model. Returns a bit-packed response where each bit represents one input state.

Request format:

  • Starting Address (2 bytes)

  • Quantity of Inputs (2 bytes)

Response format:

  • Byte Count (1 byte)

  • Input Status (n bytes, bit-packed)

Note

Inputs are packed 8 per byte, LSB first

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Read Discrete Inputs command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame containing input status or exception

class ReadInputRegisterCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Read Input Registers function (FC 04)

Reads input register values from the data model. Returns register values in big-endian format.

Request format:

  • Starting Address (2 bytes)

  • Quantity of Registers (2 bytes)

Response format:

  • Byte Count (1 byte)

  • Register Values (n*2 bytes, big-endian)

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Read Input Registers command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame containing register values or exception

class ReadHoldingRegisterCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Read Holding Registers function (FC 03)

Reads holding register values from the data model. Returns register values in big-endian format.

Request format:

  • Starting Address (2 bytes)

  • Quantity of Registers (2 bytes)

Response format:

  • Byte Count (1 byte)

  • Register Values (n*2 bytes, big-endian)

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Read Holding Registers command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame containing register values or exception

class WriteCoilCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Write Single Coil function (FC 05)

Writes a single coil value to the data model.

Request format:

  • Output Address (2 bytes)

  • Output Value (2 bytes: 0x0000 for OFF, 0xFF00 for ON)

Response format:

  • Echo of the complete request

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Write Single Coil command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame (echo of request) or exception

class WriteHoldingRegisterCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Write Single Register function (FC 06)

Writes a single holding register value to the data model.

Request format:

  • Register Address (2 bytes)

  • Register Value (2 bytes)

Response format:

  • Echo of the complete request

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Write Single Register command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame (echo of request) or exception

class WriteMultipleCoilsCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Write Multiple Coils function (FC 15)

Writes multiple coil values to the data model. Coil values are transmitted as bit-packed bytes.

Request format:

  • Starting Address (2 bytes)

  • Quantity of Outputs (2 bytes)

  • Byte Count (1 byte)

  • Outputs Value (n bytes, bit-packed)

Response format:

  • Starting Address (2 bytes)

  • Quantity of Outputs (2 bytes)

Note

Coils are packed 8 per byte, LSB first

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Write Multiple Coils command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame containing address and quantity or exception

class WriteMultipleRegistersCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Write Multiple Registers function (FC 16)

Writes multiple holding register values to the data model. Register values are transmitted in big-endian format.

Request format:

  • Starting Address (2 bytes)

  • Quantity of Registers (2 bytes)

  • Byte Count (1 byte)

  • Registers Value (n*2 bytes, big-endian)

Response format:

  • Starting Address (2 bytes)

  • Quantity of Registers (2 bytes)

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Write Multiple Registers command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame containing address and quantity or exception

class DiagnosticsCommand : public ModbusCommand
#include <ModbusCommand.hpp>

Implementation of Diagnostics function (FC 08)

Provides a series of diagnostic and testing functions for Modbus communication. Currently supports basic sub-functions like Return Query Data and communication restart.

Request format:

  • Sub-function (2 bytes)

  • Data (2 bytes, sub-function specific)

Response format:

  • Sub-function (2 bytes, echo)

  • Data (2 bytes, sub-function specific)

Note

Only basic diagnostic sub-functions are currently implemented

Public Functions

virtual ModbusFrame execute(ModbusDataModel &data, const ModbusFrame &request)

Execute the Diagnostics command.

Parameters:
  • data โ€“ Reference to the Modbus data model

  • request โ€“ The incoming request frame

Returns:

Response frame containing diagnostic response or exception

๐Ÿ–ฅ๏ธ Server Implementation๏ƒ

Base Modbus server implementation with protocol-specific derivatives.

This file contains the base Modbus server class that provides common functionality for all Modbus server implementations, along with the RTU-specific server implementation.

Author

libmodbus Project

Version

1.0

Date

2024

class ModbusBaseServer
#include <ModbusBaseServer.hpp>

Abstract base class for all Modbus server implementations.

This class provides the foundation for Modbus server implementations across different transport protocols (RTU, ASCII, TCP). It manages the data model and command registry that are common to all protocols.

The class uses the Command pattern to handle different function codes, with each function code mapped to a specific command implementation. This design allows for easy extension and modification of supported function codes.

Note

This is an abstract base class. Use the protocol-specific derived classes (ModbusRtuServer, etc.) for actual server implementation.

Subclassed by ModbusRtuServer

Public Functions

inline ModbusBaseServer()

Constructor initializes the command registry.

Registers all supported Modbus function codes with their corresponding command implementations. Currently supports:

  • FC 01: Read Coils

  • FC 02: Read Discrete Inputs

  • FC 03: Read Holding Registers

  • FC 04: Read Input Registers

  • FC 05: Write Single Coil

  • FC 06: Write Single Register

  • FC 08: Diagnostics

  • FC 15: Write Multiple Coils

  • FC 16: Write Multiple Registers

inline virtual std::vector<uint8_t> process(const std::vector<uint8_t> &requestData)

Process a Modbus request and generate a response.

This is the main entry point for request processing. Each protocol-specific derived class must implement this method to handle the protocol-specific frame formatting and validation.

Note

The base implementation returns an empty vector. Derived classes must override this method to provide actual functionality.

Parameters:

requestData โ€“ Raw request data as received from the transport layer

Returns:

Raw response data to be sent back, or empty vector if no response

Public Members

ModbusDataModel data

Modbus data model instance.

Contains all four types of Modbus data: coils, discrete inputs, holding registers, and input registers. This data model is shared across all command implementations.

std::map<ModbusFunctionCode, std::unique_ptr<ModbusCommand>> commands

Command registry mapping function codes to command implementations.

This map contains the association between Modbus function codes and their corresponding command implementations. New function codes can be supported by adding entries to this map.

class ModbusRtuServer : public ModbusBaseServer
#include <ModbusBaseServer.hpp>

Modbus RTU server implementation.

Implements the Modbus RTU (Remote Terminal Unit) protocol for serial communication. This class handles RTU-specific frame processing including:

  • CRC validation and generation

  • Slave address checking

  • Binary frame formatting

  • Exception response generation

The RTU protocol uses binary encoding and CRC-16 checksums for error detection. Frames are transmitted without start/stop delimiters, relying on timing gaps for frame synchronization.

Note

This server is configured to respond to slave address 1 by default. Broadcast messages (address 0) are processed but no response is sent.

Public Functions

virtual std::vector<uint8_t> process(const std::vector<uint8_t> &requestData)

Process an RTU request and generate an RTU response.

This method handles the complete RTU request processing pipeline:

  1. Frame validation (minimum size, CRC check)

  2. Slave address verification

  3. Function code lookup and command execution

  4. Response frame generation and CRC calculation

The method performs the following validations:

  • Minimum frame size (4 bytes: address + function + CRC)

  • CRC integrity check

  • Slave address matching (responds to address 1 only)

  • Function code support check

Exception responses are generated for:

  • Unsupported function codes

  • Invalid request parameters

  • Data access errors

Note

No response is generated for:

  • Invalid CRC

  • Wrong slave address

  • Broadcast messages (address 0)

Parameters:

requestData โ€“ Raw RTU frame data including slave address and CRC

Returns:

Complete RTU response frame, or empty vector if no response needed

๐Ÿงฎ Checksum Utilities๏ƒ

Checksum calculation utilities for Modbus protocols.

This file provides checksum calculation functions for different Modbus transport protocols. It includes implementations for:

  • CRC-16 (used by Modbus RTU)

  • LRC (Longitudinal Redundancy Check, used by Modbus ASCII)

Author

libmodbus Project

Version

1.0

Date

2024

class Checksum
#include <Checksum.hpp>

Static utility class for Modbus checksum calculations.

This class provides static methods for calculating checksums used in different Modbus transport protocols. The checksums are essential for error detection in serial communications where data corruption can occur.

Note

All methods are static and the class is not meant to be instantiated.

Public Static Functions

static uint8_t calculateLRC(const uint8_t *pucFrame, uint16_t usLen)

Calculate LRC (Longitudinal Redundancy Check) for Modbus ASCII.

Calculates the LRC checksum used by Modbus ASCII protocol. The LRC is computed by adding all bytes in the message and taking the twoโ€™s complement of the result.

Algorithm:

  1. Add all bytes in the frame (excluding the LRC itself)

  2. Take the twoโ€™s complement of the sum

  3. Return the result as a single byte

Note

The LRC is calculated over the binary representation of the ASCII characters, not the ASCII characters themselves.

Parameters:
  • pucFrame โ€“ Pointer to the frame data

  • usLen โ€“ Length of the frame data in bytes

Returns:

LRC checksum value (8-bit)

static uint16_t calculateCRC16(const uint8_t *buffer, uint16_t length)

Calculate CRC-16 checksum for Modbus RTU.

Calculates the CRC-16 checksum used by Modbus RTU protocol. This implementation uses the standard Modbus CRC-16 algorithm with polynomial 0xA001 (reversed representation of 0x8005).

Algorithm:

  1. Initialize CRC register to 0xFFFF

  2. For each byte: a. XOR byte with low byte of CRC register b. For each bit (8 iterations):

    • If LSB of CRC is 1: shift right and XOR with 0xA001

    • If LSB of CRC is 0: shift right only

  3. Return final CRC value

Note

The CRC is transmitted LSB first in RTU frames. This function returns the CRC in native byte order; the caller is responsible for proper byte ordering.

Note

This is the standard Modbus CRC-16 algorithm as specified in the Modbus over Serial Line Specification and Implementation Guide V1.02.

Parameters:
  • buffer โ€“ Pointer to the data buffer

  • length โ€“ Length of the data buffer in bytes

Returns:

CRC-16 checksum value (16-bit)

๐Ÿ”— Detailed API Sections๏ƒ