use core::marker::PhantomData;
use crate::gpio::AnyPin;
use crate::sercom::*;
use crate::typelevel::{NoneT, Sealed};
use super::{Capability, Duplex, Rx, Tx};
pub trait Dipo: OptionalPadNum {
const DIPO: Option<u8>;
}
impl Dipo for NoneT {
const DIPO: Option<u8> = None;
}
impl Dipo for Pad0 {
const DIPO: Option<u8> = Some(0);
}
impl Dipo for Pad1 {
const DIPO: Option<u8> = Some(1);
}
impl Dipo for Pad2 {
const DIPO: Option<u8> = Some(2);
}
impl Dipo for Pad3 {
const DIPO: Option<u8> = Some(3);
}
pub trait Dopo: OptionalPadNum {
const DOPO: Option<u8>;
}
impl Dopo for NoneT {
const DOPO: Option<u8> = None;
}
impl Dopo for Pad0 {
const DOPO: Option<u8> = Some(0);
}
impl Dopo for Pad1 {
const DOPO: Option<u8> = Some(1);
}
impl Dopo for Pad3 {
const DOPO: Option<u8> = Some(2);
}
pub trait DipoDopo: Sealed {
const DIPO_DOPO: (u8, u8);
}
impl<S, DI, DO, CK, SS> DipoDopo for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
(DI, DO, CK, SS): ShareIoSet,
DI::PadNum: Dipo,
DO::PadNum: Dopo,
{
const DIPO_DOPO: (u8, u8) = match (DI::PadNum::DIPO, DO::PadNum::DOPO) {
(None, None) => (0, 2),
(Some(dipo), None) => {
let dopo = if dipo == 0 { 2 } else { 0 };
(dipo, dopo)
}
(None, Some(dopo)) => {
let dipo = if dopo == 0 { 3 } else { 0 };
(dipo, dopo)
}
(Some(dipo), Some(dopo)) => (dipo, dopo),
};
}
pub struct Pads<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
(DI, DO, CK, SS): ShareIoSet,
{
sercom: PhantomData<S>,
data_in: DI,
data_out: DO,
sclk: CK,
ss: SS,
}
impl<S: Sercom> Default for Pads<S> {
fn default() -> Self {
Self {
sercom: PhantomData,
data_in: NoneT,
data_out: NoneT,
sclk: NoneT,
ss: NoneT,
}
}
}
impl<S, DI, DO, CK, SS> Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
(DI, DO, CK, SS): ShareIoSet,
{
#[inline]
pub fn data_in<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, Pad<S, Id>, DO, CK, SS>
where
Id: GetPad<S>,
Id::PadNum: Dipo,
(Pad<S, Id>, DO, CK, SS): ShareIoSet,
Pad<S, Id>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: pin.into().into_mode(),
data_out: self.data_out,
sclk: self.sclk,
ss: self.ss,
}
}
#[inline]
pub fn data_out<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, DI, Pad<S, Id>, CK, SS>
where
Id: GetPad<S>,
Id::PadNum: Dopo,
(DI, Pad<S, Id>, CK, SS): ShareIoSet,
Pad<S, Id>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: pin.into().into_mode(),
sclk: self.sclk,
ss: self.ss,
}
}
#[inline]
pub fn sclk<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, DI, DO, Pad<S, Id>, SS>
where
Id: GetPad<S, PadNum = Pad1>,
(DI, DO, Pad<S, Id>, SS): ShareIoSet,
Pad<S, Id>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: self.data_out,
sclk: pin.into().into_mode(),
ss: self.ss,
}
}
#[inline]
pub fn ss<Id>(self, pin: impl AnyPin<Id = Id>) -> Pads<S, DI, DO, CK, Pad<S, Id>>
where
Id: GetPad<S, PadNum = Pad2>,
(DI, DO, CK, Pad<S, Id>): ShareIoSet,
Pad<S, Id>: IsPad,
{
Pads {
sercom: self.sercom,
data_in: self.data_in,
data_out: self.data_out,
sclk: self.sclk,
ss: pin.into().into_mode(),
}
}
#[inline]
pub fn free(self) -> (DI, DO, CK, SS) {
(self.data_in, self.data_out, self.sclk, self.ss)
}
}
pub type PadsFromIds<S, DI = NoneT, DO = NoneT, CK = NoneT, SS = NoneT> = Pads<
S,
<DI as GetOptionalPad<S>>::Pad,
<DO as GetOptionalPad<S>>::Pad,
<CK as GetOptionalPad<S>>::Pad,
<SS as GetOptionalPad<S>>::Pad,
>;
pub trait PadSet: Sealed {
type Sercom: Sercom;
type DataIn: OptionalPad;
type DataOut: OptionalPad;
type Sclk: OptionalPad;
type SS: OptionalPad;
}
impl<S, DI, DO, CK, SS> Sealed for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
(DI, DO, CK, SS): ShareIoSet,
{
}
impl<S, DI, DO, CK, SS> PadSet for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: OptionalPad,
DO: OptionalPad,
CK: OptionalPad,
SS: OptionalPad,
(DI, DO, CK, SS): ShareIoSet,
{
type Sercom = S;
type DataIn = DI;
type DataOut = DO;
type Sclk = CK;
type SS = SS;
}
pub trait ValidPads: PadSet + DipoDopo {
type Capability: Capability;
}
impl<S, DI, CK, SS> ValidPads for Pads<S, DI, NoneT, CK, SS>
where
S: Sercom,
DI: SomePad,
CK: SomePad,
SS: OptionalPad,
(DI, NoneT, CK, SS): ShareIoSet,
Pads<S, DI, NoneT, CK, SS>: DipoDopo,
{
type Capability = Rx;
}
impl<S, DO, CK, SS> ValidPads for Pads<S, NoneT, DO, CK, SS>
where
S: Sercom,
DO: SomePad,
CK: SomePad,
SS: OptionalPad,
(NoneT, DO, CK, SS): ShareIoSet,
Pads<S, NoneT, DO, CK, SS>: DipoDopo,
{
type Capability = Tx;
}
impl<S, DI, DO, CK, SS> ValidPads for Pads<S, DI, DO, CK, SS>
where
S: Sercom,
DI: SomePad,
DO: SomePad,
CK: SomePad,
SS: OptionalPad,
(DI, DO, CK, SS): ShareIoSet,
Pads<S, DI, DO, CK, SS>: DipoDopo,
{
type Capability = Duplex;
}