From 472d5f93e011a3291febd25cdf1adcd5d7bab9c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Wed, 16 Oct 2024 15:34:11 +0200 Subject: [PATCH] Add `PeripheralRef::map_into` (#2326) * Add PeripheralRef::map_into * Update clone_unchecked to take shared self * Simplify pin erasure --- esp-hal/CHANGELOG.md | 2 + esp-hal/src/gpio/interconnect.rs | 6 +-- esp-hal/src/gpio/mod.rs | 78 ++++++++++++------------------- esp-hal/src/gpio/placeholder.rs | 4 +- esp-hal/src/interrupt/software.rs | 2 +- esp-hal/src/peripheral.rs | 64 ++++++++++++++++++++++--- esp-hal/src/timer/mod.rs | 2 +- esp-hal/src/timer/systimer.rs | 2 +- esp-hal/src/timer/timg.rs | 2 +- 9 files changed, 100 insertions(+), 62 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index c82f7cc28..e9674a946 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add burst transfer support to DMA buffers (#2236) +- `AnyPin` now implements `From>`. (#2326) + ### Changed ### Fixed diff --git a/esp-hal/src/gpio/interconnect.rs b/esp-hal/src/gpio/interconnect.rs index db0dd706d..4acf6f754 100644 --- a/esp-hal/src/gpio/interconnect.rs +++ b/esp-hal/src/gpio/interconnect.rs @@ -48,7 +48,7 @@ impl Clone for InputSignal { impl Peripheral for InputSignal { type P = Self; - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { self.clone() } } @@ -187,7 +187,7 @@ pub struct OutputSignal { impl Peripheral for OutputSignal { type P = Self; - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { Self { pin: self.pin.clone_unchecked(), is_inverted: self.is_inverted, @@ -345,7 +345,7 @@ pub struct AnyInputSignal(AnyInputSignalInner); impl Peripheral for AnyInputSignal { type P = Self; - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { self.clone() } } diff --git a/esp-hal/src/gpio/mod.rs b/esp-hal/src/gpio/mod.rs index 39833d385..0580a8e34 100644 --- a/esp-hal/src/gpio/mod.rs +++ b/esp-hal/src/gpio/mod.rs @@ -448,7 +448,7 @@ pub trait PeripheralOutput: PeripheralSignal { } /// Trait implemented by pins which can be used as inputs. -pub trait InputPin: Pin + PeripheralInput { +pub trait InputPin: Pin + PeripheralInput + Into + 'static { /// Listen for interrupts #[doc(hidden)] fn listen(&mut self, event: Event, _: private::Internal) { @@ -519,7 +519,7 @@ pub trait InputPin: Pin + PeripheralInput { } /// Trait implemented by pins which can be used as outputs. -pub trait OutputPin: Pin + PeripheralOutput {} +pub trait OutputPin: Pin + PeripheralOutput + Into + 'static {} /// Trait implemented by pins which can be used as analog pins pub trait AnalogPin: Pin { @@ -776,7 +776,7 @@ where { type P = GpioPin; - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { core::ptr::read(self as *const _) } } @@ -1131,6 +1131,13 @@ macro_rules! gpio { input_signals } } + + impl From> for AnyPin { + fn from(pin: GpioPin<$gpionum>) -> Self { + use $crate::gpio::Pin; + pin.degrade() + } + } )+ pub(crate) enum AnyPinInner { @@ -1142,8 +1149,9 @@ macro_rules! gpio { /// Type-erased GPIO pin pub struct AnyPin(pub(crate) AnyPinInner); - impl AnyPin { - pub(crate) unsafe fn clone_unchecked(&self) -> Self { + impl $crate::peripheral::Peripheral for AnyPin { + type P = AnyPin; + unsafe fn clone_unchecked(&self) -> Self { match self.0 { $(AnyPinInner::[](_) => { Self(AnyPinInner::[< Gpio $gpionum >](unsafe { GpioPin::steal() })) @@ -1152,13 +1160,6 @@ macro_rules! gpio { } } - impl $crate::peripheral::Peripheral for AnyPin { - type P = AnyPin; - unsafe fn clone_unchecked(&mut self) -> Self { - AnyPin::clone_unchecked(self) - } - } - // These macros call the code block on the actually contained GPIO pin. #[doc(hidden)] @@ -1598,18 +1599,17 @@ impl

private::Sealed for Output<'_, P> {} impl<'d, P> Peripheral for Output<'d, P> { type P = P; - unsafe fn clone_unchecked(&mut self) -> P { + unsafe fn clone_unchecked(&self) -> P { self.pin.clone_unchecked() } } impl<'d> Output<'d> { - /// Create GPIO output driver for a [GpioPin] with the provided level + /// Create GPIO open-drain output driver for a [Pin] with the provided + /// initial output-level and [Pull] configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { - let pin = Flex::new(pin); - - Self::new_inner(pin, initial_output) + pub fn new(pin: impl Peripheral

+ 'd, initial_output: Level) -> Self { + Self::new_typed(pin.map_into(), initial_output) } } @@ -1702,7 +1702,7 @@ impl

private::Sealed for Input<'_, P> {} impl<'d, P> Peripheral for Input<'d, P> { type P = P; - unsafe fn clone_unchecked(&mut self) -> P { + unsafe fn clone_unchecked(&self) -> P { self.pin.clone_unchecked() } } @@ -1711,10 +1711,8 @@ impl<'d> Input<'d> { /// Create GPIO input driver for a [Pin] with the provided [Pull] /// configuration. #[inline] - pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { - let pin = Flex::new(pin); - - Self::new_inner(pin, pull) + pub fn new(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { + Self::new_typed(pin.map_into(), pull) } } @@ -1726,12 +1724,8 @@ where /// configuration. #[inline] pub fn new_typed(pin: impl Peripheral

+ 'd, pull: Pull) -> Self { - let pin = Flex::new_typed(pin); + let mut pin = Flex::new_typed(pin); - Self::new_inner(pin, pull) - } - - fn new_inner(mut pin: Flex<'d, P>, pull: Pull) -> Self { pin.set_as_input(pull); Self { pin } @@ -1806,7 +1800,7 @@ impl

private::Sealed for OutputOpenDrain<'_, P> {} impl<'d, P> Peripheral for OutputOpenDrain<'d, P> { type P = P; - unsafe fn clone_unchecked(&mut self) -> P { + unsafe fn clone_unchecked(&self) -> P { self.pin.clone_unchecked() } } @@ -1815,14 +1809,12 @@ impl<'d> OutputOpenDrain<'d> { /// Create GPIO open-drain output driver for a [Pin] with the provided /// initial output-level and [Pull] configuration. #[inline] - pub fn new( - pin: impl Peripheral

+ 'd, + pub fn new( + pin: impl Peripheral

+ 'd, initial_output: Level, pull: Pull, ) -> Self { - let pin = Flex::new(pin); - - Self::new_inner(pin, initial_output, pull) + Self::new_typed(pin.map_into(), initial_output, pull) } } @@ -1834,15 +1826,9 @@ where /// initial output-level and [Pull] configuration. #[inline] pub fn new_typed(pin: impl Peripheral

+ 'd, initial_output: Level, pull: Pull) -> Self { - let pin = Flex::new_typed(pin); - - Self::new_inner(pin, initial_output, pull) - } - - fn new_inner(mut pin: Flex<'d, P>, initial_output: Level, pull: Pull) -> Self { - pin.pin - .set_output_high(initial_output.into(), private::Internal); + let mut pin = Flex::new_typed(pin); + pin.set_level(initial_output); pin.set_as_open_drain(pull); Self { pin } @@ -1945,7 +1931,7 @@ impl

private::Sealed for Flex<'_, P> {} impl<'d, P> Peripheral for Flex<'d, P> { type P = P; - unsafe fn clone_unchecked(&mut self) -> P { + unsafe fn clone_unchecked(&self) -> P { core::ptr::read(&*self.pin as *const _) } } @@ -1954,10 +1940,8 @@ impl<'d> Flex<'d> { /// Create flexible pin driver for a [Pin]. /// No mode change happens. #[inline] - pub fn new(pin: impl Peripheral

+ 'd) -> Self { - crate::into_ref!(pin); - let pin = pin.degrade_pin(private::Internal); - Self::new_typed(pin) + pub fn new(pin: impl Peripheral

> + 'd) -> Self { + Self::new_typed(pin.map_into()) } } diff --git a/esp-hal/src/gpio/placeholder.rs b/esp-hal/src/gpio/placeholder.rs index 3ced27796..5e604324b 100644 --- a/esp-hal/src/gpio/placeholder.rs +++ b/esp-hal/src/gpio/placeholder.rs @@ -10,7 +10,7 @@ use super::*; impl crate::peripheral::Peripheral for Level { type P = Self; - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { *self } } @@ -96,7 +96,7 @@ pub struct NoPin; impl crate::peripheral::Peripheral for NoPin { type P = Self; - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { Self } } diff --git a/esp-hal/src/interrupt/software.rs b/esp-hal/src/interrupt/software.rs index 67aab7dcb..64156a68d 100644 --- a/esp-hal/src/interrupt/software.rs +++ b/esp-hal/src/interrupt/software.rs @@ -138,7 +138,7 @@ impl crate::peripheral::Peripheral for SoftwareInterrupt { type P = SoftwareInterrupt; #[inline] - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { Self::steal() } } diff --git a/esp-hal/src/peripheral.rs b/esp-hal/src/peripheral.rs index 887835f22..7075f0f9b 100644 --- a/esp-hal/src/peripheral.rs +++ b/esp-hal/src/peripheral.rs @@ -44,7 +44,7 @@ impl<'a, T> PeripheralRef<'a, T> { /// You should strongly prefer using `reborrow()` instead. It returns a /// `PeripheralRef` that borrows `self`, which allows the borrow checker /// to enforce this at compile time. - pub unsafe fn clone_unchecked(&mut self) -> PeripheralRef<'a, T> + pub unsafe fn clone_unchecked(&self) -> PeripheralRef<'a, T> where T: Peripheral

, { @@ -62,6 +62,24 @@ impl<'a, T> PeripheralRef<'a, T> { // self, so user code can't use both at the same time. PeripheralRef::new(unsafe { self.inner.clone_unchecked() }) } + + /// Map the inner peripheral using `Into`. + /// + /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, + /// using an `Into` impl to convert from `T` to `U`. + /// + /// For example, this can be useful to degrade GPIO pins: converting from + /// PeripheralRef<'a, GpioPin<11>>` to `PeripheralRef<'a, AnyPin>`. + #[inline] + pub fn map_into(self) -> PeripheralRef<'a, U> + where + T: Into, + { + PeripheralRef { + inner: self.inner.into(), + _lifetime: PhantomData, + } + } } impl<'a, T> Deref for PeripheralRef<'a, T> { @@ -137,19 +155,32 @@ pub trait Peripheral: Sized + crate::private::Sealed { /// You should strongly prefer using `into_ref()` instead. It returns a /// `PeripheralRef`, which allows the borrow checker to enforce this at /// compile time. - unsafe fn clone_unchecked(&mut self) -> Self::P; + unsafe fn clone_unchecked(&self) -> Self::P; /// Convert a value into a `PeripheralRef`. /// /// When called on an owned `T`, yields a `PeripheralRef<'static, T>`. /// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`. #[inline] - fn into_ref<'a>(mut self) -> PeripheralRef<'a, Self::P> + fn into_ref<'a>(self) -> PeripheralRef<'a, Self::P> where Self: 'a, { PeripheralRef::new(unsafe { self.clone_unchecked() }) } + + /// Map the peripheral using `Into`. + /// + /// This converts from `Peripheral

` to `Peripheral

`, + /// using an `Into` impl to convert from `T` to `U`. + #[inline] + fn map_into(self) -> U + where + Self::P: Into, + U: Peripheral

, + { + unsafe { self.clone_unchecked().into() } + } } impl Peripheral for &mut T @@ -158,12 +189,22 @@ where { type P = P; - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { T::clone_unchecked(self) } } impl crate::private::Sealed for &mut T where T: crate::private::Sealed {} +impl crate::private::Sealed for PeripheralRef<'_, T> where T: crate::private::Sealed {} + +impl Peripheral for PeripheralRef<'_, T> { + type P = T::P; + + #[inline] + unsafe fn clone_unchecked(&self) -> Self::P { + T::clone_unchecked(self) + } +} mod peripheral_macros { #[doc(hidden)] @@ -257,6 +298,17 @@ mod peripheral_macros { } } + #[doc(hidden)] + #[macro_export] + macro_rules! into_mapped_ref { + ($($name:ident),*) => { + $( + #[allow(unused_mut)] + let mut $name = $name.map_into().into_ref(); + )* + } + } + #[doc(hidden)] #[macro_export] /// Macro to create a peripheral structure. @@ -288,7 +340,7 @@ mod peripheral_macros { type P = $name; #[inline] - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { Self::steal() } } @@ -346,7 +398,7 @@ mod peripheral_macros { type P = $name; #[inline] - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { Self::steal() } } diff --git a/esp-hal/src/timer/mod.rs b/esp-hal/src/timer/mod.rs index e7d2ea0bf..d0ffb517c 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -461,7 +461,7 @@ impl Peripheral for AnyTimer { type P = Self; #[inline] - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { core::ptr::read(self as *const _) } } diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index 0d1ae5e94..7ecbd9f5e 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -1003,7 +1003,7 @@ where type P = Self; #[inline] - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { core::ptr::read(self as *const _) } } diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index 19397971d..96a7bb1c6 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -591,7 +591,7 @@ where type P = Self; #[inline] - unsafe fn clone_unchecked(&mut self) -> Self::P { + unsafe fn clone_unchecked(&self) -> Self::P { core::ptr::read(self as *const _) } }