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}