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]
10
macro_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]
42
macro_rules! after_snippet {
43
    () => {
44
        r#"
45
# Ok(())
46
# }
47
"#
48
    };
49
}
50

            
51
#[doc(hidden)]
52
#[macro_export]
53
macro_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]
79
macro_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
26
                    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
        /// A type-erased version of a peripheral singleton. 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
            /// The caller must ensure that only one instance of this type is used at a time.
159
            #[inline]
160
            #[allow(unused)]
161
            pub unsafe fn clone_unchecked(&self) -> Self { unsafe {
162
36
                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 to keep working with the peripheral after
168
            /// dropping the driver that consumes this.
169
            ///
170
            /// See [Peripheral singleton] section for more information.
171
            ///
172
            /// [Peripheral singleton]: crate#peripheral-singletons
173
            #[inline]
174
            #[allow(unused)]
175
            pub fn reborrow(&mut self) -> $name<'_> {
176
                unsafe { self.clone_unchecked() }
177
            }
178

            
179
            #[procmacros::doc_replace]
180
            /// Attempts to downcast the pin into the underlying peripheral instance.
181
            #[cfg_attr(
182
                // Feature-gated so that this doesn't prevent gradual device bringup. Any
183
                // stable driver would serve the purpose here, so this block will be part
184
                // of the released documentation.
185
                uart_driver_supported,
186
                doc = r#"
187
## Example
188

            
189
```rust,no_run
190
# {before_snippet}
191
#
192
# use esp_hal::{
193
#     uart::AnyUart as AnyPeripheral,
194
#     peripherals::{UART0 as PERI0, UART1 as PERI1},
195
# };
196
#
197
# let peri0 = peripherals.UART0;
198
# let peri1 = peripherals.UART1;
199
// let peri0 = peripherals.PERI0;
200
// let peri1 = peripherals.PERI1;
201
let any_peri0 = AnyPeripheral::from(peri0);
202
let any_peri1 = AnyPeripheral::from(peri1);
203

            
204
let uart0 = any_peri0
205
    .downcast::<PERI0>()
206
    .expect("This downcast succeeds because AnyPeripheral was created from Peri0");
207
let uart0 = any_peri1
208
    .downcast::<PERI0>()
209
    .expect_err("This AnyPeripheral was created from Peri1, it cannot be downcast to Peri0");
210
#
211
# {after_snippet}
212
```
213
"#
214
            )]
215
            #[inline]
216
            #[allow(unused)]
217
            pub fn downcast<P>(self) -> Result<P, Self>
218
            where
219
                Self: TryInto<P, Error = Self>
220
            {
221
                self.try_into()
222
            }
223
        }
224

            
225
        impl $crate::private::Sealed for $name<'_> {}
226

            
227
        // AnyPeripheral converts into itself
228
        impl<'d> any::Degrade for $name<'d> {
229
            #[inline]
230
            fn degrade<'a>(self) -> $name<'a>
231
            where
232
                Self: 'a,
233
            {
234
                self
235
            }
236
        }
237

            
238
        $(
239
            // Variants convert into AnyPeripheral
240
            $(#[cfg($variant_meta)])*
241
            impl<'d> any::Degrade for $inner {
242
                #[inline]
243
                fn degrade<'a>(self) -> $name<'a>
244
                where
245
                    Self: 'a,
246
                {
247
                    $name::from(self)
248
                }
249
            }
250

            
251
            $(#[cfg($variant_meta)])*
252
            impl<'d> From<$inner> for $name<'d> {
253
                #[inline]
254
                fn from(inner: $inner) -> Self {
255
24
                    Self(any::Inner::$variant(inner))
256
                }
257
            }
258

            
259
            $(#[cfg($variant_meta)])*
260
            impl<'d> TryFrom<$name<'d>> for $inner {
261
                type Error = $name<'d>;
262

            
263
                #[inline]
264
                fn try_from(any: $name<'d>) -> Result<Self, $name<'d>> {
265
                    #[allow(irrefutable_let_patterns)]
266
                    if let $name(any::Inner::$variant(inner)) = any {
267
                        Ok(inner)
268
                    } else {
269
                        Err(any)
270
                    }
271
                }
272
            }
273
        )*
274
    };
275
}
276

            
277
/// Macro to choose between two expressions. Useful for implementing "else" for
278
/// `$()?` macro syntax.
279
#[macro_export]
280
#[doc(hidden)]
281
macro_rules! if_set {
282
    (, $not_set:expr) => {
283
        $not_set
284
    };
285
    ($set:expr, $not_set:expr) => {
286
        $set
287
    };
288
}
289

            
290
#[cfg(feature = "unstable")]
291
include!(concat!(env!("OUT_DIR"), "/version_macro.rs"));
292

            
293
#[doc_replace]
294
/// Selects code based on the `esp-hal` version.
295
///
296
/// Branches are considered from top to bottom. The first branch whose version
297
/// is less than or equal to the current `esp-hal` version is
298
/// expanded. The fallback branch is expanded if no version branch matches.
299
///
300
/// Version branches should be listed in descending order.
301
///
302
/// # Examples
303
///
304
/// ```rust,no_run
305
/// # {before_snippet}
306
/// use esp_hal::at_least_version;
307
///
308
/// let description = at_least_version! {
309
///     (2, 0, 0) => { "esp-hal 2.0.0 or newer" }
310
///     (1, 1, 0) => { "esp-hal 1.1.0 or newer" }
311
///     _ => { "an older esp-hal version" }
312
/// };
313
/// # {after_snippet}
314
/// ```
315
#[macro_export]
316
#[cfg(feature = "unstable")]
317
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
318
macro_rules! at_least_version {
319
    ($($branch:tt)*) => {
320
        $crate::__esp_hal_at_least_version! { $($branch)* }
321
    };
322
}
323

            
324
/// Macro to ignore tokens.
325
///
326
/// This is useful when a metavariable must exist (to expand a
327
/// repetition), but need not be used.
328
#[macro_export]
329
#[doc(hidden)]
330
macro_rules! ignore {
331
    ($($item:tt)*) => {};
332
}
333

            
334
/// Defines a piece of (Espressif-specific) metadata that external tools may
335
/// parse.
336
///
337
/// The symbol name be formatted as `_ESP_METADATA_<category>_<name>`.
338
///
339
/// This metadata is zero cost, i.e. the value will not be flashed to the
340
/// device.
341
#[macro_export]
342
#[doc(hidden)]
343
macro_rules! metadata {
344
    ($category:literal, $key:ident, $value:expr) => {
345
        #[cfg(feature = "rt")]
346
        #[unsafe(link_section = concat!(".espressif.metadata"))]
347
        #[used]
348
        #[unsafe(export_name = concat!($category, ".", stringify!($key)))]
349
        static $key: [u8; $value.len()] = const {
350
            let val_bytes = $value.as_bytes();
351
            let mut val_bytes_array = [0; $value.len()];
352
            let mut i = 0;
353
            while i < val_bytes.len() {
354
                val_bytes_array[i] = val_bytes[i];
355
                i += 1;
356
            }
357
            val_bytes_array
358
        };
359
    };
360
}
361

            
362
#[procmacros::doc_replace]
363
/// Extract fields from [`Peripherals`][crate::peripherals::Peripherals] into named groups.
364
#[cfg_attr(
365
    // Feature-gated so that this doesn't prevent gradual device bringup. Any
366
    // stable driver would serve the purpose here, so this block will be part
367
    // of the released documentation.
368
    all(soc_has_spi2, soc_has_i2c0, gpio_driver_supported),
369
    doc = r#"
370
## Example
371

            
372
```rust,no_run
373
# {before_snippet}
374
#
375
use esp_hal::assign_resources;
376

            
377
assign_resources! {
378
    Resources<'d> {
379
        display: DisplayResources<'d> {
380
            spi:  SPI2,
381
            sda:  GPIO5,
382
            sclk: GPIO4,
383
            cs:   GPIO3,
384
            dc:   GPIO2,
385
        },
386
        axl: AccelerometerResources<'d> {
387
            i2c: I2C0,
388
            sda: GPIO0,
389
            scl: GPIO1,
390
        },
391
    }
392
}
393

            
394
# struct Display<'d>(core::marker::PhantomData<&'d ()>);
395
fn init_display<'d>(r: DisplayResources<'d>) -> Display<'d> {
396
    // use `r.spi`, `r.sda`, `r.sclk`, `r.cs`, `r.dc`
397
    todo!()
398
}
399

            
400
# struct Accelerometer<'d>(core::marker::PhantomData<&'d ()>);
401
fn init_accelerometer<'d>(r: AccelerometerResources<'d>) -> Accelerometer<'d> {
402
    // use `r.i2c`, `r.sda`, `r.scl`
403
    todo!()
404
}
405

            
406
// let peripherals = esp_hal::init(...);
407
let resources = split_resources!(peripherals);
408

            
409
let display = init_display(resources.display);
410
let axl = init_accelerometer(resources.axl);
411

            
412
// Other fields (`peripherals.UART0`, ...) of the `peripherals` struct can still be accessed.
413
# {after_snippet}
414
```
415
"#
416
)]
417
// Based on https://crates.io/crates/assign-resources
418
#[macro_export]
419
#[cfg(feature = "unstable")]
420
#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
421
macro_rules! assign_resources {
422
    {
423
        $(#[$struct_meta:meta])*
424
        $vis:vis $struct_name:ident<$struct_lt:lifetime> {
425
            $(
426
                $(#[$group_meta:meta])*
427
                $group_name:ident : $group_struct:ident<$group_lt:lifetime> {
428
                    $(
429
                        $(#[$resource_meta:meta])*
430
                        $resource_name:ident : $resource_field:ident
431
                    ),*
432
                    $(,)?
433
                }
434
            ),+
435
            $(,)?
436
        }
437
    } => {
438
        // Group structs
439
        $(
440
            $(#[$group_meta])*
441
            #[allow(missing_docs)]
442
            $vis struct $group_struct<$group_lt> {
443
                $(
444
                    $(#[$resource_meta])*
445
                    pub $resource_name: $crate::peripherals::$resource_field<$group_lt>,
446
                )+
447
            }
448

            
449
            impl<$group_lt> $group_struct<$group_lt> {
450
                /// Unsafely creates an instance of the assigned peripherals out of thin air.
451
                ///
452
                /// # Safety
453
                ///
454
                /// The caller must ensure that only one instance of the contained peripherals is used at a time.
455
                pub unsafe fn steal() -> Self {
456
                    unsafe {
457
                        Self {
458
                            $($resource_name: $crate::peripherals::$resource_field::steal()),*
459
                        }
460
                    }
461
                }
462

            
463
                /// Creates a new reference to the peripheral group with a shorter lifetime.
464
                ///
465
                /// Use this method to keep working with the peripherals after
466
                /// dropping the drivers that consume this.
467
                pub fn reborrow(&mut self) -> $group_struct<'_> {
468
                    $group_struct {
469
                        $($resource_name: self.$resource_name.reborrow()),*
470
                    }
471
                }
472
            }
473
        )+
474

            
475
        // Outer struct
476
        $(#[$struct_meta])*
477
        /// Assigned resources.
478
        $vis struct $struct_name<$struct_lt> {
479
            $( pub $group_name: $group_struct<$struct_lt>, )+
480
        }
481

            
482
        impl<$struct_lt> $struct_name<$struct_lt> {
483
            /// Unsafely creates an instance of the assigned peripherals out of thin air.
484
            ///
485
            /// # Safety
486
            ///
487
            /// The caller must ensure that only one instance of the contained peripherals is used at a time.
488
            pub unsafe fn steal() -> Self {
489
                unsafe {
490
                    Self {
491
                        $($group_name: $group_struct::steal()),*
492
                    }
493
                }
494
            }
495

            
496
            /// Creates a new reference to the assigned peripherals with a shorter lifetime.
497
            ///
498
            /// Use this method to keep working with the peripherals after
499
            /// dropping the drivers that consume this.
500
            pub fn reborrow(&mut self) -> $struct_name<'_> {
501
                $struct_name {
502
                    $($group_name: self.$group_name.reborrow()),*
503
                }
504
            }
505
        }
506

            
507
        /// Extracts resources from the `Peripherals` struct.
508
        #[macro_export]
509
        macro_rules! split_resources {
510
            ($peris:ident) => {
511
                $struct_name {
512
                    $($group_name: $group_struct {
513
                        $($resource_name: $peris.$resource_field),*
514
                    }),*
515
                }
516
            }
517
        }
518
    };
519
}
520

            
521
/// Helper macro to implement the relevant DMA channel compatibility trait for peripheral
522
/// instances and DMA channel types.
523
///
524
/// Expected uses:
525
///
526
/// Drivers that define an AnyPeripheral type:
527
///
528
/// ```rust, ignore
529
/// with_spi_dma_engine! {
530
///     ($engine:tt, $any_peri:ident) => {
531
///         crate::impl_dma_channel_trait! {
532
///             $engine,
533
///             any_peri = AnySpi,
534
///             peris = for_each_spi_master,
535
///             ($peri:path, $ch:path) => {
536
///                 impl<'d> SpiMasterDmaChannel<'d, $peri<'d>> for $ch<'d> {}
537
///             }
538
///         }
539
///     }
540
/// }
541
/// ```
542
///
543
/// Drivers that do not:
544
///
545
/// ```rust, ignore
546
/// with_aes_dma_engine! {
547
///     ($engine:tt, $any_peri:ident) => {
548
///         crate::impl_dma_channel_trait! {
549
///             $engine,
550
///             peri = AES, // no lifetime!
551
///             ($peri:path, $ch:path) => {
552
///                 impl<'d> AesDmaChannel<'d> for $ch<'d> {}
553
///             }
554
///         }
555
///     }
556
/// }
557
/// ```
558
#[doc(hidden)]
559
#[rustfmt::skip]
560
#[cfg(dma_driver_supported)]
561
macro_rules! impl_dma_channel_trait {
562
    // Single peripheral instance case
563
    (
564
        $dma_engine:tt,
565
        peri = $peri:tt,
566
        $pattern:tt => $body:tt
567
    ) => {
568
        macro_rules! impl_dma_channel_trait_inner {
569
            ($pattern) => $body;
570
        }
571

            
572
        for_each_dma_channel_peri_pair! {
573
            ($dma_engine, any_channel = $any_ch:ident, $peri) => {
574
                impl_dma_channel_trait_inner! { ( $peri <'d>, $crate::dma::$any_ch<'d>) }
575
            };
576
            ($dma_engine, $ch:ident, $peri) => {
577
                impl_dma_channel_trait_inner! { ( $peri <'d>, $crate::peripherals::$ch<'d>) }
578
            };
579
        }
580
    };
581

            
582
    // Multiple peripheral instances case - implies AnyPeripheral
583
    (
584
        $dma_engine:tt,
585
        any_peri = $any_peri:ty,
586
        peris = $for_each_peri_macro:ident,
587
        $pattern:tt => $body:tt
588
    ) => {
589
        macro_rules! impl_dma_channel_trait_inner {
590
            ($pattern) => $body;
591
        }
592

            
593
        for_each_dma_channel! {
594
            ($dma_engine, any_channel = $any_ch:ident) => {
595
                impl_dma_channel_trait_inner! { ($any_peri, $crate::dma::$any_ch<'d>) }
596
            };
597
            ($dma_engine, $ch:ident) => {
598
                impl_dma_channel_trait_inner! { ($any_peri, $crate::peripherals::$ch<'d>) }
599
            };
600
        }
601

            
602
        $for_each_peri_macro! {
603
            ($peri:ident) => {
604
                for_each_dma_channel_peri_pair! {
605
                    ($dma_engine, any_channel = $any_ch:ident, $peri) => {
606
                        impl_dma_channel_trait_inner! { ($crate::peripherals::$peri<'d>, $crate::dma::$any_ch<'d>) }
607
                    };
608
                    ($dma_engine, $ch:ident, $peri) => {
609
                        impl_dma_channel_trait_inner! { ($crate::peripherals::$peri<'d>, $crate::peripherals::$ch<'d>) }
610
                    };
611
                }
612
            };
613
        }
614
    };
615
}
616
#[cfg(dma_driver_supported)]
617
pub(crate) use impl_dma_channel_trait;
618
#[cfg(feature = "unstable")]
619
use procmacros::doc_replace;
620

            
621
/// Reads the RISC-V CSR that `csr` numbers.
622
///
623
/// The `riscv` crate names no debug CSR and no Espressif custom CSR, so the retention code reads
624
/// them by number. `csr` is an `asm!` `const` operand, so it must be a constant expression.
625
///
626
/// # Safety
627
///
628
/// The caller must make sure that the CSR exists on this chip, and that the read has no effect
629
/// that the caller does not expect.
630
#[cfg(all(cpu_retention = "software", supports_cpu_power_down))]
631
macro_rules! read_csr {
632
    ($csr:expr) => {{
633
        let value: u32;
634
        core::arch::asm!("csrr {0}, {1}", out(reg) value, const $csr);
635
        value
636
    }};
637
}
638
#[cfg(all(cpu_retention = "software", supports_cpu_power_down))]
639
pub(crate) use read_csr;
640

            
641
/// Writes `value` to the RISC-V CSR that `csr` numbers.
642
///
643
/// `csr` is an `asm!` `const` operand, so it must be a constant expression.
644
///
645
/// # Safety
646
///
647
/// The caller must make sure that the CSR exists on this chip, and that the write has no effect
648
/// that the caller does not expect.
649
#[cfg(all(cpu_retention = "software", supports_cpu_power_down))]
650
macro_rules! write_csr {
651
    ($csr:expr, $value:expr) => {
652
        core::arch::asm!("csrw {1}, {0}", in(reg) $value, const $csr)
653
    };
654
}
655
#[cfg(all(cpu_retention = "software", supports_cpu_power_down))]
656
pub(crate) use write_csr;
657

            
658
/// Macro to allow using unstable HAL features conditionally. Other crates can
659
/// use this to "detect" the esp-hal/unstable feature.
660
#[macro_export]
661
#[doc(hidden)]
662
#[cfg(feature = "unstable")]
663
macro_rules! if_unstable_hal {
664
    ($($tt:tt)*) => {
665
        $($tt)*
666
    };
667
}
668

            
669
/// Macro to allow using unstable HAL features conditionally. Other crates can
670
/// use this to "detect" the esp-hal/unstable feature.
671
#[macro_export]
672
#[doc(hidden)]
673
#[cfg(not(feature = "unstable"))]
674
macro_rules! if_unstable_hal {
675
    ($($tt:tt)*) => {};
676
}