#include "watchos.h" #include "Module_Power.h" void Module_Power::start() { // TODO: Fetch input module to poll for button presses m_last_tick = 0; m_light_sleep_accumulator = 0; m_deep_sleep_accumulator = 0; m_did_light_sleep = false; switch (esp_sleep_get_wakeup_cause()) { // Interactive case ESP_SLEEP_WAKEUP_EXT1: // Button press m_light_sleep_delay = MODULE_POWER_INTERACTIVE_LIGHT_SLEEP_DELAY_MS; m_deep_sleep_delay = MODULE_POWER_INTERACTIVE_DEEP_SLEEP_DELAY_MS; break; // Non-interactive case ESP_SLEEP_WAKEUP_EXT0: // External RTC case ESP_SLEEP_WAKEUP_TIMER: // Internal RTC default: // Reset or something else m_light_sleep_delay = MODULE_POWER_NONINTERACTIVE_LIGHT_SLEEP_DELAY_MS; m_deep_sleep_delay = MODULE_POWER_NONINTERACTIVE_DEEP_SLEEP_DELAY_MS; break; } watchos::subscribe(this, WATCHOS_MODULE_INPUT, WATCHOS_EVENT_TYPE_INPUT_PRESSED); } void Module_Power::tick() { if (m_last_tick == 0) { m_last_tick = millis(); } else { if (m_light_sleep_enabled) { m_light_sleep_accumulator += millis() - m_last_tick; } if (m_deep_sleep_enabled) { m_deep_sleep_accumulator += millis() - m_last_tick; } } m_last_tick = millis(); Event* e; while (this->hasEvent()) { e = this->getEvent(); if (e->source == WATCHOS_MODULE_INPUT && e->event == WATCHOS_EVENT_TYPE_INPUT_PRESSED) { watchos::debug("Resetting accumulators"); m_light_sleep_delay = MODULE_POWER_INTERACTIVE_LIGHT_SLEEP_DELAY_MS; m_deep_sleep_delay = MODULE_POWER_INTERACTIVE_DEEP_SLEEP_DELAY_MS; m_light_sleep_accumulator = 0; m_deep_sleep_accumulator = 0; } this->popEvent(); } if (m_deep_sleep_accumulator > m_deep_sleep_delay) { watchos::debug("Going into deep sleep"); //watchos::debug("Power: light %d/%d; heavy %d/%d", m_light_sleep_accumulator, m_light_sleep_delay, m_deep_sleep_accumulator, m_deep_sleep_delay); watchos::kernel()->suspend(); // TODO: Configure a... hourly? alarm to wake up and refresh other things. // Interrogate tasks for next requested wakeup? if (m_did_light_sleep) { esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER); } esp_sleep_enable_ext0_wakeup(HW_RTC, 0); esp_sleep_enable_ext1_wakeup(HW_BUTTON_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); // Turn off RTC -- needs to be on to handle ext0/ext1 interrupts properly I guess //esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); // Turn off RTC fast mem esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF); // Keep RTC slow ram on explicitly esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON); esp_deep_sleep_start(); } else if (m_light_sleep_accumulator > m_light_sleep_delay) { //watchos::debug("Going into light sleep"); //watchos::debug("Power: light %d/%d; heavy %d/%d", m_light_sleep_accumulator, m_light_sleep_delay, m_deep_sleep_accumulator, m_deep_sleep_delay); m_did_light_sleep = true; // If nothing else happens, wake up when it's time to hibernate. esp_sleep_enable_timer_wakeup((m_deep_sleep_delay - m_deep_sleep_accumulator) * 1000); // Wake up if the RTC fires esp_sleep_enable_ext0_wakeup(HW_RTC, 0); // Wake up if any button is pressed esp_sleep_enable_ext1_wakeup(HW_BUTTON_MASK, ESP_EXT1_WAKEUP_ANY_HIGH); // Go into light sleep esp_light_sleep_start(); // And we're back, let everything continue! m_light_sleep_accumulator = 0; } } void Module_Power::disableLightSleep() { m_light_sleep_enabled = false; } void Module_Power::enableLightSleep() { m_light_sleep_enabled = true; } void Module_Power::disableDeepSleep() { m_deep_sleep_enabled = false; } void Module_Power::enableDeepSleep() { m_deep_sleep_enabled = true; }