1use crate::pac::rtc::{dr, tr};
6use crate::pac::{PWR, RCC, RTC};
7use crate::rcc::{Clocks, APB1};
8use core::convert::TryInto;
9use time::{Date, PrimitiveDateTime, Time};
10
11#[derive(Debug)]
13pub enum Error {
14 InvalidInputData,
15}
16
17pub const LSE_BITS: u8 = 0b01;
18
19#[derive(Copy, Clone, PartialEq)]
20pub enum RtcClock {
21 Lse,
26 Lsi,
32 Hse { divider: u8 },
38}
39
40pub struct Rtc {
41 pub regs: RTC,
42}
43
44impl Rtc {
45 pub fn new(
62 regs: RTC,
63 prediv_s: u16,
64 prediv_a: u8,
65 clock_source: RtcClock,
66 clocks: Clocks,
67 apb1: &mut APB1,
68 pwr: &mut PWR,
69 ) -> Option<Self> {
70 let mut result = Self { regs };
71 let rcc = unsafe { &(*RCC::ptr()) };
72
73 unlock(apb1, pwr);
86
87 match clock_source {
88 RtcClock::Lse => {
89 clocks.lse()?;
91 rcc.bdcr.modify(|_, w| w.bdrst().enabled());
93 rcc.bdcr.modify(|_, w| w.bdrst().disabled());
94 rcc.bdcr.modify(|_, w| w.rtcsel().lse());
96 }
97 RtcClock::Lsi => {
98 clocks.lsi()?;
100 rcc.bdcr.modify(|_, w| w.bdrst().enabled());
102 rcc.bdcr.modify(|_, w| w.bdrst().disabled());
103 rcc.bdcr.modify(|_, w| w.rtcsel().lsi());
105 }
106 RtcClock::Hse { divider } => {
107 clocks.hse()?;
109 rcc.cfgr.modify(|_, w| w.rtcpre().bits(divider));
111 rcc.bdcr.modify(|_, w| w.bdrst().enabled());
113 rcc.bdcr.modify(|_, w| w.bdrst().disabled());
114 rcc.bdcr.modify(|_, w| w.rtcsel().hse());
116 }
117 }
118 rcc.bdcr.modify(|_, w| w.rtcen().enabled());
120
121 result.modify(|regs| {
122 regs.cr.modify(|_, w| w.fmt().clear_bit());
124 regs.prer.modify(|_, w| {
126 w.prediv_s().bits(prediv_s);
127 w.prediv_a().bits(prediv_a)
128 })
129 });
130
131 Some(result)
132 }
133
134 fn modify<F>(&mut self, mut closure: F)
138 where
139 F: FnMut(&mut RTC),
140 {
141 self.regs.wpr.write(|w| unsafe { w.bits(0xCA) });
143 self.regs.wpr.write(|w| unsafe { w.bits(0x53) });
144 let isr = self.regs.isr.read();
146 if isr.initf().bit_is_clear() {
147 self.regs.isr.modify(|_, w| w.init().set_bit());
148 while self.regs.isr.read().initf().bit_is_clear() {}
149 }
150 closure(&mut self.regs);
152 self.regs.isr.modify(|_, w| w.init().clear_bit());
154 while !self.regs.isr.read().initf().bit_is_clear() {}
156
157 self.regs.wpr.write(|w| unsafe { w.bits(0xFF) });
159 }
160
161 pub fn set_time(&mut self, time: &Time) -> Result<(), Error> {
163 let (ht, hu) = bcd2_encode(time.hour().into())?;
164 let (mnt, mnu) = bcd2_encode(time.minute().into())?;
165 let (st, su) = bcd2_encode(time.second().into())?;
166 self.modify(|regs| {
167 regs.tr.write(|w| {
168 w.ht().bits(ht);
169 w.hu().bits(hu);
170 w.mnt().bits(mnt);
171 w.mnu().bits(mnu);
172 w.st().bits(st);
173 w.su().bits(su);
174 w.pm().clear_bit()
175 })
176 });
177
178 Ok(())
179 }
180
181 pub fn set_seconds(&mut self, seconds: u8) -> Result<(), Error> {
183 if seconds > 59 {
184 return Err(Error::InvalidInputData);
185 }
186 let (st, su) = bcd2_encode(seconds.into())?;
187 self.modify(|regs| regs.tr.modify(|_, w| w.st().bits(st).su().bits(su)));
188
189 Ok(())
190 }
191
192 pub fn set_minutes(&mut self, minutes: u8) -> Result<(), Error> {
194 if minutes > 59 {
195 return Err(Error::InvalidInputData);
196 }
197 let (mnt, mnu) = bcd2_encode(minutes.into())?;
198 self.modify(|regs| regs.tr.modify(|_, w| w.mnt().bits(mnt).mnu().bits(mnu)));
199
200 Ok(())
201 }
202
203 pub fn set_hours(&mut self, hours: u8) -> Result<(), Error> {
205 if hours > 23 {
206 return Err(Error::InvalidInputData);
207 }
208 let (ht, hu) = bcd2_encode(hours.into())?;
209
210 self.modify(|regs| regs.tr.modify(|_, w| w.ht().bits(ht).hu().bits(hu)));
211
212 Ok(())
213 }
214
215 pub fn set_weekday(&mut self, weekday: u8) -> Result<(), Error> {
217 if !(1..=7).contains(&weekday) {
218 return Err(Error::InvalidInputData);
219 }
220 self.modify(|regs| regs.dr.modify(|_, w| unsafe { w.wdu().bits(weekday) }));
221
222 Ok(())
223 }
224
225 pub fn set_day(&mut self, day: u8) -> Result<(), Error> {
227 if !(1..=31).contains(&day) {
228 return Err(Error::InvalidInputData);
229 }
230 let (dt, du) = bcd2_encode(day as u32)?;
231 self.modify(|regs| regs.dr.modify(|_, w| w.dt().bits(dt).du().bits(du)));
232
233 Ok(())
234 }
235
236 pub fn set_month(&mut self, month: u8) -> Result<(), Error> {
238 if !(1..=12).contains(&month) {
239 return Err(Error::InvalidInputData);
240 }
241 let (mt, mu) = bcd2_encode(month as u32)?;
242 self.modify(|regs| regs.dr.modify(|_, w| w.mt().bit(mt > 0).mu().bits(mu)));
243
244 Ok(())
245 }
246
247 pub fn set_year(&mut self, year: u16) -> Result<(), Error> {
252 if !(1970..=2069).contains(&year) {
253 return Err(Error::InvalidInputData);
254 }
255 let (yt, yu) = bcd2_encode(year as u32 - 1970)?;
256 self.modify(|regs| regs.dr.modify(|_, w| w.yt().bits(yt).yu().bits(yu)));
257
258 Ok(())
259 }
260
261 pub fn set_date(&mut self, date: &Date) -> Result<(), Error> {
266 if !(1970..=2069).contains(&date.year()) {
267 return Err(Error::InvalidInputData);
268 }
269
270 let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
271 let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
272 let (dt, du) = bcd2_encode(date.day().into())?;
273
274 self.modify(|regs| {
275 regs.dr.write(|w| {
276 w.dt().bits(dt);
277 w.du().bits(du);
278 w.mt().bit(mt > 0);
279 w.mu().bits(mu);
280 w.yt().bits(yt);
281 w.yu().bits(yu)
282 })
283 });
284
285 Ok(())
286 }
287
288 pub fn set_datetime(&mut self, date: &PrimitiveDateTime) -> Result<(), Error> {
293 if !(1970..=2069).contains(&date.year()) {
294 return Err(Error::InvalidInputData);
295 }
296
297 let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
298 let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
299 let (dt, du) = bcd2_encode(date.day().into())?;
300
301 let (ht, hu) = bcd2_encode(date.hour().into())?;
302 let (mnt, mnu) = bcd2_encode(date.minute().into())?;
303 let (st, su) = bcd2_encode(date.second().into())?;
304
305 self.modify(|regs| {
306 regs.dr.write(|w| {
307 w.dt().bits(dt);
308 w.du().bits(du);
309 w.mt().bit(mt > 0);
310 w.mu().bits(mu);
311 w.yt().bits(yt);
312 w.yu().bits(yu)
313 });
314 regs.tr.write(|w| {
315 w.ht().bits(ht);
316 w.hu().bits(hu);
317 w.mnt().bits(mnt);
318 w.mnu().bits(mnu);
319 w.st().bits(st);
320 w.su().bits(su);
321 w.pm().clear_bit()
322 })
323 });
324
325 Ok(())
326 }
327
328 pub fn get_datetime(&mut self) -> PrimitiveDateTime {
329 while self.regs.isr.read().rsf().bit_is_clear() {}
331
332 let tr = self.regs.tr.read();
335 let dr = self.regs.dr.read();
336 self.regs.isr.modify(|_, w| w.rsf().clear_bit());
339
340 let seconds = decode_seconds(&tr);
341 let minutes = decode_minutes(&tr);
342 let hours = decode_hours(&tr);
343 let day = decode_day(&dr);
344 let month = decode_month(&dr);
345 let year = decode_year(&dr);
346
347 PrimitiveDateTime::new(
348 Date::from_calendar_date(year.into(), month.try_into().unwrap(), day).unwrap(),
349 Time::from_hms(hours, minutes, seconds).unwrap(),
350 )
351 }
352}
353
354fn bcd2_encode(word: u32) -> Result<(u8, u8), Error> {
361 let l = match (word / 10).try_into() {
362 Ok(v) => v,
363 Err(_) => {
364 return Err(Error::InvalidInputData);
365 }
366 };
367 let r = match (word % 10).try_into() {
368 Ok(v) => v,
369 Err(_) => {
370 return Err(Error::InvalidInputData);
371 }
372 };
373
374 Ok((l, r))
375}
376
377fn bcd2_decode(fst: u8, snd: u8) -> u32 {
378 (fst * 10 + snd).into()
379}
380
381fn unlock(apb1: &mut APB1, pwr: &mut PWR) {
382 apb1.enr().modify(|_, w| {
383 w
384 .pwren()
386 .set_bit()
387 });
388 pwr.cr1.modify(|_, w| {
389 w
390 .dbp()
392 .set_bit()
393 });
394}
395
396#[inline(always)]
397fn decode_seconds(tr: &tr::R) -> u8 {
398 bcd2_decode(tr.st().bits(), tr.su().bits()) as u8
399}
400
401#[inline(always)]
402fn decode_minutes(tr: &tr::R) -> u8 {
403 bcd2_decode(tr.mnt().bits(), tr.mnu().bits()) as u8
404}
405
406#[inline(always)]
407fn decode_hours(tr: &tr::R) -> u8 {
408 bcd2_decode(tr.ht().bits(), tr.hu().bits()) as u8
409}
410
411#[inline(always)]
412fn decode_day(dr: &dr::R) -> u8 {
413 bcd2_decode(dr.dt().bits(), dr.du().bits()) as u8
414}
415
416#[inline(always)]
417fn decode_month(dr: &dr::R) -> u8 {
418 let mt: u8 = if dr.mt().bit() { 1 } else { 0 };
419 bcd2_decode(mt, dr.mu().bits()) as u8
420}
421
422#[inline(always)]
423fn decode_year(dr: &dr::R) -> u16 {
424 let year = bcd2_decode(dr.yt().bits(), dr.yu().bits()) + 1970; year as u16
426}