esp_hal/
macros.rs

1//! Macros used by the HAL.
2//!
3//! Most of the macros in this module are hidden and intended for internal use
4//! only. For the list of public macros, see the [procmacros](https://docs.rs/esp-hal-procmacros/latest/esp_hal_procmacros/)
5//! documentation.
6
7#[doc(hidden)]
8/// Helper macro for checking doctest code snippets
9#[macro_export]
10macro_rules! before_snippet {
11    () => {
12        r#"
13# #![no_std]
14# use procmacros::handler;
15# use esp_hal::{interrupt::{self, InterruptConfigurable}, time::{Duration, Instant, Rate}};
16# macro_rules! println {
17#     ($($tt:tt)*) => { };
18# }
19# macro_rules! print {
20#     ($($tt:tt)*) => { };
21# }
22# #[panic_handler]
23# fn panic(_ : &core::panic::PanicInfo) -> ! {
24#     loop {}
25# }
26# fn main() {
27#   let _ = example();
28# }
29# struct ExampleError {}
30# impl <T> From<T> for ExampleError where T: core::fmt::Debug {
31#   fn from(_value: T) -> Self {
32#       Self{}
33#   }
34# }
35# async fn example() -> Result<(), ExampleError> {
36#   let mut peripherals = esp_hal::init(esp_hal::Config::default());
37"#
38    };
39}
40
41#[doc(hidden)]
42#[macro_export]
43macro_rules! after_snippet {
44    () => {
45        r#"
46# Ok(())
47# }
48"#
49    };
50}
51
52#[doc(hidden)]
53#[macro_export]
54macro_rules! trm_markdown_link {
55    () => {
56        concat!("[Technical Reference Manual](", property!("trm"), ")")
57    };
58    ($anchor:literal) => {
59        concat!(
60            "[Technical Reference Manual](",
61            property!("trm"),
62            "#",
63            $anchor,
64            ")"
65        )
66    };
67}
68
69#[doc(hidden)]
70/// Shorthand to define AnyPeripheral instances.
71///
72/// This macro generates the following:
73///
74/// - An `AnyPeripheral` struct, name provided by the macro call.
75/// - An `any::Degrade` trait which is supposed to be used as a supertrait of a relevant Instance.
76/// - An `any::Inner` enum, with the same variants as the original peripheral.
77/// - A `From` implementation for each peripheral variant.
78/// - A `degrade` method for each peripheral variant using the `any::Degrade` trait.
79#[macro_export]
80macro_rules! any_peripheral {
81    ($(#[$meta:meta])* $vis:vis peripheral $name:ident<'d> {
82        $(
83            $(#[cfg($variant_meta:meta)])*
84            $variant:ident($inner:ty)
85        ),* $(,)?
86    }) => {
87        #[doc = concat!("Utilities related to [`", stringify!($name), "`]")]
88        #[doc(hidden)]
89        #[instability::unstable]
90        pub mod any {
91            #[allow(unused_imports)]
92            use super::*;
93
94            macro_rules! delegate {
95                ($any:ident, $inner_ident:ident => $code:tt) => {
96                    match &$any.0 {
97                        $(
98                            $(#[cfg($variant_meta)])*
99                            any::Inner::$variant($inner_ident) => $code,
100                        )*
101                    }
102                }
103            }
104
105            pub(crate) use delegate;
106
107            $(#[$meta])*
108            #[derive(Debug)]
109            pub(crate) enum Inner<'d> {
110                $(
111                    $(#[cfg($variant_meta)])*
112                    $variant($inner),
113                )*
114            }
115
116            #[cfg(feature = "defmt")]
117            impl defmt::Format for Inner<'_> {
118                fn format(&self, fmt: defmt::Formatter<'_>) {
119                    match self {
120                        $(
121                            $(#[cfg($variant_meta)])*
122                            Self::$variant(inner) => inner.format(fmt),
123                        )*
124                    }
125                }
126            }
127
128            // Trick to make peripherals implement something Into-like, without
129            // requiring Instance traits to have lifetimes. Rustdoc will list
130            // this trait as a supertrait, but will not give its definition.
131            // Users are encouraged to use From to convert a singleton into its
132            // relevant AnyPeripheral counterpart.
133            #[allow(unused)]
134            pub trait Degrade: Sized + $crate::private::Sealed {
135                fn degrade<'a>(self) -> super::$name<'a>
136                where
137                    Self: 'a;
138            }
139        }
140
141        $(#[$meta])*
142        ///
143        /// This struct is a type-erased version of a peripheral singleton. It is useful
144        /// for creating arrays of peripherals, or avoiding generics. Peripheral singletons
145        /// can be type erased by using their `From` implementation.
146        ///
147        /// ```rust,ignore
148        #[doc = concat!("let any_peripheral = ", stringify!($name), "::from(peripheral);")]
149        /// ```
150        #[derive(Debug)]
151        #[cfg_attr(feature = "defmt", derive(defmt::Format))]
152        $vis struct $name<'d>(any::Inner<'d>);
153
154        impl $name<'_> {
155            /// Unsafely clone this peripheral reference.
156            ///
157            /// # Safety
158            ///
159            /// You must ensure that you're only using one instance of this type at a time.
160            #[inline]
161            pub unsafe fn clone_unchecked(&self) -> Self { unsafe {
162                any::delegate!(self, inner => { Self::from(inner.clone_unchecked()) })
163            }}
164
165            /// Creates a new peripheral reference with a shorter lifetime.
166            ///
167            /// Use this method if you would like to keep working with the peripheral after
168            /// you dropped the driver that consumes this.
169            ///
170            /// See [Peripheral singleton] section for more information.
171            ///
172            /// [Peripheral singleton]: crate#peripheral-singletons
173            #[inline]
174            pub fn reborrow(&mut self) -> $name<'_> {
175                unsafe { self.clone_unchecked() }
176            }
177
178            #[procmacros::doc_replace]
179            /// Attempts to downcast the pin into the underlying peripheral instance.
180            ///
181            /// ## Example
182            ///
183            /// ```rust,no_run
184            /// # {before_snippet}
185            /// #
186            /// # use esp_hal::{
187            /// #     uart::AnyUart as AnyPeripheral,
188            /// #     peripherals::{UART0 as PERI0, UART1 as PERI1},
189            /// # };
190            /// #
191            /// # let peri0 = peripherals.UART0;
192            /// # let peri1 = peripherals.UART1;
193            /// // let peri0 = peripherals.PERI0;
194            /// // let peri1 = peripherals.PERI1;
195            /// let any_peri0 = AnyPeripheral::from(peri0);
196            /// let any_peri1 = AnyPeripheral::from(peri1);
197            ///
198            /// let uart0 = any_peri0
199            ///     .downcast::<PERI0>()
200            ///     .expect("This downcast succeeds because AnyPeripheral was created from Peri0");
201            /// let uart0 = any_peri1
202            ///     .downcast::<PERI0>()
203            ///     .expect_err("This AnyPeripheral was created from Peri1, it cannot be downcast to Peri0");
204            /// #
205            /// # {after_snippet}
206            /// ```
207            #[inline]
208            pub fn downcast<P>(self) -> Result<P, Self>
209            where
210                Self: TryInto<P, Error = Self>
211            {
212                self.try_into()
213            }
214        }
215
216        impl $crate::private::Sealed for $name<'_> {}
217
218        // AnyPeripheral converts into itself
219        impl<'d> any::Degrade for $name<'d> {
220            #[inline]
221            fn degrade<'a>(self) -> $name<'a>
222            where
223                Self: 'a,
224            {
225                self
226            }
227        }
228
229        $(
230            // Variants convert into AnyPeripheral
231            $(#[cfg($variant_meta)])*
232            impl<'d> any::Degrade for $inner {
233                #[inline]
234                fn degrade<'a>(self) -> $name<'a>
235                where
236                    Self: 'a,
237                {
238                    $name::from(self)
239                }
240            }
241
242            $(#[cfg($variant_meta)])*
243            impl<'d> From<$inner> for $name<'d> {
244                #[inline]
245                fn from(inner: $inner) -> Self {
246                    Self(any::Inner::$variant(inner))
247                }
248            }
249
250            $(#[cfg($variant_meta)])*
251            impl<'d> TryFrom<$name<'d>> for $inner {
252                type Error = $name<'d>;
253
254                #[inline]
255                fn try_from(any: $name<'d>) -> Result<Self, $name<'d>> {
256                    #[allow(irrefutable_let_patterns)]
257                    if let $name(any::Inner::$variant(inner)) = any {
258                        Ok(inner)
259                    } else {
260                        Err(any)
261                    }
262                }
263            }
264        )*
265    };
266}
267
268/// Macro to choose between two expressions. Useful for implementing "else" for
269/// `$()?` macro syntax.
270#[macro_export]
271#[doc(hidden)]
272macro_rules! if_set {
273    (, $not_set:expr) => {
274        $not_set
275    };
276    ($set:expr, $not_set:expr) => {
277        $set
278    };
279}
280
281/// Macro to ignore tokens.
282///
283/// This is useful when we need existence of a metavariable (to expand a
284/// repetition), but we don't need to use it.
285#[macro_export]
286#[doc(hidden)]
287macro_rules! ignore {
288    ($($item:tt)*) => {};
289}
290
291/// Define a piece of (Espressif-specific) metadata that external tools may
292/// parse.
293///
294/// The symbol name be formatted as `_ESP_METADATA_<category>_<name>`.
295///
296/// This metadata is zero cost, i.e. the value will not be flashed to the
297/// device.
298#[macro_export]
299#[doc(hidden)]
300macro_rules! metadata {
301    ($category:literal, $key:ident, $value:expr) => {
302        #[cfg(feature = "rt")]
303        #[unsafe(link_section = concat!(".espressif.metadata"))]
304        #[used]
305        #[unsafe(export_name = concat!($category, ".", stringify!($key)))]
306        static $key: [u8; $value.len()] = const {
307            let val_bytes = $value.as_bytes();
308            let mut val_bytes_array = [0; $value.len()];
309            let mut i = 0;
310            while i < val_bytes.len() {
311                val_bytes_array[i] = val_bytes[i];
312                i += 1;
313            }
314            val_bytes_array
315        };
316    };
317}
318
319#[procmacros::doc_replace]
320/// Extract fields from [`Peripherals`][crate::peripherals::Peripherals] into named groups.
321///
322/// ## Example
323///
324/// ```rust,no_run
325/// # {before_snippet}
326/// #
327/// use esp_hal::assign_resources;
328///
329/// assign_resources! {
330///     Resources<'d> {
331///         display: DisplayResources<'d> {
332///             spi:  SPI2,
333///             sda:  GPIO5,
334///             sclk: GPIO4,
335///             cs:   GPIO3,
336///             dc:   GPIO2,
337///         },
338///         axl: AccelerometerResources<'d> {
339///             i2c: I2C0,
340///             sda: GPIO0,
341///             scl: GPIO1,
342///         },
343///     }
344/// }
345///
346/// # struct Display<'d>(core::marker::PhantomData<&'d ()>);
347/// fn init_display<'d>(r: DisplayResources<'d>) -> Display<'d> {
348///     // use `r.spi`, `r.sda`, `r.sclk`, `r.cs`, `r.dc`
349///     todo!()
350/// }
351///
352/// # struct Accelerometer<'d>(core::marker::PhantomData<&'d ()>);
353/// fn init_accelerometer<'d>(r: AccelerometerResources<'d>) -> Accelerometer<'d> {
354///     // use `r.i2c`, `r.sda`, `r.scl`
355///     todo!()
356/// }
357///
358/// // let peripherals = esp_hal::init(...);
359/// let resources = split_resources!(peripherals);
360///
361/// let display = init_display(resources.display);
362/// let axl = init_accelerometer(resources.axl);
363///
364/// // Other fields (`peripherals.UART0`, ...) of the `peripherals` struct can still be accessed.
365/// # {after_snippet}
366/// ```
367// Based on https://crates.io/crates/assign-resources
368#[macro_export]
369#[cfg(feature = "unstable")]
370#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
371macro_rules! assign_resources {
372    {
373        $(#[$struct_meta:meta])*
374        $vis:vis $struct_name:ident<$struct_lt:lifetime> {
375            $(
376                $(#[$group_meta:meta])*
377                $group_name:ident : $group_struct:ident<$group_lt:lifetime> {
378                    $(
379                        $(#[$resource_meta:meta])*
380                        $resource_name:ident : $resource_field:ident
381                    ),*
382                    $(,)?
383                }
384            ),+
385            $(,)?
386        }
387    } => {
388        // Group structs
389        $(
390            $(#[$group_meta])*
391            #[allow(missing_docs)]
392            $vis struct $group_struct<$group_lt> {
393                $(
394                    $(#[$resource_meta])*
395                    pub $resource_name: $crate::peripherals::$resource_field<$group_lt>,
396                )+
397            }
398
399            impl<$group_lt> $group_struct<$group_lt> {
400                /// Unsafely create an instance of the assigned peripherals out of thin air.
401                ///
402                /// # Safety
403                ///
404                /// You must ensure that you're only using one instance of the contained peripherals at a time.
405                pub unsafe fn steal() -> Self {
406                    unsafe {
407                        Self {
408                            $($resource_name: $crate::peripherals::$resource_field::steal()),*
409                        }
410                    }
411                }
412
413                /// Creates a new reference to the peripheral group with a shorter lifetime.
414                ///
415                /// Use this method if you would like to keep working with the peripherals after
416                /// you dropped the drivers that consume this.
417                pub fn reborrow(&mut self) -> $group_struct<'_> {
418                    $group_struct {
419                        $($resource_name: self.$resource_name.reborrow()),*
420                    }
421                }
422            }
423        )+
424
425        // Outer struct
426        $(#[$struct_meta])*
427        /// Assigned resources.
428        $vis struct $struct_name<$struct_lt> {
429            $( pub $group_name: $group_struct<$struct_lt>, )+
430        }
431
432        impl<$struct_lt> $struct_name<$struct_lt> {
433            /// Unsafely create an instance of the assigned peripherals out of thin air.
434            ///
435            /// # Safety
436            ///
437            /// You must ensure that you're only using one instance of the contained peripherals at a time.
438            pub unsafe fn steal() -> Self {
439                unsafe {
440                    Self {
441                        $($group_name: $group_struct::steal()),*
442                    }
443                }
444            }
445
446            /// Creates a new reference to the assigned peripherals with a shorter lifetime.
447            ///
448            /// Use this method if you would like to keep working with the peripherals after
449            /// you dropped the drivers that consume this.
450            pub fn reborrow(&mut self) -> $struct_name<'_> {
451                $struct_name {
452                    $($group_name: self.$group_name.reborrow()),*
453                }
454            }
455        }
456
457        /// Extracts resources from the `Peripherals` struct.
458        #[macro_export]
459        macro_rules! split_resources {
460            ($peris:ident) => {
461                $struct_name {
462                    $($group_name: $group_struct {
463                        $($resource_name: $peris.$resource_field),*
464                    }),*
465                }
466            }
467        }
468    };
469}