use core::{cell::UnsafeCell, mem::zeroed};
use crate::{
bindings::{
rt_timer, rt_timer_change_period, rt_timer_command, rt_timer_daemon, rt_timer_fn,
rt_timer_start, rt_timer_stop, rt_timer_timedchange_period, rt_timer_timedstart,
rt_timer_timedstop, rt_timer_trychange_period, rt_timer_trystart, rt_timer_trystop,
},
list::list_init,
ptr_macros::{ptr_to_field, ptr_to_field_mut},
sync::Queue,
tick::Utick,
};
#[repr(transparent)]
pub struct Timer {
timer: UnsafeCell<rt_timer>,
}
unsafe impl Send for Timer {}
unsafe impl Sync for Timer {}
#[repr(transparent)]
pub struct TimerCommand(rt_timer_command);
unsafe impl Send for TimerCommand {}
unsafe impl Sync for TimerCommand {}
impl Timer {
#[must_use]
pub const unsafe fn init(
this: *const Self,
queue: &'static Queue<TimerCommand>,
f: extern "C" fn(),
periodic: bool,
period: Utick,
) -> Timer {
let timer = UnsafeCell::raw_get(ptr_to_field!(this, timer));
Timer {
timer: UnsafeCell::new(rt_timer {
list: list_init(ptr_to_field_mut!(timer, list)),
tick: 0,
period,
fn_: unsafe {
let mut x: rt_timer_fn = zeroed();
x.no_arg = Some(f);
x
},
arg: 0,
queue: queue.queue.get(),
has_arg: false,
periodic,
}),
}
}
pub fn start(&self) {
unsafe { rt_timer_start(self.timer.get()) }
}
pub fn try_start(&self) -> bool {
unsafe { rt_timer_trystart(self.timer.get()) }
}
pub fn timed_start(&self, block_ticks: Utick) -> bool {
unsafe { rt_timer_timedstart(self.timer.get(), block_ticks) }
}
pub fn stop(&self) {
unsafe { rt_timer_stop(self.timer.get()) }
}
pub fn try_stop(&self) -> bool {
unsafe { rt_timer_trystop(self.timer.get()) }
}
pub fn timed_stop(&self, block_ticks: Utick) -> bool {
unsafe { rt_timer_timedstop(self.timer.get(), block_ticks) }
}
pub fn change_period(&self, period: Utick) {
unsafe { rt_timer_change_period(self.timer.get(), period) }
}
pub fn try_change_period(&self, period: Utick) -> bool {
unsafe { rt_timer_trychange_period(self.timer.get(), period) }
}
pub fn timed_change_period(&self, period: Utick, block_ticks: Utick) -> bool {
unsafe { rt_timer_timedchange_period(self.timer.get(), period, block_ticks) }
}
}
pub fn timer_daemon(queue: &'static Queue<TimerCommand>) {
let queue_addr = queue.queue.get().addr();
unsafe { rt_timer_daemon(queue_addr) }
}
#[macro_export]
macro_rules! timer_queue {
($name: ident, $depth: expr) => {
$crate::queue!($name, $crate::timer::TimerCommand, $depth);
};
}
#[macro_export]
macro_rules! timer_task {
($queue: expr, $stack_size: expr, $priority: expr$(, $mpu_regions: expr)*) => {
const _: () = {
use $crate::timer::timer_daemon;
$crate::task!(timer_daemon($queue), $stack_size, $priority $(, $mpu_regions)*);
};
};
}
#[macro_export]
macro_rules! timer_common {
($name: ident, $queue: expr, $fn: ident, $periodic: expr, $period: expr) => {
$crate::timer_common!($name, $queue, $fn(), $periodic, $period);
};
($name: ident, $queue: expr, $expr: expr, $periodic: expr, $period: expr) => {
static $name: $crate::timer::Timer = {
let ptr = &raw const $name;
let queue = $queue;
extern "C" fn timer_fn() {
$expr;
}
let periodic = $periodic;
let period = $period;
unsafe { $crate::timer::Timer::init(ptr, queue, timer_fn, periodic, period) }
};
};
}
#[macro_export]
macro_rules! timer_periodic {
($name: ident, $queue: expr, $fn: ident, $period: expr) => {
$crate::timer_common!($name, $queue, $fn, true, $period);
};
($name: ident, $queue: expr, $expr: expr, $period: expr) => {
$crate::timer_common!($name, $queue, $expr, true, $period);
};
}
#[macro_export]
macro_rules! timer_one_shot {
($name: ident, $queue: expr, $fn: ident, $period: expr) => {
$crate::timer_common!($name, $queue, $fn, false, $period);
};
($name: ident, $queue: expr, $expr: expr, $period: expr) => {
$crate::timer_common!($name, $queue, $expr, false, $period);
};
}
#[macro_export]
macro_rules! timer_autostart {
($name: ident) => {
const _: () = {
extern "C" fn timer_autostart() {
assert!($name.try_start(), "can't autostart timer");
}
$crate::ctor!(TIMER_AUTOSTART, timer_autostart);
};
};
}