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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
//==============================================================================
// bsp_peripherals
//==============================================================================
/// # Helper macro to give meaningful names to peripherals
///
/// The [`pac::Peripherals`](crate::pac::Peripherals) struct refers to each
/// peripheral by its datasheet name. However, in the context of a BSP,
/// peripherals can often be given more meaningful names. This macro gives BSP
/// authors a convenient way to provide custom names for each peripheral.
///
/// ## Calling the macro
///
/// The `bsp_peripherals!` macro takes a series of `PERIPHERAL` blocks. Each
/// block starts with a peripheral name from the `pac::Peripherals` struct and
/// is delimited by curly brackets. The brackets should contain a
/// comma-separated list of alternate names for the peripheral, in `PascalCase`.
/// The example below defines `Uart` as an alias for the `SERCOM2` peripheral
/// and `DisplaySpi` as an alias for the `SERCOM4` peripheral.
///
/// ```
/// atsamd_hal::bsp_peripherals!(
/// SERCOM2 { Uart }
/// SERCOM4 { DisplaySpi }
/// );
/// ```
///
/// The macro defines a type alias for each name within curly brackets. The
/// example above would exand to
///
/// ```
/// pub type Uart = pac::SERCOM2;
/// pub type DisplaySpi = pac::SERCOM4;
/// ```
///
/// While these type aliases are useful, they do not completely separate the
/// mapping of each peripheral from the corresponding code.
///
/// In Rust, each struct field can only have one name. Fields of the
/// `pac::Peripherals` struct are named according to their datasheet identifier.
/// Consequently, you must access the peripheral using that name. For example,
///
/// ```
/// let mut peripherals = pac::Peripherals::take().unwrap();
/// let uart = peripherals.SERCOM2;
/// ```
///
/// To provide access to the same struct field using *different* names, the
/// `bsp_peripherals!` macro defines another macro, `periph_alias!`. Based on
/// the example above, we could use the `periph_alias!` macro to access the
/// `SERCOM2` peripheral without ever referring to it directly.
///
/// ```
/// let mut peripherals = pac::Peripherals::take().unwrap();
/// let uart = periph_alias!(peripherals.uart);
/// ```
///
/// Note that the `Uart` alias was translated to `snake_case` when accessing
/// the `pac::Peripherals` field. The same is true for the `DisplaySpi` alias.
///
/// ```
/// let mut peripherals = pac::Peripherals::take().unwrap();
/// let display_spi = periph_alias!(peripherals.display_spi);
/// ```
///
/// ## Attributes and documentation
///
/// BSP authors can also add attributes to various parts of the macro
/// declaration. Attributes can be added to the entire `PERIPHERAL` block. These
/// attributes will be propagated to every use of the corresponding
/// `PERIPHERAL`. Attributes applied to each alias, on the other hand, will only
/// be propagated to items specific to that alias, like the corresponding type
/// alias.
///
/// ```
/// atsamd_hal::bsp_peripherals!(
/// SERCOM2 {
/// #[cfg(feature = "uart")]
/// Uart
/// }
/// #[cfg(feature = "display")]
/// SERCOM4 { DisplaySpi }
/// );
/// ```
#[macro_export]
macro_rules! bsp_peripherals {
(
$(
$( #[$peripheral_cfg:meta] )*
$PERIPHERAL:ident {
$(
$( #[$alias_cfg:meta] )*
$Alias:ident $(,)?
)+
} $(,)?
)+
) => {
$(
$( #[$peripheral_cfg] )*
$crate::__create_peripheral_aliases!(
$PERIPHERAL
$(
$( #[$alias_cfg] )*
$Alias
)+
);
)+
$crate::__define_periph_alias_macro!(
$(
$(
$( #[$alias_cfg] )*
($PERIPHERAL, $Alias)
)+
)+
);
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __create_peripheral_aliases {
(
$PERIPHERAL:ident
$(
$( #[$attr:meta] )*
$Alias:ident
)+
) => {
$crate::paste::paste! {
$(
$( #[$attr] )*
#[
doc = "Alias for the "
"[`" $PERIPHERAL "`](atsamd_hal::pac::" $PERIPHERAL ") "
"peripheral"
]
pub type $Alias = atsamd_hal::pac::$PERIPHERAL;
)+
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __define_periph_alias_macro {
(
$(
$( #[$attr:meta] )*
($PERIPHERAL:ident, $Alias:ident)
)+
) => {
$crate::paste::paste! {
/// Refer to fields of the [`Peripherals`](atsamd_hal::pac::Peripherals)
/// struct by alternate names
///
/// This macro can be used to access fields of the `Peripherals`
/// struct by alternate names. The available aliases are:
///
#[ doc =
$(
" - [`" $PERIPHERAL "`](atsamd_hal::pac::" $PERIPHERAL ") \
can be refered to with the type alias [`" $Alias "`] and \
accessed as the field name `" $Alias:snake "`\n"
)+
]
///
/// For example. suppose `display_spi` were an alternate name for
/// the `SERCOM4` peripheral. You could use the `periph_alias!`
/// macro to access it like this:
///
/// ```
/// let mut peripherals = pac::Peripherals::take().unwrap();
/// // Replace this
/// let display_spi = peripherals.SERCOM4;
/// // With this
/// let display_spi = periph_alias!(peripherals.display_spi);
/// ```
#[macro_export]
macro_rules! periph_alias {
$(
( $peripherals:ident . [<$Alias:snake>] ) => {
{
$( #[$attr] )*
macro_rules! [<peripheral_alias_ $Alias:snake>] {
() => { $peripherals.$PERIPHERAL };
}
[<peripheral_alias_ $Alias:snake>]!()
}
};
)+
}
}
}
}