1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#![no_std]

/// Extract the specified fields from the `Peripherals` struct into several named
/// structs which can be passed to other tasks to provide them with all their
/// resources, including pins, peripherals, DMA channels, etc.
///
/// The `peripherals` module must be in scope when `resource_assigs!{}` is called,
/// and it defines a new macro `split_resources!()` which uses the `Peripherals` struct
/// and returns a new struct with a field for each of the structs named in `resource_assigs!{}`.
///
/// Defines new structs containing the specified structs from the `peripherals` module,
/// a top-level struct that contains an instance of each of these new structs, and a macro
/// that creates the top-level struct and populates it with fields from a `Peripherals` instance.
///
/// # Example
///
/// ```
/// assign_resources! {
///     usb: UsbResources {
///         dp: PA12,
///         dm: PA11,
///         usb: USB,
///     }
///     leds: LedResources {
///         r: PA2,
///         g: PA3,
///         b: PA4,
///         tim2: TIM2,
///     }
/// }
///
/// #[embassy_executor::task]
/// async fn usb_task(r: UsbResources) {
///     // use r.dp, r.dm, r.usb
/// }
///
/// #[embassy_executor::task]
/// async fn led_task(r: LedResources) {
///     // use r.r, r.g, r.b, r.tim2
/// }
///
/// #[embassy_executor::main]
/// async fn main(spawner: embassy_executor::Spawner) {
///     let p = embassy_stm32::init(Default::default());
///     let r = split_resources!(p);
///     spawner.spawn(usb_task(r.usb)).unwrap();
///     spawner.spawn(led_task(r.leds)).unwrap();
///
///     // can still use p.PA0, p.PA1, etc
/// }
/// ```
#[macro_export]
macro_rules! assign_resources {
    {
        $(
            $group_name:ident : $group_struct:ident {
                $($resource_name:ident : $resource_field:ident $(=$resource_alias:ident)?),*
                $(,)?
            }
            $(,)?
        )+
    } => {
        $($($(type $resource_alias = peripherals::$resource_field;)?)*)*

        #[allow(dead_code,non_snake_case)]
        struct _ResourceAssigs {
            $($group_name : $group_struct),*
        }
        $(
            #[allow(dead_code,non_snake_case)]
            struct $group_struct {
                $(pub $resource_name: peripherals::$resource_field),*
            }
        )+
        macro_rules! split_resources (
            ($p:ident) => {
                _ResourceAssigs {
                    $($group_name: $group_struct {
                        $($resource_name: $p.$resource_field),*
                    }),*
                }
            }
        );
    }
}