diff options
Diffstat (limited to 'src/devices/clock_device.rs')
-rw-r--r-- | src/devices/clock_device.rs | 225 |
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) } } |