esp_metadata/cfg/
rmt.rs

1use proc_macro2::TokenStream;
2use quote::{format_ident, quote};
3
4use crate::{cfg::GenericProperty, generate_for_each_macro, number};
5
6/// The capabilities of an RMT channel, used in [device.rmt.channels]
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
8pub(crate) enum RmtChannelCapability {
9    Rx,
10    Tx,
11    RxTx,
12}
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
15pub(crate) struct RmtChannelConfig(
16    /// The capability of each channel
17    Vec<RmtChannelCapability>,
18);
19
20/// Generates `for_each_rmt_channel!` which can be used to implement channel creators and the main
21/// driver struct for the RMT peripheral.
22///
23/// The macro generates code for each [device.rmt.channels[X]] entry.
24impl GenericProperty for RmtChannelConfig {
25    fn macros(&self) -> Option<TokenStream> {
26        let channel_cfgs = self
27            .0
28            .iter()
29            .enumerate()
30            .map(|(num, _)| {
31                let num = number(num);
32                quote! {
33                    #num
34                }
35            })
36            .collect::<Vec<_>>();
37
38        let make_channel_cfgs = |filter: fn(RmtChannelCapability) -> bool| {
39            self.0
40                .iter()
41                .enumerate()
42                .filter(|&(_, &cap)| filter(cap))
43                .enumerate()
44                .map(|(idx, (num, _))| {
45                    let num = number(num);
46                    let idx = number(idx);
47                    quote! {
48                        #num, #idx
49                    }
50                })
51                .collect::<Vec<_>>()
52        };
53
54        let tx_channel_cfgs = make_channel_cfgs(|cap| {
55            matches!(cap, RmtChannelCapability::Tx | RmtChannelCapability::RxTx)
56        });
57        let rx_channel_cfgs = make_channel_cfgs(|cap| {
58            matches!(cap, RmtChannelCapability::Rx | RmtChannelCapability::RxTx)
59        });
60
61        let for_each = generate_for_each_macro(
62            "rmt_channel",
63            &[
64                ("all", &channel_cfgs),
65                ("tx", &tx_channel_cfgs),
66                ("rx", &rx_channel_cfgs),
67            ],
68        );
69
70        Some(quote! {
71            /// This macro can be used to generate code for each channel of the RMT peripheral.
72            ///
73            /// For an explanation on the general syntax, as well as usage of individual/repeated
74            /// matchers, refer to [the crate-level documentation][crate#for_each-macros].
75            ///
76            /// This macro has three options for its "Individual matcher" case:
77            ///
78            /// - `all`: `($num:literal)`
79            /// - `tx`: `($num:literal, $idx:literal)`
80            /// - `rx`: `($num:literal, $idx:literal)`
81            ///
82            /// Macro fragments:
83            ///
84            /// - `$num`: number of the channel, e.g. `0`
85            /// - `$idx`: index of the channel among channels of the same capability, e.g. `0`
86            ///
87            /// Example data:
88            ///
89            /// - `all`: `(0)`
90            /// - `tx`: `(1, 1)`
91            /// - `rx`: `(2, 0)`
92            #for_each
93        })
94    }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
98pub(crate) struct RmtClockSourcesConfig {
99    supported: Vec<String>,
100    default: String,
101}
102
103impl GenericProperty for RmtClockSourcesConfig {
104    fn cfgs(&self) -> Option<Vec<String>> {
105        let mut cfgs = Vec::new();
106
107        for value in &self.supported {
108            cfgs.push(format!("rmt_supports_{}_clock", value.to_lowercase()));
109        }
110
111        Some(cfgs)
112    }
113
114    fn macros(&self) -> Option<TokenStream> {
115        let clock_sources = self
116            .supported
117            .iter()
118            .enumerate()
119            .filter(|(_, name)| *name != "None")
120            .map(|(bits, name)| {
121                let src_name = format_ident!("{}", name);
122                let bits = number(bits);
123                quote! {
124                    #src_name, #bits
125                }
126            })
127            .collect::<Vec<_>>();
128
129        let default = format_ident!("{}", self.default);
130        let default_clock_source = [quote!( #default )];
131
132        let branches: &[(&str, &[TokenStream])] = if self.supported.len() <= 2 {
133            &[
134                ("all", &clock_sources),
135                ("default", &default_clock_source),
136                ("is_boolean", &[]),
137            ]
138        } else {
139            &[("all", &clock_sources), ("default", &default_clock_source)]
140        };
141
142        Some(generate_for_each_macro("rmt_clock_source", branches))
143    }
144}