Fix light sleep global alarms, API revisions

This commit is contained in:
Lucian Copeland 2021-04-13 18:31:57 -04:00
parent 9a3f04a1b8
commit 7eeea869ac
10 changed files with 94 additions and 58 deletions

2
main.c
View File

@ -161,7 +161,7 @@ STATIC void start_mp(supervisor_allocation* heap) {
#if CIRCUITPY_ALARM
// Record which alarm woke us up, if any. An object may be created so the heap must be functional.
shared_alarm_save_wake_alarm();
shared_alarm_save_wake_alarm(common_hal_alarm_create_wake_alarm());
// Reset alarm module only after we retrieved the wakeup alarm.
alarm_reset();
#endif

View File

@ -63,15 +63,18 @@ void alarm_reset(void) {
}
STATIC esp_sleep_wakeup_cause_t _get_wakeup_cause(void) {
if (alarm_pin_pinalarm_woke_us_up()) {
// First check if the modules remember what last woke up
if (alarm_pin_pinalarm_woke_this_cycle()) {
return ESP_SLEEP_WAKEUP_GPIO;
}
if (alarm_time_timealarm_woke_us_up()) {
if (alarm_time_timealarm_woke_this_cycle()) {
return ESP_SLEEP_WAKEUP_TIMER;
}
if (alarm_touch_touchalarm_woke_us_up()) {
if (alarm_touch_touchalarm_woke_this_cycle()) {
return ESP_SLEEP_WAKEUP_TOUCHPAD;
}
// If waking from true deep sleep, modules will have lost their state,
// so check the deep wakeup cause manually
return esp_sleep_get_wakeup_cause();
}
@ -79,21 +82,23 @@ bool common_hal_alarm_woken_from_sleep(void) {
return _get_wakeup_cause() != ESP_SLEEP_WAKEUP_UNDEFINED;
}
STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
mp_obj_t common_hal_alarm_create_wake_alarm(void) {
// If woken from deep sleep, create a copy alarm similar to what would have
// been passed in originally. Otherwise, just return none
esp_sleep_wakeup_cause_t cause = _get_wakeup_cause();
switch (cause) {
case ESP_SLEEP_WAKEUP_TIMER: {
return alarm_time_timealarm_get_wakeup_alarm(n_alarms, alarms);
return alarm_time_timealarm_create_wakeup_alarm();
}
case ESP_SLEEP_WAKEUP_GPIO:
case ESP_SLEEP_WAKEUP_EXT0:
case ESP_SLEEP_WAKEUP_EXT1: {
return alarm_pin_pinalarm_get_wakeup_alarm(n_alarms, alarms);
return alarm_pin_pinalarm_create_wakeup_alarm();
}
case ESP_SLEEP_WAKEUP_TOUCHPAD: {
return alarm_touch_touchalarm_get_wakeup_alarm(n_alarms, alarms);
return alarm_touch_touchalarm_create_wakeup_alarm();
}
case ESP_SLEEP_WAKEUP_UNDEFINED:
@ -104,10 +109,6 @@ STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
return mp_const_none;
}
mp_obj_t common_hal_alarm_get_wake_alarm(void) {
return _get_wake_alarm(0, NULL);
}
// Set up light sleep or deep sleep alarms.
STATIC void _setup_sleep_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms) {
alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms);
@ -115,30 +116,44 @@ STATIC void _setup_sleep_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t
alarm_touch_touchalarm_set_alarm(deep_sleep, n_alarms, alarms);
}
STATIC void _idle_until_alarm(void) {
// Poll for alarms.
while (!mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
// Allow ctrl-C interrupt.
if (common_hal_alarm_woken_from_sleep()) {
shared_alarm_save_wake_alarm();
return;
}
port_idle_until_interrupt();
}
}
mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
_setup_sleep_alarms(false, n_alarms, alarms);
mp_obj_t wake_alarm = mp_const_none;
// We cannot esp_light_sleep_start() here because it shuts down all non-RTC peripherals.
_idle_until_alarm();
while (!mp_hal_is_interrupted()) {
RUN_BACKGROUND_TASKS;
// Detect if interrupt was alarm or ctrl-C interrupt.
if (common_hal_alarm_woken_from_sleep()) {
esp_sleep_wakeup_cause_t cause = _get_wakeup_cause();
switch (cause) {
case ESP_SLEEP_WAKEUP_TIMER: {
wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms,alarms);
break;
}
case ESP_SLEEP_WAKEUP_GPIO: {
wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms,alarms);
break;
}
case ESP_SLEEP_WAKEUP_TOUCHPAD: {
wake_alarm = alarm_touch_touchalarm_find_triggered_alarm(n_alarms,alarms);
break;
}
default:
// Should not reach this, if all light sleep types are covered correctly
break;
}
shared_alarm_save_wake_alarm(wake_alarm);
break;
}
port_idle_until_interrupt();
}
if (mp_hal_is_interrupted()) {
return mp_const_none; // Shouldn't be given to python code because exception handling should kick in.
}
mp_obj_t wake_alarm = _get_wake_alarm(n_alarms, alarms);
alarm_reset();
return wake_alarm;
}

View File

@ -96,12 +96,11 @@ void gpio_interrupt(void *arg) {
}
}
bool alarm_pin_pinalarm_woke_us_up(void) {
bool alarm_pin_pinalarm_woke_this_cycle(void) {
return pin_31_0_status != 0 || pin_63_32_status != 0;
}
mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) {
// First, check to see if we match any given alarms.
mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms) {
uint64_t pin_status = ((uint64_t)pin_63_32_status) << 32 | pin_31_0_status;
for (size_t i = 0; i < n_alarms; i++) {
if (!MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pinalarm_type)) {
@ -112,8 +111,16 @@ mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *al
return alarms[i];
}
}
return mp_const_none;
}
mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(void) {
esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause();
// Pin status will persist into a fake deep sleep
uint64_t pin_status = ((uint64_t)pin_63_32_status) << 32 | pin_31_0_status;
size_t pin_number = 64;
if (cause == ESP_SLEEP_WAKEUP_EXT0) {
pin_number = REG_GET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL);
} else {

View File

@ -34,8 +34,10 @@ typedef struct {
bool pull;
} alarm_pin_pinalarm_obj_t;
mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms);
mp_obj_t alarm_pin_pinalarm_create_wakeup_alarm(void);
void alarm_pin_pinalarm_prepare_for_deep_sleep(void);
void alarm_pin_pinalarm_reset(void);
void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
void alarm_pin_pinalarm_prepare_for_deep_sleep(void);
mp_obj_t alarm_pin_pinalarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
bool alarm_pin_pinalarm_woke_us_up(void);
bool alarm_pin_pinalarm_woke_this_cycle(void);

View File

@ -42,13 +42,16 @@ mp_float_t common_hal_alarm_time_timealarm_get_monotonic_time(alarm_time_timeala
return self->monotonic_time;
}
mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms) {
// First, check to see if we match
mp_obj_t alarm_time_timealarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms) {
for (size_t i = 0; i < n_alarms; i++) {
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_timealarm_type)) {
return alarms[i];
}
}
return mp_const_none;
}
mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void) {
alarm_time_timealarm_obj_t *timer = m_new_obj(alarm_time_timealarm_obj_t);
timer->base.type = &alarm_time_timealarm_type;
// TODO: Set monotonic_time based on the RTC state.
@ -66,7 +69,7 @@ void timer_callback(void *arg) {
xTaskNotifyGive(circuitpython_task);
}
bool alarm_time_timealarm_woke_us_up(void) {
bool alarm_time_timealarm_woke_this_cycle(void) {
return woke_up;
}

View File

@ -32,9 +32,9 @@ typedef struct {
mp_float_t monotonic_time; // values compatible with time.monotonic_time()
} alarm_time_timealarm_obj_t;
// Find the alarm object that caused us to wake up or create an equivalent one.
mp_obj_t alarm_time_timealarm_get_wakeup_alarm(size_t n_alarms, const mp_obj_t *alarms);
// Check for the wake up alarm from pretend deep sleep.
bool alarm_time_timealarm_woke_us_up(void);
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
mp_obj_t alarm_time_timealarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t *alarms);
mp_obj_t alarm_time_timealarm_create_wakeup_alarm(void);
void alarm_time_timealarm_reset(void);
void alarm_time_timealarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_obj_t *alarms);
bool alarm_time_timealarm_woke_this_cycle(void);

View File

@ -42,14 +42,16 @@ void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *s
self->pin = pin;
}
mp_obj_t alarm_touch_touchalarm_get_wakeup_alarm(const size_t n_alarms, const mp_obj_t *alarms) {
// First, check to see if we match any given alarms.
mp_obj_t alarm_touch_touchalarm_find_triggered_alarm(const size_t n_alarms, const mp_obj_t *alarms) {
for (size_t i = 0; i < n_alarms; i++) {
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_touch_touchalarm_type)) {
return alarms[i];
}
}
return mp_const_none;
}
mp_obj_t alarm_touch_touchalarm_create_wakeup_alarm(void) {
// Create TouchAlarm object.
alarm_touch_touchalarm_obj_t *alarm = m_new_obj(alarm_touch_touchalarm_obj_t);
alarm->base.type = &alarm_touch_touchalarm_type;
@ -168,7 +170,7 @@ void alarm_touch_touchalarm_prepare_for_deep_sleep(void) {
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
}
bool alarm_touch_touchalarm_woke_us_up(void) {
bool alarm_touch_touchalarm_woke_this_cycle(void) {
return woke_up;
}

View File

@ -35,12 +35,12 @@ typedef struct {
const mcu_pin_obj_t *pin;
} alarm_touch_touchalarm_obj_t;
// Find the alarm object that caused us to wake up or create an equivalent one.
mp_obj_t alarm_touch_touchalarm_get_wakeup_alarm(const size_t n_alarms, const mp_obj_t *alarms);
// Check for the wake up alarm from pretend deep sleep.
void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alarms, const mp_obj_t *alarms);
mp_obj_t alarm_touch_touchalarm_find_triggered_alarm(const size_t n_alarms, const mp_obj_t *alarms);
mp_obj_t alarm_touch_touchalarm_create_wakeup_alarm(void);
void alarm_touch_touchalarm_prepare_for_deep_sleep(void);
bool alarm_touch_touchalarm_woke_us_up(void);
void alarm_touch_touchalarm_reset(void);
void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alarms, const mp_obj_t *alarms);
bool alarm_touch_touchalarm_woke_this_cycle(void);
#endif // MICROPY_INCLUDED_COMMON_HAL_ALARM_TOUCH_TOUCHALARM_H

View File

@ -228,13 +228,13 @@ mp_obj_t shared_alarm_get_wake_alarm(void) {
}
// Initialize .wake_alarm value.
void shared_alarm_save_wake_alarm(void) {
void shared_alarm_save_wake_alarm(mp_obj_t alarm) {
// Equivalent of:
// alarm.wake_alarm = alarm
mp_map_elem_t *elem =
mp_map_lookup(&alarm_module_globals.map, MP_ROM_QSTR(MP_QSTR_wake_alarm), MP_MAP_LOOKUP);
if (elem) {
elem->value = common_hal_alarm_get_wake_alarm();
elem->value = alarm;
}
}

View File

@ -31,6 +31,9 @@
#include "common-hal/alarm/__init__.h"
// Light sleep fully self-contained and does not exit user code. It will return
// the same alarm object that was orignally passed in, unlike deep sleep, which
// must create an identical copy due to the VM reset
extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms);
// Deep sleep is a two step process. Alarms are set when the VM is valid but
@ -38,22 +41,26 @@ extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const
// not actually happen if the user is connected to the device. In this case, the
// supervisor will idle using `port_wait_for_interrupt`. After each call, it will
// call alarm_woken_from_sleep to see if we've been woken by an alarm and if so,
// it will exit idle as if deep sleep was exited.
// it will exit idle as if deep sleep was exited
extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms);
extern NORETURN void common_hal_alarm_enter_deep_sleep(void);
// May be used to re-initialize peripherals like GPIO, if the VM reset returned
// them to a default state
extern void common_hal_alarm_pretending_deep_sleep(void);
// Fetches value from module dict.
extern mp_obj_t shared_alarm_get_wake_alarm(void);
extern void common_hal_alarm_gc_collect(void);
extern mp_obj_t common_hal_alarm_get_wake_alarm(void);
// Creates a new alarm object after exiting deep sleep (real or fake)
extern mp_obj_t common_hal_alarm_create_wake_alarm(void);
// Used by wake-up code.
void shared_alarm_save_wake_alarm(void);
// Saves alarm to global array
void shared_alarm_save_wake_alarm(mp_obj_t alarm);
// True if an alarm is alerting. This is most useful for pretend deep sleep.
// True if an alarm is alerting. Used in light sleep/fake deep sleep
extern bool common_hal_alarm_woken_from_sleep(void);
extern void common_hal_alarm_gc_collect(void);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ALARM___INIT___H