use core::cell::RefCell;
#[cfg(any(esp32, esp32c3, esp32s2, esp32s3, esp32c6, esp32c2, esp32h2))]
use core::time::Duration;
#[cfg(any(esp32, esp32s2, esp32s3))]
use crate::gpio::RtcPin as RtcIoWakeupPinType;
#[cfg(any(esp32c3, esp32c6, esp32c2, esp32h2))]
use crate::gpio::RtcPinWithResistors as RtcIoWakeupPinType;
use crate::rtc_cntl::Rtc;
#[cfg_attr(esp32, path = "esp32.rs")]
#[cfg_attr(esp32s2, path = "esp32s2.rs")]
#[cfg_attr(esp32s3, path = "esp32s3.rs")]
#[cfg_attr(esp32c3, path = "esp32c3.rs")]
#[cfg_attr(esp32c6, path = "esp32c6.rs")]
#[cfg_attr(esp32c2, path = "esp32c2.rs")]
#[cfg_attr(esp32h2, path = "esp32h2.rs")]
mod sleep_impl;
pub use sleep_impl::*;
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub enum WakeupLevel {
Low,
#[default]
High,
}
#[procmacros::doc_replace]
#[derive(Debug, Default, Clone, Copy)]
#[cfg(any(esp32, esp32c3, esp32s2, esp32s3, esp32c6, esp32c2, esp32h2))]
pub struct TimerWakeupSource {
duration: Duration,
}
#[cfg(any(esp32, esp32c3, esp32s2, esp32s3, esp32c6, esp32c2, esp32h2))]
impl TimerWakeupSource {
pub fn new(duration: Duration) -> Self {
Self { duration }
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Error {
NotRtcPin,
TooManyWakeupSources,
}
#[procmacros::doc_replace]
#[cfg(any(esp32, esp32s2, esp32s3))]
pub struct Ext0WakeupSource<P: RtcIoWakeupPinType> {
pin: RefCell<P>,
level: WakeupLevel,
}
#[cfg(any(esp32, esp32s2, esp32s3))]
impl<P: RtcIoWakeupPinType> Ext0WakeupSource<P> {
pub fn new(pin: P, level: WakeupLevel) -> Self {
Self {
pin: RefCell::new(pin),
level,
}
}
}
#[procmacros::doc_replace]
#[cfg(any(esp32, esp32s2, esp32s3))]
pub struct Ext1WakeupSource<'a, 'b> {
pins: RefCell<&'a mut [&'b mut dyn RtcIoWakeupPinType]>,
level: WakeupLevel,
}
#[cfg(any(esp32, esp32s2, esp32s3))]
impl<'a, 'b> Ext1WakeupSource<'a, 'b> {
pub fn new(pins: &'a mut [&'b mut dyn RtcIoWakeupPinType], level: WakeupLevel) -> Self {
Self {
pins: RefCell::new(pins),
level,
}
}
}
#[procmacros::doc_replace(
"pin_low" => {
cfg(esp32c6) => "GPIO2",
cfg(esp32h2) => "GPIO9",
},
"pin_high" => {
cfg(esp32c6) => "GPIO3",
cfg(esp32h2) => "GPIO10"
},
)]
#[cfg(any(esp32c6, esp32h2))]
pub struct Ext1WakeupSource<'a, 'b> {
pins: RefCell<&'a mut [(&'b mut dyn RtcIoWakeupPinType, WakeupLevel)]>,
}
#[cfg(any(esp32c6, esp32h2))]
impl<'a, 'b> Ext1WakeupSource<'a, 'b> {
pub fn new(pins: &'a mut [(&'b mut dyn RtcIoWakeupPinType, WakeupLevel)]) -> Self {
Self {
pins: RefCell::new(pins),
}
}
}
#[procmacros::doc_replace(
"pin0" => {
cfg(any(esp32c3, esp32c2)) => "GPIO2",
cfg(any(esp32s2, esp32s3)) => "GPIO17"
},
"pin1" => {
cfg(any(esp32c3, esp32c2)) => "GPIO3",
cfg(any(esp32s2, esp32s3)) => "GPIO18"
},
"rtc_pin_trait" => {
cfg(any(esp32c3, esp32c2)) => "gpio::RtcPinWithResistors",
cfg(any(esp32s2, esp32s3)) => "gpio::RtcPin"
},
)]
#[cfg(any(esp32c3, esp32s2, esp32s3, esp32c2))]
pub struct RtcioWakeupSource<'a, 'b> {
pins: RefCell<&'a mut [(&'b mut dyn RtcIoWakeupPinType, WakeupLevel)]>,
}
#[cfg(any(esp32c3, esp32s2, esp32s3, esp32c2))]
impl<'a, 'b> RtcioWakeupSource<'a, 'b> {
pub fn new(pins: &'a mut [(&'b mut dyn RtcIoWakeupPinType, WakeupLevel)]) -> Self {
Self {
pins: RefCell::new(pins),
}
}
}
#[cfg(esp32c6)]
pub struct WakeFromLpCoreWakeupSource {}
#[cfg(esp32c6)]
impl WakeFromLpCoreWakeupSource {
pub fn new() -> Self {
Self {}
}
}
#[cfg(esp32c6)]
impl Default for WakeFromLpCoreWakeupSource {
fn default() -> Self {
Self::new()
}
}
#[cfg(any(esp32s2, esp32s3))]
pub struct UlpWakeupSource {
wake_on_interrupt: bool,
wake_on_trap: bool,
clear_interrupts_on_sleep: bool,
}
#[cfg(any(esp32s2, esp32s3))]
impl UlpWakeupSource {
pub const fn new() -> Self {
Self {
wake_on_interrupt: true,
wake_on_trap: true,
clear_interrupts_on_sleep: true,
}
}
pub fn set_wake_on_interrupt(mut self, value: bool) -> Self {
self.wake_on_interrupt = value;
self
}
pub fn set_wake_on_trap(mut self, value: bool) -> Self {
self.wake_on_trap = value;
self
}
pub fn set_clear_interrupts_on_sleep(mut self, value: bool) -> Self {
self.clear_interrupts_on_sleep = value;
self
}
pub fn clear_interrupts(&self) {
crate::peripherals::LPWR::regs().int_clr().write(|w| {
w.cocpu_trap().clear_bit_by_one();
w.cocpu().clear_bit_by_one();
w.ulp_cp().clear_bit_by_one()
});
}
}
#[cfg(any(esp32s2, esp32s3))]
impl Default for UlpWakeupSource {
fn default() -> Self {
Self::new()
}
}
pub struct GpioWakeupSource {}
impl GpioWakeupSource {
pub fn new() -> Self {
Self {}
}
}
impl Default for GpioWakeupSource {
fn default() -> Self {
Self::new()
}
}
impl WakeSource for GpioWakeupSource {
fn apply(
&self,
_rtc: &Rtc<'_>,
triggers: &mut WakeTriggers,
_sleep_config: &mut RtcSleepConfig,
) {
triggers.set_gpio(true);
}
}
macro_rules! uart_wakeup_impl {
($num:literal) => {
paste::paste! {
#[doc = concat!("UART", $num, " wakeup source")]
pub struct [< Uart $num WakeupSource >] {
threshold: u16,
}
impl [< Uart $num WakeupSource >] {
#[doc = concat!("Create a new instance of UART", $num, " wakeup source>") ]
pub fn new(threshold: u16) -> Self {
if threshold > 1023 {
panic!("Invalid threshold");
}
Self { threshold }
}
}
impl WakeSource for [< Uart $num WakeupSource >] {
fn apply(&self, _rtc: &Rtc<'_>, triggers: &mut WakeTriggers, _sleep_config: &mut RtcSleepConfig) {
triggers.[< set_uart $num >](true);
let uart = crate::peripherals::[< UART $num >]::regs();
#[cfg(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3))]
uart.sleep_conf()
.modify(|_, w| unsafe { w.active_threshold().bits(self.threshold) });
#[cfg(not(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3)))]
uart.sleep_conf2().modify(|_, w| unsafe {
w.wk_mode_sel()
.bits(0)
.active_threshold()
.bits(self.threshold)
});
}
}
}
};
}
uart_wakeup_impl!(0);
uart_wakeup_impl!(1);
#[cfg(esp32s2)]
bitfield::bitfield! {
#[derive(Default, Clone, Copy)]
pub struct WakeTriggers(u16);
impl Debug;
pub ext0, set_ext0: 0;
pub ext1, set_ext1: 1;
pub gpio, set_gpio: 2;
pub timer, set_timer: 3;
pub wifi_soc, set_wifi_soc: 5;
pub uart0, set_uart0: 6;
pub uart1, set_uart1: 7;
pub touch, set_touch: 8;
pub ulp, set_ulp: 11;
pub ulp_riscv_trap, set_ulp_riscv_trap: 13;
pub usb, set_usb: 15;
}
#[cfg(esp32s3)]
bitfield::bitfield! {
#[derive(Default, Clone, Copy)]
pub struct WakeTriggers(u16);
impl Debug;
pub ext0, set_ext0: 0;
pub ext1, set_ext1: 1;
pub gpio, set_gpio: 2;
pub timer, set_timer: 3;
pub sdio, set_sdio: 4;
pub mac, set_mac: 5;
pub uart0, set_uart0: 6;
pub uart1, set_uart1: 7;
pub touch, set_touch: 8;
pub ulp_fsm, set_ulp_fsm: 9;
pub bt, set_bt: 10;
pub ulp_riscv, set_ulp_riscv: 11;
pub ulp_riscv_trap, set_ulp_riscv_trap: 13;
}
#[cfg(any(esp32, esp32c2, esp32c3))]
bitfield::bitfield! {
#[derive(Default, Clone, Copy)]
pub struct WakeTriggers(u16);
impl Debug;
pub ext0, set_ext0: 0;
pub ext1, set_ext1: 1;
pub gpio, set_gpio: 2;
pub timer, set_timer: 3;
pub sdio, set_sdio: 4;
pub mac, set_mac: 5;
pub uart0, set_uart0: 6;
pub uart1, set_uart1: 7;
pub touch, set_touch: 8;
pub ulp, set_ulp: 9;
pub bt, set_bt: 10;
}
#[cfg(soc_has_pmu)]
bitfield::bitfield! {
#[derive(Default, Clone, Copy)]
pub struct WakeTriggers(u16);
impl Debug;
pub ext0, set_ext0: 0;
pub ext1, set_ext1: 1;
pub gpio, set_gpio: 2;
pub wifi_beacon, set_wifi_beacon: 3;
pub timer, set_timer: 4;
pub wifi_soc, set_wifi_soc: 5;
pub uart0, set_uart0: 6;
pub uart1, set_uart1: 7;
pub sdio, set_sdio: 8;
pub bt, set_bt: 10;
pub lp_core, set_lp_core: 11;
pub usb, set_usb: 14;
}
pub trait WakeSource {
fn apply(&self, rtc: &Rtc<'_>, triggers: &mut WakeTriggers, sleep_config: &mut RtcSleepConfig);
}