use crate::gpio::{
Alternate2, Floating, Input, Pin, Pin0, Pin1, Pin2, Pin3, Pin4, Pin7,
P4, P5
};
use crate::hw_traits::timerb::{CCRn, Ccis, Cm};
use crate::timer::{read_tbxiv, CapCmpTimer3, CapCmpTimer7, TimerVector};
use core::marker::PhantomData;
use msp430fr247x as pac;
pub use crate::timer::{
CapCmp, TimerConfig, TimerDiv, TimerExDiv, TimerPeriph, CCR0, CCR1, CCR2, CCR3, CCR4, CCR5,
CCR6,
};
pub enum CapTrigger {
RisingEdge,
FallingEdge,
BothEdges,
}
impl Into<Cm> for CapTrigger {
#[inline]
fn into(self) -> Cm {
match self {
CapTrigger::RisingEdge => Cm::RisingEdge,
CapTrigger::FallingEdge => Cm::FallingEdge,
CapTrigger::BothEdges => Cm::BothEdges,
}
}
}
struct PinConfig {
select: Ccis,
trigger: CapTrigger,
}
impl Default for PinConfig {
fn default() -> Self {
Self {
select: Ccis::Gnd,
trigger: CapTrigger::RisingEdge,
}
}
}
pub trait CapturePeriph: TimerPeriph {
type Gpio1;
type Gpio2;
type Gpio3;
type Gpio4;
type Gpio5;
type Gpio6;
}
impl CapturePeriph for pac::TB0 {
type Gpio1 = Pin<P4, Pin7, Alternate2<Input<Floating>>>;
type Gpio2 = Pin<P5, Pin0, Alternate2<Input<Floating>>>;
type Gpio3 = Pin<P5, Pin1, Alternate2<Input<Floating>>>;
type Gpio4 = Pin<P5, Pin2, Alternate2<Input<Floating>>>;
type Gpio5 = Pin<P5, Pin3, Alternate2<Input<Floating>>>;
type Gpio6 = Pin<P5, Pin4, Alternate2<Input<Floating>>>;
}
macro_rules! config_fn {
(methods $config_sel_b:ident, $config_trigger:ident, $pin:ident) => {
#[allow(non_snake_case)]
#[inline(always)]
pub fn $config_sel_b(mut self) -> Self {
self.$pin.select = Ccis::InputB;
self
}
#[inline(always)]
pub fn $config_trigger(mut self, trigger: CapTrigger) -> Self {
self.$pin.trigger = trigger;
self
}
};
($config_sel_a:ident, $config_sel_b:ident, $config_trigger:ident, $pin:ident, $gpio:ident) => {
#[allow(non_snake_case)]
#[inline(always)]
pub fn $config_sel_a(mut self, _gpio: T::$gpio) -> Self {
self.$pin.select = Ccis::InputA;
self
}
config_fn!(methods $config_sel_b, $config_trigger, $pin);
};
($config_sel_a:ident, $config_sel_b:ident, $config_trigger:ident, $pin:ident) => {
#[allow(non_snake_case)]
#[inline(always)]
pub fn $config_sel_a(mut self) -> Self {
self.$pin.select = Ccis::InputA;
self
}
config_fn!(methods $config_sel_b, $config_trigger, $pin);
};
}
pub struct CaptureConfig3<T: CapturePeriph>
where
T: CapCmpTimer3,
{
timer: T,
config: TimerConfig<T>,
cap0: PinConfig,
cap1: PinConfig,
cap2: PinConfig,
}
impl<T: CapturePeriph + CapCmpTimer3> CaptureParts3<T> {
pub fn config(timer: T, config: TimerConfig<T>) -> CaptureConfig3<T> {
CaptureConfig3 {
timer,
config,
cap0: PinConfig::default(),
cap1: PinConfig::default(),
cap2: PinConfig::default(),
}
}
}
impl<T: CapturePeriph + CapCmpTimer3> CaptureConfig3<T> {
config_fn!(
config_cap0_input_A,
config_cap0_input_B,
config_cap0_trigger,
cap0
);
config_fn!(
config_cap1_input_A,
config_cap1_input_B,
config_cap1_trigger,
cap1,
Gpio1
);
config_fn!(
config_cap2_input_A,
config_cap2_input_B,
config_cap2_trigger,
cap2,
Gpio2
);
pub fn commit(self) -> CaptureParts3<T> {
let timer = self.timer;
self.config.write_regs(&timer);
CCRn::<CCR0>::config_cap_mode(&timer, self.cap0.trigger.into(), self.cap0.select.into());
CCRn::<CCR1>::config_cap_mode(&timer, self.cap1.trigger.into(), self.cap1.select.into());
CCRn::<CCR2>::config_cap_mode(&timer, self.cap2.trigger.into(), self.cap2.select.into());
timer.continuous();
CaptureParts3 {
cap0: Capture::new(),
cap1: Capture::new(),
cap2: Capture::new(),
tbxiv: TBxIV(PhantomData),
}
}
}
pub struct CaptureConfig7<T: CapturePeriph>
where
T: CapCmpTimer7,
{
timer: T,
config: TimerConfig<T>,
cap0: PinConfig,
cap1: PinConfig,
cap2: PinConfig,
cap3: PinConfig,
cap4: PinConfig,
cap5: PinConfig,
cap6: PinConfig,
}
impl<T: CapturePeriph + CapCmpTimer7> CaptureParts7<T> {
pub fn config(timer: T, config: TimerConfig<T>) -> CaptureConfig7<T> {
CaptureConfig7 {
timer,
config,
cap0: PinConfig::default(),
cap1: PinConfig::default(),
cap2: PinConfig::default(),
cap3: PinConfig::default(),
cap4: PinConfig::default(),
cap5: PinConfig::default(),
cap6: PinConfig::default(),
}
}
}
impl<T: CapturePeriph + CapCmpTimer7> CaptureConfig7<T> {
config_fn!(
config_cap0_input_A,
config_cap0_input_B,
config_cap0_trigger,
cap0
);
config_fn!(
config_cap1_input_A,
config_cap1_input_B,
config_cap1_trigger,
cap1,
Gpio1
);
config_fn!(
config_cap2_input_A,
config_cap2_input_B,
config_cap2_trigger,
cap2,
Gpio2
);
config_fn!(
config_cap3_input_A,
config_cap3_input_B,
config_cap3_trigger,
cap3,
Gpio3
);
config_fn!(
config_cap4_input_A,
config_cap4_input_B,
config_cap4_trigger,
cap4,
Gpio4
);
config_fn!(
config_cap5_input_A,
config_cap5_input_B,
config_cap5_trigger,
cap5,
Gpio5
);
config_fn!(
config_cap6_input_A,
config_cap6_input_B,
config_cap6_trigger,
cap6,
Gpio6
);
pub fn commit(self) -> CaptureParts7<T> {
let timer = self.timer;
self.config.write_regs(&timer);
CCRn::<CCR0>::config_cap_mode(&timer, self.cap0.trigger.into(), self.cap0.select.into());
CCRn::<CCR1>::config_cap_mode(&timer, self.cap1.trigger.into(), self.cap1.select.into());
CCRn::<CCR2>::config_cap_mode(&timer, self.cap2.trigger.into(), self.cap2.select.into());
CCRn::<CCR3>::config_cap_mode(&timer, self.cap3.trigger.into(), self.cap3.select.into());
CCRn::<CCR4>::config_cap_mode(&timer, self.cap4.trigger.into(), self.cap4.select.into());
CCRn::<CCR5>::config_cap_mode(&timer, self.cap5.trigger.into(), self.cap5.select.into());
CCRn::<CCR6>::config_cap_mode(&timer, self.cap6.trigger.into(), self.cap6.select.into());
timer.continuous();
CaptureParts7 {
cap0: Capture::new(),
cap1: Capture::new(),
cap2: Capture::new(),
cap3: Capture::new(),
cap4: Capture::new(),
cap5: Capture::new(),
cap6: Capture::new(),
tbxiv: TBxIV(PhantomData),
}
}
}
pub struct CaptureParts3<T: CapCmpTimer3> {
pub cap0: Capture<T, CCR0>,
pub cap1: Capture<T, CCR1>,
pub cap2: Capture<T, CCR2>,
pub tbxiv: TBxIV<T>,
}
pub struct CaptureParts7<T: CapCmpTimer7> {
pub cap0: Capture<T, CCR0>,
pub cap1: Capture<T, CCR1>,
pub cap2: Capture<T, CCR2>,
pub cap3: Capture<T, CCR3>,
pub cap4: Capture<T, CCR4>,
pub cap5: Capture<T, CCR5>,
pub cap6: Capture<T, CCR6>,
pub tbxiv: TBxIV<T>,
}
pub struct Capture<T: CapCmp<C>, C>(PhantomData<T>, PhantomData<C>);
impl<T: CapCmp<C>, C> Capture<T, C> {
fn new() -> Self {
Self(PhantomData, PhantomData)
}
}
pub trait CapturePin {
type Capture;
type Error;
fn capture(&mut self) -> nb::Result<Self::Capture, Self::Error>;
}
impl<T: CapCmp<C>, C> CapturePin for Capture<T, C> {
type Capture = u16;
type Error = OverCapture;
#[inline]
fn capture(&mut self) -> nb::Result<Self::Capture, Self::Error> {
let timer = unsafe { T::steal() };
let (cov, ccifg) = timer.cov_ccifg_rd();
if ccifg {
let ccrn = timer.get_ccrn();
timer.cov_ccifg_clr();
if cov {
Err(nb::Error::Other(OverCapture(ccrn)))
} else {
Ok(ccrn)
}
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<T: CapCmp<C>, C> Capture<T, C> {
#[inline]
pub fn enable_interrupts(&mut self) {
let timer = unsafe { T::steal() };
timer.ccie_set();
}
#[inline]
pub fn disable_interrupts(&mut self) {
let timer = unsafe { T::steal() };
timer.ccie_clr();
}
}
pub struct OverCapture(pub u16);
pub enum CaptureVector<T> {
NoInterrupt,
Capture1(InterruptCapture<T, CCR1>),
Capture2(InterruptCapture<T, CCR2>),
Capture3(InterruptCapture<T, CCR3>),
Capture4(InterruptCapture<T, CCR4>),
Capture5(InterruptCapture<T, CCR5>),
Capture6(InterruptCapture<T, CCR6>),
MainTimer,
}
pub struct InterruptCapture<T, C>(PhantomData<T>, PhantomData<C>);
impl<T: CapCmp<C>, C> InterruptCapture<T, C> {
#[inline]
pub fn interrupt_capture(self, _cap: &mut Capture<T, C>) -> Result<u16, OverCapture> {
let timer = unsafe { T::steal() };
let (cov, _) = timer.cov_ccifg_rd();
let ccrn = timer.get_ccrn();
if cov {
timer.cov_ccifg_clr();
Err(OverCapture(ccrn))
} else {
Ok(ccrn)
}
}
}
pub struct TBxIV<T: TimerPeriph>(PhantomData<T>);
impl<T: TimerPeriph> TBxIV<T> {
#[inline]
pub fn interrupt_vector(&mut self) -> CaptureVector<T> {
let timer = unsafe { T::steal() };
match read_tbxiv(&timer) {
TimerVector::NoInterrupt => CaptureVector::NoInterrupt,
TimerVector::SubTimer1 => {
CaptureVector::Capture1(InterruptCapture(PhantomData, PhantomData))
}
TimerVector::SubTimer2 => {
CaptureVector::Capture2(InterruptCapture(PhantomData, PhantomData))
}
TimerVector::SubTimer3 => {
CaptureVector::Capture3(InterruptCapture(PhantomData, PhantomData))
}
TimerVector::SubTimer4 => {
CaptureVector::Capture4(InterruptCapture(PhantomData, PhantomData))
}
TimerVector::SubTimer5 => {
CaptureVector::Capture5(InterruptCapture(PhantomData, PhantomData))
}
TimerVector::SubTimer6 => {
CaptureVector::Capture6(InterruptCapture(PhantomData, PhantomData))
}
TimerVector::MainTimer => CaptureVector::MainTimer,
}
}
}