use crate::{LayerSelect, Sequencer}; use embedded_hal::{ digital::v2::{InputPin, OutputPin}, prelude::*, }; use stm32f1xx_hal::{ delay::Delay, gpio::{ gpioa::{PA1, PA2, PA3, PA4}, gpiob::{PB0, PB1, PB5, PB6, PB7, PB8}, Input, Output, PullDown, PushPull, }, }; /// An I/O abstraction for yesman /// /// The main I/O of the yesman module is buttons as inputs that need /// to be polled, and LEDs as outputs. All LED states are written at /// the same time. An "active step" can be fed into the `Io` /// abstraction from the `Sequencer` module. pub struct Io { // LED output states pub led1: PA1>, pub led2: PA2>, pub led3: PA3>, pub led4: PA4>, // Button input states pub btn1: PB0>, pub btn1_last: bool, pub btn2: PB1>, pub btn2_last: bool, pub btn3: PB5>, pub btn3_last: bool, pub btn4: PB6>, pub btn4_last: bool, // Eurorack signal I/O pub clk: PB7>, pub clk_last: bool, pub gate: PB8>, } impl Io { pub fn startup(&mut self, _: &mut Delay) { set_output(&mut self.led1, true); set_output(&mut self.led2, true); set_output(&mut self.led3, true); set_output(&mut self.led4, true); // TODO: silly start-up animation here } /// Check the state of each pin and update the sequencer accordingly pub fn update_sequence(&mut self, seq: &mut Sequencer) { // Update sequencer states based on button inputs btn_rising_edge(&mut self.btn1_last, &mut self.btn1, || seq.toggle(0)); btn_rising_edge(&mut self.btn2_last, &mut self.btn2, || seq.toggle(1)); btn_rising_edge(&mut self.btn3_last, &mut self.btn3, || seq.toggle(2)); btn_rising_edge(&mut self.btn4_last, &mut self.btn4, || seq.toggle(3)); // Update LED states based on sequencer let l = seq.layer(LayerSelect::A); set_output(&mut self.led1, l[0]); set_output(&mut self.led2, l[1]); set_output(&mut self.led3, l[2]); set_output(&mut self.led4, l[3]); } pub fn update_cv(&mut self, _: &mut Sequencer) { // Always output the current steps - if no clock is coming in this will change nothing in our output // set_output(&mut self.gate, seq.get().0); // On a rising clock edge, step the sequencer // btn_rising_edge(&mut self.clk_last, &mut self.clk, || seq.step()); } } /// If the button is pressed _and_ it was previously not pressed, /// run the given closure and update the button state to avoid /// running it again fn btn_rising_edge(last: &mut bool, i: &mut I, mut f: F) { if let Ok(true) = i.is_high() { if !*last { f(); *last = true; } } else if let Ok(false) = i.is_high() { *last = false; } } /// Set the output of a PIN. For LEDs this means `true` is off, /// `false` is on. /// /// This is because LEDs are wired from 3V3 to the output, which turns /// a low pin into a drain, and thus power can flow. This is done to /// reduce load on the stm32 when a lot of LEDs are active at once. fn set_output(o: &mut O, s: bool) { if s { o.set_high().ok(); } else { o.set_low().ok(); } }