summaryrefslogtreecommitdiff
path: root/src/devices/clock.rs
blob: 60b1cad42a8b1194442352a9959c1472cb8137b4 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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)))
    }
}