From 7a79cf496c6a488c4e6e8747c150a3a24a2a510b Mon Sep 17 00:00:00 2001 From: Rahix Date: Mon, 4 Jul 2022 21:45:05 +0200 Subject: [PATCH] [WIP] generic: port: Add methods to temporarily switch a pin to a different mode --- avr-hal-generic/src/port.rs | 85 +++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/avr-hal-generic/src/port.rs b/avr-hal-generic/src/port.rs index e880afba99..1a4bfe0bed 100644 --- a/avr-hal-generic/src/port.rs +++ b/avr-hal-generic/src/port.rs @@ -215,6 +215,91 @@ impl Pin { } } + +impl Pin { + /// Temporarily put this pin into input mode (with pull-up enabled) and revert back to output afterwards. + pub fn with_pin_as_pull_up_input(&mut self, f: F) -> R + where + F: FnOnce(&mut Pin, PIN>) -> R, + { + // Save state so we can restore it afterwards + let state = self.is_set_high(); + // To "move" the pin out of current "owner" variable without actually moving + // SAFETY: This is okay because the pins are trivial structs. + let pin: Self = unsafe { core::ptr::read(self) }; + let mut pin = pin.into_pull_up_input(); + let res = f(&mut pin); + *self = if state { + pin.into_output_high() + } else { + pin.into_output() + }; + res + } + + /// Temporarily put this pin into input mode (floating) and revert back to output afterwards. + pub fn with_pin_as_floating_input(&mut self, f: F) -> R + where + F: FnOnce(&mut Pin, PIN>) -> R, + { + // Save state so we can restore it afterwards + let state = self.is_set_high(); + // To "move" the pin out of current "owner" variable without actually moving + // SAFETY: This is okay because the pins are trivial structs. + let pin: Self = unsafe { core::ptr::read(self) }; + let mut pin = pin.into_floating_input(); + let res = f(&mut pin); + *self = if state { + pin.into_output_high() + } else { + pin.into_output() + }; + res + } +} + +impl Pin, PIN> { + pub fn with_pin_as_output(&mut self, f: F) -> R + where + F: FnOnce(&mut Pin) -> R, + { + // Find out if pull-up was enabled + let was_pull_up = unsafe { self.pin.out_get() }; + // To "move" the pin out of current "owner" variable without actually moving + // SAFETY: This is okay because the pins are trivial structs. + let pin: Self = unsafe { core::ptr::read(self) }; + let mut pin = pin.into_output(); + let res = f(&mut pin); + // TODO: Here it would be nice to write back to *self, but should work without for now. + if was_pull_up { + pin.into_pull_up_input(); + } else { + pin.into_floating_input(); + }; + res + } + + pub fn with_pin_as_output_high(&mut self, f: F) -> R + where + F: FnOnce(&mut Pin) -> R, + { + // Find out if pull-up was enabled + let was_pull_up = unsafe { self.pin.out_get() }; + // To "move" the pin out of current "owner" variable without actually moving + // SAFETY: This is okay because the pins are trivial structs. + let pin: Self = unsafe { core::ptr::read(self) }; + let mut pin = pin.into_output_high(); + let res = f(&mut pin); + // TODO: Here it would be nice to write back to *self, but should work without for now. + if was_pull_up { + pin.into_pull_up_input(); + } else { + pin.into_floating_input(); + }; + res + } +} + /// # Downgrading /// For applications where the exact pin is irrelevant, a specific pin can be downgraded to a /// "dynamic pin" which can represent any pin: