Add documentation; tiny code refactoring
This commit is contained in:
parent
a49a04e06f
commit
1fff7f634f
|
@ -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 {
|
||||||
|
|
16
src/main.rs
16
src/main.rs
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue