stm32f4disc-demo/src/led_ring.rs

144 lines
4.0 KiB
Rust

//! Module for manipulating the LED ring.
/// The cycle direction of the LED ring.
///
/// The direction can be interpreted as such when the mini-USB port of the board is being held
/// down.
#[derive(Debug, Eq, PartialEq)]
pub enum Direction {
/// Cycle clockwise.
Clockwise,
/// Cycle counter-clockwise.
CounterClockwise,
}
impl Direction {
/// Returns the flipped/reversed direction.
fn flip(&self) -> Direction {
match self {
Direction::Clockwise => Direction::CounterClockwise,
Direction::CounterClockwise => Direction::Clockwise,
}
}
}
/// The mode the LED ring is in.
#[derive(Debug, Eq, PartialEq)]
pub enum Mode {
/// All LEDs are off.
Off,
/// The LEDs are cycling (two on at any time) following some direction.
Cycle,
/// The LEDs follow the accelerometer (shows which side of the board is pointing down).
Accelerometer,
}
/// The LED ring.
///
/// The ring on this board is comprised of four LEDs. This struct provides methods
/// for animating them.
pub struct LedRing {
/// The current cycle direction.
direction: Direction,
/// The current mode.
mode: Mode,
/// The index of the current LED being lit.
index: usize,
/// The LED outputs being used to comprise the LED ring.
leds: [crate::Led; 4],
}
impl LedRing {
/// Sets up the LED ring using using four LED GPIO outputs.
pub fn from(leds: [Led; 4]) -> LedRing {
LedRing {
direction: Direction::Clockwise,
mode: Mode::Cycle,
index: 0,
leds,
}
}
/// Enables cycle mode.
pub fn enable_cycle(&mut self) {
self.mode = Mode::Cycle;
}
/// Enables accelerometer mode.
pub fn enable_accel(&mut self) {
self.mode = Mode::Accelerometer;
}
/// Disables either cycle or accelerometer mode.
pub fn disable(&mut self) {
self.mode = Mode::Off;
}
/// Returns whether the LED ring is in cycle mode.
pub fn is_mode_cycle(&self) -> bool {
self.mode == Mode::Cycle
}
/// Returns whether the LED ring is in acceleromter mode.
pub fn is_mode_accel(&self) -> bool {
self.mode == Mode::Accelerometer
}
/// Reverses the cycle direction.
///
/// This will have no immediately visible effect if the LED ring is not in cycle mode
/// but it will be used when the cycle mode is enabled again.
pub fn reverse(&mut self) {
self.direction = self.direction.flip();
}
/// Advances the cycling one step.
///
/// This will have have directly visible effect regardless of the mode the
/// LED ring is in and override what is shown at that moment.
pub fn advance(&mut self) {
let num_leds = self.leds.len();
self.leds[self.index].set_high();
self.leds[(self.index + 2) % num_leds].set_low();
self.index = match self.direction {
Direction::Clockwise => (self.index + 1) % num_leds,
Direction::CounterClockwise => (self.index + 3) % num_leds,
};
}
/// Turns all LEDs on.
///
/// This is done immediately, regardless of the current mode.
pub fn all_on(&mut self) {
for led in self.leds.iter_mut() {
led.set_high();
}
}
/// Turns all LEDs off.
///
/// This is done immediately, regardless of the current mode.
pub fn all_off(&mut self) {
for led in self.leds.iter_mut() {
led.set_low();
}
}
/// Turns on specific LEDs based on the "direction" array.
///
/// When looking with the mini-USB port of the board held down (south), the directions of
/// the array can be interpreted as: `[east, south, west, north]`.
pub fn specific_on(&mut self, directions: [bool; 4]) {
for (led, on_off) in self.leds.iter_mut().zip(directions.iter()) {
if *on_off {
led.set_high();
} else {
led.set_low();
}
}
}
}