Skip to main content

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};