good_os_framework/drivers/
rtc.rs

1use time::{error::ComponentRange, Time};
2use time::{Date, Month, OffsetDateTime, PrimitiveDateTime};
3use x86_64::instructions::port::Port;
4
5#[derive(Debug)]
6pub struct RtcDateTime {
7    second: u8,
8    minute: u8,
9    hour: u8,
10    day: u8,
11    month: u8,
12    year: u8,
13}
14
15impl RtcDateTime {
16    pub fn new() -> Self {
17        let mut rtc_time = Self {
18            second: Self::get_rtc_register(0x00),
19            minute: Self::get_rtc_register(0x02),
20            hour: Self::get_rtc_register(0x04),
21            day: Self::get_rtc_register(0x07),
22            month: Self::get_rtc_register(0x08),
23            year: Self::get_rtc_register(0x09),
24        };
25
26        let format = Self::get_rtc_register(0x0b);
27        let is_24_hour = format & (1 << 1) != 0;
28        let is_binary = format & (1 << 2) != 0;
29
30        if !is_binary {
31            rtc_time.second = Self::rtc_bcd_to_bin(rtc_time.second);
32            rtc_time.minute = Self::rtc_bcd_to_bin(rtc_time.minute);
33            rtc_time.hour = Self::rtc_bcd_to_bin(rtc_time.hour);
34            rtc_time.day = Self::rtc_bcd_to_bin(rtc_time.day);
35            rtc_time.month = Self::rtc_bcd_to_bin(rtc_time.month);
36            rtc_time.year = Self::rtc_bcd_to_bin(rtc_time.year);
37        }
38
39        if !is_24_hour {
40            let is_pm = (rtc_time.hour & 0x80) != 0;
41            rtc_time.hour = ((rtc_time.hour & !0x80) % 12) + 12 * is_pm as u8;
42        }
43
44        rtc_time
45    }
46
47    fn get_rtc_register(idx: u8) -> u8 {
48        unsafe {
49            Port::new(0x70).write(idx);
50            Port::new(0x71).read()
51        }
52    }
53
54    fn rtc_bcd_to_bin(bcd: u8) -> u8 {
55        let msb = bcd & 0x80;
56        let msb_masked = bcd & !0x80;
57        (((msb_masked / 16) * 10) + (msb_masked % 16)) | msb
58    }
59
60    pub fn to_datetime(&self) -> Result<OffsetDateTime, ComponentRange> {
61        let month = Month::try_from(self.month)?;
62        let date = Date::from_calendar_date(self.year as i32 + 2000, month, self.day)?;
63        let time = Time::from_hms(self.hour, self.minute, self.second)?;
64
65        Ok(PrimitiveDateTime::new(date, time).assume_utc())
66    }
67}