Expand description
Commercial library by Step Function I/O
A high-performance implementation of the Modbus protocol using Tokio and Rust’s async/await syntax.
§Features
- Panic-free parsing
- Correctness and compliance to the specification
- Built-in logging and protocol decoding
- Automatic connection management with configurable reconnect strategy
- Scalable performance using Tokio’s multi-threaded executor
- TLS is implemented using rustls not openssl
- Model-generated bindings for C, C++, Java, and .NET Core
- Runs on all platforms and operating systems supported by the Tokio runtime:
- Official support for: Windows x64 and Linux x64, AArch64, ARMv7 and ARMv6
- Unofficial support: MacOS, PowerPC, MIPS, FreeBSD, and others
§Supported Modes
- TCP, RTU (serial), and Modbus security (TLS) with and without X.509 extension containing the user role.
- Client and server
§Function Codes
The client and server examples demonstrate simple
usage of the API.
The following function codes are supported:
- Read Coils (
0x01) - Read Discrete Inputs (
0x02) - Read Holding Registers (
0x03) - Read Input Registers (
0x04) - Write Single Coil (
0x05) - Write Single Register (
0x06) - Write Multiple Coils (
0x0F) - Write Multiple Registers (
0x10)
§License
This library is publicly available under a non-commercial / non-production license.
Refer to LICENSE.txt for the terms
of this non-commercial license.
This software is publicly available, but is not “open source”. You must purchase a commercial license to use this software for profit.
Please inquire about commercial licensing on our website:
§Cargo Features
Default features can be disabled at compile time:
tls- Build the library with support for TLS (secure Modbus)serial- Build the library with support for Modbus RTU and serial ports
§Bindings
Bindings in C, C++, java, and .NET Core are available for this library. See the documentation for more details.
§Example Client
A simple client application that periodically polls for some Coils
use rodbus::*;
use rodbus::client::*;
use std::net::SocketAddr;
use std::time::Duration;
use std::str::FromStr;
#[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut channel = spawn_tcp_client_task(
HostAddr::ip("127.0.0.1".parse()?, 502),
10,
default_retry_strategy(),
DecodeLevel::default(),
None
);
channel.enable().await?;
let param = RequestParam::new(
UnitId::new(0x02),
Duration::from_secs(1),
);
// try to poll for some coils every 3 seconds
loop {
match channel.read_coils(param, AddressRange::try_from(0, 5).unwrap()).await {
Ok(values) => {
for x in values {
println!("index: {} value: {}", x.index, x.value)
}
}
Err(err) => println!("Error: {:?}", err)
}
tokio::time::sleep(std::time::Duration::from_secs(3)).await
}
}§Example Server
use rodbus::*;
use rodbus::server::*;
use std::net::SocketAddr;
use std::str::FromStr;
use tokio::net::TcpListener;
struct CoilsOnlyHandler {
pub coils: [bool; 10]
}
impl CoilsOnlyHandler {
fn new() -> Self {
Self {
coils: [false; 10]
}
}
}
impl RequestHandler for CoilsOnlyHandler {
fn read_coil(&self, address: u16) -> Result<bool, ExceptionCode> {
self.coils.get(0).to_result()
}
}
#[tokio::main(flavor = "multi_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let handler = CoilsOnlyHandler::new().wrap();
// map unit ids to a handler for processing requests
let map = ServerHandlerMap::single(UnitId::new(1), handler.clone());
// spawn a server to handle connections onto its own task
// if the handle _server is dropped, the server shuts down
let _server = rodbus::server::spawn_tcp_server_task(
1,
SocketAddr::from_str("127.0.0.1:502")?,
map,
AddressFilter::Any,
DecodeLevel::default(),
).await?;
let mut next = tokio::time::Instant::now();
// toggle all coils every couple of seconds
loop {
next += tokio::time::Duration::from_secs(2);
{
let mut guard = handler.lock().unwrap();
for c in &mut guard.coils {
*c = !*c;
}
}
tokio::time::sleep_until(next).await;
}
}Modules§
Structs§
- Address
Range - Start and count tuple used when making various requests Cannot be constructed with invalid start/count
- BitIterator
- Zero-copy type used to iterate over a collection of bits
- Decode
Level - Controls the decoding of transmitted and received data at the application, frame, and physical layer
- Indexed
- Value and its address
- Maybe
Async - Represents a result that may be computed synchronously or asynchronously by user code.
- Register
Iterator - Zero-copy type used to iterate over a collection of registers
- Serial
Settings - Serial port settings
- Shutdown
- The task processing requests has terminated
- UnitId
- Modbus unit identifier, just a type-safe wrapper around
u8
Enums§
- AduParse
Error - Errors that occur while parsing requests and responses
- AppDecode
Level - Controls how transmitted and received message at the application layer are decoded at the INFO log level
- Data
Bits - Number of bits per character
- Exception
Code - Exception codes defined in the Modbus specification
- Flow
Control - Flow control modes
- Frame
Decode Level - Controls how the transmitted and received frames are decoded at the INFO log level
- Frame
Parse Error - Errors that occur while parsing a frame off a stream (TCP or serial)
- Internal
Error - Errors that indicate faulty logic in the library itself if they occur
- Invalid
Range - Errors that can be produced when validating start/count
- Invalid
Request - Errors that result because of bad request parameter
- Parity
- Parity checking modes
- Phys
Decode Level - Controls how data transmitted at the physical layer (TCP, serial, etc) is logged
- Request
Error - Top level error type for the client API
- Stop
Bits - Number of stop bits
Constants§
- VERSION
- Current version of the library
Traits§
- Retry
Strategy - Trait that controls how the channel retries failed connect (TCP/TLS) or open (serial) attempts
Functions§
- default_
retry_ strategy - Return the default
RetryStrategy - doubling_
retry_ strategy - Return a
RetryStrategythat doubles on failure up to a maximum value