Skip to main content

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}