use core::marker::PhantomData;
use core::ops::BitOr;
use super::Instance;
use super::errors::GroupError;
use super::io_pin::*;
use crate::Peri;
use crate::gpio::{AfType, Flex, OutputType, Speed};
#[derive(PartialEq, Clone, Copy)]
pub enum PinType {
Channel,
Sample,
Shield,
}
#[allow(missing_docs)]
pub struct Pin<'d, T, Group> {
_pin: Flex<'d>,
role: PinType,
tsc_io_pin: IOPin,
phantom: PhantomData<(T, Group)>,
}
impl<'d, T, Group> Pin<'d, T, Group> {
pub fn role(&self) -> PinType {
self.role
}
pub fn tsc_io_pin(&self) -> IOPin {
self.tsc_io_pin
}
}
#[allow(missing_docs)]
pub struct PinGroup<'d, T, Group> {
pin1: Option<Pin<'d, T, Group>>,
pin2: Option<Pin<'d, T, Group>>,
pin3: Option<Pin<'d, T, Group>>,
pin4: Option<Pin<'d, T, Group>>,
}
impl<'d, T, G> Default for PinGroup<'d, T, G> {
fn default() -> Self {
Self {
pin1: None,
pin2: None,
pin3: None,
pin4: None,
}
}
}
pub mod pin_roles {
use super::{OutputType, PinType};
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Channel;
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Sample;
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct Shield;
pub trait Role {
fn pin_type() -> PinType;
fn output_type() -> OutputType;
}
impl Role for Channel {
fn pin_type() -> PinType {
PinType::Channel
}
fn output_type() -> OutputType {
OutputType::PushPull
}
}
impl Role for Sample {
fn pin_type() -> PinType {
PinType::Sample
}
fn output_type() -> OutputType {
OutputType::OpenDrain
}
}
impl Role for Shield {
fn pin_type() -> PinType {
PinType::Shield
}
fn output_type() -> OutputType {
OutputType::PushPull
}
}
}
pub struct PinGroupWithRoles<
'd,
T: Instance,
G,
R1 = pin_roles::Channel,
R2 = pin_roles::Channel,
R3 = pin_roles::Channel,
R4 = pin_roles::Channel,
> {
pub pin_group: PinGroup<'d, T, G>,
_phantom: PhantomData<(R1, R2, R3, R4)>,
}
impl<'d, T: Instance, G, R1, R2, R3, R4> Default for PinGroupWithRoles<'d, T, G, R1, R2, R3, R4> {
fn default() -> Self {
Self {
pin_group: PinGroup::default(),
_phantom: PhantomData,
}
}
}
impl<'d, T: Instance, G> PinGroup<'d, T, G> {
fn contains_exactly_one_shield_pin(&self) -> bool {
let shield_count = self.shield_pins().count();
shield_count == 1
}
fn check_group(&self) -> Result<(), GroupError> {
let mut channel_count = 0;
let mut shield_count = 0;
let mut sample_count = 0;
for pin in self.pins().into_iter().flatten() {
match pin.role {
PinType::Channel => {
channel_count += 1;
}
PinType::Shield => {
shield_count += 1;
}
PinType::Sample => {
sample_count += 1;
}
}
}
if sample_count != 1 {
return Err(GroupError::NoSamplingCapacitor);
}
if shield_count == 0 && channel_count == 0 {
return Err(GroupError::NoChannelOrShield);
}
if shield_count != 0 && channel_count != 0 {
return Err(GroupError::MixedChannelAndShield);
}
if shield_count > 1 {
return Err(GroupError::MultipleShields);
}
Ok(())
}
pub fn pin1(&self) -> Option<&Pin<'d, T, G>> {
self.pin1.as_ref()
}
pub fn pin2(&self) -> Option<&Pin<'d, T, G>> {
self.pin2.as_ref()
}
pub fn pin3(&self) -> Option<&Pin<'d, T, G>> {
self.pin3.as_ref()
}
pub fn pin4(&self) -> Option<&Pin<'d, T, G>> {
self.pin4.as_ref()
}
fn sample_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
self.pins_filtered(PinType::Sample)
}
fn shield_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
self.pins_filtered(PinType::Shield)
}
fn channel_pins(&self) -> impl Iterator<Item = IOPin> + '_ {
self.pins_filtered(PinType::Channel)
}
fn pins_filtered(&self, pin_type: PinType) -> impl Iterator<Item = IOPin> + '_ {
self.pins().into_iter().filter_map(move |pin| {
pin.as_ref()
.and_then(|p| if p.role == pin_type { Some(p.tsc_io_pin) } else { None })
})
}
fn make_channel_ios_mask(&self) -> u32 {
self.channel_pins().fold(0, u32::bitor)
}
fn make_shield_ios_mask(&self) -> u32 {
self.shield_pins().fold(0, u32::bitor)
}
fn make_sample_ios_mask(&self) -> u32 {
self.sample_pins().fold(0, u32::bitor)
}
fn pins(&self) -> [&Option<Pin<'d, T, G>>; 4] {
[&self.pin1, &self.pin2, &self.pin3, &self.pin4]
}
fn pins_mut(&mut self) -> [&mut Option<Pin<'d, T, G>>; 4] {
[&mut self.pin1, &mut self.pin2, &mut self.pin3, &mut self.pin4]
}
}
#[cfg(any(tsc_v2, tsc_v3))]
macro_rules! TSC_V2_V3_GUARD {
($e:expr) => {{
#[cfg(any(tsc_v2, tsc_v3))]
{
$e
}
#[cfg(not(any(tsc_v2, tsc_v3)))]
{
compile_error!("Group 7 is not supported in this TSC version")
}
}};
}
#[cfg(tsc_v3)]
macro_rules! TSC_V3_GUARD {
($e:expr) => {{
#[cfg(tsc_v3)]
{
$e
}
#[cfg(not(tsc_v3))]
{
compile_error!("Group 8 is not supported in this TSC version")
}
}};
}
macro_rules! trait_to_io_pin {
(G1IO1Pin) => {
IOPin::Group1Io1
};
(G1IO2Pin) => {
IOPin::Group1Io2
};
(G1IO3Pin) => {
IOPin::Group1Io3
};
(G1IO4Pin) => {
IOPin::Group1Io4
};
(G2IO1Pin) => {
IOPin::Group2Io1
};
(G2IO2Pin) => {
IOPin::Group2Io2
};
(G2IO3Pin) => {
IOPin::Group2Io3
};
(G2IO4Pin) => {
IOPin::Group2Io4
};
(G3IO1Pin) => {
IOPin::Group3Io1
};
(G3IO2Pin) => {
IOPin::Group3Io2
};
(G3IO3Pin) => {
IOPin::Group3Io3
};
(G3IO4Pin) => {
IOPin::Group3Io4
};
(G4IO1Pin) => {
IOPin::Group4Io1
};
(G4IO2Pin) => {
IOPin::Group4Io2
};
(G4IO3Pin) => {
IOPin::Group4Io3
};
(G4IO4Pin) => {
IOPin::Group4Io4
};
(G5IO1Pin) => {
IOPin::Group5Io1
};
(G5IO2Pin) => {
IOPin::Group5Io2
};
(G5IO3Pin) => {
IOPin::Group5Io3
};
(G5IO4Pin) => {
IOPin::Group5Io4
};
(G6IO1Pin) => {
IOPin::Group6Io1
};
(G6IO2Pin) => {
IOPin::Group6Io2
};
(G6IO3Pin) => {
IOPin::Group6Io3
};
(G6IO4Pin) => {
IOPin::Group6Io4
};
(G7IO1Pin) => {
TSC_V2_V3_GUARD!(IOPin::Group7Io1)
};
(G7IO2Pin) => {
TSC_V2_V3_GUARD!(IOPin::Group7Io2)
};
(G7IO3Pin) => {
TSC_V2_V3_GUARD!(IOPin::Group7Io3)
};
(G7IO4Pin) => {
TSC_V2_V3_GUARD!(IOPin::Group7Io4)
};
(G8IO1Pin) => {
TSC_V3_GUARD!(IOPin::Group8Io1)
};
(G8IO2Pin) => {
TSC_V3_GUARD!(IOPin::Group8Io2)
};
(G8IO3Pin) => {
TSC_V3_GUARD!(IOPin::Group8Io3)
};
(G8IO4Pin) => {
TSC_V3_GUARD!(IOPin::Group8Io4)
};
}
macro_rules! impl_set_io {
($method:ident, $group:ident, $trait:ident, $index:expr) => {
#[doc = concat!("Create a new pin1 for ", stringify!($group), " TSC group instance.")]
pub fn $method<Role: pin_roles::Role>(&mut self, pin: Peri<'d, impl $trait<T>>) -> IOPinWithRole<$group, Role> {
critical_section::with(|_| {
pin.set_low();
set_as_af!(pin, AfType::output(Role::output_type(), Speed::VeryHigh));
let tsc_io_pin = trait_to_io_pin!($trait);
let new_pin = Pin {
_pin: Flex::new(pin),
role: Role::pin_type(),
tsc_io_pin,
phantom: PhantomData,
};
*self.pin_group.pins_mut()[$index] = Some(new_pin);
IOPinWithRole {
pin: tsc_io_pin,
phantom: PhantomData,
}
})
}
};
}
macro_rules! group_impl {
($group:ident, $trait1:ident, $trait2:ident, $trait3:ident, $trait4:ident) => {
impl<'d, T: Instance, R1: pin_roles::Role, R2: pin_roles::Role, R3: pin_roles::Role, R4: pin_roles::Role>
PinGroupWithRoles<'d, T, $group, R1, R2, R3, R4>
{
impl_set_io!(set_io1, $group, $trait1, 0);
impl_set_io!(set_io2, $group, $trait2, 1);
impl_set_io!(set_io3, $group, $trait3, 2);
impl_set_io!(set_io4, $group, $trait4, 3);
}
};
}
group_impl!(G1, G1IO1Pin, G1IO2Pin, G1IO3Pin, G1IO4Pin);
group_impl!(G2, G2IO1Pin, G2IO2Pin, G2IO3Pin, G2IO4Pin);
group_impl!(G3, G3IO1Pin, G3IO2Pin, G3IO3Pin, G3IO4Pin);
group_impl!(G4, G4IO1Pin, G4IO2Pin, G4IO3Pin, G4IO4Pin);
group_impl!(G5, G5IO1Pin, G5IO2Pin, G5IO3Pin, G5IO4Pin);
group_impl!(G6, G6IO1Pin, G6IO2Pin, G6IO3Pin, G6IO4Pin);
#[cfg(any(tsc_v2, tsc_v3))]
group_impl!(G7, G7IO1Pin, G7IO2Pin, G7IO3Pin, G7IO4Pin);
#[cfg(tsc_v3)]
group_impl!(G8, G8IO1Pin, G8IO2Pin, G8IO3Pin, G8IO4Pin);
#[derive(Clone, Copy, Debug)]
pub enum G1 {}
#[derive(Clone, Copy, Debug)]
pub enum G2 {}
#[derive(Clone, Copy, Debug)]
pub enum G3 {}
#[derive(Clone, Copy, Debug)]
pub enum G4 {}
#[derive(Clone, Copy, Debug)]
pub enum G5 {}
#[derive(Clone, Copy, Debug)]
pub enum G6 {}
#[derive(Clone, Copy, Debug)]
pub enum G7 {}
#[derive(Clone, Copy, Debug)]
pub enum G8 {}
#[allow(missing_docs)]
pub struct PinGroups<'d, T: Instance> {
pub g1: Option<PinGroup<'d, T, G1>>,
pub g2: Option<PinGroup<'d, T, G2>>,
pub g3: Option<PinGroup<'d, T, G3>>,
pub g4: Option<PinGroup<'d, T, G4>>,
pub g5: Option<PinGroup<'d, T, G5>>,
pub g6: Option<PinGroup<'d, T, G6>>,
#[cfg(any(tsc_v2, tsc_v3))]
pub g7: Option<PinGroup<'d, T, G7>>,
#[cfg(tsc_v3)]
pub g8: Option<PinGroup<'d, T, G8>>,
}
impl<'d, T: Instance> PinGroups<'d, T> {
pub(super) fn check(&self) -> Result<(), GroupError> {
let mut shield_count = 0;
fn check_group<C, T: Instance>(
group: &Option<PinGroup<'_, T, C>>,
shield_count: &mut u32,
) -> Result<(), GroupError> {
if let Some(group) = group {
group.check_group()?;
if group.contains_exactly_one_shield_pin() {
*shield_count += 1;
if *shield_count > 1 {
return Err(GroupError::MultipleShields);
}
}
}
Ok(())
}
check_group(&self.g1, &mut shield_count)?;
check_group(&self.g2, &mut shield_count)?;
check_group(&self.g3, &mut shield_count)?;
check_group(&self.g4, &mut shield_count)?;
check_group(&self.g5, &mut shield_count)?;
check_group(&self.g6, &mut shield_count)?;
#[cfg(any(tsc_v2, tsc_v3))]
check_group(&self.g7, &mut shield_count)?;
#[cfg(tsc_v3)]
check_group(&self.g8, &mut shield_count)?;
Ok(())
}
pub(super) fn make_channel_ios_mask(&self) -> u32 {
#[allow(unused_mut)]
let mut mask = self.g1.as_ref().map_or(0, |g| g.make_channel_ios_mask())
| self.g2.as_ref().map_or(0, |g| g.make_channel_ios_mask())
| self.g3.as_ref().map_or(0, |g| g.make_channel_ios_mask())
| self.g4.as_ref().map_or(0, |g| g.make_channel_ios_mask())
| self.g5.as_ref().map_or(0, |g| g.make_channel_ios_mask())
| self.g6.as_ref().map_or(0, |g| g.make_channel_ios_mask());
#[cfg(any(tsc_v2, tsc_v3))]
{
mask |= self.g7.as_ref().map_or(0, |g| g.make_channel_ios_mask());
}
#[cfg(tsc_v3)]
{
mask |= self.g8.as_ref().map_or(0, |g| g.make_channel_ios_mask());
}
mask
}
pub(super) fn make_shield_ios_mask(&self) -> u32 {
#[allow(unused_mut)]
let mut mask = self.g1.as_ref().map_or(0, |g| g.make_shield_ios_mask())
| self.g2.as_ref().map_or(0, |g| g.make_shield_ios_mask())
| self.g3.as_ref().map_or(0, |g| g.make_shield_ios_mask())
| self.g4.as_ref().map_or(0, |g| g.make_shield_ios_mask())
| self.g5.as_ref().map_or(0, |g| g.make_shield_ios_mask())
| self.g6.as_ref().map_or(0, |g| g.make_shield_ios_mask());
#[cfg(any(tsc_v2, tsc_v3))]
{
mask |= self.g7.as_ref().map_or(0, |g| g.make_shield_ios_mask());
}
#[cfg(tsc_v3)]
{
mask |= self.g8.as_ref().map_or(0, |g| g.make_shield_ios_mask());
}
mask
}
pub(super) fn make_sample_ios_mask(&self) -> u32 {
#[allow(unused_mut)]
let mut mask = self.g1.as_ref().map_or(0, |g| g.make_sample_ios_mask())
| self.g2.as_ref().map_or(0, |g| g.make_sample_ios_mask())
| self.g3.as_ref().map_or(0, |g| g.make_sample_ios_mask())
| self.g4.as_ref().map_or(0, |g| g.make_sample_ios_mask())
| self.g5.as_ref().map_or(0, |g| g.make_sample_ios_mask())
| self.g6.as_ref().map_or(0, |g| g.make_sample_ios_mask());
#[cfg(any(tsc_v2, tsc_v3))]
{
mask |= self.g7.as_ref().map_or(0, |g| g.make_sample_ios_mask());
}
#[cfg(tsc_v3)]
{
mask |= self.g8.as_ref().map_or(0, |g| g.make_sample_ios_mask());
}
mask
}
}
impl<'d, T: Instance> Default for PinGroups<'d, T> {
fn default() -> Self {
Self {
g1: None,
g2: None,
g3: None,
g4: None,
g5: None,
g6: None,
#[cfg(any(tsc_v2, tsc_v3))]
g7: None,
#[cfg(tsc_v3)]
g8: None,
}
}
}
pin_trait!(G1IO1Pin, Instance);
pin_trait!(G1IO2Pin, Instance);
pin_trait!(G1IO3Pin, Instance);
pin_trait!(G1IO4Pin, Instance);
pin_trait!(G2IO1Pin, Instance);
pin_trait!(G2IO2Pin, Instance);
pin_trait!(G2IO3Pin, Instance);
pin_trait!(G2IO4Pin, Instance);
pin_trait!(G3IO1Pin, Instance);
pin_trait!(G3IO2Pin, Instance);
pin_trait!(G3IO3Pin, Instance);
pin_trait!(G3IO4Pin, Instance);
pin_trait!(G4IO1Pin, Instance);
pin_trait!(G4IO2Pin, Instance);
pin_trait!(G4IO3Pin, Instance);
pin_trait!(G4IO4Pin, Instance);
pin_trait!(G5IO1Pin, Instance);
pin_trait!(G5IO2Pin, Instance);
pin_trait!(G5IO3Pin, Instance);
pin_trait!(G5IO4Pin, Instance);
pin_trait!(G6IO1Pin, Instance);
pin_trait!(G6IO2Pin, Instance);
pin_trait!(G6IO3Pin, Instance);
pin_trait!(G6IO4Pin, Instance);
pin_trait!(G7IO1Pin, Instance);
pin_trait!(G7IO2Pin, Instance);
pin_trait!(G7IO3Pin, Instance);
pin_trait!(G7IO4Pin, Instance);
pin_trait!(G8IO1Pin, Instance);
pin_trait!(G8IO2Pin, Instance);
pin_trait!(G8IO3Pin, Instance);
pin_trait!(G8IO4Pin, Instance);