mecha10_controllers/lib.rs
1//! Hardware Controller Abstractions for Mecha10
2//!
3//! This crate provides a composable layer between hardware drivers and nodes.
4//! Controllers wrap device SDKs/libraries and provide standardized interfaces
5//! for nodes to manage hardware.
6//!
7//! # Architecture
8//!
9//! ```text
10//! ┌─────────────────┐
11//! │ Node │ (Business logic)
12//! └────────┬────────┘
13//! │
14//! ▼
15//! ┌─────────────────┐
16//! │ Controller │ (Device management + SDK abstraction)
17//! └────────┬────────┘
18//! │
19//! ▼
20//! ┌──────────────┐
21//! │ Hardware SDK │ (realsense-rust, bno055, etc.)
22//! └──────────────┘
23//! ```
24//!
25//! # Core Concepts
26//!
27//! - **Controller**: Base trait for all hardware controllers
28//! - **Domain-specific traits**: CameraController, ImuController, etc.
29//! - **Health monitoring**: Built-in health checks and diagnostics
30//! - **Capability discovery**: Query what a controller can do
31//! - **Testing support**: Mock implementations for easy testing
32//!
33//! # Example
34//!
35//! ```rust,no_run
36//! use mecha10_controllers::{Controller, CameraController};
37//! use mecha10_controllers::camera::RealSenseController;
38//!
39//! #[tokio::main]
40//! async fn main() -> anyhow::Result<()> {
41//! // Initialize controller
42//! let config = RealSenseConfig::default();
43//! let mut camera = RealSenseController::init(config).await?;
44//!
45//! // Start acquisition
46//! camera.start().await?;
47//!
48//! // Use controller
49//! let frame = camera.capture_frame().await?;
50//! println!("Captured frame: {}x{}", frame.width, frame.height);
51//!
52//! // Clean shutdown
53//! camera.stop().await?;
54//! Ok(())
55//! }
56//! ```
57
58use async_trait::async_trait;
59use serde::{Deserialize, Serialize};
60use std::collections::HashMap;
61use std::fmt;
62
63pub mod camera;
64pub mod imu;
65pub mod l298n;
66pub mod lidar;
67pub mod mock;
68pub mod motor;
69
70#[cfg(feature = "mpu6050")]
71pub mod mpu6050;
72
73// Re-export traits
74pub use camera::CameraController;
75pub use imu::ImuController;
76pub use lidar::LidarController;
77pub use motor::MotorController;
78
79// Re-export L298N controller
80pub use l298n::{L298nControllerConfig, L298nMotorController, L298nMotorPins};
81
82// ============================================================================
83// Core Controller Trait
84// ============================================================================
85
86/// Base trait for all hardware controllers
87///
88/// Controllers manage the lifecycle and interaction with physical hardware
89/// or simulated devices. They abstract device SDKs and provide consistent
90/// interfaces for nodes to use.
91#[async_trait]
92pub trait Controller: Send + Sync {
93 /// Configuration type for this controller
94 type Config: Send + Sync;
95
96 /// Error type for this controller
97 type Error: std::error::Error + Send + Sync + 'static;
98
99 /// Initialize the controller with the given configuration
100 ///
101 /// This should perform all necessary setup including:
102 /// - Opening device connections
103 /// - Configuring device parameters
104 /// - Running initialization sequences
105 /// - Loading calibration data
106 async fn init(config: Self::Config) -> Result<Self, Self::Error>
107 where
108 Self: Sized;
109
110 /// Start the controller
111 ///
112 /// Begin data acquisition, motor control, or other active operations.
113 /// This may start background threads or async tasks.
114 async fn start(&mut self) -> Result<(), Self::Error>;
115
116 /// Stop the controller
117 ///
118 /// Stop all active operations gracefully. The controller should still
119 /// be in a valid state and can be restarted with `start()`.
120 async fn stop(&mut self) -> Result<(), Self::Error>;
121
122 /// Check the health status of the controller
123 async fn health_check(&self) -> ControllerHealth;
124
125 /// Get the capabilities of this controller
126 ///
127 /// Returns metadata about what features and operations this controller
128 /// supports. This is useful for runtime capability detection.
129 fn capabilities(&self) -> ControllerCapabilities;
130
131 /// Get controller-specific diagnostics
132 ///
133 /// Returns detailed diagnostic information for debugging and monitoring.
134 async fn diagnostics(&self) -> HashMap<String, String> {
135 HashMap::new()
136 }
137}
138
139// ============================================================================
140// Health and Capabilities
141// ============================================================================
142
143/// Health status of a controller
144#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
145pub enum ControllerHealth {
146 /// Controller is healthy and ready
147 Healthy,
148
149 /// Controller is running but degraded (e.g., some sensors failing)
150 Degraded { reason: String },
151
152 /// Controller is unhealthy and not functioning
153 Unhealthy { reason: String },
154
155 /// Controller health is unknown (e.g., not initialized)
156 Unknown,
157}
158
159impl fmt::Display for ControllerHealth {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 match self {
162 Self::Healthy => write!(f, "Healthy"),
163 Self::Degraded { reason } => write!(f, "Degraded: {}", reason),
164 Self::Unhealthy { reason } => write!(f, "Unhealthy: {}", reason),
165 Self::Unknown => write!(f, "Unknown"),
166 }
167 }
168}
169
170/// Capabilities of a controller
171///
172/// Describes what features and operations a controller supports.
173/// This allows runtime capability detection and adaptation.
174#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct ControllerCapabilities {
176 /// Controller type identifier (e.g., "camera", "imu", "lidar")
177 pub controller_type: String,
178
179 /// Specific implementation (e.g., "realsense", "bno055", "rplidar")
180 pub implementation: String,
181
182 /// Hardware vendor (e.g., "Intel", "Bosch", "Slamtec")
183 pub vendor: Option<String>,
184
185 /// Hardware model (e.g., "D435i", "BNO055", "A2M8")
186 pub model: Option<String>,
187
188 /// Firmware version if available
189 pub firmware_version: Option<String>,
190
191 /// Feature flags indicating what operations are supported
192 pub features: HashMap<String, bool>,
193
194 /// Additional metadata
195 pub metadata: HashMap<String, String>,
196}
197
198impl ControllerCapabilities {
199 /// Create a new capabilities struct
200 pub fn new(controller_type: impl Into<String>, implementation: impl Into<String>) -> Self {
201 Self {
202 controller_type: controller_type.into(),
203 implementation: implementation.into(),
204 vendor: None,
205 model: None,
206 firmware_version: None,
207 features: HashMap::new(),
208 metadata: HashMap::new(),
209 }
210 }
211
212 /// Add a feature flag
213 pub fn with_feature(mut self, name: impl Into<String>, supported: bool) -> Self {
214 self.features.insert(name.into(), supported);
215 self
216 }
217
218 /// Add metadata
219 pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
220 self.metadata.insert(key.into(), value.into());
221 self
222 }
223
224 /// Set vendor
225 pub fn with_vendor(mut self, vendor: impl Into<String>) -> Self {
226 self.vendor = Some(vendor.into());
227 self
228 }
229
230 /// Set model
231 pub fn with_model(mut self, model: impl Into<String>) -> Self {
232 self.model = Some(model.into());
233 self
234 }
235
236 /// Check if a feature is supported
237 pub fn supports(&self, feature: &str) -> bool {
238 self.features.get(feature).copied().unwrap_or(false)
239 }
240}
241
242// ============================================================================
243// Common Errors
244// ============================================================================
245
246/// Common controller errors
247#[derive(Debug, thiserror::Error)]
248pub enum ControllerError {
249 /// Device not found or not connected
250 #[error("Device not found: {0}")]
251 DeviceNotFound(String),
252
253 /// Device initialization failed
254 #[error("Initialization failed: {0}")]
255 InitializationFailed(String),
256
257 /// Device communication error
258 #[error("Communication error: {0}")]
259 CommunicationError(String),
260
261 /// Invalid configuration
262 #[error("Invalid configuration: {0}")]
263 InvalidConfiguration(String),
264
265 /// Operation timeout
266 #[error("Operation timed out: {0}")]
267 Timeout(String),
268
269 /// Device is not in the correct state for this operation
270 #[error("Invalid state: {0}")]
271 InvalidState(String),
272
273 /// Hardware fault detected
274 #[error("Hardware fault: {0}")]
275 HardwareFault(String),
276
277 /// Feature not supported by this controller
278 #[error("Feature not supported: {0}")]
279 NotSupported(String),
280
281 /// Generic error
282 #[error("Controller error: {0}")]
283 Other(String),
284}
285
286// ============================================================================
287// Controller State
288// ============================================================================
289
290/// Common controller states
291#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
292pub enum ControllerState {
293 /// Not initialized
294 Uninitialized,
295
296 /// Initialized but not started
297 Initialized,
298
299 /// Running normally
300 Running,
301
302 /// Stopped
303 Stopped,
304
305 /// Error state
306 Error,
307}
308
309impl fmt::Display for ControllerState {
310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311 match self {
312 Self::Uninitialized => write!(f, "Uninitialized"),
313 Self::Initialized => write!(f, "Initialized"),
314 Self::Running => write!(f, "Running"),
315 Self::Stopped => write!(f, "Stopped"),
316 Self::Error => write!(f, "Error"),
317 }
318 }
319}