From 3a456bb9ddf3f3ca0b1f69f0962f1205249526d3 Mon Sep 17 00:00:00 2001 From: Alexander Ananiev <37944234+Volkalex28@users.noreply.github.com> Date: Thu, 8 Feb 2024 09:29:30 +0200 Subject: [PATCH] Add type for gpio::AnyPin (#1067) 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 5f55ae54b..55abd846d 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 e8e3df688..72acc23ab 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 170a687ba..e02d40c1d 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 27bde11d5..ae57ad2b3 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 2c926800d..3a46a0553 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 a82c4e5df..24eb8efab 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 b5032957c..4dc0b83bc 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 2ee4ba9a8..90bae4353 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 d7b6256a3..842488ca2 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.