use std::time::{Duration, Instant};
macro_rules! now { () => {
time::OffsetDateTime::now_local()
.unwrap_or_else(|_| time::OffsetDateTime::now_utc())
};}
macro_rules! time_from_ticks {
($ticks:expr) => { Instant::now() + Duration::from_millis(($ticks * 4).into()) };
}
macro_rules! ticks_since_time {
($time:expr) => { ($time.duration_since(Instant::now()).as_millis() / 4) as u16 };
}
/// Create a method to set the instant of a timer.
macro_rules! generate_set_timer_method {
($i:tt) => {mini_paste::item!{
pub fn [< set_timer_ $i >] (&mut self) {
self. [< timer_ $i _instant >] = time_from_ticks!(self. [< timer_ $i >]);
}
}};
}
/// Create a method to update the value of a timer.
macro_rules! generate_update_timer_method {
($i:tt) => {mini_paste::item!{
pub fn [< update_timer_ $i >] (&mut self) {
if self. [< timer_ $i >] > 0 {
self. [< timer_ $i >] = ticks_since_time!(self.[< timer_ $i _instant >]);
if self. [< timer_ $i >] == 0 { self.wake_flag = true; }
}
}
}};
}
pub struct ClockDevice {
pub wake_flag: bool,
pub boot_time: Instant,
pub cumulative_seconds: u16,
pub timer_1_instant: Instant,
pub timer_2_instant: Instant,
pub timer_3_instant: Instant,
pub timer_4_instant: Instant,
pub timer_1: u16,
pub timer_2: u16,
pub timer_3: u16,
pub timer_4: u16,
}
impl ClockDevice {
pub fn new() -> Self {
Self {
wake_flag: false,
boot_time: Instant::now(),
cumulative_seconds: 0,
timer_1_instant: Instant::now(),
timer_2_instant: Instant::now(),
timer_3_instant: Instant::now(),
timer_4_instant: Instant::now(),
timer_1: 0,
timer_2: 0,
timer_3: 0,
timer_4: 0,
}
}
pub fn update_cumulative_seconds(&mut self) {
self.cumulative_seconds = self.boot_time.elapsed().as_secs() as u16;
}
generate_set_timer_method!{1}
generate_set_timer_method!{2}
generate_set_timer_method!{3}
generate_set_timer_method!{4}
generate_update_timer_method!{1}
generate_update_timer_method!{2}
generate_update_timer_method!{3}
generate_update_timer_method!{4}
pub fn year(&self) -> u8 {
now!().year().saturating_sub(2000).try_into().unwrap_or(u8::MAX)
}
pub fn month(&self) -> u8 {
now!().month() as u8 - 1
}
pub fn day(&self) -> u8 {
now!().day() as u8 - 1
}
pub fn hour(&self) -> u8 {
now!().hour()
}
pub fn minute(&self) -> u8 {
now!().minute()
}
pub fn second(&self) -> u8 {
now!().second()
}
pub fn shortest_active_timer(&self) -> Option<Duration> {
let mut is_some = false;
let mut value = u16::MAX;
macro_rules! contribute_to_min {
($timer:expr) => {
if $timer > 0 {
is_some = true;
value = std::cmp::min(value, $timer);
}
};
}
contribute_to_min!(self.timer_1);
contribute_to_min!(self.timer_2);
contribute_to_min!(self.timer_3);
contribute_to_min!(self.timer_4);
match is_some {
true => Some(Duration::from_millis((value*4).into())),
false => None,
}
}
}