1#![no_std]
11use core::cmp::Ordering;
12use x86_64::instructions::port::Port;
13
14const CMOS_ADDRESS: u16 = 0x70;
16
17const CMOS_DATA: u16 = 0x71;
19
20#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
22pub struct Time {
23 pub second: u8,
24 pub minute: u8,
25 pub hour: u8,
26 pub day: u8,
27 pub month: u8,
28 pub year: u8,
29 pub century: u8,
30}
31
32impl PartialOrd for Time {
33 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
34 Some(self.cmp(other))
35 }
36}
37
38impl Ord for Time {
39 fn cmp(&self, other: &Self) -> Ordering {
40 self.century
41 .cmp(&other.century)
42 .then(self.year.cmp(&other.year))
43 .then(self.month.cmp(&other.month))
44 .then(self.day.cmp(&other.day))
45 .then(self.hour.cmp(&other.hour))
46 .then(self.minute.cmp(&other.minute))
47 .then(self.second.cmp(&other.second))
48 }
49}
50
51pub struct ReadRTC {
53 cmos_address: Port<u8>,
54 cmos_data: Port<u8>,
55 current_year: u8,
56 century_register: u8,
57}
58
59impl ReadRTC {
60 #[must_use]
62 pub const fn new(current_year: u8, century_register: u8) -> ReadRTC {
63 ReadRTC {
64 cmos_address: Port::new(CMOS_ADDRESS),
65 cmos_data: Port::new(CMOS_DATA),
66 current_year,
67 century_register,
68 }
69 }
70
71 fn get_update_in_progress_flag(&mut self) -> u8 {
73 unsafe {
74 self.cmos_address.write(0x0A);
75 self.cmos_data.read() & 0x80
76 }
77 }
78
79 fn get_rtc_register(&mut self, reg: u8) -> u8 {
81 unsafe {
82 self.cmos_address.write(reg);
83 self.cmos_data.read()
84 }
85 }
86
87 fn update_time(&mut self) -> Time {
89 while self.get_update_in_progress_flag() != 0 {}
91
92 Time {
93 second: self.get_rtc_register(0x00),
94 minute: self.get_rtc_register(0x02),
95 hour: self.get_rtc_register(0x04),
96 day: self.get_rtc_register(0x07),
97 month: self.get_rtc_register(0x08),
98 year: self.get_rtc_register(0x09),
99 century: if self.century_register == 0 {
100 0
101 } else {
102 self.get_rtc_register(self.century_register)
103 },
104 }
105 }
106
107 pub fn read(&mut self) -> Time {
109 let mut last_time: Time;
110 let mut time: Time = self.update_time();
111
112 loop {
113 last_time = time;
114 time = self.update_time();
115
116 if (last_time.second == time.second)
117 && (last_time.minute == time.minute)
118 && (last_time.hour == time.hour)
119 && (last_time.day == time.day)
120 && (last_time.month == time.month)
121 && (last_time.year == time.year)
122 && (last_time.century == time.century)
123 {
124 break;
125 }
126 }
127
128 let register_b = self.get_rtc_register(0x0B);
129
130 if register_b & 0x04 == 0 {
131 time.second = (time.second & 0x0F) + ((time.second / 16) * 10);
132 time.minute = (time.minute & 0x0F) + ((time.minute / 16) * 10);
133 time.hour =
134 ((time.hour & 0x0F) + (((time.hour & 0x70) / 16) * 10)) | (time.hour & 0x80);
135 time.day = (time.day & 0x0F) + ((time.day / 16) * 10);
136 time.month = (time.month & 0x0F) + ((time.month / 16) * 10);
137 time.year = (time.year & 0x0F) + ((time.year / 16) * 10);
138
139 if self.century_register != 0 {
140 time.century = (time.century & 0x0F) + ((time.century / 16) * 10);
141 }
142 }
143
144 if register_b & 0x02 == 0 && (time.hour & 0x80 != 0) {
146 time.hour = ((time.hour & 0x7F) + 12) % 24;
147 }
148
149 if self.century_register == 0 {
151 time.year += (self.current_year / 100) * 100;
152
153 if time.year < self.current_year {
154 time.year += 100;
155 };
156 } else {
157 time.year += time.century * 100;
158 }
159
160 time
161 }
162}