use core::{marker::PhantomData, mem::ManuallyDrop, num::NonZeroUsize};
use crate::{
kernel::{cfg::CfgBuilder, timeout, timer, utils::CpuLockCell, Kernel, Port},
time::Duration,
};
impl<System: Port> timer::Timer<System> {
pub const fn build() -> CfgTimerBuilder<System> {
CfgTimerBuilder::new()
}
}
#[must_use = "must call `finish()` to complete registration"]
pub struct CfgTimerBuilder<System> {
_phantom: PhantomData<System>,
start: Option<fn(usize)>,
param: usize,
delay: Option<Duration>,
period: Option<Duration>,
active: bool,
}
impl<System: Port> CfgTimerBuilder<System> {
const fn new() -> Self {
Self {
_phantom: PhantomData,
start: None,
param: 0,
delay: None,
period: None,
active: false,
}
}
pub const fn start(self, start: fn(usize)) -> Self {
Self {
start: Some(start),
..self
}
}
pub const fn param(self, param: usize) -> Self {
Self { param, ..self }
}
pub const fn active(self, active: bool) -> Self {
Self { active, ..self }
}
pub const fn delay(self, delay: Duration) -> Self {
Self {
delay: Some(delay),
..self
}
}
pub const fn period(self, period: Duration) -> Self {
Self {
period: Some(period),
..self
}
}
pub const fn finish(self, cfg: &mut CfgBuilder<System>) -> timer::Timer<System> {
let inner = &mut cfg.inner;
let period = if let Some(period) = self.period {
if let Ok(x) = timeout::time32_from_duration(period) {
x
} else {
panic!("`period` must not be negative");
}
} else {
timeout::BAD_DURATION32
};
let delay = if let Some(delay) = self.delay {
if let Ok(x) = timeout::time32_from_duration(delay) {
x
} else {
panic!("`delay` must not be negative");
}
} else {
timeout::BAD_DURATION32
};
inner.timers.push(CfgBuilderTimer {
start: if let Some(x) = self.start {
x
} else {
panic!("`start` (timer callback function) is not specified")
},
param: self.param,
delay,
period,
active: self.active,
});
unsafe { timer::Timer::from_id(NonZeroUsize::new_unchecked(inner.timers.len())) }
}
}
#[doc(hidden)]
pub struct CfgBuilderTimer {
start: fn(usize),
param: usize,
delay: timeout::Time32,
period: timeout::Time32,
active: bool,
}
impl Clone for CfgBuilderTimer {
fn clone(&self) -> Self {
Self {
start: self.start,
param: self.param,
delay: self.delay,
period: self.period,
active: self.active,
}
}
}
impl Copy for CfgBuilderTimer {}
impl CfgBuilderTimer {
pub const fn to_state<System: Kernel>(
&self,
attr: &'static timer::TimerAttr<System>,
i: usize,
) -> timer::TimerCb<System> {
let timeout = timeout::Timeout::new(timer::timer_timeout_handler::<System>, i);
let timeout = if self.delay == timeout::BAD_DURATION32 {
timeout.with_at_raw(self.delay)
} else {
timeout.with_expiration_at(self.delay)
};
timer::TimerCb {
attr,
timeout: ManuallyDrop::new(timeout),
period: CpuLockCell::new(self.period),
active: CpuLockCell::new(false),
}
}
pub const fn to_attr<System: Port>(&self) -> timer::TimerAttr<System> {
timer::TimerAttr {
entry_point: self.start,
entry_param: self.param,
init_active: self.active,
_phantom: PhantomData,
}
}
}