use crate::pac::{RCC, RTC};
use crate::time::{Hertz, Hz};
use core::convert::Infallible;
use core::marker::PhantomData;
#[cfg(feature = "py32f030")]
const LSE_HERTZ: Hertz = Hz(32_768);
const LSI_HERTZ: Hertz = Hz(32_768);
pub struct RtcClkHseDiv128;
#[cfg(feature = "py32f030")]
pub struct RtcClkLse;
pub struct RtcClkLsi;
pub enum RestoredOrNewRtc<CS> {
Restored(Rtc<CS>),
New(Rtc<CS>),
}
pub struct Rtc<CS = RtcClkLsi> {
regs: RTC,
_clock_source: PhantomData<CS>,
}
#[cfg(feature = "py32f030")]
impl Rtc<RtcClkLse> {
pub fn new(regs: RTC) -> Self {
let mut result = Rtc {
regs,
_clock_source: PhantomData,
};
Self::enable_rtc();
let prl = LSE_HERTZ.raw() - 1;
assert!(prl < 1 << 20);
result.perform_write(|s| {
s.regs.prlh.write(|w| unsafe { w.bits(prl >> 16) });
s.regs.prll.write(|w| unsafe { w.bits(prl as u16 as u32) });
});
result
}
pub fn restore_or_new(regs: RTC) -> RestoredOrNewRtc<RtcClkLse> {
if !Self::is_enabled() {
RestoredOrNewRtc::New(Rtc::new(regs))
} else {
RestoredOrNewRtc::Restored(Rtc {
regs,
_clock_source: PhantomData,
})
}
}
fn is_enabled() -> bool {
let rcc = unsafe { &*RCC::ptr() };
let bdcr = rcc.bdcr.read();
bdcr.rtcen().is_enabled() && bdcr.rtcsel().is_lse()
}
fn enable_rtc() {
let rcc = unsafe { &*RCC::ptr() };
rcc.bdcr.modify(|_, w| {
w.lseon().set_bit();
w.rtcen().set_bit();
w.rtcsel().lse()
})
}
}
impl Rtc<RtcClkLsi> {
pub fn new_lsi(regs: RTC) -> Self {
let mut result = Rtc {
regs,
_clock_source: PhantomData,
};
Self::enable_rtc();
let prl = LSI_HERTZ.raw() - 1;
assert!(prl < 1 << 20);
result.perform_write(|s| {
s.regs.prlh.write(|w| unsafe { w.bits(prl >> 16) });
s.regs.prll.write(|w| unsafe { w.bits(prl as u16 as u32) });
});
result
}
pub fn restore_or_new_lsi(regs: RTC) -> RestoredOrNewRtc<RtcClkLsi> {
if !Rtc::<RtcClkLsi>::is_enabled() {
RestoredOrNewRtc::New(Rtc::new_lsi(regs))
} else {
RestoredOrNewRtc::Restored(Rtc {
regs,
_clock_source: PhantomData,
})
}
}
fn is_enabled() -> bool {
let rcc = unsafe { &*RCC::ptr() };
rcc.bdcr.read().rtcen().bit() && rcc.bdcr.read().rtcsel().is_lsi()
}
fn enable_rtc() {
let rcc = unsafe { &*RCC::ptr() };
rcc.csr.modify(|_, w| {
w.lsion().set_bit()
});
rcc.bdcr.modify(|_, w| {
w.rtcen().set_bit();
w.rtcsel().lsi()
})
}
}
impl Rtc<RtcClkHseDiv128> {
pub fn new_hse(regs: RTC, hse: Hertz) -> Self {
let mut result = Rtc {
regs,
_clock_source: PhantomData,
};
Self::enable_rtc();
let prl = hse.raw() / 128 - 1;
assert!(prl < 1 << 20);
result.perform_write(|s| {
s.regs.prlh.write(|w| unsafe { w.bits(prl >> 16) });
s.regs.prll.write(|w| unsafe { w.bits(prl as u16 as u32) });
});
result
}
pub fn restore_or_new_hse(regs: RTC, hse: Hertz) -> RestoredOrNewRtc<RtcClkHseDiv128> {
if !Self::is_enabled() {
RestoredOrNewRtc::New(Rtc::new_hse(regs, hse))
} else {
RestoredOrNewRtc::Restored(Rtc {
regs,
_clock_source: PhantomData,
})
}
}
fn is_enabled() -> bool {
let rcc = unsafe { &*RCC::ptr() };
let bdcr = rcc.bdcr.read();
bdcr.rtcen().is_enabled() && bdcr.rtcsel().is_hse()
}
fn enable_rtc() {
let rcc = unsafe { &*RCC::ptr() };
if rcc.cr.read().hserdy().bit_is_clear() {
panic!("HSE oscillator not ready");
}
rcc.bdcr.modify(|_, w| {
w.rtcen().set_bit();
w.rtcsel().hse()
})
}
}
impl<CS> Rtc<CS> {
pub fn select_frequency(&mut self, frequency: Hertz) {
assert!(frequency <= LSI_HERTZ / 2);
let prescaler = LSI_HERTZ.raw() / frequency.raw() - 1;
self.perform_write(|s| {
s.regs.prlh.write(|w| unsafe { w.bits(prescaler >> 16) });
s.regs
.prll
.write(|w| unsafe { w.bits(prescaler as u16 as u32) });
});
}
pub fn set_time(&mut self, counter_value: u32) {
self.perform_write(|s| {
s.regs
.cnth
.write(|w| unsafe { w.bits(counter_value >> 16) });
s.regs
.cntl
.write(|w| unsafe { w.bits(counter_value as u16 as u32) });
});
}
pub fn set_alarm(&mut self, counter_value: u32) {
let alarm_value = counter_value - 1;
#[allow(unused_unsafe)]
self.perform_write(|s| {
s.regs
.alrh
.write(|w| unsafe { w.alrh().bits((alarm_value >> 16) as u16) });
s.regs
.alrl
.write(|w| unsafe { w.alrl().bits(alarm_value as u16) });
});
self.clear_alarm_flag();
}
pub fn listen_alarm(&mut self) {
self.perform_write(|s| {
s.regs.crh.modify(|_, w| w.alrie().set_bit());
})
}
pub fn unlisten_alarm(&mut self) {
self.perform_write(|s| {
s.regs.crh.modify(|_, w| w.alrie().clear_bit());
})
}
pub fn current_time(&self) -> u32 {
while !self.regs.crl.read().rsf().bit() {}
self.regs.cnth.read().bits() << 16 | self.regs.cntl.read().bits()
}
pub fn listen_seconds(&mut self) {
self.perform_write(|s| s.regs.crh.modify(|_, w| w.secie().set_bit()))
}
pub fn unlisten_seconds(&mut self) {
self.perform_write(|s| s.regs.crh.modify(|_, w| w.secie().clear_bit()))
}
pub fn clear_second_flag(&mut self) {
self.perform_write(|s| s.regs.crl.modify(|_, w| w.secf().clear_bit()))
}
pub fn clear_alarm_flag(&mut self) {
self.perform_write(|s| s.regs.crl.modify(|_, w| w.alrf().clear_bit()))
}
pub fn wait_alarm(&mut self) -> nb::Result<(), Infallible> {
if self.regs.crl.read().alrf().bit() {
self.regs.crl.modify(|_, w| w.alrf().clear_bit());
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
fn perform_write(&mut self, func: impl Fn(&mut Self)) {
while !self.regs.crl.read().rtoff().bit() {}
self.regs.crl.modify(|_, w| w.cnf().set_bit());
func(self);
self.regs.crl.modify(|_, w| w.cnf().clear_bit());
while !self.regs.crl.read().rtoff().bit() {}
}
}