good_os_framework/drivers/
rtc.rs1use 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}