Agile Modbus
1.1.4
Lightweight modbus protocol stack.
|
Agile Modbus is a lightweight modbus protocol stack that meets the needs of users in any scenario.
examples
folder provides examples on PCName | Description |
---|---|
doc | documentation |
examples | examples |
figures | materials |
inc | header file |
src | source code |
util | Provides simple and practical components |
Agile Modbus complies with the Apache-2.0
license, see the LICENSE
file for details.
Please view the help document doc/doxygen/Agile_Modbus.chm
Users need to implement the send data
, wait for data reception to end
and clear the receive buffer
functions of the hardware interface
Regarding waiting for data reception to end
, the following ideas are provided:
General method
Every 20 /50 ms (this time can be set according to the baud rate and hardware, here is just a reference value) reads data from the hardware interface and stores it in the buffer and updates the offset until it cannot be read or the buffer is full. , exit reading.
This applies to both bare metal and operating systems, which can accomplish blocking via select
or semaphore
.
Serial port DMA + IDLE
interrupt mode
Configure the DMA + IDLE
interrupt, enable the flag in the interrupt, and determine whether the flag is set in the application program.
However, this solution is prone to problems. If the data bytes are slightly staggered, it will not be a frame. The first option is recommended.
agile_modbus_rtu_init
/ agile_modbus_tcp_init
initializes RTU/TCP
environmentagile_modbus_set_slave
sets the slave addressClear the receive cache
agile_modbus_serialize_xxx
package request dataSend data
Waiting for data reception to end
agile_modbus_deserialize_xxx
Parse response dataagile_modbus_slave_callback_t
type callback functionagile_modbus_rtu_init
/ agile_modbus_tcp_init
initializes RTU/TCP
environmentagile_modbus_set_slave
sets the slave addressWaiting for data reception to end
agile_modbus_slave_handle
processes request dataClear the receive buffer
(optional)Send data
Special function code
You need to call the agile_modbus_set_compute_meta_length_after_function_cb
and agile_modbus_set_compute_data_length_after_meta_cb
APIs to set the callbacks for special function codes to be processed in master-slave mode.
agile_modbus_set_compute_meta_length_after_function_cb
msg_type == AGILE_MODBUS_MSG_INDICATION
: Returns the data element length of the host request message (uint8_t type). If it is not a special function code, 0 must be returned.
msg_type == MSG_CONFIRMATION
: Returns the data element length (uint8_t type) of the slave response message. If it is not a special function code, 1 must be returned.
agile_modbus_set_compute_data_length_after_meta_cb
msg_type == AGILE_MODBUS_MSG_INDICATION
: Returns the data length after the data element of the host request message. If it is not a special function code, 0 must be returned.
msg_type == MSG_CONFIRMATION
: Returns the data length after the data element of the slave response message. If it is not a special function code, it must return 0.
agile_modbus_rtu_init
/ agile_modbus_tcp_init
When initializing the RTU/TCP
environment, the user needs to pass in the send buffer
and receive buffer
. It is recommended that the size of both buffers is AGILE_MODBUS_MAX_ADU_LENGTH
(260) bytes. Special function code
is determined by the user according to the agreement.
But for small memory MCUs, these two buffers can also be set small, and all APIs will judge the buffer size:
Send buffer setting: If expected request data length
or expected response data length
is greater than set send buffer size
, an exception is returned.
Receive buffer setting: If the message length requested by the host
is greater than the set receive buffer size
, an exception will be returned. This is reasonable. When a small memory MCU is used as a slave, certain function codes must be restricted.
See 2.1. Transplantation
.
agile_modbus_slave_handle
msg_length: The length of data received after waiting for the end of data reception
.
slave_strict: slave address strictness check (0: Do not judge whether the address is consistent, it will be processed by user callback; 1: The address must be consistent, otherwise the callback will not be called and the response data will not be packaged).
slave_cb: agile_modbus_slave_callback_t
type callback function, implemented and passed in by the user. If it is NULL, all function codes can respond and are successful, but the register data is still 0.
slave_data: slave callback function private data.
frame_length: Get the length of the parsed modbus data frame. The meaning of this parameter is:
clear receive cache
Introduction to agile_modbus_slave_callback_t
sft: Contains slave address and function code attributes, which can be used in callbacks
rsp_length: response data length pointer, its value needs to be updated when processing special function code
in the callback, otherwise not allowed to change
address: register address (not used by all function codes)
nb: number (not used by all function codes)
buf: data field required by different function codes (not used by all function codes)
send_index: the current index of the send buffer (not used by all function codes)
agile_modbus_slave_info
used by different function codesAGILE_MODBUS_FC_READ_COILS、AGILE_MODBUS_FC_READ_DISCRETE_INPUTS
The address
, nb
, and send_index
attributes need to be used, and the agile_modbus_slave_io_set
API needs to be called to store the IO data in the data area starting from ctx->send_buf + send_index
.
AGILE_MODBUS_FC_READ_HOLDING_REGISTERS、AGILE_MODBUS_FC_READ_INPUT_REGISTERS
The address
, nb
, and send_index
attributes need to be used, and the agile_modbus_slave_register_set
API needs to be called to store the register data in the data area starting from ctx->send_buf + send_index
.
AGILE_MODBUS_FC_WRITE_SINGLE_COIL、AGILE_MODBUS_FC_WRITE_SINGLE_REGISTER
You need to use the address
and buf
attributes, force buf
to the int *
type, and get the value and store it in a register.
AGILE_MODBUS_FC_WRITE_MULTIPLE_COILS
The address
, nb
, buf
attributes need to be used, and the agile_modbus_slave_io_get
API needs to be called to obtain the IO data to be written.
AGILE_MODBUS_FC_WRITE_MULTIPLE_REGISTERS
The address
, nb
, and buf
attributes need to be used, and the agile_modbus_slave_register_get
API needs to be called to obtain the register data to be written.
AGILE_MODBUS_FC_MASK_WRITE_REGISTER
You need to use the address
and buf
attributes, pass (buf[0] << 8) + buf[1]
to get the and
value, pass (buf[2] << 8) + buf[3 ]
Gets the or
value. Get the register value data
, perform the data = (data & and) | (or & (~and))
operation to update the data
value, and write it to the register.
AGILE_MODBUS_FC_WRITE_AND_READ_REGISTERS
You need to use the address
, buf
, send_index
attributes, pass (buf[0] << 8) + buf[1]
to get the number of registers to be read, pass (buf[2] << 8) + buf[3]
Get the register address to be written, and use (buf[4] << 8) + buf[5]
to get the number of registers to be written. You need to call the agile_modbus_slave_register_get
API to obtain the register data to be written, and call the agile_modbus_slave_register_set
API to store the register data in the data area starting from ctx->send_buf + send_index
.
Custom function code
You need to use the send_index
, nb
, and buf
attributes, and the user processes the data in the callback.
send_index: current index of send buffer
nb: PUD - 1, which is the modbus data field length
buf: starting position of modbus data field
Note: After the user fills data into the send buffer in the callback, the rsp_length
value of agile_modbus_slave_info
needs to be updated.
Agile Modbus provides an implementation of agile_modbus_slave_callback_t
, allowing users to access it simply and conveniently.
See examples/slave for examples of usage.
How to use:
agile_modbus_slave_util_callback
agile_modbus_slave_callback_t
provided by Agile Modbus, which requires agile_modbus_slave_util_t
type variable pointer as private data.agile_modbus_slave_util_t
Register related
Users need to implement the definitions of bits
, input_bits
, registers
and input_registers
. If a register is defined as NULL, the function code corresponding to the register can respond and is successful, but the register data is all 0.
Interface calling process
Introduction to agile_modbus_slave_util_map
map_buf
array inside the function can make it larger.get
interface
Copy all data in the address field to buf
.
set
interface
index
: offset within the address fieldlen
: lengthModify data based on index
and len
.
WSL
or Linux
.Examples of special function codes
RTU point-to-point transmission of files: Demonstrates the use of special function codes
RTU broadcast transmission file: Demonstrates the use of frame_length
in agile_modbus_slave_handle
Doxywizard
to open Doxyfile and run it. The generated file will be under doxygen/output.Graphviz
path needs to be changed.HTML
is generated without using chm
format. If it is enabled, you need to change the hhc.exe
path.If Agile Modbus solves your problem, you might as well scan the QR code above and invite me for a cup of coffee ~