modbus-bridge
Portable no_std Modbus RTU/TCP bridge — async and blocking.
Bridges Modbus TCP clients to Modbus RTU serial devices (and vice-versa) with no
heap allocation. All internal buffers use fixed-capacity heapless collections.
Targets Embassy, esp-idf, FreeRTOS, and bare-metal environments equally.
Modes
| Mode | Direction | Use when |
|---|---|---|
| Bridge | TCP → RTU | A TCP client talks to this device; it forwards to an RTU slave |
| Client | RTU → TCP | An RTU master talks to this device; it forwards to a TCP server |
Quick Start
Add to Cargo.toml:
# Async (Embassy, smoltcp — enabled by default)
= { = "0.2" }
# Blocking (esp-idf-hal, FreeRTOS tasks, bare-metal loops)
= { = "0.2", = false, = ["sync"] }
async and sync are mutually exclusive — enable exactly one.
Bridge mode (async — Embassy)
use ;
async
Client mode (async)
use ;
let mut client = builder
.rtu
.build;
// tcp_stream connects to the upstream Modbus TCP server
let mut session = client.connect;
loop
let tcp_stream = session.into_stream;
Blocking (sync)
Compile with default-features = false, features = ["sync"]. The API is identical —
replace every .await with nothing, and omit the async executor.
use ;
let mut bridge = builder.rtu.build;
loop
Timeouts
Configure per-operation deadlines with .rtu_timeout(), .tcp_timeout(), and .delay():
let bridge = builder
.rtu
.rtu_timeout // 500 ms for RTU device response
.tcp_timeout // 5 s for incoming TCP request
.delay // embedded_hal_async::delay::DelayNs (async) or embedded_hal::delay::DelayNs (sync)
.build;
Without .delay(), timeouts are disabled regardless of the ms values.
Hardware
RS-485 TX-enable pin
If your transceiver handles direction control automatically, use NoPin:
// Shorthand
let bridge = builder.rtu_no_pin.build;
// Equivalent
let bridge = builder.rtu.build;
TCP socket buffer sizing
When allocating a TCP socket for embassy-net or smoltcp, use the exported constants:
use ;
let mut rx_buf = ; // 512 B
let mut tx_buf = ; // 512 B
Feature Flags
| Feature | Default | Description |
|---|---|---|
async |
yes | Async I/O via embedded_io_async |
sync |
no | Blocking I/O via embedded_io |
defmt |
no | Structured logging via defmt |
log |
no | Logging via the log facade |
License
Licensed under either of
at your option.