1use core::time::Duration;
2use esp_idf_sys::*;
3
4#[cfg(not(any(esp32c2, esp32c3)))]
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)))]
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 Level::Low => esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_LOW,
139 Level::High => esp_deepsleep_gpio_wake_up_mode_t_ESP_GPIO_WAKEUP_GPIO_HIGH,
140 };
141 esp!(unsafe { esp_deep_sleep_enable_gpio_wakeup(mask, mode) })
142 }
143}
144
145pub mod uart {
146 use crate::uart::UartDriver;
147 use esp_idf_sys::*;
148
149 pub fn configure(uart: &UartDriver, threshold: i32) -> Result<(), EspError> {
150 esp!(unsafe { uart_set_wakeup_threshold(uart.port(), threshold) })?;
151 esp!(unsafe { esp_sleep_enable_uart_wakeup(uart.port() as _) })
152 }
153}
154
155#[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
156pub mod touch {
157 use esp_idf_sys::*;
158 pub fn configure() -> Result<(), EspError> {
159 esp!(unsafe { esp_sleep_enable_touchpad_wakeup() })
160 }
161}
162
163#[cfg(any(esp32, esp32s2, esp32s3, esp32c5, esp32c6, esp32p4))]
164pub mod ulp {
165 use esp_idf_sys::*;
166 pub fn configure() -> Result<(), EspError> {
167 esp!(unsafe { esp_sleep_enable_ulp_wakeup() })
168 }
169}
170
171fn reset_wakeup_sources() -> Result<(), EspError> {
172 esp!(unsafe { esp_sleep_disable_wakeup_source(esp_sleep_source_t_ESP_SLEEP_WAKEUP_ALL) })
173}
174
175pub struct LightSleep(());
176
177impl LightSleep {
178 pub fn new() -> Result<Self, EspError> {
179 reset_wakeup_sources()?;
180 Ok(Self(()))
181 }
182
183 pub fn wakeup_on_timer(self, duration: Duration) -> Result<Self, EspError> {
184 timer::configure(duration)?;
185 Ok(self)
186 }
187
188 pub fn wakeup_on_uart(
189 self,
190 uart: &crate::uart::UartDriver,
191 threshold: i32,
192 ) -> Result<Self, EspError> {
193 uart::configure(uart, threshold)?;
194 Ok(self)
195 }
196
197 pub fn wakeup_on_gpio<M: crate::gpio::GPIOMode>(
198 self,
199 pin: &crate::gpio::PinDriver<M>,
200 level: crate::gpio::Level,
201 ) -> Result<Self, EspError> {
202 gpio::configure_light(pin.pin(), level)?;
203 Ok(self)
204 }
205
206 #[cfg(not(any(esp32c2, esp32c3)))]
207 pub fn wakeup_on_rtc<P>(self, pins: P, level: rtc::RtcWakeLevel) -> Result<Self, EspError>
208 where
209 P: rtc::RtcWakeupPins,
210 {
211 rtc::configure(pins, level)?;
212 Ok(self)
213 }
214
215 #[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
216 pub fn wakeup_on_touch(self) -> Result<Self, EspError> {
217 touch::configure()?;
218 Ok(self)
219 }
220
221 #[cfg(any(esp32, esp32s2, esp32s3, esp32c5, esp32c6, esp32p4))]
222 pub fn wakeup_on_ulp(self) -> Result<Self, EspError> {
223 ulp::configure()?;
224 Ok(self)
225 }
226
227 pub fn enter(&mut self) -> Result<(), EspError> {
228 esp!(unsafe { esp_light_sleep_start() })
229 }
230}
231
232pub struct DeepSleep(());
233
234impl DeepSleep {
235 pub fn new() -> Result<Self, EspError> {
236 reset_wakeup_sources()?;
237 Ok(Self(()))
238 }
239
240 pub fn wakeup_on_timer(self, duration: Duration) -> Result<Self, EspError> {
241 timer::configure(duration)?;
242 Ok(self)
243 }
244
245 #[cfg(not(any(esp32c2, esp32c3)))]
246 pub fn wakeup_on_rtc<P>(self, pins: P, level: rtc::RtcWakeLevel) -> Result<Self, EspError>
247 where
248 P: rtc::RtcWakeupPins,
249 {
250 rtc::configure(pins, level)?;
251 Ok(self)
252 }
253
254 #[cfg(any(esp32c2, esp32c3))]
255 pub fn wakeup_on_gpio<M: crate::gpio::GPIOMode>(
256 self,
257 pin: &crate::gpio::PinDriver<M>,
258 level: crate::gpio::Level,
259 ) -> Result<Self, EspError> {
260 gpio::configure_deep(pin.pin(), level)?;
261 Ok(self)
262 }
263
264 #[cfg(any(esp32, esp32s2, esp32s3, esp32p4))]
265 pub fn wakeup_on_touch(self) -> Result<Self, EspError> {
266 touch::configure()?;
267 Ok(self)
268 }
269
270 #[cfg(any(esp32, esp32s2, esp32s3, esp32c5, esp32c6, esp32p4))]
271 pub fn wakeup_on_ulp(self) -> Result<Self, EspError> {
272 ulp::configure()?;
273 Ok(self)
274 }
275
276 pub fn enter(self) -> ! {
277 unsafe { esp_deep_sleep_start() }
278 #[allow(unreachable_code)]
279 {
280 panic!("Deep sleep failed to start");
281 }
282 }
283}