xpanse_api/driver.rs
1//! Module driver traits.
2//!
3//! A driver identifies its hardware through [`DriverMeta::ID`], consumes the
4//! detected module's [`crate::gpio_bank::GpioBank`], initializes any buses it
5//! needs, and publishes app-facing capabilities in a [`crate::registry::Registry`].
6
7use crate::bus::allocator::BusAllocator;
8use crate::gpio_bank::{BankPins, GpioBank};
9use crate::metadata::{ModuleID, ModuleSlot};
10use crate::registry::Registry;
11use core::future::Future;
12
13/// Error returned when a module driver cannot be initialized.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, defmt::Format)]
15pub enum DriverError {
16 /// Peripheral setup, device communication, or resource registration failed.
17 InitFailed,
18}
19
20/// Static metadata used to match a driver to a detected module.
21pub trait DriverMeta {
22 /// Resistor-coded module identifier handled by this driver.
23 const ID: ModuleID;
24}
25
26/// Initializes a module and publishes the capabilities it provides.
27///
28/// The platform transfers ownership of the complete [`GpioBank`] to the driver.
29/// Bus resources allocated through [`BusAllocator`] are startup allocations and
30/// remain owned by the resulting capability for the rest of the boot.
31///
32/// Drivers are run on core 0, so any task spawn will also run on core 0
33///
34/// # Example
35///
36/// A two-button module can consume GPIO 0 and GPIO 1 and publish each button as
37/// an independent resource:
38///
39/// ```ignore
40/// use xpanse_api::{
41/// bus::allocator::BusAllocator,
42/// driver::{Driver, DriverError, DriverMeta},
43/// gpio_bank::{BankPins, GpioBank},
44/// interfaces::buttons::{A, B, pin_button},
45/// metadata::{ModuleDetectResistor, ModuleID, ModuleSlot},
46/// registry::Registry,
47/// };
48///
49/// struct TwoButtonDriver;
50///
51/// impl DriverMeta for TwoButtonDriver {
52/// const ID: ModuleID = ModuleID {
53/// md0: ModuleDetectResistor::R1K6,
54/// md1: ModuleDetectResistor::R1K5,
55/// };
56/// }
57///
58/// impl<G: BankPins> Driver<G> for TwoButtonDriver {
59/// async fn create(
60/// bank: GpioBank<G>,
61/// slot: ModuleSlot,
62/// registry: &mut Registry,
63/// buses: &mut BusAllocator,
64/// ) -> Result<(), DriverError> {
65/// registry.register(slot, Self::ID, pin_button::<A>(bank.gpio0.into()));
66/// registry.register(slot, Self::ID, pin_button::<B>(bank.gpio1.into()));
67/// let _ = buses;
68/// Ok(())
69/// }
70/// }
71/// ```
72pub trait Driver<G: BankPins>: DriverMeta {
73 /// Consumes a module's pins, initializes its hardware, and registers its
74 /// capabilities.
75 ///
76 /// Implementations should avoid publishing partially initialized resources
77 /// and return [`DriverError::InitFailed`] if setup cannot complete.
78 fn create(
79 gpio_bank: GpioBank<G>,
80 slot: ModuleSlot,
81 registry: &mut Registry,
82 bus_allocator: &mut BusAllocator,
83 ) -> impl Future<Output = Result<(), DriverError>>;
84}