Skip to main content

mbus_client/
lib.rs

1//! # mbus-client
2//!
3//! `mbus-client` is a high-level, `no_std` compatible Modbus client implementation.
4//! It provides a structured way to interact with Modbus servers (slaves) over various
5//! transport layers like TCP, RTU, or ASCII.
6//!
7//! ## Core Concepts
8//!
9//! - **`ClientServices`**: The central coordinator. It manages the lifecycle of a request,
10//!   including ADU construction, transmission, response tracking, timeouts, and retries.
11//! - **`Transport`**: An abstraction over the physical or link layer. This allows the client
12//!   to work seamlessly over hardware-specific UARTs, TCP sockets, or custom implementations.
13//! - **`App` Traits**: A set of traits (e.g., `CoilResponse`, `RegisterResponse`) that the
14//!   user implements to receive asynchronous-style callbacks when a response is parsed.
15//!
16//! ## Features
17//!
18//! - **Pipelining**: Supports multiple concurrent outstanding requests (configurable via const generics).
19//! - **Reliability**: Built-in support for automatic retries and configurable response timeouts.
20//! - **Memory Safety**: Uses `heapless` for all internal buffering, ensuring zero dynamic
21//!   allocation and suitability for hard real-time or embedded systems.
22//! - **Protocol Coverage**: Implements standard function codes for coils, discrete inputs,
23//!   holding/input registers, FIFO queues, and file records.
24//!
25//! ## Example Usage
26//!
27//! ```rust,no_run
28//! // These core imports are always available
29//! use mbus_core::transport::{UnitIdOrSlaveAddr, ModbusConfig, ModbusTcpConfig, Transport, TransportType, TimeKeeper};
30//! use mbus_core::errors::MbusError;
31//!
32//! # use mbus_core::data_unit::common::MAX_ADU_FRAME_LEN;
33//! # use mbus_client::app::{CoilResponse, RequestErrorNotifier};
34//! # #[cfg(feature = "traffic")]
35//! # use mbus_client::app::TrafficNotifier;
36//! # use mbus_client::services::coil::Coils;
37//! # use mbus_client::services::ClientServices;
38//! # use heapless::Vec;
39//! #
40//! # struct YourTransport;
41//! # impl YourTransport { fn new() -> Self { Self } }
42//! # impl Transport for YourTransport {
43//! #     type Error = MbusError;
44//! #     const TRANSPORT_TYPE: TransportType = TransportType::StdTcp;
45//! #     fn connect(&mut self, _: &ModbusConfig) -> Result<(), Self::Error> { Ok(()) }
46//! #     fn disconnect(&mut self) -> Result<(), Self::Error> { Ok(()) }
47//! #     fn send(&mut self, _: &[u8]) -> Result<(), Self::Error> { Ok(()) }
48//! #     fn recv(&mut self) -> Result<Vec<u8, MAX_ADU_FRAME_LEN>, Self::Error> { Ok(Vec::new()) }
49//! #     fn is_connected(&self) -> bool { true }
50//! # }
51//! // 1. Define your application state and implement response traits
52//! // Application traits and service modules are feature-gated.
53//! // To use Coil services, enable the "coils" feature in Cargo.toml.
54//! struct MyDevice;
55//! #[cfg(feature = "coils")]
56//! impl CoilResponse for MyDevice {
57//!     fn read_coils_response(&mut self, txn_id: u16, unit_id: UnitIdOrSlaveAddr, coils: &Coils) {
58//!         // Handle the data here
59//!     }
60//!     // Implement other CoilResponse methods or use default empty implementations if not needed
61//!     fn read_single_coil_response(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: u16, _: bool) {}
62//!     fn write_single_coil_response(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: u16, _: bool) {}
63//!     fn write_multiple_coils_response(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: u16, _: u16) {}
64//! }
65//! # impl RequestErrorNotifier for MyDevice {
66//! #     fn request_failed(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: MbusError) {}
67//! # }
68//! # #[cfg(feature = "traffic")]
69//! # impl TrafficNotifier for MyDevice {}
70//! # impl TimeKeeper for MyDevice {
71//! #     fn current_millis(&self) -> u64 { 0 }
72//! # }
73//!
74//! # fn main() -> Result<(), MbusError> {
75//! // 2. Initialize transport and config
76//! let transport = YourTransport::new();
77//! let config = ModbusConfig::Tcp(ModbusTcpConfig::new("192.168.1.10", 502)?);
78//!
79//! // 3. Create the service (N=5 allows 5 concurrent requests)
80//! let mut client = ClientServices::<_, _, 5>::new(transport, MyDevice, config)?;
81//! client.connect()?;
82//!
83//! // 4. Send a request (only available if the "coils" feature is enabled)
84//! #[cfg(feature = "coils")]
85//! {
86//!     client.coils().read_multiple_coils(1, UnitIdOrSlaveAddr::new(1)?, 0, 8)?;
87//! }
88//!
89//! // 5. Periodically poll to process incoming bytes and handle timeouts
90//! loop {
91//!     client.poll();
92//! #   break;
93//! }
94//! # Ok(())
95//! # }
96//! ```
97
98#![cfg_attr(not(doc), no_std)]
99#![warn(missing_docs)]
100
101/// Application-level traits and callback definitions. Users implement these to handle data
102/// returned by the Modbus server. These modules are conditionally compiled based on features.
103pub mod app;
104
105/// Internal Modbus services.
106/// Contains logic for specific function codes (Coils, Registers, etc.) and
107/// the core `ClientServices` orchestration logic.
108pub mod services;