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//! # use mbus_client::services::coil::Coils;
35//! # use mbus_client::services::ClientServices;
36//! # use heapless::Vec;
37//! #
38//! # struct YourTransport;
39//! # impl YourTransport { fn new() -> Self { Self } }
40//! # impl Transport for YourTransport {
41//! #     type Error = MbusError;
42//! #     fn connect(&mut self, _: &ModbusConfig) -> Result<(), Self::Error> { Ok(()) }
43//! #     fn disconnect(&mut self) -> Result<(), Self::Error> { Ok(()) }
44//! #     fn send(&mut self, _: &[u8]) -> Result<(), Self::Error> { Ok(()) }
45//! #     fn recv(&mut self) -> Result<Vec<u8, MAX_ADU_FRAME_LEN>, Self::Error> { Ok(Vec::new()) }
46//! #     fn is_connected(&self) -> bool { true }
47//! #     fn transport_type(&self) -> TransportType { TransportType::StdTcp }
48//! # }
49//! // 1. Define your application state and implement response traits
50//! // Application traits and service modules are feature-gated.
51//! // To use Coil services, enable the "coils" feature in Cargo.toml.
52//! struct MyDevice;
53//! #[cfg(feature = "coils")]
54//! impl CoilResponse for MyDevice {
55//!     fn read_coils_response(&mut self, txn_id: u16, unit_id: UnitIdOrSlaveAddr, coils: &Coils) {
56//!         // Handle the data here
57//!     }
58//!     // Implement other CoilResponse methods or use default empty implementations if not needed
59//!     fn read_single_coil_response(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: u16, _: bool) {}
60//!     fn write_single_coil_response(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: u16, _: bool) {}
61//!     fn write_multiple_coils_response(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: u16, _: u16) {}
62//! }
63//! # impl RequestErrorNotifier for MyDevice {
64//! #     fn request_failed(&mut self, _: u16, _: UnitIdOrSlaveAddr, _: MbusError) {}
65//! # }
66//! # impl TimeKeeper for MyDevice {
67//! #     fn current_millis(&self) -> u64 { 0 }
68//! # }
69//!
70//! # fn main() -> Result<(), MbusError> {
71//! // 2. Initialize transport and config
72//! let transport = YourTransport::new();
73//! let config = ModbusConfig::Tcp(ModbusTcpConfig::new("192.168.1.10", 502)?);
74//!
75//! // 3. Create the service (N=5 allows 5 concurrent requests)
76//! let mut client = ClientServices::<_, _, 5>::new(transport, MyDevice, config)?;
77//!
78//! // 4. Send a request (only available if the "coils" feature is enabled)
79//! #[cfg(feature = "coils")]
80//! {
81//!     client.coils().read_multiple_coils(1, UnitIdOrSlaveAddr::new(1)?, 0, 8)?;
82//! }
83//!
84//! // 5. Periodically poll to process incoming bytes and handle timeouts
85//! loop {
86//!     client.poll();
87//! #   break;
88//! }
89//! # Ok(())
90//! # }
91//! ```
92
93#![cfg_attr(not(doc), no_std)]
94#![warn(missing_docs)]
95
96/// Application-level traits and callback definitions. Users implement these to handle data
97/// returned by the Modbus server. These modules are conditionally compiled based on features.
98pub mod app;
99
100/// Internal Modbus services.
101/// Contains logic for specific function codes (Coils, Registers, etc.) and
102/// the core `ClientServices` orchestration logic.
103pub mod services;