#![no_std]
use core::cmp::Ordering;
use x86_64::instructions::port::Port;
const CMOS_ADDRESS: u16 = 0x70;
const CMOS_DATA: u16 = 0x71;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub struct Time {
pub second: u8,
pub minute: u8,
pub hour: u8,
pub day: u8,
pub month: u8,
pub year: u8,
pub century: u8,
}
impl PartialOrd for Time {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Time {
fn cmp(&self, other: &Self) -> Ordering {
self.century
.cmp(&other.century)
.then(self.year.cmp(&other.year))
.then(self.month.cmp(&other.month))
.then(self.day.cmp(&other.day))
.then(self.hour.cmp(&other.hour))
.then(self.minute.cmp(&other.minute))
.then(self.second.cmp(&other.second))
}
}
pub struct ReadRTC {
cmos_address: Port<u8>,
cmos_data: Port<u8>,
current_year: u8,
century_register: u8,
}
impl ReadRTC {
#[must_use]
pub const fn new(current_year: u8, century_register: u8) -> ReadRTC {
ReadRTC {
cmos_address: Port::new(CMOS_ADDRESS),
cmos_data: Port::new(CMOS_DATA),
current_year,
century_register,
}
}
fn get_update_in_progress_flag(&mut self) -> u8 {
unsafe {
self.cmos_address.write(0x0A);
self.cmos_data.read() & 0x80
}
}
fn get_rtc_register(&mut self, reg: u8) -> u8 {
unsafe {
self.cmos_address.write(reg);
self.cmos_data.read()
}
}
fn update_time(&mut self) -> Time {
while self.get_update_in_progress_flag() != 0 {}
Time {
second: self.get_rtc_register(0x00),
minute: self.get_rtc_register(0x02),
hour: self.get_rtc_register(0x04),
day: self.get_rtc_register(0x07),
month: self.get_rtc_register(0x08),
year: self.get_rtc_register(0x09),
century: if self.century_register == 0 {
0
} else {
self.get_rtc_register(self.century_register)
},
}
}
pub fn read(&mut self) -> Time {
let mut last_time: Time;
let mut time: Time = self.update_time();
loop {
last_time = time;
time = self.update_time();
if (last_time.second == time.second)
&& (last_time.minute == time.minute)
&& (last_time.hour == time.hour)
&& (last_time.day == time.day)
&& (last_time.month == time.month)
&& (last_time.year == time.year)
&& (last_time.century == time.century)
{
break;
}
}
let register_b = self.get_rtc_register(0x0B);
if register_b & 0x04 == 0 {
time.second = (time.second & 0x0F) + ((time.second / 16) * 10);
time.minute = (time.minute & 0x0F) + ((time.minute / 16) * 10);
time.hour =
((time.hour & 0x0F) + (((time.hour & 0x70) / 16) * 10)) | (time.hour & 0x80);
time.day = (time.day & 0x0F) + ((time.day / 16) * 10);
time.month = (time.month & 0x0F) + ((time.month / 16) * 10);
time.year = (time.year & 0x0F) + ((time.year / 16) * 10);
if self.century_register != 0 {
time.century = (time.century & 0x0F) + ((time.century / 16) * 10);
}
}
if register_b & 0x02 == 0 && (time.hour & 0x80 != 0) {
time.hour = ((time.hour & 0x7F) + 12) % 24;
}
if self.century_register == 0 {
time.year += (self.current_year / 100) * 100;
if time.year < self.current_year {
time.year += 100;
};
} else {
time.year += time.century * 100;
}
time
}
}