use crate::{gpt, pit};
#[doc(hidden)]
pub trait HardwareTimer {
type Ticks;
fn is_elapsed(&self) -> bool;
fn clear_elapsed(&mut self);
fn set_ticks(&mut self, ticks: Self::Ticks);
fn set_enable(&mut self, enable: bool);
}
impl<const N: u8> HardwareTimer for pit::Pit<N> {
type Ticks = u32;
fn is_elapsed(&self) -> bool {
pit::Pit::<N>::is_elapsed(self)
}
fn clear_elapsed(&mut self) {
pit::Pit::<N>::clear_elapsed(self);
}
fn set_ticks(&mut self, ticks: Self::Ticks) {
self.set_load_timer_value(ticks);
}
fn set_enable(&mut self, enable: bool) {
if enable {
self.enable();
} else {
self.disable();
}
}
}
impl<const L: u8, const R: u8> HardwareTimer for pit::Chained<L, R> {
type Ticks = u64;
fn is_elapsed(&self) -> bool {
pit::Chained::<L, R>::is_elapsed(self)
}
fn clear_elapsed(&mut self) {
pit::Chained::<L, R>::clear_elapsed(self);
}
fn set_ticks(&mut self, ticks: Self::Ticks) {
self.set_load_timer_value(ticks);
}
fn set_enable(&mut self, enable: bool) {
if enable {
self.enable();
} else {
self.disable();
}
}
}
const GPT_OCR: gpt::OutputCompareRegister = gpt::OutputCompareRegister::OCR1;
impl<const N: u8> HardwareTimer for gpt::Gpt<N> {
type Ticks = u32;
fn is_elapsed(&self) -> bool {
self.is_elapsed(GPT_OCR)
}
fn clear_elapsed(&mut self) {
gpt::Gpt::<N>::clear_elapsed(self, GPT_OCR);
}
fn set_ticks(&mut self, ticks: Self::Ticks) {
self.set_output_compare_count(GPT_OCR, ticks);
}
fn set_enable(&mut self, enable: bool) {
if enable {
self.enable();
} else {
self.disable();
}
}
}
#[doc(hidden)]
pub trait TimerDurationExt {
type Repr;
fn from_ticks(ticks: Self::Repr) -> Self;
fn ticks(&self) -> Self::Repr;
fn convert<const OTHER_HZ: u32>(&self) -> fugit::TimerDuration<Self::Repr, OTHER_HZ>;
}
impl<const HZ: u32> TimerDurationExt for fugit::TimerDurationU32<HZ> {
type Repr = u32;
fn from_ticks(ticks: Self::Repr) -> Self {
fugit::TimerDuration::<Self::Repr, HZ>::from_ticks(ticks)
}
fn ticks(&self) -> Self::Repr {
fugit::TimerDuration::<Self::Repr, HZ>::ticks(self)
}
fn convert<const OTHER_HZ: u32>(&self) -> fugit::TimerDuration<Self::Repr, OTHER_HZ> {
fugit::TimerDuration::<Self::Repr, HZ>::convert::<1, OTHER_HZ>(*self)
}
}
impl<const HZ: u32> TimerDurationExt for fugit::TimerDurationU64<HZ> {
type Repr = u64;
fn from_ticks(ticks: Self::Repr) -> Self {
fugit::TimerDuration::<Self::Repr, HZ>::from_ticks(ticks)
}
fn ticks(&self) -> Self::Repr {
fugit::TimerDuration::<Self::Repr, HZ>::ticks(self)
}
fn convert<const OTHER_HZ: u32>(&self) -> fugit::TimerDuration<Self::Repr, OTHER_HZ> {
fugit::TimerDuration::<Self::Repr, HZ>::convert::<1, OTHER_HZ>(*self)
}
}
pub struct Blocking<T, const HZ: u32> {
timer: T,
}
impl<T, const HZ: u32> Blocking<T, HZ>
where
T: HardwareTimer,
{
fn new(timer: T) -> Self {
Self { timer }
}
pub fn release(self) -> T {
self.timer
}
pub fn block(&mut self, duration: fugit::TimerDuration<T::Ticks, HZ>)
where
fugit::TimerDuration<T::Ticks, HZ>: TimerDurationExt<Repr = T::Ticks>,
{
self.timer.set_ticks(duration.ticks());
self.timer.set_enable(true);
while !self.timer.is_elapsed() {}
self.timer.clear_elapsed();
self.timer.set_enable(false);
}
pub fn block_ms(&mut self, ms: T::Ticks)
where
fugit::TimerDuration<T::Ticks, HZ>: TimerDurationExt<Repr = T::Ticks>,
fugit::TimerDuration<T::Ticks, 1_000>: TimerDurationExt<Repr = T::Ticks>,
{
self.block(fugit::TimerDuration::<T::Ticks, 1_000>::from_ticks(ms).convert())
}
pub fn block_us(&mut self, us: T::Ticks)
where
fugit::TimerDuration<T::Ticks, HZ>: TimerDurationExt<Repr = T::Ticks>,
fugit::TimerDuration<T::Ticks, 1_000_000>: TimerDurationExt<Repr = T::Ticks>,
{
self.block(fugit::TimerDuration::<T::Ticks, 1_000_000>::from_ticks(us).convert())
}
}
fn prepare_pit_channel<const N: u8>(pit: &mut pit::Pit<N>) {
pit.disable();
pit.clear_elapsed();
pit.set_chained(false);
pit.set_interrupt_enable(false);
}
fn prepare_pit_chained<const L: u8, const R: u8>(chain: &mut pit::Chained<L, R>) {
chain.disable();
chain.clear_elapsed();
chain.set_interrupt_enable(false);
}
fn prepare_gpt<const N: u8>(gpt: &mut gpt::Gpt<N>) {
gpt.disable();
gpt.clear_rollover();
gpt.set_rollover_interrupt_enable(false);
gpt.set_mode(gpt::Mode::Restart);
gpt.set_reset_on_enable(true);
use gpt::OutputCompareRegister::*;
for ocr in [OCR1, OCR2, OCR3] {
gpt::Gpt::<N>::clear_elapsed(gpt, ocr);
gpt.set_output_interrupt_on_compare(ocr, false);
}
}
pub type BlockingPitChan<const N: u8, const HZ: u32> = Blocking<pit::Pit<N>, HZ>;
impl<const N: u8, const HZ: u32> BlockingPitChan<N, HZ> {
pub fn from_pit_channel(mut pit: pit::Pit<N>) -> Self {
prepare_pit_channel(&mut pit);
Self::new(pit)
}
}
pub type BlockingPitChain<const L: u8, const R: u8, const HZ: u32> =
Blocking<pit::Chained<L, R>, HZ>;
impl<const L: u8, const R: u8, const HZ: u32> BlockingPitChain<L, R, HZ> {
pub fn from_pit_chained(mut chain: pit::Chained<L, R>) -> Self {
prepare_pit_chained(&mut chain);
Self::new(chain)
}
}
pub type BlockingGpt<const N: u8, const HZ: u32> = Blocking<gpt::Gpt<N>, HZ>;
impl<const N: u8, const HZ: u32> BlockingGpt<N, HZ> {
pub fn from_gpt(mut gpt: gpt::Gpt<N>) -> Self {
prepare_gpt(&mut gpt);
Self::new(gpt)
}
}
impl<R, T, const HZ: u32> eh02::blocking::delay::DelayMs<R> for Blocking<T, HZ>
where
R: Into<T::Ticks>,
T: HardwareTimer,
fugit::TimerDuration<T::Ticks, HZ>: TimerDurationExt<Repr = T::Ticks>,
fugit::TimerDuration<T::Ticks, 1_000>: TimerDurationExt<Repr = T::Ticks>,
{
fn delay_ms(&mut self, ms: R) {
self.block_ms(ms.into());
}
}
impl<R, T, const HZ: u32> eh02::blocking::delay::DelayUs<R> for Blocking<T, HZ>
where
R: Into<T::Ticks>,
T: HardwareTimer,
fugit::TimerDuration<T::Ticks, HZ>: TimerDurationExt<Repr = T::Ticks>,
fugit::TimerDuration<T::Ticks, 1_000_000>: TimerDurationExt<Repr = T::Ticks>,
{
fn delay_us(&mut self, us: R) {
self.block_us(us.into());
}
}
pub struct RawCountDown<T> {
timer: T,
}
impl<T> RawCountDown<T>
where
T: HardwareTimer,
{
fn new(timer: T) -> Self {
Self { timer }
}
pub fn release(self) -> T {
self.timer
}
pub fn start(&mut self, ticks: T::Ticks) {
self.timer.set_enable(false);
self.timer.clear_elapsed();
self.timer.set_ticks(ticks);
self.timer.set_enable(true);
}
pub fn cancel(&mut self) {
self.timer.set_enable(false);
}
pub fn is_elapsed(&self) -> bool {
self.timer.is_elapsed()
}
pub fn clear_elapsed(&mut self) {
self.timer.clear_elapsed()
}
}
pub type RawCountDownPitChan<const N: u8> = RawCountDown<pit::Pit<N>>;
impl<const N: u8> RawCountDownPitChan<N> {
pub fn from_pit_channel(mut pit: pit::Pit<N>) -> Self {
prepare_pit_channel(&mut pit);
Self::new(pit)
}
}
pub type RawCountDownPitChain<const L: u8, const R: u8> = RawCountDown<pit::Chained<L, R>>;
impl<const L: u8, const R: u8> RawCountDownPitChain<L, R> {
pub fn from_pit_chained(mut chain: pit::Chained<L, R>) -> Self {
prepare_pit_chained(&mut chain);
Self::new(chain)
}
}
pub type RawCountDownGpt<const N: u8> = RawCountDown<gpt::Gpt<N>>;
impl<const N: u8> RawCountDownGpt<N> {
pub fn from_gpt(mut gpt: gpt::Gpt<N>) -> Self {
prepare_gpt(&mut gpt);
Self::new(gpt)
}
}
impl<T> eh02::timer::CountDown for RawCountDown<T>
where
T: HardwareTimer,
{
type Time = T::Ticks;
fn start<C>(&mut self, count: C)
where
C: Into<Self::Time>,
{
RawCountDown::<T>::start(self, count.into());
}
fn wait(&mut self) -> nb::Result<(), void::Void> {
if self.is_elapsed() {
self.clear_elapsed();
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<T> eh02::timer::Periodic for RawCountDown<T> {}
pub struct CountDown<T, const HZ: u32> {
timer: RawCountDown<T>,
}
impl<T, const HZ: u32> CountDown<T, HZ>
where
T: HardwareTimer,
{
pub fn new(raw: RawCountDown<T>) -> Self {
Self { timer: raw }
}
pub fn release(self) -> RawCountDown<T> {
self.timer
}
pub fn start(&mut self, duration: fugit::TimerDuration<T::Ticks, HZ>)
where
fugit::TimerDuration<T::Ticks, HZ>: TimerDurationExt<Repr = T::Ticks>,
{
self.timer.start(duration.ticks());
}
pub fn cancel(&mut self) {
self.timer.cancel();
}
pub fn is_elapsed(&self) -> bool {
self.timer.is_elapsed()
}
pub fn clear_elapsed(&mut self) {
self.timer.clear_elapsed()
}
}
impl<T, const HZ: u32> eh02::timer::CountDown for CountDown<T, HZ>
where
T: HardwareTimer,
fugit::TimerDuration<T::Ticks, HZ>: TimerDurationExt<Repr = T::Ticks>,
{
type Time = fugit::TimerDuration<T::Ticks, HZ>;
fn start<C>(&mut self, count: C)
where
C: Into<Self::Time>,
{
let duration = count.into();
self.start(duration);
}
fn wait(&mut self) -> nb::Result<(), void::Void> {
self.timer.wait()
}
}
impl<T, const HZ: u32> eh02::timer::Periodic for CountDown<T, HZ> {}