From 9836fd3088ebe756a8bb6ad586f086bd2a9ba1da Mon Sep 17 00:00:00 2001 From: Volkalex28 Date: Tue, 9 Jan 2024 02:36:30 +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 undefined --- CHANGELOG.md | 1 + esp-hal-common/src/analog/adc/esp32.rs | 1 + esp-hal-common/src/gpio.rs | 398 ++++++++++++++++++++- 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 +- 10 files changed, 397 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 781eb5845b9..0a782d865b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - A macro to make it easier to create DMA buffers and descriptors (#935) - I2C timeout is configurable (#1011) - ESP32-C6/ESP32-H2: `flip-link` feature gives zero-cost stack overflow protection (#1008) +- Implementation OutputPin and InputPin for AnyPin ### Changed diff --git a/esp-hal-common/src/analog/adc/esp32.rs b/esp-hal-common/src/analog/adc/esp32.rs index 03a571b6cb5..d4d596ba13a 100644 --- a/esp-hal-common/src/analog/adc/esp32.rs +++ b/esp-hal-common/src/analog/adc/esp32.rs @@ -423,6 +423,7 @@ macro_rules! impl_adc_interface { } } +#[allow(unused_imports)] pub use implementation::*; mod implementation { diff --git a/esp-hal-common/src/gpio.rs b/esp-hal-common/src/gpio.rs index dcaf8dc086a..e8d251abc49 100644 --- a/esp-hal-common/src/gpio.rs +++ b/esp-hal-common/src/gpio.rs @@ -1355,7 +1355,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::default(), + } + } +} + +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::default(), + } + } +} + +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::default(), + } + } +} + +impl AnyPin { + pub fn into_input_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData::default(), + } + } +} + +impl AnyPin { + pub fn into_input_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData::default(), + } + } + + pub fn into_input_output_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData::default(), + } + } + + pub fn into_input_only_analog_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData::default(), + } + } +} + +impl AnyPin { + pub fn into_input_type(self) -> AnyPin { + AnyPin { + inner: self.inner, + _type: core::marker::PhantomData::default(), + } + } +} + +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 { @@ -1370,12 +1722,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(&self) -> Result { let inner = &self.inner; handle_gpio_input!(inner, target, { target.is_high() }) @@ -1387,7 +1739,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> { @@ -1401,7 +1753,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() }) @@ -1413,7 +1765,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> { @@ -1423,12 +1775,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() }) @@ -1441,7 +1793,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(&self) -> Result { let inner = &self.inner; handle_gpio_output!(inner, target, { target.is_set_high() }) @@ -1454,7 +1806,7 @@ impl embedded_hal_1::digital::StatefulOutputPin for AnyPin> { } #[cfg(feature = "eh1")] -impl embedded_hal_1::digital::ToggleableOutputPin for AnyPin> { +impl embedded_hal_1::digital::ToggleableOutputPin for AnyPin, TYPE> { fn toggle(&mut self) -> Result<(), Self::Error> { let inner = &mut self.inner; handle_gpio_output!(inner, target, { target.toggle() }) @@ -1462,7 +1814,7 @@ impl embedded_hal_1::digital::ToggleableOutputPin 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 }) @@ -1600,28 +1952,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::default(), + } + } + } + impl From< [] > for AnyPin { fn from(value: []) -> Self { AnyPin { - inner: ErasedPin::[](value) + inner: ErasedPin::[](value), + _type: core::marker::PhantomData::default(), } } } impl [] { - pub fn degrade(self) -> AnyPin { + pub fn degrade(self) -> AnyPin]> { AnyPin { - inner: ErasedPin::[](self) + inner: ErasedPin::[](self), + _type: core::marker::PhantomData::default(), } } } - 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..f2a8ff2d363 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().degrade().degrade(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().degrade()]; // 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..c0b7c611834 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().degrade().degrade(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().degrade()]; // 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..86f13bccd1a 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().degrade().degrade(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().degrade()]; // 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..83ca907b061 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().degrade().degrade(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().degrade()]; // 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..efae6bb5223 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().degrade().degrade(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().degrade()]; // 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..bca1a917494 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().degrade().degrade(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().degrade()]; // 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..0eca429b04e 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().degrade().degrade(); // You can use `into` or `degrade` - let mut pins = [led1.into(), led2.into(), led3.degrade()]; + let mut pins = [led1.into(), led2.into(), led3.degrade().degrade()]; // Initialize the Delay peripheral, and use it to toggle the LED state in a // loop.