diff --git a/fw/dtlogic/src/input.rs b/fw/dtlogic/src/input.rs index 0ad0a63..be7dd97 100644 --- a/fw/dtlogic/src/input.rs +++ b/fw/dtlogic/src/input.rs @@ -1,4 +1,5 @@ #[derive(Clone)] +/// A stateful button debouncer. pub struct Buttons { state: [Option; 4], } @@ -10,6 +11,8 @@ impl Buttons { } } + /// Update internal state from raw input state, with given millisecond timestamp. The input + /// state is proccessed/debounced into the internal state. pub fn update(&mut self, ts: u32, state: [bool; 4]) { for (&s, v) in state.iter().zip(self.state.iter_mut()) { if let Some(pressed) = v { @@ -29,6 +32,8 @@ impl Buttons { } } + /// Return a watcher, which is used to detect edge-triggered button events. Multiple + /// independent watchers can exist, eg. for different downstream code. pub fn watch(&self) -> ButtonWatcher { let mut pending = [false; 4]; for (i, v) in self.state.iter().enumerate() { @@ -43,12 +48,17 @@ impl Buttons { } } +/// A edge-triggered button event watcher. Updates events from a Buttons struct and yields button +/// press events once per button press. pub struct ButtonWatcher { state: [Option; 4], pending: [bool; 4], } impl ButtonWatcher { + /// Update internal state from Buttons. If any events are missed, a best effort is made to + /// reconstruct missing presses - but for all presses to be available, they should be processed + /// as early as possible via the events function. pub fn update(&mut self, buttons: &Buttons) { for (i, (v, o)) in self.state.iter_mut().zip(buttons.state.iter()).enumerate() { @@ -79,6 +89,8 @@ impl ButtonWatcher { } } + /// Returns an iterator over pending button presses. Button presses are registered as processed + /// one-by-one as the returned iterator is consumed. pub fn events<'a>(&'a mut self) -> ButtonWatcherPending<'a> { ButtonWatcherPending { w: self, @@ -86,6 +98,7 @@ impl ButtonWatcher { } } +/// Button press iterator, yielding a button number for each pending button press (edge-triggered). pub struct ButtonWatcherPending<'a> { w: &'a mut ButtonWatcher, } diff --git a/fw/dtlogic/src/ui.rs b/fw/dtlogic/src/ui.rs index 59b4399..cc2f0b5 100644 --- a/fw/dtlogic/src/ui.rs +++ b/fw/dtlogic/src/ui.rs @@ -17,31 +17,47 @@ use profont::{ use crate::input; +/// Color space that we expect to support: some form of RGB. pub trait ColorSpace = RgbColor + PixelColor; +/// Context passed to state tick functions. pub struct Context { pub buttons: input::Buttons, pub ticks: u32, } +/// Transitions (ie. FSM edges) returned by state tick functions. pub enum Transition { + /// Do nothing (keep current state). Keep, + /// Start the 'Running' state. Running { + /// Tickcount at which the timer started running. start: u32, + /// Number of milliseconds that the timer should run. msec: u32, }, + /// Start the 'Time Select' state. TimeSelect, } +/// State combining state logic, transition logic and drawing logic. pub trait State> { + /// Called when the state becomes active, before tick is called. fn enter(&mut self, tr: Transition); + /// Called on each tick of the application when the state is active. fn tick(&mut self, ctx: &Context) -> Transition; + /// Called whenever the application can/should draw. Called after tick. fn draw(&mut self, target: &mut D) -> Result<(), ::Error>; + + /// Return the size of the target display. Helper function for draw(). fn size(&mut self, target: &mut D) -> (u32, u32) { let bb = target.bounding_box(); (bb.size.width, bb.size.height) } + + /// Fully clear the target display with a given color. Helper function for draw(). fn clear(&mut self, target: &mut D, color: D::Color) -> Result<(), ::Error> { let (width, height) = self.size(target); @@ -49,6 +65,8 @@ pub trait State> { .into_styled(PrimitiveStyle::with_fill(color)) .draw(target) } + + /// Draw bottom soft buttons. Each button should be one-character string. Helper for draw(). fn draw_softbuttons(&mut self, target: &mut D, labels: [&str; 4]) -> Result<(), ::Error> { @@ -80,6 +98,8 @@ pub trait State> { } } +/// State used to select the time for the timer. Has +/- buttons and a start button (which +/// transitions to Running). pub struct TimeSelect { cleared: bool, bw: Option, @@ -195,6 +215,7 @@ impl> State for TimeSelect { } } +/// State when the timer is counting down. pub struct Running { cleared: bool, msec: u32,