rmodbus - Modbus for Rust
A framework to build fast and reliable Modbus-powered applications.
Cargo crate: https://crates.io/crates/rmodbus
What is rmodbus
rmodbus is not a yet another Modbus client/server. rmodbus is a set of tools to quickly build Modbus-powered applications. Consider rmodbus is a request/response codec, plus context manager.
Why yet another Modbus lib?
-
rmodbus is transport- and protocol-independent
-
rmodbus is platform independent (no_std is fully supported!)
-
can be easily used in blocking and async (non-blocking) applications
-
tuned for speed and reliability
-
provides a set of tools to easily work with Modbus context
-
supports client/server frame processing for Modbus TCP/UDP, RTU and ASCII
-
server context can be easily managed, imported and exported
So no server is included?
Yes, there is no server included. You build the server by your own. You choose the transport protocol, technology and everything else. rmodbus just process frames and works with Modbus context.
Here is an example of a simple TCP blocking server:
use ;
use TcpListener;
use thread;
use lazy_static;
use RwLock;
use ;
lazy_static!
There are also examples for Serial-RTU, Serial-ASCII and UDP in examples folder (if you're reading this text somewhere else, visit rmodbus project repository.
Launch the examples as:
cargo run --example app --features std
cargo run --example tcpserver --features std
Modbus context
The rule is simple: one standard Modbus context per application. 10k+10k 16-bit registers and 10k+10k coils are usually more than enough. This takes about 43Kbytes of RAM, but if you need to reduce context size, download the library source and change CONTEXT_SIZE constant in "context.rs". There is also a "smallcontext", features, which makes context 10x more compact by reducing number of each register type and is cool for embedded apps.
rmodbus server context is thread-safe, easy to use and has a lot of functions.
The context must be protected with a mutex/rwlock and every time Modbus context is accessed, a context mutex must be locked. This slows down performance, but guarantees that the context always has valid data after bulk-sets and after writes of long data types. So make sure your application locks context only when required and only for a short period time.
A simple PLC example:
use File;
use ;
use ModbusContext;
To let the above program communicate with outer world, Modbus server must be up and running in the separate thread, asynchronously or whatever is preferred.
no_std
rmodbus supports no_std mode. Most of the library code is written the way to support both std and no_std.
Set the dependency as:
= { = "*", = ["nostd"] }
Small context
Default Modbus context has 10000 registers of each type, which requires 42500 bytes total. For systems with small RAM amount it is possible to reduce the context size to the 1000 registers of each type (4250 bytes) with the following feature:
= { = "*", = ["nostd", "smallcontext"] }
Vectors
Some of rmodbus functions use vectors to store result. In std mode, either standard std::vec::Vec or FixedVec can be used. In nostd mode, only FixedVec is supported.
Also supported:
- heapless::Vec with "heapless" feature
Modbus client
Modbus client is designed with the same principles as the server: the crate gives frame generator / processor, while the frames can be read / written with any source and with any required way.
TCP client Example:
use ;
use TcpStream;
use Duration;
use ;
Changelog
v0.6
-
guess_request_frame_len function now supports TCP (and perhaps UDP)
-
huge code refactoring, fixed and formatted for the nowadays Rust standards
-
majority of functions correctly check overflows and report errors instead of invalid values/panics
v0.5
-
Common functions and structures moved to main crate module
-
Modbus client
v0.4
-
Modbus context is no longer created automatically and no mutex guard is provided by default. Use ModbusContext::new() to create context object and then use it as you wish - protect with any kind of Mutex, with RwLock or just put into UnsafeCell.
-
Context SDK changes: all functions moved inside context, removed unnecessary ones, function args optimized.
-
FixedVec support included by default, both in std and nostd.
-
Added support for 64-bit integers