Skip to content

Commit

Permalink
Add PeripheralRef::map_into (#2326)
Browse files Browse the repository at this point in the history
* Add PeripheralRef::map_into

* Update clone_unchecked to take shared self

* Simplify pin erasure
  • Loading branch information
bugadani authored Oct 16, 2024
1 parent 6e2606b commit 472d5f9
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 62 deletions.
2 changes: 2 additions & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<GpioPin<N>>`. (#2326)

### Changed

### Fixed
Expand Down
6 changes: 3 additions & 3 deletions esp-hal/src/gpio/interconnect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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()
}
}
Expand Down
78 changes: 31 additions & 47 deletions esp-hal/src/gpio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<AnyPin> + 'static {
/// Listen for interrupts
#[doc(hidden)]
fn listen(&mut self, event: Event, _: private::Internal) {
Expand Down Expand Up @@ -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<AnyPin> + 'static {}

/// Trait implemented by pins which can be used as analog pins
pub trait AnalogPin: Pin {
Expand Down Expand Up @@ -776,7 +776,7 @@ where
{
type P = GpioPin<GPIONUM>;

unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(self as *const _)
}
}
Expand Down Expand Up @@ -1131,6 +1131,13 @@ macro_rules! gpio {
input_signals
}
}

impl From<GpioPin<$gpionum>> for AnyPin {
fn from(pin: GpioPin<$gpionum>) -> Self {
use $crate::gpio::Pin;
pin.degrade()
}
}
)+

pub(crate) enum AnyPinInner {
Expand All @@ -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::[<Gpio $gpionum >](_) => {
Self(AnyPinInner::[< Gpio $gpionum >](unsafe { GpioPin::steal() }))
Expand All @@ -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)]
Expand Down Expand Up @@ -1598,18 +1599,17 @@ impl<P> 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<P: OutputPin>(pin: impl Peripheral<P = P> + 'd, initial_output: Level) -> Self {
let pin = Flex::new(pin);

Self::new_inner(pin, initial_output)
pub fn new(pin: impl Peripheral<P = impl OutputPin> + 'd, initial_output: Level) -> Self {
Self::new_typed(pin.map_into(), initial_output)
}
}

Expand Down Expand Up @@ -1702,7 +1702,7 @@ impl<P> 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()
}
}
Expand All @@ -1711,10 +1711,8 @@ impl<'d> Input<'d> {
/// Create GPIO input driver for a [Pin] with the provided [Pull]
/// configuration.
#[inline]
pub fn new<P: InputPin>(pin: impl Peripheral<P = P> + 'd, pull: Pull) -> Self {
let pin = Flex::new(pin);

Self::new_inner(pin, pull)
pub fn new(pin: impl Peripheral<P = impl InputPin> + 'd, pull: Pull) -> Self {
Self::new_typed(pin.map_into(), pull)
}
}

Expand All @@ -1726,12 +1724,8 @@ where
/// configuration.
#[inline]
pub fn new_typed(pin: impl Peripheral<P = P> + '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 }
Expand Down Expand Up @@ -1806,7 +1800,7 @@ impl<P> 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()
}
}
Expand All @@ -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<P: InputPin + OutputPin>(
pin: impl Peripheral<P = P> + 'd,
pub fn new(
pin: impl Peripheral<P = impl InputPin + OutputPin> + '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)
}
}

Expand All @@ -1834,15 +1826,9 @@ where
/// initial output-level and [Pull] configuration.
#[inline]
pub fn new_typed(pin: impl Peripheral<P = P> + '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 }
Expand Down Expand Up @@ -1945,7 +1931,7 @@ impl<P> 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 _)
}
}
Expand All @@ -1954,10 +1940,8 @@ impl<'d> Flex<'d> {
/// Create flexible pin driver for a [Pin].
/// No mode change happens.
#[inline]
pub fn new<P: Pin>(pin: impl Peripheral<P = P> + 'd) -> Self {
crate::into_ref!(pin);
let pin = pin.degrade_pin(private::Internal);
Self::new_typed(pin)
pub fn new(pin: impl Peripheral<P = impl Into<AnyPin>> + 'd) -> Self {
Self::new_typed(pin.map_into())
}
}

Expand Down
4 changes: 2 additions & 2 deletions esp-hal/src/gpio/placeholder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down Expand Up @@ -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
}
}
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/interrupt/software.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl<const NUM: u8> crate::peripheral::Peripheral for SoftwareInterrupt<NUM> {
type P = SoftwareInterrupt<NUM>;

#[inline]
unsafe fn clone_unchecked(&mut self) -> Self::P {
unsafe fn clone_unchecked(&self) -> Self::P {
Self::steal()
}
}
Expand Down
64 changes: 58 additions & 6 deletions esp-hal/src/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<P = T>,
{
Expand All @@ -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<U>(self) -> PeripheralRef<'a, U>
where
T: Into<U>,
{
PeripheralRef {
inner: self.inner.into(),
_lifetime: PhantomData,
}
}
}

impl<'a, T> Deref for PeripheralRef<'a, T> {
Expand Down Expand Up @@ -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<P = T>` to `Peripheral<P = U>`,
/// using an `Into` impl to convert from `T` to `U`.
#[inline]
fn map_into<U>(self) -> U
where
Self::P: Into<U>,
U: Peripheral<P = U>,
{
unsafe { self.clone_unchecked().into() }
}
}

impl<T, P> Peripheral for &mut T
Expand All @@ -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<T> crate::private::Sealed for &mut T where T: crate::private::Sealed {}
impl<T> crate::private::Sealed for PeripheralRef<'_, T> where T: crate::private::Sealed {}

impl<T: Peripheral> 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)]
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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()
}
}
Expand Down Expand Up @@ -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()
}
}
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/timer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 _)
}
}
Loading

0 comments on commit 472d5f9

Please sign in to comment.