Skip to content

Commit 0e4faf6

Browse files
committed
sleep: Adds module for light and deep sleep with examples
1 parent 9a8f51e commit 0e4faf6

File tree

4 files changed

+213
-0
lines changed

4 files changed

+213
-0
lines changed

examples/deep_sleep.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//! Tests deep sleep
2+
//!
3+
//! Prints reset and wakeup reason on start, before enabling mutiple
4+
//! wakeup sources and start deep sleep. Deep sleep will reset the
5+
//! device, so after sleep it will restart the application.
6+
7+
use esp_idf_hal::reset::ResetReason;
8+
use esp_idf_hal::reset::WakeupReason;
9+
use esp_idf_hal::sleep::DeepSleep;
10+
use esp_idf_hal::sleep::Sleep;
11+
use esp_idf_hal::sleep::WakeupSource;
12+
use std::thread;
13+
use std::time::Duration;
14+
15+
fn main() -> anyhow::Result<()> {
16+
esp_idf_sys::link_patches();
17+
18+
let reset_reason = ResetReason::get();
19+
let wakeup_reason = WakeupReason::get();
20+
println!(
21+
"start up after reset {:?} wake up reason {:?}",
22+
reset_reason, wakeup_reason
23+
);
24+
25+
thread::sleep(Duration::from_secs(2));
26+
27+
let mut dsleep = DeepSleep::default();
28+
dsleep.add_wakeup_source(WakeupSource::Timer {
29+
dur: Duration::from_secs(5),
30+
})?;
31+
println!("{:?}", dsleep);
32+
33+
dsleep.sleep()?;
34+
35+
Ok(())
36+
}

examples/light_sleep.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! Tests light sleep
2+
//!
3+
//! Enables multiple light sleep wakeup sources and do sleeps in a loop.
4+
//! Prints wakeup reason and sleep time on wakeup.
5+
6+
use esp_idf_hal::reset::WakeupReason;
7+
use esp_idf_hal::sleep::LightSleep;
8+
use esp_idf_hal::sleep::Sleep;
9+
use esp_idf_hal::sleep::WakeupSource;
10+
use std::thread;
11+
use std::time::Duration;
12+
use std::time::Instant;
13+
14+
fn print_wakeup_result(time_before: Instant) {
15+
let time_after = Instant::now();
16+
17+
let wakeup_reason = WakeupReason::get();
18+
println!(
19+
"wake up from light sleep due to {:?} which lasted for {:?}",
20+
wakeup_reason,
21+
time_after - time_before
22+
);
23+
}
24+
25+
fn main() -> anyhow::Result<()> {
26+
esp_idf_sys::link_patches();
27+
28+
println!("test timer light sleep oneliner first:");
29+
thread::sleep(Duration::from_millis(20));
30+
31+
let time_before = Instant::now();
32+
LightSleep::timer(Duration::from_secs(5))?.sleep()?;
33+
print_wakeup_result(time_before);
34+
35+
// run in a thread with increased stack size to prevent overflow
36+
let builder = std::thread::Builder::new().stack_size(8 * 1024);
37+
let th = builder.spawn(move || -> anyhow::Result<()> {
38+
let mut lsleep = LightSleep::default();
39+
lsleep.add_wakeup_source(WakeupSource::Timer {
40+
dur: Duration::from_secs(5),
41+
})?;
42+
lsleep.add_wakeup_source(WakeupSource::Uart {
43+
uart_num: 0,
44+
threshold: 3,
45+
})?;
46+
47+
loop {
48+
println!("{:?}", lsleep);
49+
// short sleep to flush stdout (stdout().flush() did not work)
50+
thread::sleep(Duration::from_millis(20));
51+
52+
let time_before = Instant::now();
53+
lsleep.sleep()?;
54+
print_wakeup_result(time_before);
55+
56+
println!("---");
57+
}
58+
})?;
59+
60+
th.join();
61+
62+
loop {
63+
thread::sleep(Duration::from_secs(1));
64+
}
65+
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ pub mod rmt;
6565
#[cfg(not(feature = "riscv-ulp-hal"))]
6666
pub mod rom;
6767
#[cfg(not(feature = "riscv-ulp-hal"))]
68+
pub mod sleep;
69+
#[cfg(not(feature = "riscv-ulp-hal"))]
6870
pub mod spi;
6971
#[cfg(not(feature = "riscv-ulp-hal"))]
7072
pub mod task;

src/sleep.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//! Driver for light and deep sleep.
2+
//!
3+
//! Currently implemented Timer and UART wakeup sources.
4+
5+
use esp_idf_sys::*;
6+
use std::time::Duration;
7+
8+
#[derive(Debug)]
9+
pub enum WakeupSource {
10+
Timer { dur: Duration },
11+
Uart { uart_num: i32, threshold: i32 },
12+
// TODO: add more sources
13+
}
14+
15+
impl WakeupSource {
16+
pub fn apply(&self) -> Result<(), EspError> {
17+
match *self {
18+
WakeupSource::Timer { dur } => {
19+
esp!(unsafe { esp_sleep_enable_timer_wakeup(dur.as_micros() as u64) })?;
20+
}
21+
WakeupSource::Uart {
22+
uart_num,
23+
threshold,
24+
} => {
25+
esp!(unsafe { uart_set_wakeup_threshold(uart_num, threshold) })?;
26+
esp!(unsafe { esp_sleep_enable_uart_wakeup(uart_num) })?;
27+
}
28+
}
29+
30+
Ok(())
31+
}
32+
}
33+
34+
pub trait Sleep {
35+
fn add_wakeup_source(&mut self, wakeup: WakeupSource) -> Result<(), EspError>;
36+
fn sleep(&self) -> Result<(), EspError>;
37+
38+
fn apply_wakeup_sources(&self, wakeup_sources: &[WakeupSource]) -> Result<(), EspError> {
39+
// reset wakeup sources
40+
esp!(unsafe { esp_sleep_disable_wakeup_source(esp_sleep_source_t_ESP_SLEEP_WAKEUP_ALL) })?;
41+
42+
for wakeup in wakeup_sources.iter() {
43+
wakeup.apply()?;
44+
}
45+
Ok(())
46+
}
47+
}
48+
49+
#[derive(Default, Debug)]
50+
pub struct LightSleep {
51+
wakeup_sources: Vec<WakeupSource>,
52+
}
53+
54+
impl LightSleep {
55+
pub fn timer(dur: Duration) -> Result<Self, EspError> {
56+
// TODO: checks for duplicate wakeup sources
57+
58+
let mut lsleep = Self::default();
59+
lsleep.add_wakeup_source(WakeupSource::Timer { dur })?;
60+
Ok(lsleep)
61+
}
62+
}
63+
64+
impl Sleep for LightSleep {
65+
fn add_wakeup_source(&mut self, wakeup: WakeupSource) -> Result<(), EspError> {
66+
self.wakeup_sources.push(wakeup);
67+
Ok(())
68+
}
69+
70+
fn sleep(&self) -> Result<(), EspError> {
71+
self.apply_wakeup_sources(&self.wakeup_sources)?;
72+
73+
esp!(unsafe { esp_light_sleep_start() })?;
74+
Ok(())
75+
}
76+
}
77+
78+
#[derive(Default, Debug)]
79+
pub struct DeepSleep {
80+
wakeup_sources: Vec<WakeupSource>,
81+
}
82+
83+
impl DeepSleep {
84+
pub fn timer(dur: Duration) -> Result<Self, EspError> {
85+
let mut dsleep = Self::default();
86+
dsleep.add_wakeup_source(WakeupSource::Timer { dur })?;
87+
Ok(dsleep)
88+
}
89+
}
90+
91+
impl Sleep for DeepSleep {
92+
fn add_wakeup_source(&mut self, wakeup: WakeupSource) -> Result<(), EspError> {
93+
// TODO: checks for duplicate wakeup sources
94+
95+
if matches!(wakeup, WakeupSource::Uart { .. }) {
96+
return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
97+
}
98+
self.wakeup_sources.push(wakeup);
99+
Ok(())
100+
}
101+
102+
fn sleep(&self) -> Result<(), EspError> {
103+
self.apply_wakeup_sources(&self.wakeup_sources)?;
104+
105+
unsafe { esp_deep_sleep_start() };
106+
#[allow(unreachable_code)]
107+
// if function returns, it means that deep sleep has been rejected
108+
Err(EspError::from_infallible::<ESP_FAIL>())
109+
}
110+
}

0 commit comments

Comments
 (0)