use crate::clocks::Clock;
use crate::clocks::RtcClock;
use rp2040_pac::{RESETS, RTC};
mod filter;
pub use self::filter::DateTimeFilter;
#[cfg_attr(feature = "chrono", path = "datetime_chrono.rs")]
#[cfg_attr(not(feature = "chrono"), path = "datetime_no_deps.rs")]
mod datetime;
pub use self::datetime::{DateTime, DayOfWeek, Error as DateTimeError};
pub struct RealTimeClock {
rtc: RTC,
}
impl RealTimeClock {
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 };
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)
}
pub fn disable_alarm(&mut self) {
self.rtc
.irq_setup_0
.modify(|_, s| s.match_ena().clear_bit());
while self.rtc.irq_setup_0.read().match_active().bit() {
core::hint::spin_loop();
}
}
pub fn schedule_alarm(&mut self, filter: DateTimeFilter) {
self.disable_alarm();
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.rtc.irq_setup_0.modify(|_, w| w.match_ena().set_bit());
while self.rtc.irq_setup_0.read().match_active().bit_is_clear() {
core::hint::spin_loop();
}
}
pub fn clear_interrupt(&mut self) {
self.disable_alarm();
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RtcError {
InvalidDateTime(DateTimeError),
NotRunning,
}