summaryrefslogtreecommitdiff
path: root/src/devices/clock.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/clock.rs')
-rw-r--r--src/devices/clock.rs130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/devices/clock.rs b/src/devices/clock.rs
new file mode 100644
index 0000000..063c67b
--- /dev/null
+++ b/src/devices/clock.rs
@@ -0,0 +1,130 @@
+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,
+ }
+ }
+}