rs_modbus/lib.rs
1//! A pure Rust implementation of MODBUS protocol.
2//!
3//! `rs-modbus` is designed as a layered architecture, including the physical layer
4//! and the application layer:
5//!
6//! - **Physical layer** implements Serial Port, TCP/IP and UDP/IP.
7//! - **Application layer** implements RTU, ASCII and TCP.
8//!
9//! Both client (master) and server (slave) are provided.
10//!
11//! ## Features
12//!
13//! - Full Modbus standard protocol implementation
14//! - Support for custom function codes
15//! - Support broadcasting
16//! - Very lightweight project
17//!
18//! ### Supported function codes
19//!
20//! | Code | Name |
21//! | ----- | ------------------------------ |
22//! | 01 | Read Coils |
23//! | 02 | Read Discrete Inputs |
24//! | 03 | Read Holding Registers |
25//! | 04 | Read Input Registers |
26//! | 05 | Write Single Coil |
27//! | 06 | Write Single Register |
28//! | 15 | Write Multiple Coils |
29//! | 16 | Write Multiple Registers |
30//! | 17 | Report Server ID |
31//! | 22 | Mask Write Register |
32//! | 23 | Read/Write Multiple Registers |
33//! | 43/14 | Read Device Identification |
34//!
35//! ### Supported protocols
36//!
37//! - Modbus RTU
38//! - Modbus ASCII
39//! - Modbus TCP/IP
40//! - Modbus UDP/IP
41//! - Modbus RTU/ASCII Over TCP/IP
42//! - Modbus RTU/ASCII Over UDP/IP
43//!
44//! ## Examples
45//!
46//! ### Modbus TCP Master
47//!
48//! ```no_run
49//! use rs_modbus::layers::application::TcpApplicationLayer;
50//! use rs_modbus::layers::physical::TcpClientPhysicalLayer;
51//! use rs_modbus::master::{ModbusMaster, ModbusMasterOptions};
52//!
53//! #[tokio::main]
54//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
55//! let physical = TcpClientPhysicalLayer::new();
56//! let application = TcpApplicationLayer::new(physical.clone());
57//! let master = ModbusMaster::new(
58//! application,
59//! physical,
60//! ModbusMasterOptions {
61//! timeout_ms: 5000,
62//! concurrent: false,
63//! },
64//! );
65//!
66//! master.open(None).await?;
67//! let res = master.read_holding_registers(1, 0, 10, None).await?;
68//! println!("{:?}", res.map(|r| r.data));
69//! master.destroy().await;
70//!
71//! Ok(())
72//! }
73//! ```
74//!
75//! ### Modbus TCP Slave
76//!
77//! ```no_run
78//! use rs_modbus::layers::application::TcpApplicationLayer;
79//! use rs_modbus::layers::physical::TcpServerPhysicalLayer;
80//! use rs_modbus::slave::{ModbusSlave, ModbusSlaveModel};
81//! use rs_modbus::types::AddressRange;
82//! use async_trait::async_trait;
83//!
84//! struct SimpleModel;
85//!
86//! #[async_trait]
87//! impl ModbusSlaveModel for SimpleModel {
88//! fn unit(&self) -> u8 { 1 }
89//! fn address_range(&self) -> AddressRange {
90//! AddressRange::default()
91//! }
92//! async fn read_holding_registers(
93//! &self, _address: u16, length: u16,
94//! ) -> Result<Vec<u16>, rs_modbus::error::ModbusError> {
95//! Ok(vec![0; length as usize])
96//! }
97//! }
98//!
99//! #[tokio::main]
100//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
101//! let physical = TcpServerPhysicalLayer::new();
102//! let application = TcpApplicationLayer::new(physical.clone());
103//! let slave = ModbusSlave::new(application, physical);
104//!
105//! slave.add(Box::new(SimpleModel));
106//! slave.open(None).await?;
107//!
108//! Ok(())
109//! }
110//! ```
111
112pub mod error;
113pub mod layers;
114pub mod master;
115pub mod master_session;
116pub mod slave;
117pub mod types;
118pub mod utils;
119pub mod vars;
120
121// Re-export commonly used types for convenience
122pub use error::{get_code_by_error, get_error_by_code, ErrorCode, ModbusError};
123pub use layers::application::{ApplicationLayer, ApplicationProtocol, ApplicationRole, Framing};
124pub use layers::physical::{ConnectionId, DataEvent, PhysicalLayer, PhysicalLayerType, ResponseFn};
125pub use master::{ModbusMaster, ModbusMasterOptions};
126pub use master_session::{MasterSession, PreCheck, PreCheckOutcome};
127pub use slave::{ModbusSlave, ModbusSlaveModel, ModbusSlaveOptions};
128pub use types::{
129 AddressRange, ApplicationDataUnit, CustomFunctionCode, DeviceIdentification, DeviceObject,
130 FramedDataUnit, MasterResponse, ServerId,
131};
132pub use vars::{
133 limits, ConformityLevel, FunctionCode, ReadDeviceIdCode, COIL_OFF, COIL_ON, EXCEPTION_OFFSET,
134 MEI_READ_DEVICE_ID,
135};