Add documentation; tiny code refactoring

This commit is contained in:
Paul van Tilburg 2019-03-17 14:19:52 +01:00
parent a49a04e06f
commit 1fff7f634f
2 changed files with 68 additions and 8 deletions

View File

@ -1,15 +1,25 @@
//! Module for manipulating the LED ring.
use hal::gpio::{Output, PushPull}; use hal::gpio::{Output, PushPull};
use hal::prelude::*; use hal::prelude::*;
/// Type alias for a generic LED output.
pub type Led = hal::gpio::gpiod::PD<Output<PushPull>>; pub type Led = hal::gpio::gpiod::PD<Output<PushPull>>;
/// 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)] #[derive(Debug, Eq, PartialEq)]
pub enum Direction { pub enum Direction {
/// Cycle clockwise.
Clockwise, Clockwise,
/// Cycle counter-clockwise.
CounterClockwise, CounterClockwise,
} }
impl Direction { impl Direction {
/// Returns the flipped/reversed direction.
fn flip(&self) -> Direction { fn flip(&self) -> Direction {
match self { match self {
Direction::Clockwise => Direction::CounterClockwise, Direction::Clockwise => Direction::CounterClockwise,
@ -18,24 +28,38 @@ impl Direction {
} }
} }
/// The mode the LED ring is in.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub enum Mode { pub enum Mode {
/// All LEDs are off.
Off, Off,
/// The LEDs are cycling (two on at any time) following some direction.
Cycle, Cycle,
/// The LEDs follow the accelerometer (shows which side of the board is pointing down).
Accelerometer, Accelerometer,
} }
/// The LED ring.
///
/// The ring on this board is comprised of four LEDs. This struct provides methods
/// for animating them.
pub struct LedRing { pub struct LedRing {
pub direction: Direction, /// The current cycle direction.
pub mode: Mode, direction: Direction,
pub index: usize, /// The current mode.
pub leds: [crate::Led; 4], 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 { impl LedRing {
/// The number of cycles between LED ring updates (used by tasks).
pub const PERIOD: u32 = 8_000_000; pub const PERIOD: u32 = 8_000_000;
pub fn from(leds: [crate::Led; 4]) -> LedRing { /// Sets up the LED ring using using four LED GPIO outputs.
pub fn from(leds: [Led; 4]) -> LedRing {
LedRing { LedRing {
direction: Direction::Clockwise, direction: Direction::Clockwise,
mode: Mode::Cycle, mode: Mode::Cycle,
@ -44,30 +68,43 @@ impl LedRing {
} }
} }
/// Enables cycle mode.
pub fn enable_cycle(&mut self) { pub fn enable_cycle(&mut self) {
self.mode = Mode::Cycle; self.mode = Mode::Cycle;
} }
/// Enables accelerometer mode.
pub fn enable_accel(&mut self) { pub fn enable_accel(&mut self) {
self.mode = Mode::Accelerometer; self.mode = Mode::Accelerometer;
} }
/// Disables either cycle or accelerometer mode.
pub fn disable(&mut self) { pub fn disable(&mut self) {
self.mode = Mode::Off; self.mode = Mode::Off;
} }
/// Returns whether the LED ring is in cycle mode.
pub fn is_mode_cycle(&self) -> bool { pub fn is_mode_cycle(&self) -> bool {
self.mode == Mode::Cycle self.mode == Mode::Cycle
} }
/// Returns whether the LED ring is in acceleromter mode.
pub fn is_mode_accel(&self) -> bool { pub fn is_mode_accel(&self) -> bool {
self.mode == Mode::Accelerometer 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) { pub fn reverse(&mut self) {
self.direction = self.direction.flip(); 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) { pub fn advance(&mut self) {
let num_leds = self.leds.len(); let num_leds = self.leds.len();
@ -80,21 +117,30 @@ impl LedRing {
}; };
} }
/// Turns all LEDs on.
///
/// This is done immediately, regardless of the current mode.
pub fn all_on(&mut self) { pub fn all_on(&mut self) {
for led in self.leds.iter_mut() { for led in self.leds.iter_mut() {
led.set_high(); led.set_high();
} }
} }
/// Turns all LEDs off.
///
/// This is done immediately, regardless of the current mode.
pub fn all_off(&mut self) { pub fn all_off(&mut self) {
for led in self.leds.iter_mut() { for led in self.leds.iter_mut() {
led.set_low(); 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 set_directions(&mut self, directions: [bool; 4]) { pub fn set_directions(&mut self, directions: [bool; 4]) {
for setting in self.leds.iter_mut().zip(directions.iter()) { for (led, on_off) in self.leds.iter_mut().zip(directions.iter()) {
let (led, on_off) = setting;
if *on_off { if *on_off {
led.set_high(); led.set_high();
} else { } else {

View File

@ -1,3 +1,8 @@
//! STM32F4DISCOVERY demo application
//!
//! This demo application sports a serial command-interface for controlling what the LED
//! ring does: cycle clock-wise, counter clock-wise, or follow the accelerometer.
#![deny(unsafe_code)] #![deny(unsafe_code)]
#![deny(warnings)] #![deny(warnings)]
#![no_main] #![no_main]
@ -40,9 +45,11 @@ const APP: () = {
static mut accel: Accelerometer = (); static mut accel: Accelerometer = ();
static mut accel_cs: AccelerometerCs = (); static mut accel_cs: AccelerometerCs = ();
/// Initializes the application by setting up the LED ring, user button, serial
/// interface and accelerometer.
#[init(spawn = [accel_leds, cycle_leds])] #[init(spawn = [accel_leds, cycle_leds])]
fn init() -> init::LateResources { fn init() -> init::LateResources {
// Set up the LED ring and spawn the LEDs switch task. // Set up the LED ring and spawn the task corresponding to the mode.
let gpiod = device.GPIOD.split(); let gpiod = device.GPIOD.split();
let leds = [ let leds = [
gpiod.pd12.into_push_pull_output().downgrade(), gpiod.pd12.into_push_pull_output().downgrade(),
@ -110,6 +117,7 @@ const APP: () = {
} }
} }
/// Task that advances the LED ring one step and schedules the next trigger (if enabled).
#[task(schedule = [cycle_leds], resources = [led_ring])] #[task(schedule = [cycle_leds], resources = [led_ring])]
fn cycle_leds() { fn cycle_leds() {
resources.led_ring.lock(|led_ring| { resources.led_ring.lock(|led_ring| {
@ -122,6 +130,8 @@ const APP: () = {
}); });
} }
/// Task that performs an accelerometers measurement and adjusts the LED ring accordingly
/// and schedules the next trigger (if enabled).
#[task(schedule = [accel_leds], resources = [accel, accel_cs, led_ring, serial_tx])] #[task(schedule = [accel_leds], resources = [accel, accel_cs, led_ring, serial_tx])]
fn accel_leds() { fn accel_leds() {
resources.accel_cs.set_low(); resources.accel_cs.set_low();
@ -149,6 +159,8 @@ const APP: () = {
}) })
} }
/// Interrupt handler that writes that the button is pressed to the serial interface
/// and reverses the LED ring cycle direction.
#[interrupt(binds = EXTI0, resources = [button, exti, led_ring, serial_tx])] #[interrupt(binds = EXTI0, resources = [button, exti, led_ring, serial_tx])]
fn button_pressed() { fn button_pressed() {
resources.led_ring.lock(|led_ring| led_ring.reverse()); resources.led_ring.lock(|led_ring| led_ring.reverse());
@ -161,6 +173,8 @@ const APP: () = {
resources.button.clear_interrupt_pending_bit(resources.exti); resources.button.clear_interrupt_pending_bit(resources.exti);
} }
/// Interrupt handler that reads data from the serial connection and handles commands
/// once an appropriate command is in the buffer.
#[interrupt( #[interrupt(
binds = USART2, binds = USART2,
priority = 2, priority = 2,