1use crate::pac::{PWR, RTC};
9use crate::rcc::{Enable, APB1, BDCR};
10use core::convert::TryInto;
11use core::fmt;
12use rtcc::{DateTimeAccess, Datelike, Hours, NaiveDate, NaiveDateTime, NaiveTime, Rtcc, Timelike};
13
14#[derive(Copy, Clone, PartialEq, Eq, Debug)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[non_exhaustive]
18pub enum Error {
19 InvalidInputData,
21 InvalidRtcData,
23}
24
25pub struct Rtc {
27 rtc: RTC,
29}
30
31#[cfg(feature = "defmt")]
32impl defmt::Format for Rtc {
33 fn format(&self, f: defmt::Formatter) {
34 defmt::write!(f, "Rtc {{ rtc: RTC }}");
35 }
36}
37
38impl fmt::Debug for Rtc {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 f.debug_struct("Rtc").field("rtc", &"RTC").finish()
41 }
42}
43
44impl Rtc {
45 pub fn new(
52 rtc: RTC,
53 prediv_s: u16,
54 prediv_a: u8,
55 bypass: bool,
56 apb1: &mut APB1,
57 bdcr: &mut BDCR,
58 pwr: &mut PWR,
59 ) -> Self {
60 let mut result = Self { rtc };
61
62 enable_lse(bdcr, bypass);
63 unlock(apb1, pwr);
64 enable(bdcr);
65 result.set_24h_fmt();
66
67 result.rtc.prer.modify(|_, w| {
68 w.prediv_s().bits(prediv_s);
69 w.prediv_a().bits(prediv_a)
70 });
71
72 result
73 }
74
75 pub fn set_24h_fmt(&mut self) {
77 self.rtc.cr.modify(|_, w| w.fmt().set_bit());
78 }
79 pub fn set_12h_fmt(&mut self) {
81 self.rtc.cr.modify(|_, w| w.fmt().clear_bit());
82 }
83
84 #[must_use]
86 pub fn is_24h_fmt(&self) -> bool {
87 self.rtc.cr.read().fmt().bit()
88 }
89
90 pub unsafe fn peripheral(&mut self) -> &mut RTC {
100 &mut self.rtc
101 }
102
103 #[must_use]
105 pub fn free(self) -> RTC {
106 self.rtc
108 }
109
110 fn modify<F>(&mut self, mut closure: F)
114 where
115 F: FnMut(&mut RTC),
116 {
117 self.rtc.wpr.write(|w| w.key().bits(0xCA));
119 self.rtc.wpr.write(|w| w.key().bits(0x53));
120 let isr = self.rtc.isr.read();
122 if isr.initf().bit_is_clear() {
123 self.rtc.isr.modify(|_, w| w.init().set_bit());
124 while self.rtc.isr.read().initf().bit_is_clear() {}
125 }
126 closure(&mut self.rtc);
128 self.rtc.isr.modify(|_, w| w.init().clear_bit());
130 while !self.rtc.isr.read().initf().bit_is_clear() {}
132 }
133}
134
135impl DateTimeAccess for Rtc {
137 type Error = Error;
138
139 fn set_datetime(&mut self, date: &NaiveDateTime) -> Result<(), Self::Error> {
140 self.set_24h_fmt();
141 let (year_tens, year_units) =
142 bcd2_encode(u32::try_from(date.year() - 1970).map_err(|_| Error::InvalidInputData)?)?;
143 let (month_tens, month_units) = bcd2_encode(date.month())?;
144 let (day_tens, day_units) = bcd2_encode(date.day())?;
145
146 let (hour_tens, hour_units) = bcd2_encode(date.hour())?;
147 let (minutes_tens, minutes_units) = bcd2_encode(date.minute())?;
148 let (second_tens, second_units) = bcd2_encode(date.second())?;
149
150 self.rtc.dr.write(|w| {
151 w.dt().bits(day_tens);
152 w.du().bits(day_units);
153 w.mt().bit(month_tens > 0);
154 w.mu().bits(month_units);
155 w.yt().bits(year_tens);
156 w.yu().bits(year_units)
157 });
158
159 self.rtc.tr.write(|w| {
160 w.ht().bits(hour_tens);
161 w.hu().bits(hour_units);
162 w.mnt().bits(minutes_tens);
163 w.mnu().bits(minutes_units);
164 w.st().bits(second_tens);
165 w.su().bits(second_units);
166 w.pm().clear_bit()
167 });
168
169 Ok(())
170 }
171
172 fn datetime(&mut self) -> Result<NaiveDateTime, Self::Error> {
173 self.set_24h_fmt();
174
175 let day = self.day()?;
176 let month = self.month()?;
177 let year = self.year()?;
178
179 let seconds = self.seconds()?;
180 let minutes = self.minutes()?;
181 let hours = hours_to_u8(self.hours()?)?;
182
183 NaiveDate::from_ymd_opt(year.into(), month.into(), day.into())
184 .ok_or(Error::InvalidRtcData)?
185 .and_hms_opt(hours.into(), minutes.into(), seconds.into())
186 .ok_or(Error::InvalidRtcData)
187 }
188}
189
190impl Rtcc for Rtc {
191 fn set_time(&mut self, time: &NaiveTime) -> Result<(), Self::Error> {
195 self.set_24h_fmt();
196 let (hour_tens, hour_units) = bcd2_encode(time.hour())?;
197 let (minutes_tens, minutes_units) = bcd2_encode(time.minute())?;
198 let (seconds_tens, seconds_units) = bcd2_encode(time.second())?;
199 self.rtc.tr.write(|w| {
200 w.ht().bits(hour_tens);
201 w.hu().bits(hour_units);
202 w.mnt().bits(minutes_tens);
203 w.mnu().bits(minutes_units);
204 w.st().bits(seconds_tens);
205 w.su().bits(seconds_units);
206 w.pm().clear_bit()
207 });
208
209 Ok(())
210 }
211
212 fn set_seconds(&mut self, seconds: u8) -> Result<(), Self::Error> {
213 if seconds > 59 {
214 return Err(Error::InvalidInputData);
215 }
216 let (seconds_tens, seconds_units) = bcd2_encode(u32::from(seconds))?;
217 self.modify(|rtc| {
218 rtc.tr
219 .modify(|_, w| w.st().bits(seconds_tens).su().bits(seconds_units));
220 });
221
222 Ok(())
223 }
224
225 fn set_minutes(&mut self, minutes: u8) -> Result<(), Self::Error> {
226 if minutes > 59 {
227 return Err(Error::InvalidInputData);
228 }
229 let (minutes_tens, minutes_units) = bcd2_encode(u32::from(minutes))?;
230 self.modify(|rtc| {
231 rtc.tr
232 .modify(|_, w| w.mnt().bits(minutes_tens).mnu().bits(minutes_units));
233 });
234
235 Ok(())
236 }
237
238 fn set_hours(&mut self, hours: Hours) -> Result<(), Self::Error> {
239 let (hour_tens, hour_units) = hours_to_register(hours)?;
240 match hours {
241 Hours::H24(_) => self.set_24h_fmt(),
242 Hours::AM(_) | Hours::PM(_) => self.set_12h_fmt(),
243 }
244
245 self.rtc
246 .tr
247 .modify(|_, w| w.ht().bits(hour_tens).hu().bits(hour_units));
248
249 Ok(())
250 }
251
252 fn set_weekday(&mut self, weekday: u8) -> Result<(), Self::Error> {
253 if !(1..=7).contains(&weekday) {
254 return Err(Error::InvalidInputData);
255 }
256 self.modify(|rtc| rtc.dr.modify(|_, w| unsafe { w.wdu().bits(weekday) }));
258
259 Ok(())
260 }
261
262 fn set_day(&mut self, day: u8) -> Result<(), Self::Error> {
263 if !(1..=31).contains(&day) {
264 return Err(Error::InvalidInputData);
265 }
266 let (day_tens, day_units) = bcd2_encode(u32::from(day))?;
267 self.modify(|rtc| {
268 rtc.dr
269 .modify(|_, w| w.dt().bits(day_tens).du().bits(day_units));
270 });
271
272 Ok(())
273 }
274
275 fn set_month(&mut self, month: u8) -> Result<(), Self::Error> {
276 if !(1..=12).contains(&month) {
277 return Err(Error::InvalidInputData);
278 }
279 let (month_tens, month_units) = bcd2_encode(u32::from(month))?;
280 self.modify(|rtc| {
281 rtc.dr
282 .modify(|_, w| w.mt().bit(month_tens > 0).mu().bits(month_units));
283 });
284
285 Ok(())
286 }
287
288 fn set_year(&mut self, year: u16) -> Result<(), Self::Error> {
289 if !(1970..=2038).contains(&year) {
290 return Err(Error::InvalidInputData);
291 }
292 let (year_tens, yu) = bcd2_encode(u32::from(year))?;
293 self.modify(|rtc| rtc.dr.modify(|_, w| w.yt().bits(year_tens).yu().bits(yu)));
294
295 Ok(())
296 }
297
298 fn set_date(&mut self, date: &NaiveDate) -> Result<(), Self::Error> {
301 let (year_tens, yu) =
302 bcd2_encode(u32::try_from(date.year() - 1970).map_err(|_| Error::InvalidInputData)?)?;
303 let (month_tens, month_units) = bcd2_encode(date.month())?;
304 let (day_tens, day_units) = bcd2_encode(date.day())?;
305
306 self.rtc.dr.write(|w| {
307 w.dt().bits(day_tens);
308 w.du().bits(day_units);
309 w.mt().bit(month_tens > 0);
310 w.mu().bits(month_units);
311 w.yt().bits(year_tens);
312 w.yu().bits(yu)
313 });
314
315 Ok(())
316 }
317
318 fn seconds(&mut self) -> Result<u8, Self::Error> {
319 let tr = self.rtc.tr.read();
320 let seconds = bcd2_decode(tr.st().bits(), tr.su().bits());
321 u8::try_from(seconds).map_err(|_| Error::InvalidRtcData)
322 }
323
324 fn minutes(&mut self) -> Result<u8, Self::Error> {
325 let tr = self.rtc.tr.read();
326 let minutes = bcd2_decode(tr.mnt().bits(), tr.mnu().bits());
327 u8::try_from(minutes).map_err(|_| Error::InvalidRtcData)
328 }
329
330 fn hours(&mut self) -> Result<Hours, Self::Error> {
331 let tr = self.rtc.tr.read();
332 let hours = bcd2_decode(tr.ht().bits(), tr.hu().bits());
333 let hours = u8::try_from(hours).map_err(|_| Error::InvalidRtcData)?;
334 if self.is_24h_fmt() {
335 return Ok(Hours::H24(hours));
336 }
337 if !tr.pm().bit() {
338 return Ok(Hours::AM(hours));
339 }
340 Ok(Hours::PM(hours))
341 }
342
343 fn time(&mut self) -> Result<NaiveTime, Self::Error> {
344 self.set_24h_fmt();
345 let seconds = self.seconds()?;
346 let minutes = self.minutes()?;
347 let hours = hours_to_u8(self.hours()?)?;
348
349 NaiveTime::from_hms_opt(hours.into(), minutes.into(), seconds.into())
350 .ok_or(Error::InvalidRtcData)
351 }
352
353 fn weekday(&mut self) -> Result<u8, Self::Error> {
354 let dr = self.rtc.dr.read();
355 let weekday = bcd2_decode(dr.wdu().bits(), 0x00);
356 u8::try_from(weekday).map_err(|_| Error::InvalidRtcData)
357 }
358
359 fn day(&mut self) -> Result<u8, Self::Error> {
360 let dr = self.rtc.dr.read();
361 let day = bcd2_decode(dr.dt().bits(), dr.du().bits());
362 u8::try_from(day).map_err(|_| Error::InvalidRtcData)
363 }
364
365 fn month(&mut self) -> Result<u8, Self::Error> {
366 let dr = self.rtc.dr.read();
367 let month_tens = u8::from(dr.mt().bit());
368 let month = bcd2_decode(month_tens, dr.mu().bits());
369 u8::try_from(month).map_err(|_| Error::InvalidRtcData)
370 }
371
372 fn year(&mut self) -> Result<u16, Self::Error> {
373 let dr = self.rtc.dr.read();
374 let year = bcd2_decode(dr.yt().bits(), dr.yu().bits());
375 u16::try_from(year).map_err(|_| Error::InvalidRtcData)
376 }
377
378 fn date(&mut self) -> Result<NaiveDate, Self::Error> {
379 let day = self.day()?;
380 let month = self.month()?;
381 let year = self.year()?;
382
383 NaiveDate::from_ymd_opt(year.into(), month.into(), day.into()).ok_or(Error::InvalidRtcData)
384 }
385}
386
387fn bcd2_encode(word: u32) -> Result<(u8, u8), Error> {
394 let l = match (word / 10).try_into() {
395 Ok(v) => v,
396 Err(_) => {
397 return Err(Error::InvalidRtcData);
398 }
399 };
400 let r = match (word % 10).try_into() {
401 Ok(v) => v,
402 Err(_) => {
403 return Err(Error::InvalidRtcData);
404 }
405 };
406
407 Ok((l, r))
408}
409
410fn bcd2_decode(fst: u8, snd: u8) -> u32 {
411 u32::from(fst) * 10 + u32::from(snd)
412}
413
414fn hours_to_register(hours: Hours) -> Result<(u8, u8), Error> {
415 match hours {
416 Hours::H24(h) => Ok(bcd2_encode(u32::from(h)))?,
417 Hours::AM(h) => Ok(bcd2_encode(u32::from(h - 1)))?,
418 Hours::PM(h) => Ok(bcd2_encode(u32::from(h + 11)))?,
419 }
420}
421
422fn hours_to_u8(hours: Hours) -> Result<u8, Error> {
423 if let Hours::H24(h) = hours {
424 Ok(h)
425 } else {
426 Err(Error::InvalidInputData)
427 }
428}
429
430fn enable_lse(bdcr: &mut BDCR, bypass: bool) {
433 bdcr.bdcr()
434 .modify(|_, w| w.lseon().set_bit().lsebyp().bit(bypass));
435 while bdcr.bdcr().read().lserdy().bit_is_clear() {}
436}
437
438fn unlock(apb1: &mut APB1, pwr: &mut PWR) {
439 PWR::enable(apb1);
441 pwr.cr.modify(|_, w| {
442 w
443 .dbp()
445 .set_bit()
446 });
447
448 while pwr.cr.read().dbp().bit_is_clear() {}
449}
450
451fn enable(bdcr: &mut BDCR) {
452 bdcr.bdcr().modify(|_, w| w.bdrst().enabled());
453 bdcr.bdcr().modify(|_, w| {
454 w.rtcsel().lse();
455 w.rtcen().enabled();
456 w.bdrst().disabled()
457 });
458}