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}