diff --git a/src/main.rs b/src/main.rs index ac1227e..eee7d6e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,16 +18,24 @@ fn main() -> ! { // Enable interrupts (needed by `millis`) unsafe { avr_device::interrupt::enable() }; - let mut sketch = sketch!(pins); let mut led = pins.d13.into_output(); + let mut sketch = sketch!(pins); + + let mut blink_last_ms = millis(); + let mut sketch_last_ms = blink_last_ms; - let mut last_ms = millis(); loop { let curr_ms = millis(); - if curr_ms.wrapping_sub(last_ms) >= Millis::ONE_SECOND { + + if sketch.update(curr_ms.wrapping_sub(sketch_last_ms)) { + sketch_last_ms = curr_ms; + + // Resync d13 blinks + led.set_low(); + blink_last_ms = curr_ms; + } else if curr_ms.wrapping_sub(blink_last_ms) >= Millis(500) { led.toggle(); - last_ms = millis(); + blink_last_ms = curr_ms; } - sketch.invoke(); } } diff --git a/src/sketch.rs b/src/sketch.rs index aa3e2b4..e3d0f12 100644 --- a/src/sketch.rs +++ b/src/sketch.rs @@ -1,9 +1,8 @@ use arduino_hal::port::mode::{Input, Output, PullUp}; use crate::{ - duration, millis::{millis, Millis}, - state::State, + state::{self, State}, }; macro_rules! pin_type { @@ -87,11 +86,12 @@ macro_rules! decl_sketch { pub fn new( $(mut $pin_field : ::arduino_hal::port::Pin<$mode, pin_type!($pin)>,)* ) -> Self { - $($($init)?)* - Sketch { + let mut this = Sketch { $($pin_field,)* $($field : $default,)* - } + }; + this.toggle_components(); + this } } @@ -118,8 +118,8 @@ decl_sketch! { input_hatch_lock_direction: pin!(Output, d8), input_hatch_lock_enable: pin!(Output, d9), water_pump: pin!(Output, d10), - lower_drain_pump: pin!(Output, d11) { lower_drain_pump.set_high() }, - upper_drain_pump: pin!(Output, d12) { upper_drain_pump.set_high() }, + lower_drain_pump: pin!(Output, d11), + upper_drain_pump: pin!(Output, d12), @ state: State = State::default(), last_ms: Millis = millis(), @@ -127,236 +127,74 @@ decl_sketch! { } impl Sketch { + #[inline] #[must_use] pub const fn state(&self) -> State { self.state } - // TODO seriously, address these vvv - #[allow(clippy::cognitive_complexity, clippy::too_many_lines)] - pub fn invoke(&mut self) { - let curr_ms = millis(); - let delta_ms = curr_ms.wrapping_sub(self.last_ms); - let stopping = self.stopping | self.stop.is_low(); + #[inline] + pub fn update(&mut self, delta_ms: Millis) -> bool { + let starting = self.start.is_low(); + let stopping = self.stopping || self.stop.is_low(); self.stopping = stopping; - macro_rules! transition_to { - ($state:ident) => { - self.state = $crate::state::State::$state; - self.last_ms = curr_ms; - }; - } - - #[allow(clippy::match_same_arms)] - match self.state { - State::InitialDraining if delta_ms < duration::DRAINING => {} - State::InitialDraining => { - transition_to!(InitialIdling); - self.lower_drain_pump.set_low(); - self.ready.set_high(); - self.upper_drain_pump.set_low(); - } - - State::InitialIdling if self.start.is_high() => {} - State::InitialIdling => { - transition_to!(InitialLocking); - self.input_hatch_lock_direction.set_low(); - self.input_hatch_lock_enable.set_high(); - } - - State::InitialLocking if self.start.is_high() => { - transition_to!(InitialUnlocking); - self.input_hatch_lock_direction.set_high(); - } - State::InitialLocking if delta_ms < duration::LOCKING => {} - State::InitialLocking => { - transition_to!(InitialSetupSeparatorOpening); - self.ready.set_low(); - self.input_hatch_lock_enable.set_low(); - self.separator_hatch_enable.set_high(); - } - - State::InitialUnlocking if delta_ms < duration::LOCKING => {} - State::InitialUnlocking => { - transition_to!(InitialIdling); - self.input_hatch_lock_enable.set_low(); - } - - State::InitialSetupSeparatorOpening if delta_ms < duration::SEPARATOR_TRANSITION => {} - State::InitialSetupSeparatorOpening => { - transition_to!(InitialSetupWaterPumping); - self.separator_hatch_enable.set_low(); - self.water_pump.set_high(); - } - - State::InitialSetupWaterPumping if delta_ms < duration::WATER_PUMPING => {} - State::InitialSetupWaterPumping => { - transition_to!(InitialSetupSeparatorClosing); - self.water_pump.set_low(); - self.separator_hatch_direction.set_high(); - self.separator_hatch_enable.set_high(); - } - - State::InitialSetupSeparatorClosing if delta_ms < duration::SEPARATOR_TRANSITION => {} - State::InitialSetupSeparatorClosing => { - transition_to!(SoakWaterPumping); - self.separator_hatch_enable.set_low(); - self.water_pump.set_high(); - } - - State::SoakWaterPumping if stopping => { - transition_to!(SoakWaterDraining); - self.upper_drain_pump.set_high(); - self.water_pump.set_low(); - } - State::SoakWaterPumping if delta_ms < duration::WATER_PUMPING => {} - State::SoakWaterPumping => { - transition_to!(SoakWaterHeating); - self.water_pump.set_low(); - self.heater.set_high(); - } - - State::SoakWaterHeating if stopping => { - transition_to!(SoakWaterDraining); - self.heater.set_low(); - self.upper_drain_pump.set_high(); - } - State::SoakWaterHeating if delta_ms < duration::HEATING => {} - State::SoakWaterHeating => { - transition_to!(SoakWaterHeatedMixing); - self.mixer.set_high(); - } - - State::SoakWaterHeatedMixing if stopping => { - transition_to!(SoakWaterDraining); - self.heater.set_low(); - self.mixer.set_low(); - self.upper_drain_pump.set_high(); - } - State::SoakWaterHeatedMixing if delta_ms < duration::HEATED_MIXING => {} - State::SoakWaterHeatedMixing => { - transition_to!(SoakWaterMixing); - self.heater.set_low(); - } - - State::SoakWaterMixing if delta_ms < duration::MIXING && !stopping => {} - State::SoakWaterMixing => { - transition_to!(SoakWaterDraining); - self.mixer.set_low(); - self.upper_drain_pump.set_high(); - } - - State::SoakWaterDraining if delta_ms < duration::DRAINING => {} - State::SoakWaterDraining if stopping => { - transition_to!(Idling); - self.upper_drain_pump.set_low(); - self.ready.set_high(); - } - State::SoakWaterDraining => { - transition_to!(RinseWaterPumping); - self.water_pump.set_high(); - } - - State::RinseWaterPumping if delta_ms < duration::RINSING => {} - State::RinseWaterPumping => { - transition_to!(RinseWaterDraining); - self.water_pump.set_low(); - } - - State::RinseWaterDraining if delta_ms < duration::DRAINING => {} - State::RinseWaterDraining if stopping => { - transition_to!(Idling); - self.upper_drain_pump.set_low(); - self.ready.set_high(); - } - State::RinseWaterDraining => { - transition_to!(SeparatorOpening); - self.upper_drain_pump.set_low(); - self.separator_hatch_direction.set_low(); - self.separator_hatch_enable.set_high(); - } - - State::SeparatorOpening if delta_ms < duration::SEPARATOR_TRANSITION => {} - State::SeparatorOpening => { - transition_to!(SeparatorHolding); - self.separator_hatch_enable.set_low(); - } - - State::SeparatorHolding if delta_ms < duration::SEPARATOR_HOLDING => {} - State::SeparatorHolding => { - transition_to!(SeparatorClosing); - self.separator_hatch_direction.set_high(); - self.separator_hatch_enable.set_high(); - } - - State::SeparatorClosing if delta_ms < duration::SEPARATOR_TRANSITION => {} - State::SeparatorClosing => { - transition_to!(Blending); - self.separator_hatch_enable.set_low(); - self.blender.set_high(); - } - - State::Blending if delta_ms < duration::BLENDING => {} - State::Blending => { - transition_to!(PulpDraining); - self.blender.set_low(); - self.lower_drain_pump.set_high(); - } + let curr_state = self.state; + let overriding_state = state::override_for(curr_state, delta_ms, starting, stopping); - State::PulpDraining if delta_ms < duration::DRAINING => {} - State::PulpDraining => { - transition_to!(SetupSeparatorOpening); - self.lower_drain_pump.set_low(); - self.separator_hatch_direction.set_low(); - self.separator_hatch_enable.set_high(); - } - - State::SetupSeparatorOpening if delta_ms < duration::SEPARATOR_TRANSITION => {} - State::SetupSeparatorOpening => { - transition_to!(SetupWaterPumping); - self.separator_hatch_enable.set_low(); - self.water_pump.set_high(); - } - - State::SetupWaterPumping if delta_ms < duration::WATER_PUMPING => {} - State::SetupWaterPumping => { - transition_to!(SetupSeparatorClosing); - self.water_pump.set_low(); - self.separator_hatch_direction.set_high(); - self.separator_hatch_enable.set_high(); - } + if let Some(next_state) = overriding_state { + self.toggle_components(); - State::SetupSeparatorClosing if delta_ms < duration::SEPARATOR_TRANSITION => {} - State::SetupSeparatorClosing => { - transition_to!(Idling); - self.separator_hatch_enable.set_low(); - self.ready.set_high(); - } + self.state = next_state; + self.stopping = self.stopping && !curr_state.is_idling(); - State::Idling if self.start.is_high() => {} - State::Idling => { - transition_to!(Locking); - self.input_hatch_lock_direction.set_low(); - self.input_hatch_lock_enable.set_high(); - } + self.toggle_components(); - State::Locking if self.start.is_high() => { - transition_to!(Unlocking); - self.input_hatch_lock_direction.set_high(); - } - State::Locking if delta_ms < duration::LOCKING => {} - State::Locking => { - transition_to!(SoakWaterPumping); - self.ready.set_low(); - self.input_hatch_lock_enable.set_low(); - self.water_pump.set_high(); - } + true + } else { + false + } + } - State::Unlocking if delta_ms < duration::LOCKING => {} - State::Unlocking => { - transition_to!(Idling); - self.input_hatch_lock_enable.set_low(); - } + /// Toggles components based on the current state. + /// + /// Usually called before and after a change in state with the former for + /// leaving and the latter for entering. + fn toggle_components(&mut self) { + macro_rules! implementation { + ($($state:ident ( $($pin:ident),* $(,)? )),* $(,)?) => { + match self.state { + $($crate::state::State::$state => { $(self.$pin.toggle();)* })* + } + }; } + + implementation!( + InitialDraining(lower_drain_pump, upper_drain_pump), + InitialIdling(ready), + InitialLocking(input_hatch_lock_enable, ready), + InitialUnlocking(input_hatch_lock_direction, input_hatch_lock_enable, ready), + InitialSetupSeparatorOpening(separator_hatch_enable), + InitialSetupWaterPumping(water_pump), + InitialSetupSeparatorClosing(separator_hatch_direction, separator_hatch_enable), + SoakWaterPumping(water_pump), + SoakWaterHeating(heater), + SoakWaterHeatedMixing(heater, mixer), + SoakWaterMixing(mixer), + SoakWaterDraining(upper_drain_pump), + RinseWaterPumping(upper_drain_pump, water_pump), + RinseWaterDraining(upper_drain_pump), + SeparatorOpening(separator_hatch_enable), + SeparatorHolding(), + SeparatorClosing(separator_hatch_direction, separator_hatch_enable), + Blending(blender), + PulpDraining(lower_drain_pump), + SetupSeparatorOpening(separator_hatch_enable), + SetupWaterPumping(water_pump), + SetupSeparatorClosing(separator_hatch_direction, separator_hatch_enable), + Idling(ready), + Locking(input_hatch_lock_enable, ready), + Unlocking(input_hatch_lock_direction, input_hatch_lock_enable, ready), + ); } } diff --git a/src/state.rs b/src/state.rs index 9a903fc..6e0d215 100644 --- a/src/state.rs +++ b/src/state.rs @@ -30,6 +30,13 @@ pub enum State { Unlocking, } +impl State { + #[inline] + #[must_use] pub const fn is_idling(self) -> bool { + matches!(self, Self::InitialIdling | Self::Idling) + } +} + #[allow(clippy::cognitive_complexity)] #[must_use] pub fn override_for(curr: State, delta: Millis, starting: bool, stopping: bool) -> Option { @@ -64,7 +71,7 @@ pub fn override_for(curr: State, delta: Millis, starting: bool, stopping: bool) State::SoakWaterDraining } - State::SoakWaterPumping if delta >= duration::WATER_PUMPING => State::SoakWaterDraining, + State::SoakWaterPumping if delta >= duration::WATER_PUMPING => State::SoakWaterHeating, State::SoakWaterHeating if delta >= duration::HEATING => State::SoakWaterHeatedMixing, State::SoakWaterHeatedMixing if delta >= duration::HEATED_MIXING => State::SoakWaterMixing, State::SoakWaterMixing if delta >= duration::MIXING => State::SoakWaterDraining,