use core::marker::PhantomData;
use paste::paste;
use super::pin::DynBankId;
pub(crate) mod func_sealed {
use super::DynFunction;
pub trait Function {
fn from(f: DynFunction) -> Self;
fn as_dyn(&self) -> DynFunction;
}
}
pub trait Function: func_sealed::Function {}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DynFunction {
Xip,
Hstx,
Spi,
Uart,
I2c,
Pwm,
Sio(DynSioConfig),
Pio0,
Pio1,
Pio2,
Clock,
XipCs1,
Usb,
UartAux,
Null,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DynSioConfig {
Input,
Output,
}
impl Function for DynFunction {}
impl func_sealed::Function for DynFunction {
#[inline]
fn from(f: DynFunction) -> Self {
f
}
#[inline]
fn as_dyn(&self) -> DynFunction {
*self
}
}
macro_rules! pin_func {
($($fn:ident $(as $alias:ident)?),*) => {
$(paste! {
/// Type-level `variant` for pin [`Function`].
#[derive(Debug)]
pub struct [<Function $fn>](pub(super) ());
impl Function for [<Function $fn>] {}
impl func_sealed::Function for [<Function $fn>] {
#[inline]
fn from(_f: DynFunction) -> Self {
Self(())
}
#[inline]
fn as_dyn(&self) -> DynFunction {
DynFunction::[<$fn>]
}
}
$(
#[doc = "Alias to [`Function" $fn "`]."]
pub type [<Function $alias>] = [<Function $fn>];
)?
})*
};
}
pin_func!(
Xip, Hstx, Spi, Uart, I2c as I2C, Pwm, Pio0, Pio1, Pio2, Clock, XipCs1, Usb, UartAux, Null
);
#[derive(Debug)]
pub struct FunctionSio<C>(PhantomData<C>);
impl<C: SioConfig> Function for FunctionSio<C> {}
impl<C: SioConfig> func_sealed::Function for FunctionSio<C> {
fn from(_f: DynFunction) -> Self {
FunctionSio(PhantomData)
}
fn as_dyn(&self) -> DynFunction {
DynFunction::Sio(C::DYN)
}
}
pub type FunctionSioInput = FunctionSio<SioInput>;
pub type FunctionSioOutput = FunctionSio<SioOutput>;
pub trait SioConfig {
#[allow(missing_docs)]
const DYN: DynSioConfig;
}
#[derive(Debug)]
pub enum SioInput {}
impl SioConfig for SioInput {
#[allow(missing_docs)]
const DYN: DynSioConfig = DynSioConfig::Input;
}
#[derive(Debug)]
pub enum SioOutput {}
impl SioConfig for SioOutput {
#[allow(missing_docs)]
const DYN: DynSioConfig = DynSioConfig::Output;
}
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct InvalidFunction;
pub trait ValidFunction<F: Function>: super::pin::PinId {}
impl DynFunction {
pub(crate) fn is_valid<P: super::pin::PinId>(&self, id: &P) -> bool {
use DynBankId::*;
use DynFunction::*;
let dyn_pin = id.as_dyn();
match (dyn_pin.bank, dyn_pin.num, self) {
(Bank0, _, Xip) => false,
(Bank0, 0 | 8 | 19 | 47, XipCs1) => true,
(Bank0, _, XipCs1) => false,
(Bank0, 12..=15 | 20..=25, Clock) => true,
(Bank0, _, Clock) => false,
(Bank0, n, UartAux) if (n & 0b10) != 0 => true,
(Bank0, _, UartAux) => false,
(Bank0, 12..=19, Hstx) => true,
(Bank0, _, Hstx) => false,
(Bank0, 0..=47, _) => true,
(Qspi, 0..=5, Xip | Sio(_)) => true,
_ => false,
}
}
}
impl<P: super::pin::PinId> ValidFunction<DynFunction> for P {}
macro_rules! pin_valid_func {
($bank:ident as $prefix:ident, [$head:ident $(, $func:ident)*], [$($name:tt),+]) => {
pin_valid_func!($bank as $prefix, [$($func),*], [$($name),+]);
paste::paste!{$(
impl ValidFunction<[<Function $head>]> for super::pin::[<$bank:lower>]::[<$prefix $name>] {}
)+}
};
($bank:ident as $prefix:ident, [], [$($name:tt),+]) => {};
}
#[rustfmt::skip]
pin_valid_func!(
bank0 as Gpio,
[Spi, Uart, I2c, Pwm, Pio0, Pio1, Pio2, Usb, Null],
[
0, 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
]
);
#[rustfmt::skip]
pin_valid_func!(
bank0 as Gpio,
[UartAux],
[
2, 3, 6, 7,
10, 11, 14, 15, 18, 19,
22, 23, 26, 27,
30, 31, 34, 35, 38, 39,
42, 43, 46, 47
]
);
pin_valid_func!(bank0 as Gpio, [Hstx], [12, 13, 14, 15, 16, 17, 18, 19]);
pin_valid_func!(
bank0 as Gpio,
[Clock],
[12, 13, 14, 15, 20, 21, 22, 23, 24, 25]
);
pin_valid_func!(bank0 as Gpio, [XipCs1], [0, 8, 19, 47]);
pin_valid_func!(qspi as Qspi, [Xip, Null], [Sclk, Sd0, Sd1, Sd2, Sd3, Ss]);
macro_rules! pin_valid_func_sio {
($bank:ident as $prefix:ident, [$($name:tt),+]) => {
paste::paste!{$(
impl<C: SioConfig> ValidFunction<FunctionSio<C>> for super::pin::[<$bank:lower>]::[<$prefix $name>] {}
)+}
};
}
#[rustfmt::skip]
pin_valid_func_sio!(
bank0 as Gpio,
[
0, 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
]
);
pin_valid_func_sio!(qspi as Qspi, [Sclk, Sd0, Sd1, Sd2, Sd3, Ss]);