Modbus
Modbus is an industrial messaging protocol. The protocol is specified for different types of networks or buses. Zephyr OS implementation supports communication over serial line and may be used with different physical interfaces, like RS485 or RS232. TCP support is not implemented directly, but there are helper functions to realize TCP support according to the application’s needs.
Modbus communication is based on client/server model. Only one client may be present on the bus. Client can communicate with several server devices. Server devices themselves are passive and must not send requests or unsolicited responses. Services requested by the client are specified by function codes (FCxx), and can be found in the specification or documentation of the API below.
Zephyr RTOS implementation supports both client and server roles.
More information about Modbus and Modbus RTU can be found on the website MODBUS Protocol Specifications.
Samples
Modbus RTU server and Modbus RTU client samples give the possibility to try out RTU server and RTU client implementation with an evaluation board.
Modbus TCP server sample is a simple Modbus TCP server.
Modbus TCP-to-serial gateway sample shows how to build a TCP to serial line gateway with Zephyr OS.
API Reference
- group modbus
MODBUS transport protocol API.
Modbus exception codes
-
MODBUS_EXC_NONE
No exception.
-
MODBUS_EXC_ILLEGAL_FC
Illegal function code.
-
MODBUS_EXC_ILLEGAL_DATA_ADDR
Illegal data address.
-
MODBUS_EXC_ILLEGAL_DATA_VAL
Illegal data value.
-
MODBUS_EXC_SERVER_DEVICE_FAILURE
Server device failure.
-
MODBUS_EXC_ACK
Acknowledge.
-
MODBUS_EXC_SERVER_DEVICE_BUSY
Server device busy.
-
MODBUS_EXC_MEM_PARITY_ERROR
Memory parity error.
-
MODBUS_EXC_GW_PATH_UNAVAILABLE
Gateway path unavailable.
-
MODBUS_EXC_GW_TARGET_FAILED_TO_RESP
Gateway target device failed to respond.
Defines
-
MODBUS_MBAP_LENGTH
Length of MBAP Header.
-
MODBUS_MBAP_AND_FC_LENGTH
Length of MBAP Header plus function code.
-
MODBUS_CUSTOM_FC_DEFINE(name, user_cb, user_fc, userdata)
INTERNAL_HIDDEN.
Helper macro for initializing custom function code structs
Typedefs
-
typedef int (*modbus_raw_cb_t)(const int iface, const struct modbus_adu *adu, void *user_data)
ADU raw callback function signature.
- Param iface:
Modbus RTU interface index
- Param adu:
Pointer to the RAW ADU struct to send
- Param user_data:
Pointer to the user data
- Retval 0:
If transfer was successful
-
typedef bool (*modbus_custom_cb_t)(const int iface, const struct modbus_adu *const rx_adu, struct modbus_adu *const tx_adu, uint8_t *const excep_code, void *const user_data)
Custom function code handler function signature.
Modbus allows user defined function codes which can be used to extend the base protocol. These callbacks can also be used to implement function codes currently not supported by Zephyr’s Modbus subsystem.
If an error occurs during the handling of the request, the handler should signal this by setting excep_code to a modbus exception code.
User data pointer can be used to pass state between subsequent calls to the handler.
- Param iface:
Modbus interface index
- Param rx_adu:
Pointer to the received ADU struct
- Param tx_adu:
Pointer to the outgoing ADU struct
- Param excep_code:
Pointer to possible exception code
- Param user_data:
Pointer to user data
- Retval true:
If response should be sent, false otherwise
Enums
Functions
-
int modbus_read_coils(const int iface, const uint8_t unit_id, const uint16_t start_addr, uint8_t *const coil_tbl, const uint16_t num_coils)
Coil read (FC01)
Sends a Modbus message to read the status of coils from a server.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Coil starting address
coil_tbl – Pointer to an array of bytes containing the value of the coils read. The format is:
Note that the array that will be receiving the coil values must be greater than or equal to: (num_coils - 1) / 8 + 1MSB LSB B7 B6 B5 B4 B3 B2 B1 B0 ------------------------------------- coil_tbl[0] #8 #7 #1 coil_tbl[1] #16 #15 #9 : :
num_coils – Quantity of coils to read
- Return values:
0 – If the function was successful
-
int modbus_read_dinputs(const int iface, const uint8_t unit_id, const uint16_t start_addr, uint8_t *const di_tbl, const uint16_t num_di)
Read discrete inputs (FC02)
Sends a Modbus message to read the status of discrete inputs from a server.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Discrete input starting address
di_tbl – Pointer to an array that will receive the state of the discrete inputs. The format of the array is as follows:
Note that the array that will be receiving the discrete input values must be greater than or equal to: (num_di - 1) / 8 + 1MSB LSB B7 B6 B5 B4 B3 B2 B1 B0 ------------------------------------- di_tbl[0] #8 #7 #1 di_tbl[1] #16 #15 #9 : :
num_di – Quantity of discrete inputs to read
- Return values:
0 – If the function was successful
-
int modbus_read_holding_regs(const int iface, const uint8_t unit_id, const uint16_t start_addr, uint16_t *const reg_buf, const uint16_t num_regs)
Read holding registers (FC03)
Sends a Modbus message to read the value of holding registers from a server.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Register starting address
reg_buf – Is a pointer to an array that will receive the current values of the holding registers from the server. The array pointed to by ‘reg_buf’ needs to be able to hold at least ‘num_regs’ entries.
num_regs – Quantity of registers to read
- Return values:
0 – If the function was successful
-
int modbus_read_input_regs(const int iface, const uint8_t unit_id, const uint16_t start_addr, uint16_t *const reg_buf, const uint16_t num_regs)
Read input registers (FC04)
Sends a Modbus message to read the value of input registers from a server.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Register starting address
reg_buf – Is a pointer to an array that will receive the current value of the holding registers from the server. The array pointed to by ‘reg_buf’ needs to be able to hold at least ‘num_regs’ entries.
num_regs – Quantity of registers to read
- Return values:
0 – If the function was successful
-
int modbus_write_coil(const int iface, const uint8_t unit_id, const uint16_t coil_addr, const bool coil_state)
Write single coil (FC05)
Sends a Modbus message to write the value of single coil to a server.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
coil_addr – Coils starting address
coil_state – Is the desired state of the coil
- Return values:
0 – If the function was successful
-
int modbus_write_holding_reg(const int iface, const uint8_t unit_id, const uint16_t start_addr, const uint16_t reg_val)
Write single holding register (FC06)
Sends a Modbus message to write the value of single holding register to a server unit.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Coils starting address
reg_val – Desired value of the holding register
- Return values:
0 – If the function was successful
-
int modbus_request_diagnostic(const int iface, const uint8_t unit_id, const uint16_t sfunc, const uint16_t data, uint16_t *const data_out)
Read diagnostic (FC08)
Sends a Modbus message to perform a diagnostic function of a server unit.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
sfunc – Diagnostic sub-function code
data – Sub-function data
data_out – Pointer to the data value
- Return values:
0 – If the function was successful
-
int modbus_write_coils(const int iface, const uint8_t unit_id, const uint16_t start_addr, uint8_t *const coil_tbl, const uint16_t num_coils)
Write coils (FC15)
Sends a Modbus message to write to coils on a server unit.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Coils starting address
coil_tbl – Pointer to an array of bytes containing the value of the coils to write. The format is:
Note that the array that will be receiving the coil values must be greater than or equal to: (num_coils - 1) / 8 + 1MSB LSB B7 B6 B5 B4 B3 B2 B1 B0 ------------------------------------- coil_tbl[0] #8 #7 #1 coil_tbl[1] #16 #15 #9 : :
num_coils – Quantity of coils to write
- Return values:
0 – If the function was successful
-
int modbus_write_holding_regs(const int iface, const uint8_t unit_id, const uint16_t start_addr, uint16_t *const reg_buf, const uint16_t num_regs)
Write holding registers (FC16)
Sends a Modbus message to write to integer holding registers to a server unit.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Register starting address
reg_buf – Is a pointer to an array containing the value of the holding registers to write. Note that the array containing the register values must be greater than or equal to ‘num_regs’
num_regs – Quantity of registers to write
- Return values:
0 – If the function was successful
-
int modbus_read_holding_regs_fp(const int iface, const uint8_t unit_id, const uint16_t start_addr, float *const reg_buf, const uint16_t num_regs)
Read floating-point holding registers (FC03)
Sends a Modbus message to read the value of floating-point holding registers from a server unit.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Register starting address
reg_buf – Is a pointer to an array that will receive the current values of the holding registers from the server. The array pointed to by ‘reg_buf’ needs to be able to hold at least ‘num_regs’ entries.
num_regs – Quantity of registers to read
- Return values:
0 – If the function was successful
-
int modbus_write_holding_regs_fp(const int iface, const uint8_t unit_id, const uint16_t start_addr, float *const reg_buf, const uint16_t num_regs)
Write floating-point holding registers (FC16)
Sends a Modbus message to write to floating-point holding registers to a server unit.
- Parameters:
iface – Modbus interface index
unit_id – Modbus unit ID of the server
start_addr – Register starting address
reg_buf – Is a pointer to an array containing the value of the holding registers to write. Note that the array containing the register values must be greater than or equal to ‘num_regs’
num_regs – Quantity of registers to write
- Return values:
0 – If the function was successful
-
int modbus_iface_get_by_name(const char *iface_name)
Get Modbus interface index according to interface name.
If there is more than one interface, it can be used to clearly identify interfaces in the application.
- Parameters:
iface_name – Modbus interface name
- Return values:
Modbus – interface index or negative error value.
-
int modbus_init_server(const int iface, struct modbus_iface_param param)
Configure Modbus Interface as raw ADU server.
- Parameters:
iface – Modbus RTU interface index
param – Configuration parameter of the server interface
- Return values:
0 – If the function was successful
-
int modbus_init_client(const int iface, struct modbus_iface_param param)
Configure Modbus Interface as raw ADU client.
- Parameters:
iface – Modbus RTU interface index
param – Configuration parameter of the client interface
- Return values:
0 – If the function was successful
-
int modbus_disable(const uint8_t iface)
Disable Modbus Interface.
This function is called to disable Modbus interface.
- Parameters:
iface – Modbus interface index
- Return values:
0 – If the function was successful
-
int modbus_raw_submit_rx(const int iface, const struct modbus_adu *adu)
Submit raw ADU.
- Parameters:
iface – Modbus RTU interface index
adu – Pointer to the RAW ADU struct that is received
- Return values:
0 – If transfer was successful
-
void modbus_raw_put_header(const struct modbus_adu *adu, uint8_t *header)
Put MBAP header into a buffer.
- Parameters:
adu – Pointer to the RAW ADU struct
header – Pointer to the buffer in which MBAP header will be placed.
-
void modbus_raw_get_header(struct modbus_adu *adu, const uint8_t *header)
Get MBAP header from a buffer.
- Parameters:
adu – Pointer to the RAW ADU struct
header – Pointer to the buffer containing MBAP header
-
void modbus_raw_set_server_failure(struct modbus_adu *adu)
Set Server Device Failure exception.
This function modifies ADU passed by the pointer.
- Parameters:
adu – Pointer to the RAW ADU struct
-
int modbus_raw_backend_txn(const int iface, struct modbus_adu *adu)
Use interface as backend to send and receive ADU.
This function overwrites ADU passed by the pointer and generates exception responses if backend interface is misconfigured or target device is unreachable.
- Parameters:
iface – Modbus client interface index
adu – Pointer to the RAW ADU struct
- Return values:
0 – If transfer was successful
-
int modbus_register_user_fc(const int iface, struct modbus_custom_fc *custom_fc)
Register a user-defined function code handler.
The Modbus specification allows users to define standard function codes missing from Zephyr’s Modbus implementation as well as add non-standard function codes in the ranges 65 to 72 and 100 to 110 (decimal), as per specification.
This function registers a new handler at runtime for the given function code.
- Parameters:
iface – Modbus client interface index
custom_fc – User defined function code and callback pair
- Return values:
0 – on success
-
struct modbus_adu
- #include <modbus.h>
Frame struct used internally and for raw ADU support.
Public Members
-
uint16_t trans_id
Transaction Identifier.
-
uint16_t proto_id
Protocol Identifier.
-
uint16_t length
Length of the data only (not the length of unit ID + PDU)
-
uint8_t unit_id
Unit Identifier.
-
uint8_t fc
Function Code.
-
uint8_t data[CONFIG_MODBUS_BUFFER_SIZE - 4]
Transaction Data.
-
uint16_t crc
RTU CRC.
-
uint16_t trans_id
-
struct modbus_user_callbacks
- #include <modbus.h>
Modbus Server User Callback structure.
Public Members
-
int (*coil_rd)(uint16_t addr, bool *state)
Coil read callback.
-
int (*coil_wr)(uint16_t addr, bool state)
Coil write callback.
-
int (*discrete_input_rd)(uint16_t addr, bool *state)
Discrete Input read callback.
-
int (*input_reg_rd)(uint16_t addr, uint16_t *reg)
Input Register read callback.
-
int (*input_reg_rd_fp)(uint16_t addr, float *reg)
Floating Point Input Register read callback.
-
int (*holding_reg_rd)(uint16_t addr, uint16_t *reg)
Holding Register read callback.
-
int (*holding_reg_wr)(uint16_t addr, uint16_t reg)
Holding Register write callback.
-
int (*holding_reg_rd_fp)(uint16_t addr, float *reg)
Floating Point Holding Register read callback.
-
int (*holding_reg_wr_fp)(uint16_t addr, float reg)
Floating Point Holding Register write callback.
-
int (*coil_rd)(uint16_t addr, bool *state)
-
struct modbus_serial_param
- #include <modbus.h>
Modbus serial line parameter.
Public Members
-
uint32_t baud
Baudrate of the serial line.
-
enum uart_config_parity parity
parity UART’s parity setting: UART_CFG_PARITY_NONE, UART_CFG_PARITY_EVEN, UART_CFG_PARITY_ODD
-
enum uart_config_stop_bits stop_bits_client
stop_bits_client UART’s stop bits setting if in client mode: UART_CFG_STOP_BITS_0_5, UART_CFG_STOP_BITS_1, UART_CFG_STOP_BITS_1_5, UART_CFG_STOP_BITS_2,
-
uint32_t baud
-
struct modbus_server_param
- #include <modbus.h>
Modbus server parameter.
Public Members
-
struct modbus_user_callbacks *user_cb
Pointer to the User Callback structure.
-
uint8_t unit_id
Modbus unit ID of the server.
-
struct modbus_user_callbacks *user_cb
-
struct modbus_raw_cb
- #include <modbus.h>
-
struct modbus_iface_param
- #include <modbus.h>
User parameter structure to configure Modbus interface as client or server.
Public Members
-
enum modbus_mode mode
Mode of the interface.
-
uint32_t rx_timeout
Amount of time client will wait for a response from the server.
-
struct modbus_serial_param serial
Serial support parameter of the interface.
-
struct modbus_raw_cb rawcb
Pointer to raw ADU callback function.
-
enum modbus_mode mode
-
MODBUS_EXC_NONE