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.rs251
1 files changed, 119 insertions, 132 deletions
diff --git a/src/devices/clock_device.rs b/src/devices/clock_device.rs
index 7cc877e..d06a92c 100644
--- a/src/devices/clock_device.rs
+++ b/src/devices/clock_device.rs
@@ -1,113 +1,18 @@
-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,
- pub t1_read: u16,
- pub t2_read: u16,
- pub t3_read: u16,
- pub t4_read: u16,
- pub t1_write: u16,
- pub t2_write: u16,
- pub t3_write: u16,
- pub t4_write: u16,
+ pub t1: CountdownTimer,
+ pub t2: CountdownTimer,
+ pub t3: CountdownTimer,
+ pub t4: CountdownTimer,
}
-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,
- }
- }
-}
impl Device for ClockDevice {
fn read(&mut self, port: u8) -> u8 {
@@ -118,16 +23,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),
- 0x8 => { self.read_t1(); read_h!(self.t1_read) },
- 0x9 => read_l!(self.t1_read),
- 0xa => { self.read_t2(); read_h!(self.t2_read) },
- 0xb => read_l!(self.t2_read),
- 0xc => { self.read_t3(); read_h!(self.t3_read) },
- 0xd => read_l!(self.t3_read),
- 0xe => { self.read_t4(); read_h!(self.t4_read) },
- 0xf => read_l!(self.t4_read),
+ 0x6 => { self.uptime_read = self.uptime() as u16;
+ read_h!(self.uptime_read) },
+ 0x7 => read_l!(self.uptime_read),
+ 0x8 => { self.t1.update(); read_h!(self.t1.read) },
+ 0x9 => read_l!(self.t1.read),
+ 0xA => { self.t2.update(); read_h!(self.t2.read) },
+ 0xB => read_l!(self.t2.read),
+ 0xC => { self.t3.update(); read_h!(self.t3.read) },
+ 0xD => read_l!(self.t3.read),
+ 0xE => { self.t4.update(); read_h!(self.t4.read) },
+ 0xF => read_l!(self.t4.read),
_ => unreachable!(),
}
}
@@ -142,33 +48,114 @@ impl Device for ClockDevice {
0x5 => (),
0x6 => (),
0x7 => (),
- 0x8 => write_h!(self.t1_write, value),
- 0x9 => { write_l!(self.t1_write, value); self.set_t1() },
- 0xa => write_h!(self.t2_write, value),
- 0xb => { write_l!(self.t2_write, value); self.set_t2() },
- 0xc => write_h!(self.t3_write, value),
- 0xd => { write_l!(self.t3_write, value); self.set_t3() },
- 0xe => write_h!(self.t4_write, value),
- 0xf => { write_l!(self.t4_write, value); self.set_t4() },
+ 0x8 => write_h!(self.t1.write, value),
+ 0x9 => { write_l!(self.t1.write, value); self.t1.commit() },
+ 0xA => write_h!(self.t2.write, value),
+ 0xB => { write_l!(self.t2.write, value); self.t2.commit() },
+ 0xC => write_h!(self.t3.write, value),
+ 0xD => { write_l!(self.t3.write, value); self.t3.commit() },
+ 0xE => write_h!(self.t4.write, value),
+ 0xF => { write_l!(self.t4.write, value); self.t4.commit() },
_ => unreachable!(),
};
return None;
}
fn wake(&mut self) -> bool {
- let uptime = self.uptime();
- macro_rules! check_timer {
- ($end:ident) => {
- if self.$end > 0 && self.$end <= uptime {
- self.$end = 0;
- self.wake = true;
- }
- };
+ let t1 = self.t1.wake();
+ let t2 = self.t2.wake();
+ let t3 = self.t3.wake();
+ let t4 = self.t4.wake();
+ return t1 | t2 | t3 | t4;
+ }
+
+ fn reset(&mut self) {
+ self.epoch = Instant::now();
+ self.uptime_read = 0;
+ self.t1.reset();
+ self.t2.reset();
+ self.t3.reset();
+ self.t4.reset();
+ }
+}
+
+
+impl ClockDevice {
+ pub fn new() -> Self {
+ Self {
+ epoch: Instant::now(),
+ uptime_read: 0,
+
+ t1: CountdownTimer::new(),
+ t2: CountdownTimer::new(),
+ t3: CountdownTimer::new(),
+ t4: CountdownTimer::new(),
+ }
+ }
+
+ pub fn uptime(&self) -> u64 {
+ (self.epoch.elapsed().as_nanos() * 256 / 1_000_000_000) as u64
+ }
+}
+
+
+
+pub struct CountdownTimer {
+ pub end: Option<Instant>,
+ pub read: u16,
+ pub write: u16,
+ pub wake: bool,
+}
+
+impl CountdownTimer {
+ pub fn new() -> Self {
+ Self {
+ end: None,
+ read: 0,
+ write: 0,
+ wake: false,
+ }
+ }
+
+ pub fn reset(&mut self) {
+ self.end = None;
+ self.read = 0;
+ self.write = 0;
+ self.wake = false;
+ }
+
+ pub fn wake(&mut self) -> bool {
+ if let Some(end) = self.end {
+ if end <= Instant::now() {
+ self.end = None;
+ self.wake = true;
+ }
+ }
+ std::mem::take(&mut self.wake)
+ }
+
+ pub fn update(&mut self) {
+ if let Some(end) = self.end {
+ let now = Instant::now();
+ if end > now {
+ let nanos = (end - now).as_nanos();
+ self.read = (nanos * 256 / 1_000_000_000) as u16;
+ } else {
+ self.read = 0;
+ self.end = None;
+ self.wake = true;
+ }
+ } else {
+ self.read = 0;
+ }
+ }
+
+ pub fn commit(&mut self) {
+ if self.write > 0 {
+ let nanos = (self.write as u64) * 1_000_000_000 / 256;
+ self.end = Some(Instant::now() + Duration::from_nanos(nanos));
+ } else {
+ self.end = None;
}
- check_timer!(t1_end);
- check_timer!(t2_end);
- check_timer!(t3_end);
- check_timer!(t4_end);
- return std::mem::take(&mut self.wake);
}
}