Expand description
A pure Rust implementation of MODBUS protocol.
rs-modbus is designed as a layered architecture, including the physical layer
and the application layer:
- Physical layer implements Serial Port, TCP/IP and UDP/IP.
- Application layer implements RTU, ASCII and TCP.
Both client (master) and server (slave) are provided.
§Features
- Full Modbus standard protocol implementation
- Support for custom function codes
- Support broadcasting
- Very lightweight project
§Supported function codes
| Code | Name |
|---|---|
| 01 | Read Coils |
| 02 | Read Discrete Inputs |
| 03 | Read Holding Registers |
| 04 | Read Input Registers |
| 05 | Write Single Coil |
| 06 | Write Single Register |
| 15 | Write Multiple Coils |
| 16 | Write Multiple Registers |
| 17 | Report Server ID |
| 22 | Mask Write Register |
| 23 | Read/Write Multiple Registers |
| 43/14 | Read Device Identification |
§Supported protocols
- Modbus RTU
- Modbus ASCII
- Modbus TCP/IP
- Modbus UDP/IP
- Modbus RTU/ASCII Over TCP/IP
- Modbus RTU/ASCII Over UDP/IP
§Examples
§Modbus TCP Master
use rs_modbus::layers::application::TcpApplicationLayer;
use rs_modbus::layers::physical::TcpClientPhysicalLayer;
use rs_modbus::master::{ModbusMaster, ModbusMasterOptions};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let physical = TcpClientPhysicalLayer::new();
let application = TcpApplicationLayer::new(physical.clone());
let master = ModbusMaster::new(
application,
physical,
ModbusMasterOptions {
timeout_ms: 5000,
concurrent: false,
},
);
master.open(None).await?;
let res = master.read_holding_registers(1, 0, 10, None).await?;
println!("{:?}", res.map(|r| r.data));
master.destroy().await;
Ok(())
}§Modbus TCP Slave
use rs_modbus::layers::application::TcpApplicationLayer;
use rs_modbus::layers::physical::TcpServerPhysicalLayer;
use rs_modbus::slave::{ModbusSlave, ModbusSlaveModel};
use rs_modbus::types::AddressRange;
use async_trait::async_trait;
struct SimpleModel;
#[async_trait]
impl ModbusSlaveModel for SimpleModel {
fn unit(&self) -> u8 { 1 }
fn address_range(&self) -> AddressRange {
AddressRange::default()
}
async fn read_holding_registers(
&self, _address: u16, length: u16,
) -> Result<Vec<u16>, rs_modbus::error::ModbusError> {
Ok(vec![0; length as usize])
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let physical = TcpServerPhysicalLayer::new();
let application = TcpApplicationLayer::new(physical.clone());
let slave = ModbusSlave::new(application, physical);
slave.add(Box::new(SimpleModel));
slave.open(None).await?;
Ok(())
}Re-exports§
pub use error::get_code_by_error;pub use error::get_error_by_code;pub use error::ErrorCode;pub use error::ModbusError;pub use layers::application::ApplicationLayer;pub use layers::application::ApplicationProtocol;pub use layers::application::ApplicationRole;pub use layers::application::Framing;pub use layers::physical::ConnectionId;pub use layers::physical::DataEvent;pub use layers::physical::PhysicalLayer;pub use layers::physical::PhysicalLayerType;pub use layers::physical::ResponseFn;pub use master::ModbusMaster;pub use master::ModbusMasterOptions;pub use master_session::MasterSession;pub use master_session::PreCheck;pub use master_session::PreCheckOutcome;pub use slave::ModbusSlave;pub use slave::ModbusSlaveModel;pub use slave::ModbusSlaveOptions;pub use types::AddressRange;pub use types::ApplicationDataUnit;pub use types::CustomFunctionCode;pub use types::DeviceIdentification;pub use types::DeviceObject;pub use types::FramedDataUnit;pub use types::MasterResponse;pub use types::ServerId;pub use vars::limits;pub use vars::ConformityLevel;pub use vars::FunctionCode;pub use vars::ReadDeviceIdCode;pub use vars::COIL_OFF;pub use vars::COIL_ON;pub use vars::EXCEPTION_OFFSET;pub use vars::MEI_READ_DEVICE_ID;
Modules§
- error
- layers
- master
- master_
session MasterSession— owns the in-flight “awaiting response” slots of aModbusMaster. Multi-slot, keyed byWaiterKey: TCP requests key by their transaction ID (TID), FIFO/RTU/ASCII requests share theWaiterKey::Fifoslot since they have no TID to disambiguate by.- slave
- types
- utils
- vars
- Modbus protocol constants — function codes, exception offsets, MEI types,
and PDU quantity limits. Mirrors njs-modbus
vars.ts.