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// Re-export traits
71pub use camera::CameraController;
72pub use imu::ImuController;
73pub use lidar::LidarController;
74pub use motor::MotorController;
75
76// Re-export L298N controller
77pub use l298n::{L298nControllerConfig, L298nMotorController, L298nMotorPins};
78
79// ============================================================================
80// Core Controller Trait
81// ============================================================================
82
83/// Base trait for all hardware controllers
84///
85/// Controllers manage the lifecycle and interaction with physical hardware
86/// or simulated devices. They abstract device SDKs and provide consistent
87/// interfaces for nodes to use.
88#[async_trait]
89pub trait Controller: Send + Sync {
90 /// Configuration type for this controller
91 type Config: Send + Sync;
92
93 /// Error type for this controller
94 type Error: std::error::Error + Send + Sync + 'static;
95
96 /// Initialize the controller with the given configuration
97 ///
98 /// This should perform all necessary setup including:
99 /// - Opening device connections
100 /// - Configuring device parameters
101 /// - Running initialization sequences
102 /// - Loading calibration data
103 async fn init(config: Self::Config) -> Result<Self, Self::Error>
104 where
105 Self: Sized;
106
107 /// Start the controller
108 ///
109 /// Begin data acquisition, motor control, or other active operations.
110 /// This may start background threads or async tasks.
111 async fn start(&mut self) -> Result<(), Self::Error>;
112
113 /// Stop the controller
114 ///
115 /// Stop all active operations gracefully. The controller should still
116 /// be in a valid state and can be restarted with `start()`.
117 async fn stop(&mut self) -> Result<(), Self::Error>;
118
119 /// Check the health status of the controller
120 async fn health_check(&self) -> ControllerHealth;
121
122 /// Get the capabilities of this controller
123 ///
124 /// Returns metadata about what features and operations this controller
125 /// supports. This is useful for runtime capability detection.
126 fn capabilities(&self) -> ControllerCapabilities;
127
128 /// Get controller-specific diagnostics
129 ///
130 /// Returns detailed diagnostic information for debugging and monitoring.
131 async fn diagnostics(&self) -> HashMap<String, String> {
132 HashMap::new()
133 }
134}
135
136// ============================================================================
137// Health and Capabilities
138// ============================================================================
139
140/// Health status of a controller
141#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
142pub enum ControllerHealth {
143 /// Controller is healthy and ready
144 Healthy,
145
146 /// Controller is running but degraded (e.g., some sensors failing)
147 Degraded { reason: String },
148
149 /// Controller is unhealthy and not functioning
150 Unhealthy { reason: String },
151
152 /// Controller health is unknown (e.g., not initialized)
153 Unknown,
154}
155
156impl fmt::Display for ControllerHealth {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 match self {
159 Self::Healthy => write!(f, "Healthy"),
160 Self::Degraded { reason } => write!(f, "Degraded: {}", reason),
161 Self::Unhealthy { reason } => write!(f, "Unhealthy: {}", reason),
162 Self::Unknown => write!(f, "Unknown"),
163 }
164 }
165}
166
167/// Capabilities of a controller
168///
169/// Describes what features and operations a controller supports.
170/// This allows runtime capability detection and adaptation.
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct ControllerCapabilities {
173 /// Controller type identifier (e.g., "camera", "imu", "lidar")
174 pub controller_type: String,
175
176 /// Specific implementation (e.g., "realsense", "bno055", "rplidar")
177 pub implementation: String,
178
179 /// Hardware vendor (e.g., "Intel", "Bosch", "Slamtec")
180 pub vendor: Option<String>,
181
182 /// Hardware model (e.g., "D435i", "BNO055", "A2M8")
183 pub model: Option<String>,
184
185 /// Firmware version if available
186 pub firmware_version: Option<String>,
187
188 /// Feature flags indicating what operations are supported
189 pub features: HashMap<String, bool>,
190
191 /// Additional metadata
192 pub metadata: HashMap<String, String>,
193}
194
195impl ControllerCapabilities {
196 /// Create a new capabilities struct
197 pub fn new(controller_type: impl Into<String>, implementation: impl Into<String>) -> Self {
198 Self {
199 controller_type: controller_type.into(),
200 implementation: implementation.into(),
201 vendor: None,
202 model: None,
203 firmware_version: None,
204 features: HashMap::new(),
205 metadata: HashMap::new(),
206 }
207 }
208
209 /// Add a feature flag
210 pub fn with_feature(mut self, name: impl Into<String>, supported: bool) -> Self {
211 self.features.insert(name.into(), supported);
212 self
213 }
214
215 /// Add metadata
216 pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
217 self.metadata.insert(key.into(), value.into());
218 self
219 }
220
221 /// Set vendor
222 pub fn with_vendor(mut self, vendor: impl Into<String>) -> Self {
223 self.vendor = Some(vendor.into());
224 self
225 }
226
227 /// Set model
228 pub fn with_model(mut self, model: impl Into<String>) -> Self {
229 self.model = Some(model.into());
230 self
231 }
232
233 /// Check if a feature is supported
234 pub fn supports(&self, feature: &str) -> bool {
235 self.features.get(feature).copied().unwrap_or(false)
236 }
237}
238
239// ============================================================================
240// Common Errors
241// ============================================================================
242
243/// Common controller errors
244#[derive(Debug, thiserror::Error)]
245pub enum ControllerError {
246 /// Device not found or not connected
247 #[error("Device not found: {0}")]
248 DeviceNotFound(String),
249
250 /// Device initialization failed
251 #[error("Initialization failed: {0}")]
252 InitializationFailed(String),
253
254 /// Device communication error
255 #[error("Communication error: {0}")]
256 CommunicationError(String),
257
258 /// Invalid configuration
259 #[error("Invalid configuration: {0}")]
260 InvalidConfiguration(String),
261
262 /// Operation timeout
263 #[error("Operation timed out: {0}")]
264 Timeout(String),
265
266 /// Device is not in the correct state for this operation
267 #[error("Invalid state: {0}")]
268 InvalidState(String),
269
270 /// Hardware fault detected
271 #[error("Hardware fault: {0}")]
272 HardwareFault(String),
273
274 /// Feature not supported by this controller
275 #[error("Feature not supported: {0}")]
276 NotSupported(String),
277
278 /// Generic error
279 #[error("Controller error: {0}")]
280 Other(String),
281}
282
283// ============================================================================
284// Controller State
285// ============================================================================
286
287/// Common controller states
288#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
289pub enum ControllerState {
290 /// Not initialized
291 Uninitialized,
292
293 /// Initialized but not started
294 Initialized,
295
296 /// Running normally
297 Running,
298
299 /// Stopped
300 Stopped,
301
302 /// Error state
303 Error,
304}
305
306impl fmt::Display for ControllerState {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 match self {
309 Self::Uninitialized => write!(f, "Uninitialized"),
310 Self::Initialized => write!(f, "Initialized"),
311 Self::Running => write!(f, "Running"),
312 Self::Stopped => write!(f, "Stopped"),
313 Self::Error => write!(f, "Error"),
314 }
315 }
316}