From da7a3907af891c334526a84bc4630e546f8b55ab Mon Sep 17 00:00:00 2001 From: Volkalex28 Date: Wed, 7 Feb 2024 20:10:58 +0200 Subject: [PATCH] Add type for gpio::AnyPin This makes it possible to safely implement the InputPin and OutputPin traits for AnyPin. Now you can convert any pin to AnyPin with the appropriate type and use it in other library modules Added: - Peripheral implementation for AnyPin - Implementation of Pin for AnyPin - Implementation of OutputPin for AnyPin with type IsOutputPin - Implementation of InputPin for AnyPin with type IsInputPin - Upgrade types for AnyPin (for example InputOutputAnalogPinType -> InputOutputPinType) - Implementation of From for AnyPin with the appropriate type Changed: - The Gpio::degrage method returns AnyPin with the appropriate type --- CHANGELOG.md | 2 + esp-hal/src/gpio.rs | 396 ++++++++++++++++++++- esp32-hal/examples/blinky_erased_pins.rs | 4 +- esp32c2-hal/examples/blinky_erased_pins.rs | 4 +- esp32c3-hal/examples/blinky_erased_pins.rs | 4 +- esp32c6-hal/examples/blinky_erased_pins.rs | 4 +- esp32h2-hal/examples/blinky_erased_pins.rs | 4 +- esp32s2-hal/examples/blinky_erased_pins.rs | 4 +- esp32s3-hal/examples/blinky_erased_pins.rs | 4 +- 9 files changed, 396 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eb73c40418..7da455b69b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- Implementation OutputPin and InputPin for AnyPin (#1067) + ### Added - Add initial support for the ESP32-P4 (#1101) diff --git a/esp-hal/src/gpio.rs b/esp-hal/src/gpio.rs index e8e3df6881c..72acc23abe2 100644 --- a/esp-hal/src/gpio.rs +++ b/esp-hal/src/gpio.rs @@ -1361,7 +1361,359 @@ where } } -impl embedded_hal::digital::v2::InputPin for AnyPin> { +impl From> for AnyPin +where + TYPE: PinType, +{ + fn from(pin: AnyPin) -> Self { + Self { + inner: pin.inner, + _type: core::marker::PhantomData, + } + } +} + +impl crate::peripheral::Peripheral for AnyPin +where + TYPE: PinType, +{ + type P = Self; + + unsafe fn clone_unchecked(&mut self) -> Self::P { + let inner = &mut self.inner; + let this: AnyPin = handle_gpio_input!(inner, target, { + crate::peripheral::Peripheral::clone_unchecked(target).into() + }); + Self { + inner: this.inner, + _type: core::marker::PhantomData, + } + } +} + +impl crate::peripheral::sealed::Sealed for AnyPin where TYPE: PinType {} + +impl AnyPin +where + TYPE: PinType, +{ + pub fn degrade(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData, + } + } +} + +impl AnyPin { + pub fn into_input_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData, + } + } +} + +impl AnyPin { + pub fn into_input_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData, + } + } + + pub fn into_input_output_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData, + } + } + + pub fn into_input_only_analog_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData, + } + } +} + +impl AnyPin { + pub fn into_input_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData, + } + } +} + +impl Pin for AnyPin +where + TYPE: PinType, +{ + fn number(&self) -> u8 { + let inner = &self.inner; + handle_gpio_input!(inner, target, { Pin::number(target) }) + } + + fn sleep_mode(&mut self, on: bool) { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { Pin::sleep_mode(target, on) }) + } + + fn set_alternate_function(&mut self, alternate: AlternateFunction) { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + Pin::set_alternate_function(target, alternate) + }) + } + + fn is_listening(&self) -> bool { + let inner = &self.inner; + handle_gpio_input!(inner, target, { Pin::is_listening(target) }) + } + + fn listen_with_options( + &mut self, + event: Event, + int_enable: bool, + nmi_enable: bool, + wake_up_from_light_sleep: bool, + ) { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + Pin::listen_with_options( + target, + event, + int_enable, + nmi_enable, + wake_up_from_light_sleep, + ) + }) + } + + fn listen(&mut self, event: Event) { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { Pin::listen(target, event) }) + } + + fn unlisten(&mut self) { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { Pin::unlisten(target) }) + } + + fn is_interrupt_set(&self) -> bool { + let inner = &self.inner; + handle_gpio_input!(inner, target, { Pin::is_interrupt_set(target) }) + } + + fn clear_interrupt(&mut self) { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { Pin::clear_interrupt(target) }) + } +} + +impl InputPin for AnyPin +where + MODE: InputMode, + TYPE: IsInputPin, +{ + fn set_to_input(&mut self) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + InputPin::set_to_input(target); + }); + self + } + + fn enable_input(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + InputPin::enable_input(target, on); + }); + self + } + + fn enable_input_in_sleep_mode(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + InputPin::enable_input_in_sleep_mode(target, on); + }); + self + } + + fn is_input_high(&self) -> bool { + let inner = &self.inner; + handle_gpio_input!(inner, target, { InputPin::is_input_high(target) }) + } + + fn connect_input_to_peripheral(&mut self, signal: InputSignal) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + InputPin::connect_input_to_peripheral(target, signal); + }); + self + } + + fn connect_input_to_peripheral_with_options( + &mut self, + signal: InputSignal, + invert: bool, + force_via_gpio_mux: bool, + ) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + InputPin::connect_input_to_peripheral_with_options( + target, + signal, + invert, + force_via_gpio_mux, + ); + }); + self + } + + fn disconnect_input_from_peripheral(&mut self, signal: InputSignal) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_input!(inner, target, { + InputPin::disconnect_input_from_peripheral(target, signal); + }); + self + } +} + +impl OutputPin for AnyPin +where + MODE: OutputMode, + TYPE: IsOutputPin, +{ + fn set_to_open_drain_output(&mut self) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::set_to_open_drain_output(target); + }); + self + } + + fn set_to_push_pull_output(&mut self) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::set_to_push_pull_output(target); + }); + self + } + + fn enable_output(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::enable_output(target, on); + }); + self + } + + fn set_output_high(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::set_output_high(target, on); + }); + self + } + + fn set_drive_strength(&mut self, strength: DriveStrength) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::set_drive_strength(target, strength); + }); + self + } + + fn enable_open_drain(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::enable_open_drain(target, on); + }); + self + } + + fn enable_output_in_sleep_mode(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::enable_output_in_sleep_mode(target, on); + }); + self + } + + fn internal_pull_up_in_sleep_mode(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::internal_pull_up_in_sleep_mode(target, on); + }); + self + } + + fn internal_pull_down_in_sleep_mode(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::internal_pull_down_in_sleep_mode(target, on); + }); + self + } + + fn internal_pull_up(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::internal_pull_up(target, on); + }); + self + } + + fn internal_pull_down(&mut self, on: bool) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::internal_pull_down(target, on); + }); + self + } + + fn connect_peripheral_to_output(&mut self, signal: OutputSignal) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::connect_peripheral_to_output(target, signal); + }); + self + } + + fn connect_peripheral_to_output_with_options( + &mut self, + signal: OutputSignal, + invert: bool, + invert_enable: bool, + enable_from_gpio: bool, + force_via_gpio_mux: bool, + ) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::connect_peripheral_to_output_with_options( + target, + signal, + invert, + invert_enable, + enable_from_gpio, + force_via_gpio_mux, + ); + }); + self + } + + fn disconnect_peripheral_from_output(&mut self) -> &mut Self { + let inner = &mut self.inner; + handle_gpio_output!(inner, target, { + OutputPin::disconnect_peripheral_from_output(target); + }); + self + } +} + +impl embedded_hal::digital::v2::InputPin for AnyPin, TYPE> { type Error = core::convert::Infallible; fn is_high(&self) -> Result { @@ -1376,12 +1728,12 @@ impl embedded_hal::digital::v2::InputPin for AnyPin> { } #[cfg(feature = "eh1")] -impl embedded_hal_1::digital::ErrorType for AnyPin> { +impl embedded_hal_1::digital::ErrorType for AnyPin, TYPE> { type Error = Infallible; } #[cfg(feature = "eh1")] -impl embedded_hal_1::digital::InputPin for AnyPin> { +impl embedded_hal_1::digital::InputPin for AnyPin, TYPE> { fn is_high(&mut self) -> Result { let inner = &mut self.inner; handle_gpio_input!(inner, target, { target.is_high() }) @@ -1393,7 +1745,7 @@ impl embedded_hal_1::digital::InputPin for AnyPin> { } } -impl embedded_hal::digital::v2::OutputPin for AnyPin> { +impl embedded_hal::digital::v2::OutputPin for AnyPin, TYPE> { type Error = Infallible; fn set_low(&mut self) -> Result<(), Self::Error> { @@ -1407,7 +1759,7 @@ impl embedded_hal::digital::v2::OutputPin for AnyPin> { } } -impl embedded_hal::digital::v2::StatefulOutputPin for AnyPin> { +impl embedded_hal::digital::v2::StatefulOutputPin for AnyPin, TYPE> { fn is_set_high(&self) -> Result { let inner = &self.inner; handle_gpio_output!(inner, target, { target.is_set_high() }) @@ -1419,7 +1771,7 @@ impl embedded_hal::digital::v2::StatefulOutputPin for AnyPin> } } -impl embedded_hal::digital::v2::ToggleableOutputPin for AnyPin> { +impl embedded_hal::digital::v2::ToggleableOutputPin for AnyPin, TYPE> { type Error = Infallible; fn toggle(&mut self) -> Result<(), Self::Error> { @@ -1429,12 +1781,12 @@ impl embedded_hal::digital::v2::ToggleableOutputPin for AnyPin embedded_hal_1::digital::ErrorType for AnyPin> { +impl embedded_hal_1::digital::ErrorType for AnyPin, TYPE> { type Error = Infallible; } #[cfg(feature = "eh1")] -impl embedded_hal_1::digital::OutputPin for AnyPin> { +impl embedded_hal_1::digital::OutputPin for AnyPin, TYPE> { fn set_low(&mut self) -> Result<(), Self::Error> { let inner = &mut self.inner; handle_gpio_output!(inner, target, { target.set_low() }) @@ -1447,7 +1799,7 @@ impl embedded_hal_1::digital::OutputPin for AnyPin> { } #[cfg(feature = "eh1")] -impl embedded_hal_1::digital::StatefulOutputPin for AnyPin> { +impl embedded_hal_1::digital::StatefulOutputPin for AnyPin, TYPE> { fn is_set_high(&mut self) -> Result { let inner = &mut self.inner; handle_gpio_output!(inner, target, { target.is_set_high() }) @@ -1460,7 +1812,7 @@ impl embedded_hal_1::digital::StatefulOutputPin for AnyPin> { } #[cfg(feature = "async")] -impl embedded_hal_async::digital::Wait for AnyPin> { +impl embedded_hal_async::digital::Wait for AnyPin, TYPE> { async fn wait_for_high(&mut self) -> Result<(), Self::Error> { let inner = &mut self.inner; handle_gpio_input!(inner, target, { target.wait_for_high().await }) @@ -1598,28 +1950,40 @@ macro_rules! gpio { )+ } - pub struct AnyPin { - pub(crate) inner: ErasedPin + pub struct AnyPin { + pub(crate) inner: ErasedPin, + pub(crate) _type: core::marker::PhantomData, } $( + impl From< [] > for AnyPin]> { + fn from(value: []) -> Self { + AnyPin { + inner: ErasedPin::[](value), + _type: core::marker::PhantomData, + } + } + } + impl From< [] > for AnyPin { fn from(value: []) -> Self { AnyPin { - inner: ErasedPin::[](value) + inner: ErasedPin::[](value), + _type: core::marker::PhantomData, } } } impl [] { - pub fn degrade(self) -> AnyPin { + pub fn degrade(self) -> AnyPin]> { AnyPin { - inner: ErasedPin::[](self) + inner: ErasedPin::[](self), + _type: core::marker::PhantomData, } } } - impl TryInto<[]> for AnyPin { + impl TryInto<[]> for AnyPin { type Error = (); fn try_into(self) -> Result<[], Self::Error> { diff --git a/esp32-hal/examples/blinky_erased_pins.rs b/esp32-hal/examples/blinky_erased_pins.rs index 170a687ba3c..e02d40c1d45 100644 --- a/esp32-hal/examples/blinky_erased_pins.rs +++ b/esp32-hal/examples/blinky_erased_pins.rs @@ -27,10 +27,10 @@ fn main() -> ! { let led3 = io.pins.gpio27.into_push_pull_output(); // Set GPIO9 as an input. - let button = io.pins.gpio0.into_pull_down_input().degrade(); + let button = io.pins.gpio0.into_pull_down_input().into(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().into()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32c2-hal/examples/blinky_erased_pins.rs b/esp32c2-hal/examples/blinky_erased_pins.rs index 27bde11d588..ae57ad2b33f 100644 --- a/esp32c2-hal/examples/blinky_erased_pins.rs +++ b/esp32c2-hal/examples/blinky_erased_pins.rs @@ -27,10 +27,10 @@ fn main() -> ! { let led3 = io.pins.gpio5.into_push_pull_output(); // Set GPIO9 as an input. - let button = io.pins.gpio9.into_pull_down_input().degrade(); + let button = io.pins.gpio9.into_pull_down_input().into(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().into()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32c3-hal/examples/blinky_erased_pins.rs b/esp32c3-hal/examples/blinky_erased_pins.rs index 2c926800d0c..3a46a05531b 100644 --- a/esp32c3-hal/examples/blinky_erased_pins.rs +++ b/esp32c3-hal/examples/blinky_erased_pins.rs @@ -27,10 +27,10 @@ fn main() -> ! { let led3 = io.pins.gpio5.into_push_pull_output(); // Set GPIO9 as an input. - let button = io.pins.gpio9.into_pull_down_input().degrade(); + let button = io.pins.gpio9.into_pull_down_input().into(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().into()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32c6-hal/examples/blinky_erased_pins.rs b/esp32c6-hal/examples/blinky_erased_pins.rs index a82c4e5dfd9..24eb8efab24 100644 --- a/esp32c6-hal/examples/blinky_erased_pins.rs +++ b/esp32c6-hal/examples/blinky_erased_pins.rs @@ -27,10 +27,10 @@ fn main() -> ! { let led3 = io.pins.gpio5.into_push_pull_output(); // Set GPIO9 as an input. - let button = io.pins.gpio9.into_pull_down_input().degrade(); + let button = io.pins.gpio9.into_pull_down_input().into(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().into()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32h2-hal/examples/blinky_erased_pins.rs b/esp32h2-hal/examples/blinky_erased_pins.rs index b5032957cb4..4dc0b83bc77 100644 --- a/esp32h2-hal/examples/blinky_erased_pins.rs +++ b/esp32h2-hal/examples/blinky_erased_pins.rs @@ -27,10 +27,10 @@ fn main() -> ! { let led3 = io.pins.gpio5.into_push_pull_output(); // Set GPIO9 as an input. - let button = io.pins.gpio9.into_pull_down_input().degrade(); + let button = io.pins.gpio9.into_pull_down_input().into(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().into()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32s2-hal/examples/blinky_erased_pins.rs b/esp32s2-hal/examples/blinky_erased_pins.rs index 2ee4ba9a8a1..90bae4353ac 100644 --- a/esp32s2-hal/examples/blinky_erased_pins.rs +++ b/esp32s2-hal/examples/blinky_erased_pins.rs @@ -27,10 +27,10 @@ fn main() -> ! { let led3 = io.pins.gpio5.into_push_pull_output(); // Set GPIO9 as an input. - let button = io.pins.gpio0.into_pull_down_input().degrade(); + let button = io.pins.gpio0.into_pull_down_input().into(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().into()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop. diff --git a/esp32s3-hal/examples/blinky_erased_pins.rs b/esp32s3-hal/examples/blinky_erased_pins.rs index d7b6256a363..842488ca2c3 100644 --- a/esp32s3-hal/examples/blinky_erased_pins.rs +++ b/esp32s3-hal/examples/blinky_erased_pins.rs @@ -27,10 +27,10 @@ fn main() -> ! { let led3 = io.pins.gpio5.into_push_pull_output(); // Set GPIO9 as an input. - let button = io.pins.gpio0.into_pull_down_input().degrade(); + let button = io.pins.gpio0.into_pull_down_input().into(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().into()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop.