1use core::time::Duration;
2use esp_idf_sys::*;
3
4#[cfg(not(any(esp32c2, esp32c3, esp32h2, esp32h4)))]
5pub use self::rtc::{ChainedRtcWakeupPins, RtcWakeLevel, RtcWakeupPins};
6
7pub mod timer {
8 use core::time::Duration;
9 use esp_idf_sys::*;
10
11 pub fn configure(duration: Duration) -> Result<(), EspError> {
12 esp!(unsafe { esp_sleep_enable_timer_wakeup(duration.as_micros() as u64) })
13 }
14}
15
16#[cfg(not(any(esp32c2, esp32c3, esp32h2, esp32h4)))]
17pub mod rtc {
18 use crate::gpio::{PinDriver, PinId, RTCMode};
19 use esp_idf_sys::*;
20
21 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
22 pub enum RtcWakeLevel {
23 AllLow,
24 AnyHigh,
25 }
26
27 impl RtcWakeLevel {
28 pub fn mode(&self) -> u32 {
29 match self {
30 Self::AllLow => esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ALL_LOW,
31 Self::AnyHigh => esp_sleep_ext1_wakeup_mode_t_ESP_EXT1_WAKEUP_ANY_HIGH,
32 }
33 }
34 }
35
36 pub trait RtcWakeupPins {
37 type Iterator<'a>: Iterator<Item = PinId>
38 where
39 Self: 'a;
40
41 fn iter(&self) -> Self::Iterator<'_>;
42
43 fn chain<P: RtcWakeupPins>(self, other: P) -> ChainedRtcWakeupPins<Self, P>
44 where
45 Self: Sized,
46 {
47 ChainedRtcWakeupPins {
48 first: self,
49 second: other,
50 }
51 }
52 }
53
54 impl<P> RtcWakeupPins for &PinDriver<'_, P>
55 where
56 P: RTCMode,
57 {
58 type Iterator<'a>
59 = core::iter::Once<PinId>
60 where
61 Self: 'a;
62
63 fn iter(&self) -> Self::Iterator<'_> {
64 core::iter::once(self.pin())
65 }
66 }
67
68 pub struct ChainedRtcWakeupPins<F, S> {
69 first: F,
70 second: S,
71 }
72
73 impl<F, S> RtcWakeupPins for ChainedRtcWakeupPins<F, S>
74 where
75 F: RtcWakeupPins,
76 S: RtcWakeupPins,
77 {
78 type Iterator<'a>
79 = core::iter::Chain<F::Iterator<'a>, S::Iterator<'a>>
80 where
81 Self: 'a;
82
83 fn iter(&self) -> Self::Iterator<'_> {
84 self.first.iter().chain(self.second.iter())
85 }
86 }
87
88 impl<F, S> RtcWakeupPins for &ChainedRtcWakeupPins<F, S>
89 where
90 F: RtcWakeupPins,
91 S: RtcWakeupPins,
92 {
93 type Iterator<'a>
94 = core::iter::Chain<F::Iterator<'a>, S::Iterator<'a>>
95 where
96 Self: 'a;
97
98 fn iter(&self) -> Self::Iterator<'_> {
99 self.first.iter().chain(self.second.iter())
100 }
101 }
102
103 pub fn configure<P: RtcWakeupPins>(pins: P, level: RtcWakeLevel) -> Result<(), EspError> {
104 let mut mask: u64 = 0;
105 for pin_id in pins.iter() {
106 mask |= 1 << pin_id;
107 }
108
109 #[cfg(any(esp32, esp32s3))]
110 esp!(unsafe {
111 esp_sleep_pd_config(
112 esp_sleep_pd_domain_t_ESP_PD_DOMAIN_RTC_PERIPH,
113 esp_sleep_pd_option_t_ESP_PD_OPTION_ON,
114 )
115 })?;
116
117 esp!(unsafe { esp_sleep_enable_ext1_wakeup(mask, level.mode()) })
118 }
119}
120
121pub mod gpio {
122 use crate::gpio::{Level, PinId};
123 use esp_idf_sys::*;
124
125 pub fn configure_light(pin: PinId, level: Level) -> Result<(), EspError> {
126 let intr = match level {
127 Level::Low => gpio_int_type_t_GPIO_INTR_LOW_LEVEL,
128 Level::High => gpio_int_type_t_GPIO_INTR_HIGH_LEVEL,
129 };
130 esp!(unsafe { gpio_wakeup_enable(pin as _, intr) })?;
131 esp!(unsafe { esp_sleep_enable_gpio_wakeup() })
132 }
133
134 #[cfg(any(esp32c2, esp32c3))]
135 pub fn configure_deep(pin: PinId, level: Level) -> Result<(), EspError> {
136 let mask = 1 << pin;
137 let mode = match level {
138 #[cfg(not(esp_idf_version_at_least_6_0_0))]
139 Level::Low => esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_LOW,
140 #[cfg(not(esp_idf_version_at_least_6_0_0))]
141 Level::High => esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_HIGH,
142 #[cfg(esp_idf_version_at_least_6_0_0)]
143 Level::Low => esp_sleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_LOW,
144 #[cfg(esp_idf_version_at_least_6_0_0)]
145 Level::High => esp_sleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_HIGH,
146 };
147 #[cfg(not(esp_idf_version_at_least_6_0_0))]
148 return esp!(unsafe { esp_deep_sleep_enable_gpio_wakeup(mask, mode) });
149 #[cfg(esp_idf_version_at_least_6_0_0)]
150 return esp!(unsafe { esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(mask, mode) });
151 }
152}
153
154pub mod uart {
155 use crate::uart::UartDriver;
156 use esp_idf_sys::*;
157
158 pub fn configure(uart: &UartDriver, threshold: i32) -> Result<(), EspError> {
159 esp!(unsafe { uart_set_wakeup_threshold(uart.port(), threshold) })?;
160 esp!(unsafe { esp_sleep_enable_uart_wakeup(uart.port() as _) })
161 }
162}
163
164#[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
165pub mod touch {
166 use esp_idf_sys::*;
167 pub fn configure() -> Result<(), EspError> {
168 esp!(unsafe { esp_sleep_enable_touchpad_wakeup() })
169 }
170}
171
172#[cfg(any(esp32, esp32s2, esp32s3, esp32c5, esp32c6, esp32p4))]
173pub mod ulp {
174 use esp_idf_sys::*;
175 pub fn configure() -> Result<(), EspError> {
176 esp!(unsafe { esp_sleep_enable_ulp_wakeup() })
177 }
178}
179
180fn reset_wakeup_sources() -> Result<(), EspError> {
181 esp!(unsafe { esp_sleep_disable_wakeup_source(esp_sleep_source_t_ESP_SLEEP_WAKEUP_ALL) })
182}
183
184pub struct LightSleep(());
185
186impl LightSleep {
187 pub fn new() -> Result<Self, EspError> {
188 reset_wakeup_sources()?;
189 Ok(Self(()))
190 }
191
192 pub fn wakeup_on_timer(self, duration: Duration) -> Result<Self, EspError> {
193 timer::configure(duration)?;
194 Ok(self)
195 }
196
197 pub fn wakeup_on_uart(
198 self,
199 uart: &crate::uart::UartDriver,
200 threshold: i32,
201 ) -> Result<Self, EspError> {
202 uart::configure(uart, threshold)?;
203 Ok(self)
204 }
205
206 pub fn wakeup_on_gpio<M: crate::gpio::GPIOMode>(
207 self,
208 pin: &crate::gpio::PinDriver<M>,
209 level: crate::gpio::Level,
210 ) -> Result<Self, EspError> {
211 gpio::configure_light(pin.pin(), level)?;
212 Ok(self)
213 }
214
215 #[cfg(not(any(esp32c2, esp32c3, esp32h2, esp32h4)))]
216 pub fn wakeup_on_rtc<P>(self, pins: P, level: rtc::RtcWakeLevel) -> Result<Self, EspError>
217 where
218 P: rtc::RtcWakeupPins,
219 {
220 rtc::configure(pins, level)?;
221 Ok(self)
222 }
223
224 #[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
225 pub fn wakeup_on_touch(self) -> Result<Self, EspError> {
226 touch::configure()?;
227 Ok(self)
228 }
229
230 #[cfg(any(esp32, esp32s2, esp32s3, esp32c5, esp32c6, esp32p4))]
231 pub fn wakeup_on_ulp(self) -> Result<Self, EspError> {
232 ulp::configure()?;
233 Ok(self)
234 }
235
236 pub fn enter(&mut self) -> Result<(), EspError> {
237 esp!(unsafe { esp_light_sleep_start() })
238 }
239}
240
241pub struct DeepSleep(());
242
243impl DeepSleep {
244 pub fn new() -> Result<Self, EspError> {
245 reset_wakeup_sources()?;
246 Ok(Self(()))
247 }
248
249 pub fn wakeup_on_timer(self, duration: Duration) -> Result<Self, EspError> {
250 timer::configure(duration)?;
251 Ok(self)
252 }
253
254 #[cfg(not(any(esp32c2, esp32c3, esp32h2, esp32h4)))]
255 pub fn wakeup_on_rtc<P>(self, pins: P, level: rtc::RtcWakeLevel) -> Result<Self, EspError>
256 where
257 P: rtc::RtcWakeupPins,
258 {
259 rtc::configure(pins, level)?;
260 Ok(self)
261 }
262
263 #[cfg(any(esp32c2, esp32c3))]
264 pub fn wakeup_on_gpio<M: crate::gpio::GPIOMode>(
265 self,
266 pin: &crate::gpio::PinDriver<M>,
267 level: crate::gpio::Level,
268 ) -> Result<Self, EspError> {
269 gpio::configure_deep(pin.pin(), level)?;
270 Ok(self)
271 }
272
273 #[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
274 pub fn wakeup_on_touch(self) -> Result<Self, EspError> {
275 touch::configure()?;
276 Ok(self)
277 }
278
279 #[cfg(any(esp32, esp32s2, esp32s3, esp32c5, esp32c6, esp32p4))]
280 pub fn wakeup_on_ulp(self) -> Result<Self, EspError> {
281 ulp::configure()?;
282 Ok(self)
283 }
284
285 pub fn enter(self) -> ! {
286 unsafe { esp_deep_sleep_start() }
287 #[allow(unreachable_code)]
288 {
289 panic!("Deep sleep failed to start");
290 }
291 }
292}