use crate::{
peripherals::RTC_TIMER,
rtc_cntl::{WakeupSource, sleep::WrappedSleepConfig},
time::Instant,
};
const ALARM_TO_SLEEP_TICKS: u64 = 16;
pub(crate) fn set_deadline(deadline: Instant) {
let now = Instant::now();
let ticks = if deadline >= now {
let ahead = crate::clock::us_to_rtc_ticks((deadline - now).as_micros());
crate::rtc_cntl::time_since_boot_raw().saturating_add(ahead)
} else {
let behind = crate::clock::us_to_rtc_ticks((now - deadline).as_micros());
crate::rtc_cntl::time_since_boot_raw().saturating_sub(behind)
};
arm(ticks);
WakeupSource::Timer.enable_with_hooks(Some(entry_hook), None);
}
pub(crate) fn clear_deadline() {
WakeupSource::Timer.disable();
disarm();
}
pub(crate) fn deadline_missed() -> bool {
let regs = RTC_TIMER::regs();
let (low, high) = cfg_select! {
any(esp32c5, esp32c6, esp32c61, esp32h2, esp32p4) => (
regs.tar0_low().read().main_timer_tar_low0().bits(),
regs.tar0_high().read().main_timer_tar_high0().bits(),
),
_ => (
regs.slp_timer0().read().slp_val_lo().bits(),
regs.slp_timer1().read().slp_val_hi().bits(),
),
};
let deadline = (u64::from(high) << 32) | u64::from(low);
deadline < crate::rtc_cntl::time_since_boot_raw() + ALARM_TO_SLEEP_TICKS
}
#[crate::ram]
fn entry_hook(config: &mut WrappedSleepConfig<'_>) {
if !cfg!(soc_has_pmu) {
config.keep_alive(super::SleepResource::LpPeripherals);
}
}
fn arm(ticks: u64) {
let low = (ticks & 0xffff_ffff) as u32;
let high = ((ticks >> 32) & 0xffff) as u16;
let regs = RTC_TIMER::regs();
cfg_select! {
any(esp32c5, esp32c6, esp32c61, esp32h2, esp32p4) => {
regs.int_clr().write(|w| w.soc_wakeup().clear_bit_by_one());
regs.tar0_low()
.write(|w| unsafe { w.main_timer_tar_low0().bits(low) });
regs.tar0_high()
.write(|w| unsafe { w.main_timer_tar_high0().bits(high) });
regs.tar0_high()
.modify(|_, w| w.main_timer_tar_en0().set_bit());
}
_ => {
regs.int_clr().write(|w| w.main_timer().clear_bit_by_one());
regs.slp_timer0()
.write(|w| unsafe { w.slp_val_lo().bits(low) });
regs.slp_timer1().write(|w| unsafe {
w.slp_val_hi().bits(high);
w.main_timer_alarm_en().set_bit()
});
}
}
}
fn disarm() {
let regs = RTC_TIMER::regs();
cfg_select! {
any(esp32c5, esp32c6, esp32c61, esp32h2, esp32p4) => {
regs.tar0_high()
.modify(|_, w| w.main_timer_tar_en0().clear_bit());
regs.int_clr().write(|w| w.soc_wakeup().clear_bit_by_one());
}
_ => {
regs.slp_timer1()
.write(|w| unsafe { w.slp_val_hi().bits(0) });
regs.int_clr().write(|w| w.main_timer().clear_bit_by_one());
}
}
}