Skip to main content

esp_idf_hal/
sleep.rs

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}