fw: comment pass
parent
0ccbf37bed
commit
5d200bad08
|
@ -1,4 +1,5 @@
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
/// A stateful button debouncer.
|
||||||
pub struct Buttons {
|
pub struct Buttons {
|
||||||
state: [Option<u32>; 4],
|
state: [Option<u32>; 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]) {
|
pub fn update(&mut self, ts: u32, state: [bool; 4]) {
|
||||||
for (&s, v) in state.iter().zip(self.state.iter_mut()) {
|
for (&s, v) in state.iter().zip(self.state.iter_mut()) {
|
||||||
if let Some(pressed) = v {
|
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 {
|
pub fn watch(&self) -> ButtonWatcher {
|
||||||
let mut pending = [false; 4];
|
let mut pending = [false; 4];
|
||||||
for (i, v) in self.state.iter().enumerate() {
|
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 {
|
pub struct ButtonWatcher {
|
||||||
state: [Option<u32>; 4],
|
state: [Option<u32>; 4],
|
||||||
pending: [bool; 4],
|
pending: [bool; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonWatcher {
|
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) {
|
pub fn update(&mut self, buttons: &Buttons) {
|
||||||
for (i, (v, o)) in self.state.iter_mut().zip(buttons.state.iter()).enumerate() {
|
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> {
|
pub fn events<'a>(&'a mut self) -> ButtonWatcherPending<'a> {
|
||||||
ButtonWatcherPending {
|
ButtonWatcherPending {
|
||||||
w: self,
|
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> {
|
pub struct ButtonWatcherPending<'a> {
|
||||||
w: &'a mut ButtonWatcher,
|
w: &'a mut ButtonWatcher,
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,31 +17,47 @@ use profont::{
|
||||||
|
|
||||||
use crate::input;
|
use crate::input;
|
||||||
|
|
||||||
|
/// Color space that we expect to support: some form of RGB.
|
||||||
pub trait ColorSpace = RgbColor + PixelColor;
|
pub trait ColorSpace = RgbColor + PixelColor;
|
||||||
|
|
||||||
|
/// Context passed to state tick functions.
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub buttons: input::Buttons,
|
pub buttons: input::Buttons,
|
||||||
pub ticks: u32,
|
pub ticks: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Transitions (ie. FSM edges) returned by state tick functions.
|
||||||
pub enum Transition {
|
pub enum Transition {
|
||||||
|
/// Do nothing (keep current state).
|
||||||
Keep,
|
Keep,
|
||||||
|
/// Start the 'Running' state.
|
||||||
Running {
|
Running {
|
||||||
|
/// Tickcount at which the timer started running.
|
||||||
start: u32,
|
start: u32,
|
||||||
|
/// Number of milliseconds that the timer should run.
|
||||||
msec: u32,
|
msec: u32,
|
||||||
},
|
},
|
||||||
|
/// Start the 'Time Select' state.
|
||||||
TimeSelect,
|
TimeSelect,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State combining state logic, transition logic and drawing logic.
|
||||||
pub trait State<D: DrawTarget<Color: ColorSpace>> {
|
pub trait State<D: DrawTarget<Color: ColorSpace>> {
|
||||||
|
/// Called when the state becomes active, before tick is called.
|
||||||
fn enter(&mut self, tr: Transition);
|
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;
|
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<(), <D as DrawTarget>::Error>;
|
fn draw(&mut self, target: &mut D) -> Result<(), <D as DrawTarget>::Error>;
|
||||||
|
|
||||||
|
/// Return the size of the target display. Helper function for draw().
|
||||||
fn size(&mut self, target: &mut D) -> (u32, u32)
|
fn size(&mut self, target: &mut D) -> (u32, u32)
|
||||||
{
|
{
|
||||||
let bb = target.bounding_box();
|
let bb = target.bounding_box();
|
||||||
(bb.size.width, bb.size.height)
|
(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<(), <D as DrawTarget>::Error>
|
fn clear(&mut self, target: &mut D, color: D::Color) -> Result<(), <D as DrawTarget>::Error>
|
||||||
{
|
{
|
||||||
let (width, height) = self.size(target);
|
let (width, height) = self.size(target);
|
||||||
|
@ -49,6 +65,8 @@ pub trait State<D: DrawTarget<Color: ColorSpace>> {
|
||||||
.into_styled(PrimitiveStyle::with_fill(color))
|
.into_styled(PrimitiveStyle::with_fill(color))
|
||||||
.draw(target)
|
.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]) ->
|
fn draw_softbuttons(&mut self, target: &mut D, labels: [&str; 4]) ->
|
||||||
Result<(), <D as DrawTarget>::Error>
|
Result<(), <D as DrawTarget>::Error>
|
||||||
{
|
{
|
||||||
|
@ -80,6 +98,8 @@ pub trait State<D: DrawTarget<Color: ColorSpace>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State used to select the time for the timer. Has +/- buttons and a start button (which
|
||||||
|
/// transitions to Running).
|
||||||
pub struct TimeSelect {
|
pub struct TimeSelect {
|
||||||
cleared: bool,
|
cleared: bool,
|
||||||
bw: Option<input::ButtonWatcher>,
|
bw: Option<input::ButtonWatcher>,
|
||||||
|
@ -195,6 +215,7 @@ impl<D: DrawTarget<Color: ColorSpace>> State<D> for TimeSelect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// State when the timer is counting down.
|
||||||
pub struct Running {
|
pub struct Running {
|
||||||
cleared: bool,
|
cleared: bool,
|
||||||
msec: u32,
|
msec: u32,
|
||||||
|
|
Loading…
Reference in New Issue