Skip to main content

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