use crate::clock::{Aclk, Smclk};
use crate::gpio::{Alternate1, Floating, Input, Pin, Pin2, P6};
use crate::hw_traits::timerb::{CCRn, Tbssel, TimerB};
use core::marker::PhantomData;
use embedded_hal::timer::{Cancel, CountDown, Periodic};
use msp430fr247x as pac;
pub use crate::hw_traits::timerb::{
TimerDiv, TimerExDiv, CCR0, CCR1, CCR2, CCR3, CCR4, CCR5, CCR6,
};
pub trait CapCmp<C>: CCRn<C> {}
impl<T: CCRn<C>, C> CapCmp<C> for T {}
pub trait TimerPeriph: TimerB + CapCmp<CCR0> {
type Tbxclk;
}
pub trait CapCmpTimer3: TimerPeriph + CapCmp<CCR1> + CapCmp<CCR2> {}
pub trait CapCmpTimer7:
TimerPeriph
+ CapCmp<CCR1>
+ CapCmp<CCR2>
+ CapCmp<CCR3>
+ CapCmp<CCR4>
+ CapCmp<CCR5>
+ CapCmp<CCR6>
{
}
impl TimerPeriph for pac::TB0 {
type Tbxclk = Pin<P6, Pin2, Alternate1<Input<Floating>>>;
}
impl CapCmpTimer7 for pac::TB0 {}
pub struct TimerConfig<T: TimerPeriph> {
_timer: PhantomData<T>,
sel: Tbssel,
div: TimerDiv,
ex_div: TimerExDiv,
}
impl<T: TimerPeriph> TimerConfig<T> {
#[inline]
pub fn aclk(_aclk: &Aclk) -> Self {
TimerConfig {
_timer: PhantomData,
sel: Tbssel::Aclk,
div: TimerDiv::_1,
ex_div: TimerExDiv::_1,
}
}
#[inline]
pub fn smclk(_smclk: &Smclk) -> Self {
TimerConfig {
_timer: PhantomData,
sel: Tbssel::Smclk,
div: TimerDiv::_1,
ex_div: TimerExDiv::_1,
}
}
#[inline]
pub fn tbclk(_pin: T::Tbxclk) -> Self {
TimerConfig {
_timer: PhantomData,
sel: Tbssel::Tbxclk,
div: TimerDiv::_1,
ex_div: TimerExDiv::_1,
}
}
#[inline]
pub fn clk_div(self, div: TimerDiv, ex_div: TimerExDiv) -> Self {
TimerConfig {
_timer: PhantomData,
sel: self.sel,
div,
ex_div,
}
}
#[inline]
pub(crate) fn write_regs(self, timer: &T) {
timer.reset();
timer.set_tbidex(self.ex_div);
timer.config_clock(self.sel, self.div);
}
}
pub struct TimerParts3<T: CapCmpTimer3> {
pub timer: Timer<T>,
pub tbxiv: TBxIV<T>,
pub subtimer1: SubTimer<T, CCR1>,
pub subtimer2: SubTimer<T, CCR2>,
}
impl<T: CapCmpTimer3> TimerParts3<T> {
#[inline(always)]
pub fn new(_timer: T, config: TimerConfig<T>) -> Self {
config.write_regs(unsafe { &T::steal() });
Self {
timer: Timer::new(),
tbxiv: TBxIV(PhantomData),
subtimer1: SubTimer::new(),
subtimer2: SubTimer::new(),
}
}
}
pub struct TimerParts7<T: CapCmpTimer7> {
pub timer: Timer<T>,
pub tbxiv: TBxIV<T>,
pub subtimer1: SubTimer<T, CCR1>,
pub subtimer2: SubTimer<T, CCR2>,
pub subtimer3: SubTimer<T, CCR3>,
pub subtimer4: SubTimer<T, CCR4>,
pub subtimer5: SubTimer<T, CCR5>,
pub subtimer6: SubTimer<T, CCR6>,
}
impl<T: CapCmpTimer7> TimerParts7<T> {
#[inline(always)]
pub fn new(_timer: T, config: TimerConfig<T>) -> Self {
config.write_regs(unsafe { &T::steal() });
Self {
timer: Timer::new(),
tbxiv: TBxIV(PhantomData),
subtimer1: SubTimer::new(),
subtimer2: SubTimer::new(),
subtimer3: SubTimer::new(),
subtimer4: SubTimer::new(),
subtimer5: SubTimer::new(),
subtimer6: SubTimer::new(),
}
}
}
pub struct Timer<T: TimerPeriph>(PhantomData<T>);
impl<T: TimerPeriph> Timer<T> {
fn new() -> Self {
Self(PhantomData)
}
}
pub struct SubTimer<T: CapCmp<C>, C>(PhantomData<T>, PhantomData<C>);
impl<T: CapCmp<C>, C> SubTimer<T, C> {
fn new() -> Self {
Self(PhantomData, PhantomData)
}
}
pub enum TimerVector {
NoInterrupt,
SubTimer1,
SubTimer2,
SubTimer3,
SubTimer4,
SubTimer5,
SubTimer6,
MainTimer,
}
#[inline]
pub(crate) fn read_tbxiv<T: TimerB>(timer: &T) -> TimerVector {
match timer.tbxiv_rd() {
0 => TimerVector::NoInterrupt,
2 => TimerVector::SubTimer1,
4 => TimerVector::SubTimer2,
6 => TimerVector::SubTimer3,
8 => TimerVector::SubTimer4,
10 => TimerVector::SubTimer5,
12 => TimerVector::SubTimer6,
14 => TimerVector::MainTimer,
_ => unsafe { core::hint::unreachable_unchecked() },
}
}
pub struct TBxIV<T>(PhantomData<T>);
impl<T: TimerB> TBxIV<T> {
#[inline]
pub fn interrupt_vector(&mut self) -> TimerVector {
let timer = unsafe { T::steal() };
read_tbxiv(&timer)
}
}
impl<T: TimerPeriph + CapCmp<CCR0>> CountDown for Timer<T> {
type Time = u16;
#[inline]
fn start<U: Into<Self::Time>>(&mut self, count: U) {
let timer = unsafe { T::steal() };
timer.stop();
timer.set_ccrn(count.into());
timer.upmode();
}
#[inline]
fn wait(&mut self) -> nb::Result<(), void::Void> {
let timer = unsafe { T::steal() };
if timer.tbifg_rd() {
timer.tbifg_clr();
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<T: TimerPeriph + CapCmp<CCR0>> Cancel for Timer<T> {
type Error = void::Void;
#[inline(always)]
fn cancel(&mut self) -> Result<(), Self::Error> {
let timer = unsafe { T::steal() };
timer.stop();
Ok(())
}
}
impl<T: TimerPeriph> Periodic for Timer<T> {}
impl<T: TimerPeriph> Timer<T> {
#[inline(always)]
pub fn enable_interrupts(&mut self) {
let timer = unsafe { T::steal() };
timer.tbie_set();
}
#[inline(always)]
pub fn disable_interrupts(&mut self) {
let timer = unsafe { T::steal() };
timer.tbie_clr();
}
}
impl<T: CapCmp<C>, C> SubTimer<T, C> {
#[inline]
pub fn set_count(&mut self, count: u16) {
let timer = unsafe { T::steal() };
timer.set_ccrn(count);
timer.ccifg_clr();
}
#[inline]
pub fn wait(&mut self) -> nb::Result<(), void::Void> {
let timer = unsafe { T::steal() };
if timer.ccifg_rd() {
timer.ccifg_clr();
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
#[inline(always)]
pub fn enable_interrupts(&mut self) {
let timer = unsafe { T::steal() };
timer.ccie_set();
}
#[inline(always)]
pub fn disable_interrupts(&mut self) {
let timer = unsafe { T::steal() };
timer.ccie_clr();
}
}