use crate::*; use chrono::prelude::*; pub struct ClockDevice { pub epoch: Instant, pub uptime_read: u16, pub t1: CountdownTimer, pub t2: CountdownTimer, pub t3: CountdownTimer, pub t4: CountdownTimer, } impl Device for ClockDevice { fn read(&mut self, port: u8) -> u8 { match port { 0x0 => Local::now().year().saturating_sub(2000) as u8, 0x1 => Local::now().month().saturating_sub(1) as u8, 0x2 => Local::now().day().saturating_sub(1) as u8, 0x3 => Local::now().hour() as u8, 0x4 => Local::now().minute() as u8, 0x5 => Local::now().second() as u8, 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!(), } } fn write(&mut self, port: u8, value: u8) -> Option { match port { 0x0 => (), 0x1 => (), 0x2 => (), 0x3 => (), 0x4 => (), 0x5 => (), 0x6 => (), 0x7 => (), 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 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, 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; } } }