diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 3887803..201e87c 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,3 @@ { - "recommendations": [ - "rust-lang.rust-analyzer", - "tamasfe.even-better-toml", - ] + "recommendations": ["rust-lang.rust-analyzer", "tamasfe.even-better-toml"] } diff --git a/.vscode/settings.json b/.vscode/settings.json index e5beea8..0a01191 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,5 +9,5 @@ }, "rust-analyzer.cargo.extraEnv": { "RUSTUP_TOOLCHAIN": "esp" - }, + } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 525e259..da5cb36 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,6 +5,7 @@ "type": "shell", "command": "cargo", "args": [ + "+stable", // needed to use the host toolchain and not conflict with the esp toolchain "test", "--workspace", "--exclude", @@ -12,7 +13,10 @@ "--features", "unit-tests" ], - "group": "build", + "group":{ + "kind":"test", + "isDefault": true + }, "label": "unit-tests", "problemMatcher": [] }, @@ -43,18 +47,17 @@ "problemMatcher": [] }, { - "type": "cargo", - "command": "run", + "type": "shell", + "command": "sh", "args": [ - "--target", - "xtensa-esp32s3-none-elf" + "${cwd}/scripts/build_flash_monitor.sh" ], "group": { "kind": "build", - "isDefault": true + "isDefault": false }, "label": "Build, Flash, Monitor", "problemMatcher": [] - } + }, ] } \ No newline at end of file diff --git a/.zed/tasks.json b/.zed/tasks.json new file mode 100644 index 0000000..f27e74f --- /dev/null +++ b/.zed/tasks.json @@ -0,0 +1,44 @@ +// Project tasks configuration. See https://zed.dev/docs/tasks for documentation. +[ + { + "label": "Test", + "command": "cargo", + "args": [ + "+stable", + "test", + "--workspace", + "--exclude", + "focus", + "--features", + "unit-tests" + ], + "use_new_terminal": false, + "allow_concurrent_runs": false, + "reveal": "always", + "reveal_target": "dock", + "hide": "never", + "shell": "system" + }, + { + "label": "Run", + "command": "sh", + "args": ["./scripts/build_flash_monitor.sh"], + "use_new_terminal": false, + "allow_concurrent_runs": false, + "reveal": "always", + "reveal_target": "dock", + "hide": "never", + "shell": "system" + }, + { + "label": "Clean", + "command": "cargo", + "args": ["clean"], + "use_new_terminal": false, + "allow_concurrent_runs": false, + "reveal": "always", + "reveal_target": "dock", + "hide": "never", + "shell": "system" + } +] diff --git a/Cargo.lock b/Cargo.lock index 973ac83..eb7cf26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -563,6 +563,7 @@ dependencies = [ "esp-hal", "esp-println", "gc9a01-rs", + "hl_driver", ] [[package]] @@ -666,6 +667,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hl_driver" version = "0.1.0" +dependencies = [ + "embedded-hal 1.0.0", +] [[package]] name = "ident_case" diff --git a/Cargo.toml b/Cargo.toml index 4652b50..4e342bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "3" -members = [ "focus", "hl_driver"] +members = ["focus", "hl_driver"] [profile.dev] @@ -17,3 +17,9 @@ incremental = false lto = 'fat' opt-level = 's' overflow-checks = false + +[profile.test] +# Rust debug is too slow. +# For debug builds always builds with some optimization +opt-level = 0 +overflow-checks = true diff --git a/focus/Cargo.toml b/focus/Cargo.toml index 348b7d0..32fb7b4 100644 --- a/focus/Cargo.toml +++ b/focus/Cargo.toml @@ -14,3 +14,4 @@ embedded-hal = "1.0.0" esp-hal = { version = "1.0.0-beta.1", features = ["esp32s3", "unstable"] } esp-println = { version = "0.13.1", features = ["esp32s3"] } gc9a01-rs = "0.4.2" +hl_driver = { path = "../hl_driver" } diff --git a/focus/src/bin/main.rs b/focus/src/bin/main.rs index 65e46b9..1f5ba3b 100644 --- a/focus/src/bin/main.rs +++ b/focus/src/bin/main.rs @@ -9,17 +9,22 @@ use embedded_graphics::{ primitives::{Circle, PrimitiveStyle}, Drawable, }; +use embedded_hal::digital::PinState; use esp_hal::{ clock::CpuClock, delay::Delay, - gpio::{Input, Io, Level, Output, OutputConfig}, - handler, main, ram, + gpio::{Input, InputConfig, Level, Output, OutputConfig, Pull}, + main, spi::master::Spi, - time::{Duration, Instant}, + time::Instant, Blocking, }; use esp_println::println; -use focus::hardware::{button, screen, spi_bus}; +use focus::hardware::{screen, spi_bus}; +use hl_driver::{ + debounce, + switch::{self, Pressable}, +}; #[panic_handler] fn panic(e: &core::panic::PanicInfo) -> ! { @@ -27,7 +32,7 @@ fn panic(e: &core::panic::PanicInfo) -> ! { loop {} } -static BUTTON: Mutex>> = Mutex::new(RefCell::new(None)); +// static BUTTON: Mutex>> = Mutex::new(RefCell::new(None)); static SPI_BUS: Mutex>>> = Mutex::new(RefCell::new(None)); #[main] @@ -38,18 +43,24 @@ fn main() -> ! { let peripherals = esp_hal::init(config); let mut delay = Delay::new(); - //IO mulitplexer for gpio interrupt - let mut io = Io::new(peripherals.IO_MUX); - io.set_interrupt_handler(button_handler); - - // Button - // let config = InputConfig::default().with_pull(Pull::Up); - // let mut boot_button = Input::new(peripherals.GPIO0, config); - let mut boot_button = button::init_boot_button(peripherals.GPIO0); - critical_section::with(|cs| { - boot_button.listen(esp_hal::gpio::Event::FallingEdge); - BUTTON.borrow_ref_mut(cs).replace(boot_button); - }); + // Switches + let mut boot_button = switch::Switch::new( + Input::new( + peripherals.GPIO0, + InputConfig::default().with_pull(Pull::Up), + ), + PinState::Low, + ) + .with_debounce(debounce::Debouncer::default()); + + let mut hy040_switch = switch::Switch::new( + Input::new( + peripherals.GPIO6, + InputConfig::default().with_pull(esp_hal::gpio::Pull::Up), + ), + PinState::Low, + ) + .with_debounce(debounce::Debouncer::default()); // SPI Bus let spi = spi_bus::init_spi_bus(peripherals.SPI2, peripherals.GPIO12, peripherals.GPIO13); @@ -87,12 +98,22 @@ fn main() -> ! { let mut iter = COLOR_LIST.iter().cycle(); loop { - let delay_start = Instant::now(); + let _delay_start = Instant::now(); - if radius == 0 { + if boot_button.has_been_pressed().unwrap() { + println!("Reset radius"); + radius = 0; + display_driver.fill(0); + } + + if hy040_switch.has_been_pressed().unwrap() { if let Some(color) = iter.next() { + println!("Change color"); circle.style.fill_color = Some(*color); } + } + + if radius == 0 { decrease = false; } else if radius == center.y as u32 { decrease = true; @@ -111,34 +132,8 @@ fn main() -> ! { circle.draw(&mut display_driver).unwrap(); display_driver.flush().unwrap(); - while delay_start.elapsed() < Duration::from_millis(20) {} + // while delay_start.elapsed() < Duration::from_millis(200) {} } // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/esp-hal-v1.0.0-beta.0/examples/src/bin } - -#[handler] -#[ram] -fn button_handler() { - println!("GPIO interrupt"); - - if critical_section::with(|cs| { - BUTTON - .borrow_ref_mut(cs) - .as_mut() - .unwrap() - .is_interrupt_set() - }) { - println!("Button was source of interrupt"); - } else { - println!("Button was not source of interrupt"); - } - - critical_section::with(|cs| { - BUTTON - .borrow_ref_mut(cs) - .as_mut() - .unwrap() - .clear_interrupt(); - }) -} diff --git a/hl_driver/Cargo.toml b/hl_driver/Cargo.toml index d52a068..01443d0 100644 --- a/hl_driver/Cargo.toml +++ b/hl_driver/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2024" [dependencies] +embedded-hal = "1.0.0" + [features] unit-tests = [] diff --git a/hl_driver/src/debounce.rs b/hl_driver/src/debounce.rs new file mode 100644 index 0000000..04969f8 --- /dev/null +++ b/hl_driver/src/debounce.rs @@ -0,0 +1,98 @@ +const DEBOUNCE_MASK: u8 = 0x07; +const RELEASED_MASK: u8 = 0x00; + +/// ## Description +/// +/// Trait defining debouncing behaviours +pub trait Debounce { + fn get_state(&self) -> DebounceState; + fn debounce(&mut self, state: bool); +} + +/// ## Description +/// +/// Possible state for a debouncer +#[derive(Debug, PartialEq)] +pub enum DebounceState { + Loaded, + Unloaded, + Transition, +} + +/// ## Description +/// +/// Allow rapid conversion between u8 and the Debounce state. +/// Useful for converting the state of a register. +impl From for DebounceState { + fn from(value: u8) -> Self { + match value { + DEBOUNCE_MASK => DebounceState::Loaded, + RELEASED_MASK => DebounceState::Unloaded, + _ => DebounceState::Transition, + } + } +} + +#[allow(dead_code)] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] +/// ## Description +/// +/// Debouncer struct implementing the debouncing trait based on a u8 register +/// +/// ## Example +/// +/// ```rust +/// use hl_driver::debounce::{Debouncer, DebounceState, Debounce}; +/// // Create a debouncer with en empty register +/// let mut debouncer = Debouncer::default(); +/// // Perform one register manipulation based on the provided boolean. For instance a gpio state. +/// debouncer.debounce(true); +/// // Retrieve the DebounceState. When the register is full (3 ticks), the state will be Loaded. +/// let state = debouncer.get_state(); +/// assert_eq!(DebounceState::Transition, state); +/// ``` +#[derive(Default)] +pub struct Debouncer { + register: u8, +} + +impl Debounce for Debouncer { + fn debounce(&mut self, state: bool) { + self.register = (self.register << 1) | state as u8; + } + + fn get_state(&self) -> DebounceState { + DebounceState::from(self.register) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[inline(never)] + #[test] + fn test_debouncer() { + let mut debouncer = Debouncer::default(); + + // 3 first ticks filling the register + for _ in 0..2 { + debouncer.debounce(true); + assert_eq!(DebounceState::Transition, debouncer.get_state()); + } + + // 3th tick should fill register and reach loaded state + debouncer.debounce(true); + assert_eq!(DebounceState::Loaded, debouncer.get_state()); + + // 7 more ticks emptying the register + for _ in 0..7 { + debouncer.debounce(false); + assert_eq!(DebounceState::Transition, debouncer.get_state()); + } + + // 8th tick should empty the register and reach unloaded state + debouncer.debounce(false); + assert_eq!(DebounceState::Unloaded, debouncer.get_state()); + } +} diff --git a/hl_driver/src/lib.rs b/hl_driver/src/lib.rs index 1dc810d..07e0cad 100644 --- a/hl_driver/src/lib.rs +++ b/hl_driver/src/lib.rs @@ -1,3 +1,7 @@ #![cfg_attr(not(feature = "unit-tests"), no_std)] +pub mod debounce; pub mod switch; + +#[cfg(test)] +pub mod test_utils; diff --git a/hl_driver/src/switch.rs b/hl_driver/src/switch.rs index b93cf3f..49bf4bf 100644 --- a/hl_driver/src/switch.rs +++ b/hl_driver/src/switch.rs @@ -1,14 +1,461 @@ -pub fn add(left: u64, right: u64) -> u64 { - left + right +use embedded_hal::digital::{Error, ErrorKind, ErrorType, InputPin, PinState}; + +use crate::debounce::{self, DebounceState}; + +/*************************************/ +/*************************************/ +/******** TRAITS AND ENUMS ***********/ +/*************************************/ +/*************************************/ + +/// ## Description +/// +/// Trait defining common switch behaviour +pub trait Pressable { + fn get_current_state(&mut self) -> SwitchState; + fn has_been_pressed(&mut self) -> Result; +} + +/// ## Description +/// +/// Possible switch states. +#[derive(Debug, PartialEq, Clone, Copy)] +pub enum SwitchState { + Pressed, // The switch is pressed + Released, // The switch is released + Transition, // The switch is transitioning from a Pressed state to a Release state or vice versa + Faulty, // The switch is faulty +} + +/// ## Description +/// +/// Easy conversion from a switch state to a boolean. +/// True == Pressed +/// False == Not pressed (any other state) +impl From for bool { + fn from(value: SwitchState) -> Self { + matches!(value, SwitchState::Pressed) + } +} + +/// ## Description +/// +/// Possible errors related to switches +#[derive(Debug, PartialEq)] +pub enum SwitchError { + ReadPinState, +} + +/*************************************/ +/*************************************/ +/* EMBEDDED HAL TRAIT IMPLEMENTATION */ +/*************************************/ +/*************************************/ + +impl Error for SwitchError { + fn kind(&self) -> ErrorKind { + match self { + SwitchError::ReadPinState => ErrorKind::Other, + } + } +} + +impl ErrorType for Switch +where + PIN: InputPin, +{ + type Error = SwitchError; +} + +/*************************************/ +/*************************************/ +/******** CONCRETE SWITCHES **********/ +/*************************************/ +/*************************************/ + +/********* SIMPLE SWITCH *************/ + +/// ## Description +/// +/// A simple switch with no specific capabilities. +/// Implements the Pressable trait. +/// +/// ## Example +/// +/// See unit tests for example of use. +/// +#[derive(Debug, PartialEq)] +pub struct Switch +where + PIN: InputPin, +{ + pin: PIN, + pressed_state: PinState, + last_state: SwitchState, +} + +/********* IMPLEMENTATION *************/ + +impl Switch +where + PIN: InputPin, +{ + /// ## Description + /// + /// Create a new switch connected to the given input pin, which inteprets the pin's state based + /// on the expected pressed state. + /// + /// ## Parameters + /// - `pin`: A gpio pin implementing `embedded_hal::digital::InputPin` + /// - `pressed_state`: The state for which the switch is considered pressed (`PressState::High` or `::Low`) + /// + /// ## Return + /// - Switch + pub fn new(pin: PIN, pressed_state: PinState) -> Self { + Switch { + pin, + pressed_state, + last_state: SwitchState::Released, + } + } + + /// ## Description + /// + /// Add a debouncer to a simple switch. The functions of the switch are filtered through the debouncer. + /// + /// ## Parameters + /// - `debouncer`: An object implementing the `hl_driver::debounce::Debounce` trait. + /// + /// ## Return + /// - DebouncedSwitch + pub fn with_debounce(self, debouncer: D) -> DebouncedSwitch + where + D: debounce::Debounce, + { + DebouncedSwitch { + switch: self, + debouncer, + } + } +} + +impl Pressable for Switch +where + PIN: InputPin, +{ + /// ## Description + /// + /// Return the state of the switch when the function is invoqued. + /// + /// ## Return + /// SwitchState: + /// - Pressed + /// - Released + /// - Faulty + /// + /// (The Transition state is not returned since there is no debouncing). + #[inline] + fn get_current_state(&mut self) -> SwitchState { + match self.pin.is_high() { + Ok(b) => { + if b == bool::from(self.pressed_state) { + SwitchState::Pressed + } else { + SwitchState::Released + } + } + Err(_) => SwitchState::Faulty, + } + } + + /// ## Description + /// + /// Return if the switch has been pressed since the last use of this method. + /// + /// ## Return + /// *Result* + /// - `bool`: `true` if the switch has been pressed, `false` otherwise + /// - `SwitchError::ReadPinState`: an error occured when reading the gpio pin of the switch + #[inline] + fn has_been_pressed(&mut self) -> Result { + let current_state = self.get_current_state(); + match current_state { + SwitchState::Faulty => Err(SwitchError::ReadPinState), + _ => { + let was_pressed = self.last_state != SwitchState::Pressed + && current_state == SwitchState::Pressed; + self.last_state = current_state; + Ok(was_pressed) + } + } + } +} + +/********* DEBOUNCED SWITCH *************/ + +/// ## Description +/// +/// A switch with debouncing capabilities. +/// Implements the Pressable trait. +/// +/// ## Example +/// +/// See unit tests for example of use. +/// +#[derive(Debug, PartialEq)] +pub struct DebouncedSwitch +where + PIN: InputPin, + D: debounce::Debounce, +{ + switch: Switch, + debouncer: D, +} + +/********* IMPLEMENTATION *************/ + +impl Pressable for DebouncedSwitch +where + PIN: InputPin, + D: debounce::Debounce, +{ + /// ## Description + /// + /// Return the state of the switch when the function is invoqued. + /// + /// ## Return + /// SwitchState: + /// - Pressed + /// - Released + /// - Transition (debouncing is ongoing) + /// - Faulty + #[inline] + fn get_current_state(&mut self) -> SwitchState { + match self.switch.pin.is_high() { + Ok(b) => { + if b == bool::from(self.switch.pressed_state) { + self.debouncer.debounce(true); + } else { + self.debouncer.debounce(false); + } + + match self.debouncer.get_state() { + debounce::DebounceState::Loaded => SwitchState::Pressed, + DebounceState::Transition => SwitchState::Transition, + DebounceState::Unloaded => SwitchState::Released, + } + } + Err(_) => SwitchState::Faulty, + } + } + + /// ## Description + /// + /// Return if the switch has been pressed since the last use of this method. + /// + /// This takes into account the debouncing. + /// + /// ## Return + /// *Result* + /// - `bool`: `true` if the switch has been pressed, `false` otherwise + /// - `SwitchError::ReadPinState`: an error occured when reading the gpio pin of the switch + #[inline] + fn has_been_pressed(&mut self) -> Result { + let current_state = self.get_current_state(); + match current_state { + SwitchState::Faulty => Err(SwitchError::ReadPinState), + _ => { + let was_pressed = self.switch.last_state != SwitchState::Pressed + && current_state == SwitchState::Pressed; + self.switch.last_state = current_state; + Ok(was_pressed) + } + } + } } +/*************************************/ +/*************************************/ +/************** TESTS ****************/ +/*************************************/ +/*************************************/ + #[cfg(test)] mod tests { use super::*; + use crate::debounce; + use crate::test_utils; + + #[inline(never)] + #[test] + fn test_switch_get_state() { + // Pull Up switch with Low level when pressed + let pressed_state = PinState::Low; + // Mocked pin with non faulty state and a reading that sets the switch as released. + let pin = test_utils::MockedGpioPin { + state: !pressed_state, + fault: false, + }; + // Object under test + let mut switch = Switch::new(pin, pressed_state); + // Should be released + assert_eq!(SwitchState::Released, switch.get_current_state()); + // State of the pin becomes pressed + switch.pin.state = PinState::Low; + // Should be pressed + assert_eq!(SwitchState::Pressed, switch.get_current_state()); + // Switch reading is faulty + switch.pin.fault = true; // simulate an error when reading the pin + // Sould be faulty + assert_eq!(SwitchState::Faulty, switch.get_current_state()); + } + + #[inline(never)] #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + fn test_simple_switch_has_been_pressed() { + // Pull Up switch with Low level when pressed + let pressed_state = PinState::Low; + // Mocked pin with non faulty state and a reading that sets the switch as released. + let pin = test_utils::MockedGpioPin { + state: !pressed_state, + fault: false, + }; + // Object under test + let mut switch = Switch::new(pin, pressed_state); + + // Should be released + assert_eq!(SwitchState::Released, switch.last_state); + // State of the pin becomes pressed + switch.pin.state = PinState::Low; + + // When checking if the button has been pressed, + // it should be true since the state has changed since last check + assert_eq!( + true, + switch + .has_been_pressed() + .expect("Problem when reading the pin") + ); + + // Should not be considered pressed since state did not change + assert_eq!( + false, + switch + .has_been_pressed() + .expect("Problem when reading the pin") + ); + + // State of the pin becomes released + switch.pin.state = PinState::High; + // It should still be false still since the button has been released + assert_eq!( + false, + switch + .has_been_pressed() + .expect("Problem when reading the pin") + ); + + // State of the pin becomes pressed again + switch.pin.state = PinState::Low; + // And this should be true again since there was a state change between checks + assert_eq!( + true, + switch + .has_been_pressed() + .expect("Problem when reading the pin") + ); + } + + #[inline(never)] + #[test] + fn test_debounced_switch_get_state() { + // Debouncer implementing the Debounce trait + let debouncer = debounce::Debouncer::default(); + + // Pull Up switch with Low level when pressed + let pressed_state = PinState::Low; + // Mocked pin with non faulty state and a reading that sets the switch as released. + let pin = test_utils::MockedGpioPin { + state: !pressed_state, + fault: false, + }; + // Object under test + let mut db_switch = Switch::new(pin, pressed_state).with_debounce(debouncer); + + // Should start in release state + assert_eq!(SwitchState::Released, db_switch.get_current_state()); + + // Set the pin to the pressed state to simulate press action + db_switch.switch.pin.state = PinState::Low; + + // The first ticks should be a transition state + for _ in 0..2 { + assert_eq!(SwitchState::Transition, db_switch.get_current_state()) + } + + // The 3th tick should consider a press + assert_eq!(SwitchState::Pressed, db_switch.get_current_state()); + + //? Maintaining the button after that is no a pressed state anymore, is it what we want? + assert_eq!(SwitchState::Transition, db_switch.get_current_state()); + + // Simulate the release of the pin + db_switch.switch.pin.state = PinState::High; + + // Empty debounce register during 7 tickes and should be tansition state + for _ in 0..7 { + assert_eq!(SwitchState::Transition, db_switch.get_current_state()) + } + // After 7 ticks of transition, the state released state is acknowledged + assert_eq!(SwitchState::Released, db_switch.get_current_state()); + } + + #[inline(never)] + #[test] + fn test_debounced_switch_has_been_pressed() { + // Pull Up switch with Low level when pressed + let pressed_state = PinState::Low; + // Mocked pin with non faulty state and a reading that sets the switch as released. + let pin = test_utils::MockedGpioPin { + state: !pressed_state, + fault: false, + }; + // Object under test + let mut db_switch = + Switch::new(pin, pressed_state).with_debounce(debounce::Debouncer::default()); + + // State of the pin becomes pressed + db_switch.switch.pin.state = PinState::Low; + + // When checking if the button has been pressed, + // first ticks should not be detected has pressed until we have a clean signal + for _tick in 0..2 { + assert_eq!( + false, + db_switch + .has_been_pressed() + .expect("Problem when reading the pin") + ); + } + + // The next tick should garantee the signal is stable which ensure that the debounced switch has been pressed + assert_eq!( + true, + db_switch + .has_been_pressed() + .expect("Problem when reading the pin") + ); + + // State of the pin becomes released + db_switch.switch.pin.state = PinState::High; + + // It should still be false still since the state is transitioning + assert_eq!( + false, + db_switch + .has_been_pressed() + .expect("Problem when reading the pin") + ); } } diff --git a/hl_driver/src/test_utils.rs b/hl_driver/src/test_utils.rs new file mode 100644 index 0000000..5335feb --- /dev/null +++ b/hl_driver/src/test_utils.rs @@ -0,0 +1,39 @@ +use embedded_hal::digital::{ErrorKind, ErrorType, InputPin, PinState}; + +/// ## Description +/// +/// Mock of a simple gpio pin for unit tests +/// +/// ## Example +/// +/// ```rust +/// use embedded_hal::digital::PinState; +/// use hl_driver::test_utils::MockedPin; +/// +/// let mocked_pin = MockedPin{state: PinState::High, fault: false}; +/// ``` +/// +pub struct MockedGpioPin { + pub state: PinState, + pub fault: bool, +} + +impl ErrorType for MockedGpioPin { + type Error = ErrorKind; +} + +impl InputPin for MockedGpioPin { + fn is_high(&mut self) -> Result { + match self.fault { + true => Err(ErrorKind::Other), + false => Ok(bool::from(self.state)), + } + } + + fn is_low(&mut self) -> Result { + match self.fault { + true => Err(ErrorKind::Other), + false => Ok(bool::from(!self.state)), + } + } +} diff --git a/scripts/build_flash_monitor.sh b/scripts/build_flash_monitor.sh new file mode 100644 index 0000000..56678cf --- /dev/null +++ b/scripts/build_flash_monitor.sh @@ -0,0 +1,8 @@ +#! /bin/bash + +# To change if not default esp32 rust toolchain installation +# Import the rust toolchain using default script location +. $HOME/export-esp.sh + +# run with defined target, the runner defined in .cargo/config.toml will flash the firmware and start monitoring +cargo run --target xtensa-esp32s3-none-elf \ No newline at end of file