use crate::clocks::Clocks;
use crate::pac;
pub use crate::rtc_alarm::{alarm_matches, Alarm, AlarmError};
pub use crate::rtc_tick::TickRate;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct DateTime {
pub year: u16,
pub month: u8,
pub day: u8,
pub weekday: u8,
pub hour: u8,
pub minute: u8,
pub second: u8,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Error {
ClockNot32768,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Event {
MinuteChanged,
HourChanged,
Midnight,
Noon,
}
pub struct Rtc {
rtc: pac::RtcBRealTimeClock,
}
impl Rtc {
pub fn new(
rtc: pac::RtcBRealTimeClock,
clocks: &Clocks,
init: &DateTime,
) -> Result<Self, Error> {
if clocks.aclk() != 32_768 {
return Err(Error::ClockNot32768);
}
rtc.rtcctl01()
.modify(|_, w| w.rtchold().set_bit().rtcbcd().clear_bit());
let this = Rtc { rtc };
this.write_calendar(init);
this.rtc.rtcctl01().modify(|_, w| w.rtchold().clear_bit());
Ok(this)
}
pub fn attach(rtc: pac::RtcBRealTimeClock, clocks: &Clocks) -> Result<Self, Error> {
if clocks.aclk() != 32_768 {
return Err(Error::ClockNot32768);
}
rtc.rtcctl01().modify(|_, w| w.rtchold().clear_bit());
Ok(Rtc { rtc })
}
pub fn set(&mut self, dt: &DateTime) {
self.rtc.rtcctl01().modify(|_, w| w.rtchold().set_bit());
self.write_calendar(dt);
self.rtc.rtcctl01().modify(|_, w| w.rtchold().clear_bit());
}
pub fn now(&self) -> DateTime {
loop {
if self.ready() {
let snapshot = self.read_calendar();
if self.ready() {
return snapshot;
}
}
}
}
pub fn ready(&self) -> bool {
self.rtc.rtcctl01().read().rtcrdy().bit_is_set()
}
pub fn enable_event_interrupt(&self, event: Event) {
self.rtc.rtcctl01().modify(|_, w| {
match event {
Event::MinuteChanged => w.rtctev().rtctev_0(),
Event::HourChanged => w.rtctev().rtctev_1(),
Event::Midnight => w.rtctev().rtctev_2(),
Event::Noon => w.rtctev().rtctev_3(),
};
w.rtctevie().set_bit()
});
}
pub fn enable_second_interrupt(&self) {
self.rtc.rtcctl01().modify(|_, w| w.rtcrdyie().set_bit());
}
pub fn set_alarm(&mut self, alarm: &Alarm) -> Result<(), AlarmError> {
let regs = crate::rtc_alarm::encode_alarm(alarm)?;
self.rtc.rtcctl01().modify(|_, w| w.rtcaie().clear_bit());
self.rtc.rtcamin().write(|w| unsafe { w.bits(regs.minute) });
self.rtc.rtcahour().write(|w| unsafe { w.bits(regs.hour) });
self.rtc.rtcadow().write(|w| unsafe { w.bits(regs.weekday) });
self.rtc.rtcaday().write(|w| unsafe { w.bits(regs.day) });
self.rtc.rtcctl01().modify(|_, w| w.rtcaifg().clear_bit());
Ok(())
}
pub fn disable_alarm(&mut self) {
self.rtc.rtcctl01().modify(|_, w| w.rtcaie().clear_bit());
self.rtc.rtcamin().write(|w| unsafe { w.bits(0) });
self.rtc.rtcahour().write(|w| unsafe { w.bits(0) });
self.rtc.rtcadow().write(|w| unsafe { w.bits(0) });
self.rtc.rtcaday().write(|w| unsafe { w.bits(0) });
self.rtc.rtcctl01().modify(|_, w| w.rtcaifg().clear_bit());
}
pub fn enable_alarm_interrupt(&self) {
self.rtc.rtcctl01().modify(|_, w| w.rtcaie().set_bit());
}
pub fn enable_tick_interrupt(&self, rate: TickRate) {
if rate.uses_rt1ps() {
self.rtc.rtcps1ctl().modify(|_, w| {
w.rt1ip().set(rate.ip_code());
w.rt1psifg().clear_bit();
w.rt1psie().set_bit()
});
} else {
self.rtc.rtcps0ctl().modify(|_, w| {
w.rt0ip().set(rate.ip_code());
w.rt0psifg().clear_bit();
w.rt0psie().set_bit()
});
}
}
pub fn disable_tick_interrupt(&self, rate: TickRate) {
if rate.uses_rt1ps() {
self.rtc
.rtcps1ctl()
.modify(|_, w| w.rt1psie().clear_bit().rt1psifg().clear_bit());
} else {
self.rtc
.rtcps0ctl()
.modify(|_, w| w.rt0psie().clear_bit().rt0psifg().clear_bit());
}
}
pub fn free(self) -> pac::RtcBRealTimeClock {
self.rtc
}
fn write_calendar(&self, dt: &DateTime) {
self.rtc.rtcsec().write(|w| unsafe { w.bits(dt.second) });
self.rtc.rtcmin().write(|w| unsafe { w.bits(dt.minute) });
self.rtc.rtchour().write(|w| unsafe { w.bits(dt.hour) });
self.rtc.rtcdow().write(|w| unsafe { w.bits(dt.weekday) });
self.rtc.rtcday().write(|w| unsafe { w.bits(dt.day) });
self.rtc.rtcmon().write(|w| unsafe { w.bits(dt.month) });
self.rtc.rtcyear().write(|w| unsafe { w.bits(dt.year) });
}
fn read_calendar(&self) -> DateTime {
DateTime {
second: self.rtc.rtcsec().read().bits(),
minute: self.rtc.rtcmin().read().bits(),
hour: self.rtc.rtchour().read().bits(),
weekday: self.rtc.rtcdow().read().bits(),
day: self.rtc.rtcday().read().bits(),
month: self.rtc.rtcmon().read().bits(),
year: self.rtc.rtcyear().read().bits(),
}
}
}
pub fn read_iv() -> u16 {
let rtc = unsafe { pac::RtcBRealTimeClock::steal() };
rtc.rtciv().read().bits()
}
pub fn event_irq_pending() -> bool {
let rtc = unsafe { pac::RtcBRealTimeClock::steal() };
rtc.rtcctl01().read().rtctevifg().bit_is_set()
}
pub fn clear_event_irq() {
let rtc = unsafe { pac::RtcBRealTimeClock::steal() };
rtc.rtcctl01().modify(|_, w| w.rtctevifg().clear_bit());
}
pub fn alarm_irq_pending() -> bool {
let rtc = unsafe { pac::RtcBRealTimeClock::steal() };
rtc.rtcctl01().read().rtcaifg().bit_is_set()
}
pub fn clear_alarm_irq() {
let rtc = unsafe { pac::RtcBRealTimeClock::steal() };
rtc.rtcctl01().modify(|_, w| w.rtcaifg().clear_bit());
}
pub fn isr_disable_tick_interrupts() {
let rtc = unsafe { pac::RtcBRealTimeClock::steal() };
rtc.rtcps0ctl()
.modify(|_, w| w.rt0psie().clear_bit().rt0psifg().clear_bit());
rtc.rtcps1ctl()
.modify(|_, w| w.rt1psie().clear_bit().rt1psifg().clear_bit());
}