rs-modbus
A pure Rust implementation of MODBUS protocol.
Introduction
rs-modbus is designed as a layered architecture, including the physical layer and the application layer:
- Physical layer implements Serial Port, TCP/IP and UDP/IP.
- Application layer implements RTU, ASCII and TCP.
rs-modbus provide both client and server.
Features
- Full Modbus standard protocol implementation
- Support for custom function codes
- Support broadcasting
- Very lightweight project
- Full async/await support via tokio
Supported function codes
| Code | Name |
|---|---|
| 01 | Read Coils |
| 02 | Read Discrete Inputs |
| 03 | Read Holding Registers |
| 04 | Read Input Registers |
| 05 | Write Single Coil |
| 06 | Write Single Register |
| 15 | Write Multiple Coils |
| 16 | Write Multiple Registers |
| 17 | Report Server ID |
| 22 | Mask Write Register |
| 23 | Read/Write Multiple Registers |
| 43/14 | Read Device Identification |
Supported protocols
- Modbus RTU
- Modbus ASCII
- Modbus TCP/IP
- Modbus UDP/IP
- Modbus RTU/ASCII Over TCP/IP
- Modbus RTU/ASCII Over UDP/IP
Installation
Add this to your Cargo.toml:
[]
= "2.0"
For serial port support, enable the serial feature:
[]
= { = "2.0", = ["serial"] }
Examples
Modbus TCP Master
use TcpApplicationLayer;
use TcpClientPhysicalLayer;
use ;
async
Modbus TCP Slave
use TcpApplicationLayer;
use TcpServerPhysicalLayer;
use ;
use AddressRange;
use async_trait;
use Arc;
;
async
Broadcasts (unit = 0)
Slaves never respond to broadcast requests, so the master's write methods with unit = 0
return as soon as the bytes are flushed to the wire.
If you broadcast over serial (RTU or ASCII), per Modbus over Serial Line V1.02 §2.4.1 you must wait a turnaround delay before sending the next request — slow slaves need time to apply the broadcast write that produced no response. The library does not insert this delay automatically because the right value is workload-specific (fast sensors vs. PLCs writing to flash differ by orders of magnitude). Insert it yourself at the call site:
master.write_single_register.await?; // broadcast
sleep.await; // turnaround — tune per devices
master.write_single_register.await?; // unicast to next slave
A safe lower bound is the RTU t3.5 inter-frame silence (e.g. ~4 ms at 9600 baud, ~1.75 ms above 19200 baud). Many real-world PLCs need 50–100 ms after a broadcast write. Modbus TCP/UDP do not require this delay (TCP gives synchronous acks; broadcasting on TCP is uncommon anyway).
Related Projects
- njs-modbus — The Node.js/TypeScript reference implementation that
rs-modbusmirrors in layer architecture and protocol semantics.