Skip to content

Commit

Permalink
sleep: Adds module for light and deep sleep with examples
Browse files Browse the repository at this point in the history
  • Loading branch information
oyvindnetland committed Aug 14, 2023
1 parent 9a8f51e commit 0e4faf6
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 0 deletions.
36 changes: 36 additions & 0 deletions examples/deep_sleep.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Tests deep sleep
//!
//! Prints reset and wakeup reason on start, before enabling mutiple
//! wakeup sources and start deep sleep. Deep sleep will reset the
//! device, so after sleep it will restart the application.
use esp_idf_hal::reset::ResetReason;
use esp_idf_hal::reset::WakeupReason;
use esp_idf_hal::sleep::DeepSleep;
use esp_idf_hal::sleep::Sleep;
use esp_idf_hal::sleep::WakeupSource;
use std::thread;
use std::time::Duration;

fn main() -> anyhow::Result<()> {
esp_idf_sys::link_patches();

let reset_reason = ResetReason::get();
let wakeup_reason = WakeupReason::get();
println!(
"start up after reset {:?} wake up reason {:?}",
reset_reason, wakeup_reason
);

thread::sleep(Duration::from_secs(2));

let mut dsleep = DeepSleep::default();
dsleep.add_wakeup_source(WakeupSource::Timer {
dur: Duration::from_secs(5),
})?;
println!("{:?}", dsleep);

dsleep.sleep()?;

Ok(())
}
65 changes: 65 additions & 0 deletions examples/light_sleep.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! Tests light sleep
//!
//! Enables multiple light sleep wakeup sources and do sleeps in a loop.
//! Prints wakeup reason and sleep time on wakeup.
use esp_idf_hal::reset::WakeupReason;
use esp_idf_hal::sleep::LightSleep;
use esp_idf_hal::sleep::Sleep;
use esp_idf_hal::sleep::WakeupSource;
use std::thread;
use std::time::Duration;
use std::time::Instant;

fn print_wakeup_result(time_before: Instant) {
let time_after = Instant::now();

let wakeup_reason = WakeupReason::get();
println!(
"wake up from light sleep due to {:?} which lasted for {:?}",
wakeup_reason,
time_after - time_before
);
}

fn main() -> anyhow::Result<()> {
esp_idf_sys::link_patches();

println!("test timer light sleep oneliner first:");
thread::sleep(Duration::from_millis(20));

let time_before = Instant::now();
LightSleep::timer(Duration::from_secs(5))?.sleep()?;
print_wakeup_result(time_before);

// run in a thread with increased stack size to prevent overflow
let builder = std::thread::Builder::new().stack_size(8 * 1024);
let th = builder.spawn(move || -> anyhow::Result<()> {
let mut lsleep = LightSleep::default();
lsleep.add_wakeup_source(WakeupSource::Timer {
dur: Duration::from_secs(5),
})?;
lsleep.add_wakeup_source(WakeupSource::Uart {
uart_num: 0,
threshold: 3,
})?;

loop {
println!("{:?}", lsleep);
// short sleep to flush stdout (stdout().flush() did not work)
thread::sleep(Duration::from_millis(20));

let time_before = Instant::now();
lsleep.sleep()?;
print_wakeup_result(time_before);

println!("---");
}
})?;

th.join();

loop {
thread::sleep(Duration::from_secs(1));
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub mod rmt;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod rom;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod sleep;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod spi;
#[cfg(not(feature = "riscv-ulp-hal"))]
pub mod task;
Expand Down
110 changes: 110 additions & 0 deletions src/sleep.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//! Driver for light and deep sleep.
//!
//! Currently implemented Timer and UART wakeup sources.
use esp_idf_sys::*;
use std::time::Duration;

#[derive(Debug)]
pub enum WakeupSource {
Timer { dur: Duration },
Uart { uart_num: i32, threshold: i32 },
// TODO: add more sources
}

impl WakeupSource {
pub fn apply(&self) -> Result<(), EspError> {
match *self {
WakeupSource::Timer { dur } => {
esp!(unsafe { esp_sleep_enable_timer_wakeup(dur.as_micros() as u64) })?;
}
WakeupSource::Uart {
uart_num,
threshold,
} => {
esp!(unsafe { uart_set_wakeup_threshold(uart_num, threshold) })?;
esp!(unsafe { esp_sleep_enable_uart_wakeup(uart_num) })?;
}
}

Ok(())
}
}

pub trait Sleep {
fn add_wakeup_source(&mut self, wakeup: WakeupSource) -> Result<(), EspError>;
fn sleep(&self) -> Result<(), EspError>;

fn apply_wakeup_sources(&self, wakeup_sources: &[WakeupSource]) -> Result<(), EspError> {
// reset wakeup sources
esp!(unsafe { esp_sleep_disable_wakeup_source(esp_sleep_source_t_ESP_SLEEP_WAKEUP_ALL) })?;

for wakeup in wakeup_sources.iter() {
wakeup.apply()?;
}
Ok(())
}
}

#[derive(Default, Debug)]
pub struct LightSleep {
wakeup_sources: Vec<WakeupSource>,
}

impl LightSleep {
pub fn timer(dur: Duration) -> Result<Self, EspError> {
// TODO: checks for duplicate wakeup sources

let mut lsleep = Self::default();
lsleep.add_wakeup_source(WakeupSource::Timer { dur })?;
Ok(lsleep)
}
}

impl Sleep for LightSleep {
fn add_wakeup_source(&mut self, wakeup: WakeupSource) -> Result<(), EspError> {
self.wakeup_sources.push(wakeup);
Ok(())
}

fn sleep(&self) -> Result<(), EspError> {
self.apply_wakeup_sources(&self.wakeup_sources)?;

esp!(unsafe { esp_light_sleep_start() })?;
Ok(())
}
}

#[derive(Default, Debug)]
pub struct DeepSleep {
wakeup_sources: Vec<WakeupSource>,
}

impl DeepSleep {
pub fn timer(dur: Duration) -> Result<Self, EspError> {
let mut dsleep = Self::default();
dsleep.add_wakeup_source(WakeupSource::Timer { dur })?;
Ok(dsleep)
}
}

impl Sleep for DeepSleep {
fn add_wakeup_source(&mut self, wakeup: WakeupSource) -> Result<(), EspError> {
// TODO: checks for duplicate wakeup sources

if matches!(wakeup, WakeupSource::Uart { .. }) {
return Err(EspError::from_infallible::<ESP_ERR_INVALID_ARG>());
}
self.wakeup_sources.push(wakeup);
Ok(())
}

fn sleep(&self) -> Result<(), EspError> {
self.apply_wakeup_sources(&self.wakeup_sources)?;

unsafe { esp_deep_sleep_start() };
#[allow(unreachable_code)]
// if function returns, it means that deep sleep has been rejected
Err(EspError::from_infallible::<ESP_FAIL>())
}
}

0 comments on commit 0e4faf6

Please sign in to comment.