omnitiles/hw/
led.rs

1// SPDX-License-Identifier: MIT
2// © 2025–2026 Christopher Liu
3
4//! LED abstraction layer.
5
6use stm32f7xx_hal::gpio::{self, Output, PinState, PushPull};
7
8/// Whether the LED is driven active-high or active-low on the board wiring.
9#[derive(Copy, Clone, Debug, Eq, PartialEq)]
10pub enum ActiveLevel {
11    High,
12    Low,
13}
14
15/// LED abstraction that remembers its active level and last known state.
16pub struct Led<const P: char, const N: u8> {
17    pin: gpio::Pin<P, N, Output<PushPull>>,
18    active: ActiveLevel,
19}
20
21impl<const P: char, const N: u8> Led<P, N> {
22    /// Create an LED wrapper, initializing it to OFF.
23    pub fn new<MODE>(pin: gpio::Pin<P, N, MODE>, active: ActiveLevel) -> Self {
24        let mut pin = pin.into_push_pull_output();
25        pin.set_state(match active {
26            ActiveLevel::High => PinState::Low,
27            ActiveLevel::Low => PinState::High,
28        });
29        Self { pin, active }
30    }
31
32    /// Drive the LED logically ON (true) or OFF (false).
33    pub fn set(&mut self, on: bool) {
34        match (self.active, on) {
35            (ActiveLevel::High, true) => self.pin.set_high(),
36            (ActiveLevel::High, false) => self.pin.set_low(),
37            (ActiveLevel::Low, true) => self.pin.set_low(),
38            (ActiveLevel::Low, false) => self.pin.set_high(),
39        }
40    }
41
42    #[inline]
43    pub fn on(&mut self) {
44        self.set(true)
45    }
46
47    #[inline]
48    pub fn off(&mut self) {
49        self.set(false)
50    }
51
52    #[inline]
53    pub fn is_on(&self) -> bool {
54        match self.active {
55            ActiveLevel::High => self.pin.is_set_high(),
56            ActiveLevel::Low => self.pin.is_set_low(),
57        }
58    }
59
60    #[inline]
61    pub fn toggle(&mut self) {
62        self.pin.toggle()
63    }
64
65    pub fn free(self) -> gpio::Pin<P, N, Output<PushPull>> {
66        self.pin
67    }
68}
69
70impl<const P: char, const N: u8> Led<P, N> {
71    pub fn active_high<MODE>(pin: gpio::Pin<P, N, MODE>) -> Self {
72        Self::new(pin, ActiveLevel::High)
73    }
74    pub fn active_low<MODE>(pin: gpio::Pin<P, N, MODE>) -> Self {
75        Self::new(pin, ActiveLevel::Low)
76    }
77}