use crate::clocks::Clock;
use crate::clocks::RtcClock;
use crate::pac::{RESETS, RTC};
mod filter;
pub use self::filter::DateTimeFilter;
mod datetime;
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
pub struct RealTimeClock {
rtc: RTC,
clock: RtcClock,
}
impl RealTimeClock {
#[allow(unknown_lints)]
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn new(
rtc: RTC,
clock: RtcClock,
resets: &mut RESETS,
initial_date: DateTime,
) -> Result<Self, RtcError> {
resets.reset().modify(|_, w| w.rtc().set_bit());
resets.reset().modify(|_, w| w.rtc().clear_bit());
while resets.reset_done().read().rtc().bit_is_clear() {
core::hint::spin_loop();
}
let freq = clock.freq().to_Hz() - 1;
rtc.clkdiv_m1().write(|w| unsafe { w.bits(freq) });
let mut result = Self { rtc, clock };
result.set_leap_year_check(true); result.set_datetime(initial_date)?;
Ok(result)
}
pub fn set_leap_year_check(&mut self, leap_year_check_enabled: bool) {
self.rtc
.ctrl()
.modify(|_, w| w.force_notleapyear().bit(!leap_year_check_enabled));
}
pub fn is_running(&self) -> bool {
self.rtc.ctrl().read().rtc_active().bit_is_set()
}
pub fn set_datetime(&mut self, t: DateTime) -> Result<(), RtcError> {
self::datetime::validate_datetime(&t).map_err(RtcError::InvalidDateTime)?;
self.rtc.ctrl().modify(|_, w| w.rtc_enable().clear_bit());
while self.rtc.ctrl().read().rtc_active().bit_is_set() {
core::hint::spin_loop();
}
self.rtc.setup_0().write(|w| {
self::datetime::write_setup_0(&t, w);
w
});
self.rtc.setup_1().write(|w| {
self::datetime::write_setup_1(&t, w);
w
});
self.rtc.ctrl().write(|w| w.load().set_bit());
self.rtc.ctrl().write(|w| w.rtc_enable().set_bit());
while self.rtc.ctrl().read().rtc_active().bit_is_clear() {
core::hint::spin_loop();
}
Ok(())
}
pub fn now(&self) -> Result<DateTime, RtcError> {
if !self.is_running() {
return Err(RtcError::NotRunning);
}
let rtc_0 = self.rtc.rtc_0().read();
let rtc_1 = self.rtc.rtc_1().read();
self::datetime::datetime_from_registers(rtc_0, rtc_1).map_err(RtcError::InvalidDateTime)
}
fn set_match_ena(&mut self, ena: bool) {
self.rtc.irq_setup_0().modify(|_, w| w.match_ena().bit(ena));
while self.rtc.irq_setup_0().read().match_active().bit() != ena {
core::hint::spin_loop();
}
}
pub fn disable_alarm(&mut self) {
self.set_match_ena(false)
}
pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
self.set_match_ena(false);
self.rtc.irq_setup_0().write(|w| {
filter.write_setup_0(w);
w
});
self.rtc.irq_setup_1().write(|w| {
filter.write_setup_1(w);
w
});
self.set_match_ena(true);
}
pub fn enable_interrupt(&mut self) {
self.rtc.inte().modify(|_, w| w.rtc().set_bit());
}
pub fn disable_interrupt(&mut self) {
self.rtc.inte().modify(|_, w| w.rtc().clear_bit());
}
pub fn clear_interrupt(&mut self) {
self.set_match_ena(false);
self.set_match_ena(true);
}
pub fn free(self, resets: &mut RESETS) -> (RTC, RtcClock) {
resets.reset().modify(|_, w| w.rtc().set_bit());
(self.rtc, self.clock)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum RtcError {
InvalidDateTime(DateTimeError),
NotRunning,
}