use crate::bb;
use crate::pac::rtc::{dr, tr};
use crate::pac::{rcc::RegisterBlock, PWR, RCC, RTC};
use crate::rcc::Enable;
use core::convert::TryInto;
use core::fmt;
use core::marker::PhantomData;
use time::{Date, PrimitiveDateTime, Time};
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum Error {
InvalidInputData,
}
pub struct Lse;
pub struct Lsi;
pub struct Rtc<CS = Lse> {
pub regs: RTC,
_clock_source: PhantomData<CS>,
}
#[cfg(feature = "defmt")]
impl defmt::Format for Rtc {
fn format(&self, f: defmt::Formatter) {
defmt::write!(f, "Rtc");
}
}
impl fmt::Debug for Rtc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Rtc")
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum LSEClockMode {
Oscillator,
Bypass,
}
impl Rtc<Lse> {
pub fn new(regs: RTC, pwr: &mut PWR) -> Self {
Self::with_config(regs, pwr, LSEClockMode::Oscillator, 255, 127)
}
pub fn with_config(
regs: RTC,
pwr: &mut PWR,
mode: LSEClockMode,
prediv_s: u16,
prediv_a: u8,
) -> Self {
let mut result = Self {
regs,
_clock_source: PhantomData,
};
unsafe {
let rcc = &(*RCC::ptr());
result.unlock(rcc, pwr);
if rcc.bdcr.read().lserdy().bit_is_clear() {
result.enable_lse(rcc, mode);
}
rcc.bdcr.modify(|_, w| w.rtcsel().lse());
result.enable(rcc);
}
result.modify(|regs| {
regs.cr.modify(|_, w| w.fmt().clear_bit());
regs.prer.modify(|_, w| {
w.prediv_s().bits(prediv_s);
w.prediv_a().bits(prediv_a)
})
});
result
}
fn enable_lse(&mut self, rcc: &RegisterBlock, mode: LSEClockMode) {
unsafe {
self.backup_reset(rcc);
bb::set(&rcc.bdcr, 0);
match mode {
LSEClockMode::Bypass => bb::set(&rcc.bdcr, 2),
LSEClockMode::Oscillator => bb::clear(&rcc.bdcr, 2),
}
while rcc.bdcr.read().lserdy().bit_is_clear() {}
}
}
}
impl Rtc<Lsi> {
pub fn new_lsi(regs: RTC, pwr: &mut PWR) -> Self {
Self::lsi_with_config(regs, pwr, 249, 127)
}
pub fn lsi_with_config(regs: RTC, pwr: &mut PWR, prediv_s: u16, prediv_a: u8) -> Self {
let mut result = Self {
regs,
_clock_source: PhantomData,
};
unsafe {
let rcc = &(*RCC::ptr());
result.unlock(rcc, pwr);
if rcc.csr.read().lsirdy().bit_is_clear() {
result.enable_lsi(rcc);
}
rcc.bdcr.modify(|_, w| w.rtcsel().lsi());
result.enable(rcc);
}
result.modify(|regs| {
regs.cr.modify(|_, w| w.fmt().clear_bit());
regs.prer.modify(|_, w| {
w.prediv_s().bits(prediv_s);
w.prediv_a().bits(prediv_a)
})
});
result
}
fn enable_lsi(&mut self, rcc: &RegisterBlock) {
self.backup_reset(rcc);
rcc.csr.modify(|_, w| w.lsion().on());
while rcc.csr.read().lsirdy().is_not_ready() {}
}
}
impl<CS> Rtc<CS> {
fn unlock(&mut self, rcc: &RegisterBlock, pwr: &mut PWR) {
PWR::enable(rcc);
pwr.cr.modify(|_, w| {
w
.dbp()
.set_bit()
});
}
fn backup_reset(&mut self, rcc: &RegisterBlock) {
unsafe {
bb::set(&rcc.bdcr, 16);
bb::clear(&rcc.bdcr, 16);
}
}
fn enable(&mut self, rcc: &RegisterBlock) {
unsafe {
bb::set(&rcc.bdcr, 15);
}
}
pub fn set_prescalers(&mut self, prediv_s: u16, prediv_a: u8) {
self.modify(|regs| {
regs.prer.modify(|_, w| {
w.prediv_s().bits(prediv_s);
w.prediv_a().bits(prediv_a)
})
});
}
fn modify<F>(&mut self, mut closure: F)
where
F: FnMut(&mut RTC),
{
self.regs.wpr.write(|w| unsafe { w.bits(0xCA) });
self.regs.wpr.write(|w| unsafe { w.bits(0x53) });
let isr = self.regs.isr.read();
if isr.initf().bit_is_clear() {
self.regs.isr.modify(|_, w| w.init().set_bit());
while self.regs.isr.read().initf().bit_is_clear() {}
}
closure(&mut self.regs);
self.regs.isr.modify(|_, w| w.init().clear_bit());
while !self.regs.isr.read().initf().bit_is_clear() {}
self.regs.wpr.write(|w| unsafe { w.bits(0xFF) });
}
pub fn set_time(&mut self, time: &Time) -> Result<(), Error> {
let (ht, hu) = bcd2_encode(time.hour().into())?;
let (mnt, mnu) = bcd2_encode(time.minute().into())?;
let (st, su) = bcd2_encode(time.second().into())?;
self.modify(|regs| {
regs.tr.write(|w| {
w.ht().bits(ht);
w.hu().bits(hu);
w.mnt().bits(mnt);
w.mnu().bits(mnu);
w.st().bits(st);
w.su().bits(su);
w.pm().clear_bit()
})
});
Ok(())
}
pub fn set_seconds(&mut self, seconds: u8) -> Result<(), Error> {
if seconds > 59 {
return Err(Error::InvalidInputData);
}
let (st, su) = bcd2_encode(seconds.into())?;
self.modify(|regs| regs.tr.modify(|_, w| w.st().bits(st).su().bits(su)));
Ok(())
}
pub fn set_minutes(&mut self, minutes: u8) -> Result<(), Error> {
if minutes > 59 {
return Err(Error::InvalidInputData);
}
let (mnt, mnu) = bcd2_encode(minutes.into())?;
self.modify(|regs| regs.tr.modify(|_, w| w.mnt().bits(mnt).mnu().bits(mnu)));
Ok(())
}
pub fn set_hours(&mut self, hours: u8) -> Result<(), Error> {
if hours > 23 {
return Err(Error::InvalidInputData);
}
let (ht, hu) = bcd2_encode(hours.into())?;
self.modify(|regs| regs.tr.modify(|_, w| w.ht().bits(ht).hu().bits(hu)));
Ok(())
}
pub fn set_weekday(&mut self, weekday: u8) -> Result<(), Error> {
if !(1..=7).contains(&weekday) {
return Err(Error::InvalidInputData);
}
self.modify(|regs| regs.dr.modify(|_, w| unsafe { w.wdu().bits(weekday) }));
Ok(())
}
pub fn set_day(&mut self, day: u8) -> Result<(), Error> {
if !(1..=31).contains(&day) {
return Err(Error::InvalidInputData);
}
let (dt, du) = bcd2_encode(day as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.dt().bits(dt).du().bits(du)));
Ok(())
}
pub fn set_month(&mut self, month: u8) -> Result<(), Error> {
if !(1..=12).contains(&month) {
return Err(Error::InvalidInputData);
}
let (mt, mu) = bcd2_encode(month as u32)?;
self.modify(|regs| regs.dr.modify(|_, w| w.mt().bit(mt > 0).mu().bits(mu)));
Ok(())
}
pub fn set_year(&mut self, year: u16) -> Result<(), Error> {
if !(1970..=2069).contains(&year) {
return Err(Error::InvalidInputData);
}
let (yt, yu) = bcd2_encode(year as u32 - 1970)?;
self.modify(|regs| regs.dr.modify(|_, w| w.yt().bits(yt).yu().bits(yu)));
Ok(())
}
pub fn set_date(&mut self, date: &Date) -> Result<(), Error> {
if !(1970..=2069).contains(&date.year()) {
return Err(Error::InvalidInputData);
}
let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
let (dt, du) = bcd2_encode(date.day().into())?;
self.modify(|regs| {
regs.dr.write(|w| {
w.dt().bits(dt);
w.du().bits(du);
w.mt().bit(mt > 0);
w.mu().bits(mu);
w.yt().bits(yt);
w.yu().bits(yu)
})
});
Ok(())
}
pub fn set_datetime(&mut self, date: &PrimitiveDateTime) -> Result<(), Error> {
if !(1970..=2069).contains(&date.year()) {
return Err(Error::InvalidInputData);
}
let (yt, yu) = bcd2_encode((date.year() - 1970) as u32)?;
let (mt, mu) = bcd2_encode(u8::from(date.month()).into())?;
let (dt, du) = bcd2_encode(date.day().into())?;
let (ht, hu) = bcd2_encode(date.hour().into())?;
let (mnt, mnu) = bcd2_encode(date.minute().into())?;
let (st, su) = bcd2_encode(date.second().into())?;
self.modify(|regs| {
regs.dr.write(|w| {
w.dt().bits(dt);
w.du().bits(du);
w.mt().bit(mt > 0);
w.mu().bits(mu);
w.yt().bits(yt);
w.yu().bits(yu)
});
regs.tr.write(|w| {
w.ht().bits(ht);
w.hu().bits(hu);
w.mnt().bits(mnt);
w.mnu().bits(mnu);
w.st().bits(st);
w.su().bits(su);
w.pm().clear_bit()
})
});
Ok(())
}
pub fn get_datetime(&mut self) -> PrimitiveDateTime {
while self.regs.isr.read().rsf().bit_is_clear() {}
let tr = self.regs.tr.read();
let dr = self.regs.dr.read();
self.regs.isr.modify(|_, w| w.rsf().clear_bit());
let seconds = decode_seconds(&tr);
let minutes = decode_minutes(&tr);
let hours = decode_hours(&tr);
let day = decode_day(&dr);
let month = decode_month(&dr);
let year = decode_year(&dr);
PrimitiveDateTime::new(
Date::from_calendar_date(year.into(), month.try_into().unwrap(), day).unwrap(),
Time::from_hms(hours, minutes, seconds).unwrap(),
)
}
}
fn bcd2_encode(word: u32) -> Result<(u8, u8), Error> {
let l = match (word / 10).try_into() {
Ok(v) => v,
Err(_) => {
return Err(Error::InvalidInputData);
}
};
let r = match (word % 10).try_into() {
Ok(v) => v,
Err(_) => {
return Err(Error::InvalidInputData);
}
};
Ok((l, r))
}
fn bcd2_decode(fst: u8, snd: u8) -> u32 {
(fst * 10 + snd).into()
}
#[inline(always)]
fn decode_seconds(tr: &tr::R) -> u8 {
bcd2_decode(tr.st().bits(), tr.su().bits()) as u8
}
#[inline(always)]
fn decode_minutes(tr: &tr::R) -> u8 {
bcd2_decode(tr.mnt().bits(), tr.mnu().bits()) as u8
}
#[inline(always)]
fn decode_hours(tr: &tr::R) -> u8 {
bcd2_decode(tr.ht().bits(), tr.hu().bits()) as u8
}
#[inline(always)]
fn decode_day(dr: &dr::R) -> u8 {
bcd2_decode(dr.dt().bits(), dr.du().bits()) as u8
}
#[inline(always)]
fn decode_month(dr: &dr::R) -> u8 {
let mt = u8::from(dr.mt().bit());
bcd2_decode(mt, dr.mu().bits()) as u8
}
#[inline(always)]
fn decode_year(dr: &dr::R) -> u16 {
let year = bcd2_decode(dr.yt().bits(), dr.yu().bits()) + 1970; year as u16
}