use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::time::Duration;
use crate::{irq::Interrupt, mmio};
static mut ENABLE_TIMER: bool = false;
static mut SYSTEM_TIMER: u32 = 0;
unsafe extern fn increase_system_timer() {
SYSTEM_TIMER += 1;
}
#[repr(u8)]
#[derive(Clone, Copy)]
pub enum TimerClock {
MCycle256 = 0x00, MCycle4 = 0x01, MCycle16 = 0x10, MCycle64 = 0x11, }
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Instant(u32);
impl Instant {
pub const FREQUENCY: u32 = 4096 / 0xFF;
pub unsafe fn init() -> Interrupt {
Self::enable_timer(TimerClock::MCycle256, 0);
ENABLE_TIMER = true;
Interrupt::Timer.add(increase_system_timer)
}
pub fn now() -> Self {
unsafe {
if !ENABLE_TIMER {
panic!("Instant is not initalized");
}
return Instant(SYSTEM_TIMER);
}
}
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
if self.0 < earlier.0 {
None
}
else {
let delta_freq = self.0 - earlier.0;
Some(Duration::from_millis(
(delta_freq / Self::FREQUENCY * 1000).into()
))
}
}
pub fn duration_since(&self, earlier: Instant) -> Duration {
if self.0 < earlier.0 {
panic!("duration_since get later instance");
}
else {
let delta_freq = self.0 - earlier.0;
Duration::from_millis(
(delta_freq / Self::FREQUENCY * 1000) as u64
)
}
}
pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
}
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
}
pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
self.0
.checked_add(duration.as_millis() as u32 / 1000 * Self::FREQUENCY)
.map(Instant)
}
pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
self.0
.checked_sub(duration.as_millis() as u32 / 1000 * Self::FREQUENCY)
.map(Instant)
}
fn enable_timer(clock: TimerClock, modulo: u8) {
mmio::TMA.write(modulo);
mmio::TAC.write(0x4 | clock as u8);
}
fn disable_timer() {
mmio::TAC.write(0);
}
}
impl Add<Duration> for Instant {
type Output = Instant;
fn add(self, rhs: Duration) -> Self::Output {
self.checked_add(rhs).expect("overflow when adding duration to instant")
}
}
impl AddAssign<Duration> for Instant {
fn add_assign(&mut self, rhs: Duration) {
*self = *self + rhs;
}
}
impl Sub<Duration> for Instant {
type Output = Instant;
fn sub(self, rhs: Duration) -> Self::Output {
self.checked_sub(rhs).expect("overflow when subtracting duration from instant")
}
}
impl SubAssign<Duration> for Instant {
fn sub_assign(&mut self, rhs: Duration) {
*self = *self - rhs;
}
}
impl Sub<Instant> for Instant {
type Output = Duration;
fn sub(self, rhs: Instant) -> Self::Output {
self.duration_since(rhs)
}
}
pub fn sleep(dur: Duration) {
sleep_until(Instant::now() + dur);
}
pub fn sleep_ms(ms: u32) {
sleep(Duration::from_millis(ms as u64));
}
pub fn sleep_until(deadline: Instant) {
while !Instant::now().saturating_duration_since(deadline).is_zero() {}
}