summaryrefslogblamecommitdiff
path: root/src/devices/clock.rs
blob: 60b1cad42a8b1194442352a9959c1472cb8137b4 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                   
                                                                                          
                          
                                                                                            

                                                  
                                   
                                                
                                                   
                                                          
                                                            




                                                   

                                                          
                                                          


                                                                           
             
                          





                        
                               
 


                             









                             
                                          
 


                                        





                       








                                    








                                                              
     






















                                                                        
                                                         



                                                                
     
use std::time::{Duration, Instant};

macro_rules! to_ticks { ($dur:expr) => {($dur.as_millis() / 4) as u16}; }
macro_rules! from_ticks { ($ticks:expr) => {Duration::from_millis(($ticks * 4).into())}; }
macro_rules! now { () => {
    time::OffsetDateTime::now_local().unwrap_or_else(|_| time::OffsetDateTime::now_utc())};}

/// 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) {
            let ticks = &mut self. [< timer_ $i >];
            let instant = &mut self. [< timer_ $i _end >];

            *instant = Instant::now() + from_ticks!(*ticks);
        }
    }};
}

/// 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) -> u16 {
            let ticks = &mut self. [< timer_ $i >];
            let instant = &mut self. [< timer_ $i _end >];

            if *ticks > 0 {
                *ticks = to_ticks!(instant.duration_since(Instant::now()));
                if *ticks == 0 { self.wake_flag = true; }
            }
            return *ticks;
        }
    }};
}

pub struct ClockDevice {
    pub wake_flag: bool,

    pub program_start: Instant,
    pub uptime: u16,

    pub timer_1_end: Instant,
    pub timer_2_end: Instant,
    pub timer_3_end: Instant,
    pub timer_4_end: 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,

            program_start: Instant::now(),
            uptime: 0,

            timer_1_end: Instant::now(),
            timer_2_end: Instant::now(),
            timer_3_end: Instant::now(),
            timer_4_end: Instant::now(),
            timer_1: 0,
            timer_2: 0,
            timer_3: 0,
            timer_4: 0,
        }
    }

    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 update_timers(&mut self) {
        self.update_timer_1();
        self.update_timer_2();
        self.update_timer_3();
        self.update_timer_4();
    }

    pub fn update_uptime(&mut self) -> u16 {
        self.uptime = to_ticks!(self.program_start.elapsed());
        return self.uptime;
    }

    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 time_to_next_wake(&self) -> Option<Duration> {
        [self.timer_1, self.timer_2, self.timer_3, self.timer_4]
            .iter()
            .filter(|t| **t > 0)
            .min()
            .and_then(|t| Some(from_ticks!(t)))
    }
}