Overview๏
libmodbus is a comprehensive C++ implementation of the Modbus protocol that provides a clean, modern interface for building Modbus servers and clients. This library supports multiple transport protocols and maintains full compliance with Modbus specifications.
๐ What is Modbus?๏
Modbus is a serial communication protocol developed in 1979 for use with programmable logic controllers (PLCs). It has become a de facto standard communication protocol for industrial electronic devices and is widely used in industrial automation systems.
Key characteristics of Modbus:
Simple: Easy to implement and understand
Reliable: Robust error detection and handling
Widely Supported: Available on many industrial devices
Open Standard: Freely available specification
๐๏ธ Library Architecture๏
The libmodbus library is designed using modern C++ principles and patterns:
Component Overview๏
-
class ModbusDataModel
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
-
class ModbusBaseServer
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.
-
inline ModbusBaseServer()
Data Model๏
The library implements the four standard Modbus data types:
Coils (Read/Write Discrete Outputs) - Boolean values that can be read and written - Typically control physical outputs like relays or indicators - Standard limit: 2000 coils
Discrete Inputs (Read-Only Discrete Inputs) - Boolean values that can only be read - Typically represent physical input states like switch positions - Standard limit: 2000 discrete inputs
Holding Registers (Read/Write 16-bit Registers) - 16-bit values that can be read and written - Store configuration parameters, setpoints, or other control data - Standard limit: 125 registers
Input Registers (Read-Only 16-bit Registers) - 16-bit values that can only be read - Typically contain measured values like temperature or pressure - Standard limit: 125 registers
๐ Supported Protocols๏
RTU (Remote Terminal Unit)๏
-
class ModbusRtuServer : public ModbusBaseServer
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:
Frame validation (minimum size, CRC check)
Slave address verification
Function code lookup and command execution
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
RTU is the most common Modbus variant for serial communication:
Binary encoding for compact transmission
CRC-16 error detection for data integrity
Variable frame length based on function code
No frame delimiters - relies on timing gaps
Frame Structure:
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ Slave Addr โ Function โ Data โ CRC Check โ
โ (1 byte) โ Code (1 byte)โ (0-252 bytes)โ (2 bytes) โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโ
ASCII (Planned)๏
ASCII variant uses hexadecimal character encoding:
Human-readable transmission format
LRC error detection (Longitudinal Redundancy Check)
Start/end delimiters (: and CRLF)
Longer frames due to character encoding
TCP (Planned)๏
TCP variant for Ethernet networks:
MBAP header for transaction management
No checksum needed (TCP provides reliability)
Connection-oriented communication
โ๏ธ Function Codes๏
The library implements all standard Modbus function codes:
Read Functions๏
-
class ReadCoilCommand : public ModbusCommand
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
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 ReadHoldingRegisterCommand : public ModbusCommand
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 ReadInputRegisterCommand : public ModbusCommand
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
Write Functions๏
-
class WriteCoilCommand : public ModbusCommand
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
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
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
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
Diagnostic Functions๏
-
class DiagnosticsCommand : public ModbusCommand
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
๐ง Frame Processing๏
Frame Types๏
-
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.
-
enumerator NONE
-
class ModbusFrame
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
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.
-
inline ModbusRtuFrame()
๐ก๏ธ Error Handling๏
Exception Codes๏
-
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.
-
enumerator NONE
The library provides comprehensive error handling through exception responses:
Validation: All requests are validated for proper format and ranges
Address Checking: Ensures addresses are within valid ranges
Quantity Limits: Enforces Modbus specification limits
CRC Verification: Validates frame integrity for RTU protocol
๐งฎ Checksum Utilities๏
-
class Checksum
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:
Add all bytes in the frame (excluding the LRC itself)
Take the twoโs complement of the sum
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:
Initialize CRC register to 0xFFFF
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
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)
-
static uint8_t calculateLRC(const uint8_t *pucFrame, uint16_t usLen)
The library includes robust checksum implementations:
CRC-16: Standard Modbus CRC using polynomial 0xA001
LRC: Longitudinal Redundancy Check for ASCII protocol
๐ Standards Compliance๏
This implementation is fully compliant with:
Modbus Application Protocol Specification V1.1b3
Modbus over Serial Line Specification and Implementation Guide V1.02
Modbus Messaging on TCP/IP Implementation Guide V1.0b (planned)
Compliance features:
Correct function code implementations
Proper exception handling
Standard quantity limits
Accurate checksum calculations
Frame format compliance
๐ Performance Features๏
Vector-based storage for efficient data access
RAII principles for automatic resource management
Move semantics for efficient data transfer
Template-based design for compile-time optimization
Minimal memory overhead with configurable limits
๐ง Extensibility๏
The library is designed for easy extension:
Command Pattern: Easy to add new function codes
Virtual interfaces: Simple to add new transport protocols
Configurable limits: Adaptable to different applications
Modular design: Components can be used independently