use crate::api::clock::DATE_TIME_ZONE; use crate::api::fs::{FileIO, IO}; use crate::sys; use crate::sys::cmos::CMOS; use time::{Duration, OffsetDateTime}; const DAYS_BEFORE_MONTH: [u64; 13] = [ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 ]; #[derive(Debug, Clone)] pub struct Uptime; impl Uptime { pub fn new() -> Self { Self {} } pub fn size() -> usize { core::mem::size_of::() } } impl FileIO for Uptime { fn read(&mut self, buf: &mut [u8]) -> Result { let time = uptime().to_be_bytes(); let n = time.len(); if buf.len() >= n { buf[0..n].clone_from_slice(&time); Ok(n) } else { Err(()) } } fn write(&mut self, _buf: &[u8]) -> Result { unimplemented!(); } fn close(&mut self) {} fn poll(&mut self, event: IO) -> bool { match event { IO::Read => true, IO::Write => false, } } } // NOTE: This clock is monotonic pub fn uptime() -> f64 { sys::time::time_between_ticks() * sys::time::ticks() as f64 } #[derive(Debug, Clone)] pub struct Realtime; impl Realtime { pub fn new() -> Self { Self {} } pub fn size() -> usize { core::mem::size_of::() } } impl FileIO for Realtime { fn read(&mut self, buf: &mut [u8]) -> Result { let time = realtime().to_be_bytes(); let n = time.len(); if buf.len() >= n { buf[0..n].clone_from_slice(&time); Ok(n) } else { Err(()) } } fn write(&mut self, _buf: &[u8]) -> Result { unimplemented!(); } fn close(&mut self) {} fn poll(&mut self, event: IO) -> bool { match event { IO::Read => true, IO::Write => false, } } } // NOTE: This clock is not monotonic pub fn realtime() -> f64 { let rtc = CMOS::new().rtc(); // Assuming GMT let ts = 86400 * days_before_year(rtc.year as u64) + 86400 * days_before_month(rtc.year as u64, rtc.month as u64) + 86400 * (rtc.day - 1) as u64 + 3600 * rtc.hour as u64 + 60 * rtc.minute as u64 + rtc.second as u64; let fract = sys::time::time_between_ticks() * (sys::time::ticks() - sys::time::last_rtc_update()) as f64; (ts as f64) + fract } fn days_before_year(year: u64) -> u64 { (1970..year).fold(0, |days, y| days + if is_leap_year(y) { 366 } else { 365 } ) } fn days_before_month(year: u64, month: u64) -> u64 { let leap_day = is_leap_year(year) && month > 2; DAYS_BEFORE_MONTH[(month as usize) - 1] + (leap_day as u64) } fn is_leap_year(year: u64) -> bool { if year % 4 != 0 { false } else if year % 100 != 0 { true } else if year % 400 != 0 { false } else { true } } pub fn init() { let s = realtime(); let ns = Duration::nanoseconds( libm::floor(1e9 * (s - libm::floor(s))) as i64 ); let dt = OffsetDateTime::from_unix_timestamp(s as i64) + ns; let rtc = dt.format(DATE_TIME_ZONE); log!("RTC {}", rtc); } #[test_case] fn test_uptime() { assert!(uptime() > 0.0); } #[test_case] fn test_realtime() { assert!(realtime() > 1234567890.0); }