Skip to main content

device_envoy_core/
led.rs

1//! A device abstraction for a single digital LED.
2//!
3//! Platform crates implement [`Led`] for their concrete single-LED device types.
4//! Constructors and platform setup stay in platform crates.
5
6use core::borrow::Borrow;
7
8/// Logical LED level.
9#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Default)]
10pub enum LedLevel {
11    /// LED on.
12    On,
13    /// LED off.
14    #[default]
15    Off,
16}
17
18/// Which GPIO pin level turns the LED on.
19#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Default)]
20pub enum OnLevel {
21    /// LED lights when the pin is driven high.
22    #[default]
23    High,
24    /// LED lights when the pin is driven low.
25    Low,
26}
27
28/// Platform-agnostic single LED device contract.
29///
30/// This trait defines a minimal operation surface for a single digital LED:
31///
32/// - Set the LED level immediately with [`Led::set_level`].
33/// - Run a looped animation with [`Led::animate`].
34///
35/// # Example
36///
37/// ```rust,no_run
38/// use device_envoy_core::led::{Led, LedLevel};
39/// use embassy_time::Duration;
40///
41/// async fn run_led_example(led: &impl Led) {
42///     // Turn the LED on
43///     led.set_level(LedLevel::On);
44///     embassy_time::Timer::after(Duration::from_secs(1)).await;
45///
46///     // Turn the LED off
47///     led.set_level(LedLevel::Off);
48///     embassy_time::Timer::after(Duration::from_millis(500)).await;
49///
50///     // Play a blinking animation (looping: 200ms on, 200ms off)
51///     led.animate([
52///         (LedLevel::On, Duration::from_millis(200)),
53///         (LedLevel::Off, Duration::from_millis(200)),
54///     ]);
55/// }
56///
57/// # struct LedSimple;
58/// # impl Led for LedSimple {
59/// #     fn set_level(&self, _led_level: LedLevel) {}
60/// #     fn animate<I>(&self, _frames: I)
61/// #     where
62/// #         I: IntoIterator,
63/// #         I::Item: core::borrow::Borrow<(LedLevel, embassy_time::Duration)>,
64/// #     {
65/// #     }
66/// # }
67/// # let led_simple = LedSimple;
68/// # let _ = run_led_example(&led_simple);
69/// ```
70pub trait Led {
71    /// Set the LED level immediately.
72    ///
73    /// See the [Led trait documentation](Self) for usage examples.
74    fn set_level(&self, led_level: LedLevel);
75
76    /// Play a looped animation sequence.
77    ///
78    /// The duration type is [`embassy_time::Duration`](https://docs.rs/embassy-time/latest/embassy_time/struct.Duration.html).
79    ///
80    /// See the [Led trait documentation](Self) for usage examples.
81    fn animate<I>(&self, frames: I)
82    where
83        I: IntoIterator,
84        I::Item: Borrow<(LedLevel, embassy_time::Duration)>;
85
86    /// Turn the LED on.
87    ///
88    /// Equivalent to `set_level(LedLevel::On)`.
89    fn on(&self) {
90        self.set_level(LedLevel::On);
91    }
92
93    /// Turn the LED off.
94    ///
95    /// Equivalent to `set_level(LedLevel::Off)`.
96    fn off(&self) {
97        self.set_level(LedLevel::Off);
98    }
99}