summaryrefslogtreecommitdiff
path: root/src/devices/clock_device.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/clock_device.rs')
-rw-r--r--src/devices/clock_device.rs225
1 files changed, 113 insertions, 112 deletions
diff --git a/src/devices/clock_device.rs b/src/devices/clock_device.rs
index 7cc877e..b7c5414 100644
--- a/src/devices/clock_device.rs
+++ b/src/devices/clock_device.rs
@@ -1,114 +1,32 @@
-use bedrock_core::*;
+use crate::*;
use chrono::prelude::*;
-use std::time::{Duration, Instant};
-
-
-macro_rules! fn_read_timer {
- ($fn_name:ident($read:ident, $end:ident)) => {
- pub fn $fn_name(&mut self) {
- let uptime = self.uptime();
- if self.$end > uptime {
- self.$read = (self.$end.saturating_sub(uptime)) as u16;
- } else {
- if self.$end > 0 {
- self.$end = 0;
- self.wake = true;
- }
- self.$read = 0;
- }
- }
- };
-}
-
-macro_rules! fn_set_timer {
- ($fn_name:ident($write:ident, $end:ident)) => {
- pub fn $fn_name(&mut self) {
- let uptime = self.uptime();
- if self.$write > 0 {
- self.$end = uptime.saturating_add(self.$write as u32);
- } else {
- self.$end = 0;
- }
- }
- };
-}
pub struct ClockDevice {
- pub wake: bool,
-
- pub start: Instant,
+ pub epoch: Instant,
pub uptime_read: u16,
- pub t1_end: u32,
- pub t2_end: u32,
- pub t3_end: u32,
- pub t4_end: u32,
+ // End time for each timer as ticks since epoch, zero if not set.
+ pub t1_end: u64,
+ pub t2_end: u64,
+ pub t3_end: u64,
+ pub t4_end: u64,
+ // Cached read value for each timer.
pub t1_read: u16,
pub t2_read: u16,
pub t3_read: u16,
pub t4_read: u16,
+ // Cached write value for each timer.
pub t1_write: u16,
pub t2_write: u16,
pub t3_write: u16,
pub t4_write: u16,
-}
-
-impl ClockDevice {
- pub fn new() -> Self {
- Self {
- start: Instant::now(),
- uptime_read: 0,
- wake: false,
-
- t1_end: 0,
- t2_end: 0,
- t3_end: 0,
- t4_end: 0,
- t1_read: 0,
- t2_read: 0,
- t3_read: 0,
- t4_read: 0,
- t1_write: 0,
- t2_write: 0,
- t3_write: 0,
- t4_write: 0,
- }
- }
- pub fn uptime(&self) -> u32 {
- (self.start.elapsed().as_millis() / 4) as u32
- }
-
- pub fn read_uptime(&mut self) {
- self.uptime_read = self.uptime() as u16;
- }
-
- fn_read_timer!{ read_t1(t1_read, t1_end) }
- fn_read_timer!{ read_t2(t2_read, t2_end) }
- fn_read_timer!{ read_t3(t3_read, t3_end) }
- fn_read_timer!{ read_t4(t4_read, t4_end) }
-
- fn_set_timer!{ set_t1(t1_write, t1_end) }
- fn_set_timer!{ set_t2(t2_write, t2_end) }
- fn_set_timer!{ set_t3(t3_write, t3_end) }
- fn_set_timer!{ set_t4(t4_write, t4_end) }
-
-
- pub fn time_remaining(&mut self) -> Option<Duration> {
- use std::cmp::max;
- let uptime = self.uptime();
-
- let end = max(self.t1_end, max(self.t2_end, max(self.t3_end, self.t4_end)));
- let remaining = end.saturating_sub(uptime);
- match remaining > 0 {
- true => Some(Duration::from_millis(remaining as u64) * 4),
- false => None,
- }
- }
+ pub wake: bool,
}
+
impl Device for ClockDevice {
fn read(&mut self, port: u8) -> u8 {
match port {
@@ -118,16 +36,17 @@ impl Device for ClockDevice {
0x3 => Local::now().hour() as u8,
0x4 => Local::now().minute() as u8,
0x5 => Local::now().second() as u8,
- 0x6 => { self.read_uptime(); read_h!(self.uptime_read) },
- 0x7 => read_l!(self.uptime_read),
+ 0x6 => { self.uptime_read = self.uptime() as u16;
+ read_h!(self.uptime_read) },
+ 0x7 => read_l!(self.uptime_read),
0x8 => { self.read_t1(); read_h!(self.t1_read) },
- 0x9 => read_l!(self.t1_read),
+ 0x9 => read_l!(self.t1_read),
0xa => { self.read_t2(); read_h!(self.t2_read) },
- 0xb => read_l!(self.t2_read),
+ 0xb => read_l!(self.t2_read),
0xc => { self.read_t3(); read_h!(self.t3_read) },
- 0xd => read_l!(self.t3_read),
+ 0xd => read_l!(self.t3_read),
0xe => { self.read_t4(); read_h!(self.t4_read) },
- 0xf => read_l!(self.t4_read),
+ 0xf => read_l!(self.t4_read),
_ => unreachable!(),
}
}
@@ -142,13 +61,13 @@ impl Device for ClockDevice {
0x5 => (),
0x6 => (),
0x7 => (),
- 0x8 => write_h!(self.t1_write, value),
+ 0x8 => write_h!(self.t1_write, value),
0x9 => { write_l!(self.t1_write, value); self.set_t1() },
- 0xa => write_h!(self.t2_write, value),
+ 0xa => write_h!(self.t2_write, value),
0xb => { write_l!(self.t2_write, value); self.set_t2() },
- 0xc => write_h!(self.t3_write, value),
+ 0xc => write_h!(self.t3_write, value),
0xd => { write_l!(self.t3_write, value); self.set_t3() },
- 0xe => write_h!(self.t4_write, value),
+ 0xe => write_h!(self.t4_write, value),
0xf => { write_l!(self.t4_write, value); self.set_t4() },
_ => unreachable!(),
};
@@ -157,18 +76,100 @@ impl Device for ClockDevice {
fn wake(&mut self) -> bool {
let uptime = self.uptime();
- macro_rules! check_timer {
- ($end:ident) => {
- if self.$end > 0 && self.$end <= uptime {
+
+ if self.t1_end > 0 && self.t1_end <= uptime {
+ self.t1_end = 0; self.wake = true; }
+ if self.t2_end > 0 && self.t2_end <= uptime {
+ self.t2_end = 0; self.wake = true; }
+ if self.t3_end > 0 && self.t3_end <= uptime {
+ self.t3_end = 0; self.wake = true; }
+ if self.t4_end > 0 && self.t4_end <= uptime {
+ self.t4_end = 0; self.wake = true; }
+
+ return std::mem::take(&mut self.wake);
+ }
+}
+
+
+impl ClockDevice {
+ pub fn new() -> Self {
+ Self {
+ epoch: Instant::now(),
+ uptime_read: 0,
+ wake: false,
+
+ t1_end: 0,
+ t2_end: 0,
+ t3_end: 0,
+ t4_end: 0,
+ t1_read: 0,
+ t2_read: 0,
+ t3_read: 0,
+ t4_read: 0,
+ t1_write: 0,
+ t2_write: 0,
+ t3_write: 0,
+ t4_write: 0,
+ }
+ }
+
+ pub fn uptime(&self) -> u64 {
+ (self.epoch.elapsed().as_nanos() * 256 / 1_000_000_000) as u64
+ }
+
+ /// Duration remaining until the next timer expires, if any timer is set.
+ pub fn duration_remaining(&mut self) -> Option<Duration> {
+ let mut end = u64::MAX;
+ if self.t1_end > 0 { end = std::cmp::min(end, self.t1_end); }
+ if self.t2_end > 0 { end = std::cmp::min(end, self.t2_end); }
+ if self.t3_end > 0 { end = std::cmp::min(end, self.t3_end); }
+ if self.t4_end > 0 { end = std::cmp::min(end, self.t4_end); }
+
+ if end != u64::MAX {
+ let remaining = end.saturating_sub(self.uptime());
+ Some(Duration::from_nanos(remaining * 1_000_000_000 / 256))
+ } else {
+ None
+ }
+ }
+}
+
+macro_rules! fn_read_timer {
+ ($fn_name:ident($read:ident, $end:ident)) => {
+ pub fn $fn_name(&mut self) {
+ let uptime = self.uptime();
+ if self.$end > uptime {
+ self.$read = (self.$end.saturating_sub(uptime)) as u16;
+ } else {
+ if self.$end > 0 {
self.$end = 0;
self.wake = true;
}
+ self.$read = 0;
+ }
+ }
+ };
+}
+
+macro_rules! fn_set_timer {
+ ($fn_name:ident($write:ident, $end:ident)) => {
+ pub fn $fn_name(&mut self) {
+ match self.$write > 0 {
+ true => self.$end = self.uptime().saturating_add(self.$write as u64),
+ false => self.$end = 0,
};
}
- check_timer!(t1_end);
- check_timer!(t2_end);
- check_timer!(t3_end);
- check_timer!(t4_end);
- return std::mem::take(&mut self.wake);
- }
+ };
+}
+
+impl ClockDevice {
+ fn_read_timer!{ read_t1(t1_read, t1_end) }
+ fn_read_timer!{ read_t2(t2_read, t2_end) }
+ fn_read_timer!{ read_t3(t3_read, t3_end) }
+ fn_read_timer!{ read_t4(t4_read, t4_end) }
+
+ fn_set_timer!{ set_t1(t1_write, t1_end) }
+ fn_set_timer!{ set_t2(t2_write, t2_end) }
+ fn_set_timer!{ set_t3(t3_write, t3_end) }
+ fn_set_timer!{ set_t4(t4_write, t4_end) }
}