Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pin alarming #3830

Merged
merged 11 commits into from
Dec 28, 2020
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
url = https://github.com/adafruit/Adafruit_CircuitPython_RFM69.git
[submodule "ports/esp32s2/esp-idf"]
path = ports/esp32s2/esp-idf
url = https://github.com/jepler/esp-idf.git
url = https://github.com/adafruit/esp-idf.git
[submodule "ports/esp32s2/certificates/nina-fw"]
path = ports/esp32s2/certificates/nina-fw
url = https://github.com/adafruit/nina-fw.git
27 changes: 16 additions & 11 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,10 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) {
STATIC bool run_code_py(safe_mode_t safe_mode) {
bool serial_connected_at_start = serial_connected();
#if CIRCUITPY_AUTORELOAD_DELAY_MS > 0
if (serial_connected_at_start) {
serial_write("\n");
print_code_py_status_message(safe_mode);
}
serial_write("\n");
print_code_py_status_message(safe_mode);
print_safe_mode_message(safe_mode);
serial_write("\n");
#endif

pyexec_result_t result;
Expand Down Expand Up @@ -307,16 +307,17 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
if (result.return_code & PYEXEC_FORCED_EXIT) {
return reload_requested;
}

if (reload_requested && result.return_code == PYEXEC_EXCEPTION) {
serial_write_compressed(translate("\nCode stopped by auto-reload.\n"));
} else {
serial_write_compressed(translate("\nCode done running.\n"));
}
}

// Program has finished running.

// Display a different completion message if the user has no USB attached (cannot save files)
if (!serial_connected_at_start) {
serial_write_compressed(translate("\nCode done running. Waiting for reload.\n"));
}

bool serial_connected_before_animation = false;
bool serial_connected_before_animation = serial_connected();
#if CIRCUITPY_DISPLAYIO
bool refreshed_epaper_display = false;
#endif
Expand Down Expand Up @@ -409,7 +410,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
alarm_enter_deep_sleep();
// Does not return.
} else {
serial_write_compressed(translate("Pretending to deep sleep until alarm, any key or file write.\n"));
serial_write_compressed(translate("Pretending to deep sleep until alarm, CTRL-C or file write.\n"));
}
}
}
Expand Down Expand Up @@ -615,6 +616,10 @@ void gc_collect(void) {

background_callback_gc_collect();

#if CIRCUITPY_ALARM
common_hal_alarm_gc_collect();
#endif

#if CIRCUITPY_DISPLAYIO
displayio_gc_collect();
#endif
Expand Down
8 changes: 3 additions & 5 deletions ports/esp32s2/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ LDFLAGS += -L$(BUILD)/esp-idf/esp-idf/esp32s2 \
-Tesp32s2.peripherals.ld \
-Lesp-idf/components/esp_rom/esp32s2/ld \
-Tesp32s2.rom.ld \
-Tesp32s2.rom.api.ld \
-Tesp32s2.rom.libgcc.ld \
-Tesp32s2.rom.newlib-data.ld \
-Tesp32s2.rom.newlib-funcs.ld \
Expand Down Expand Up @@ -276,7 +275,7 @@ menuconfig: $(BUILD)/esp-idf/config
# qstr builds include headers so we need to make sure they are up to date
$(HEADER_BUILD)/qstr.split: | $(BUILD)/esp-idf/config/sdkconfig.h

ESP_IDF_COMPONENTS_LINK = freertos log hal esp_system esp_adc_cal esp32s2 bootloader_support pthread esp_timer vfs spi_flash app_update esp_common esp32s2 heap newlib driver xtensa soc esp_ringbuf esp_wifi esp_event wpa_supplicant mbedtls efuse nvs_flash esp_netif lwip esp_rom esp-tls
ESP_IDF_COMPONENTS_LINK = freertos log esp_system esp_adc_cal esp32s2 bootloader_support pthread esp_timer vfs spi_flash app_update esp_common esp32s2 heap newlib driver xtensa soc esp_ringbuf esp_wifi esp_event wpa_supplicant mbedtls efuse nvs_flash esp_netif lwip esp-tls

ESP_IDF_COMPONENTS_INCLUDE = driver freertos log soc

Expand All @@ -288,11 +287,11 @@ ESP_IDF_WIFI_COMPONENTS_EXPANDED = $(foreach component, $(ESP_IDF_WIFI_COMPONENT
MBEDTLS_COMPONENTS_LINK = crypto tls x509
MBEDTLS_COMPONENTS_LINK_EXPANDED = $(foreach component, $(MBEDTLS_COMPONENTS_LINK), $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/library/libmbed$(component).a)

BINARY_BLOBS = esp-idf/components/xtensa/esp32s2/libxt_hal.a
BINARY_BLOBS = esp-idf/components/xtensa/esp32s2/libhal.a
BINARY_WIFI_BLOBS = libcoexist.a libcore.a libespnow.a libmesh.a libnet80211.a libpp.a librtc.a libsmartconfig.a libphy.a
BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/esp32s2/, $(BINARY_WIFI_BLOBS))

ESP_IDF_COMPONENTS_EXPANDED += $(BUILD)/esp-idf/esp-idf/soc/soc/esp32s2/libsoc_esp32s2.a esp-idf/components/xtensa/esp32s2/libxt_hal.a
ESP_IDF_COMPONENTS_EXPANDED += $(BUILD)/esp-idf/esp-idf/soc/soc/esp32s2/libsoc_esp32s2.a
ESP_AUTOGEN_LD = $(BUILD)/esp-idf/esp-idf/esp32s2/esp32s2_out.ld $(BUILD)/esp-idf/esp-idf/esp32s2/ld/esp32s2.project.ld

FLASH_FLAGS = --flash_mode $(CIRCUITPY_ESP_FLASH_MODE) --flash_freq $(CIRCUITPY_ESP_FLASH_FREQ) --flash_size $(CIRCUITPY_ESP_FLASH_SIZE)
Expand All @@ -308,7 +307,6 @@ esp-idf-stamp: $(BUILD)/esp-idf/config/sdkconfig.h
esp-idf/esp32s2/ld/esp32s2.project.ld \
esp-idf/esp_event/libesp_event.a \
esp-idf/esp_netif/libesp_netif.a \
esp-idf/esp_rom/libesp_rom.a \
esp-idf/esp_system/libesp_system.a \
esp-idf/esp_wifi/libesp_wifi.a \
esp-idf/lwip/liblwip.a \
Expand Down
64 changes: 28 additions & 36 deletions ports/esp32s2/common-hal/alarm/__init__.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
* THE SOFTWARE.
*/

#include "py/gc.h"
#include "py/obj.h"
#include "py/objtuple.h"
#include "py/runtime.h"

#include "shared-bindings/alarm/__init__.h"
#include "shared-bindings/alarm/pin/PinAlarm.h"
#include "shared-bindings/alarm/SleepMemory.h"
#include "shared-bindings/alarm/time/TimeAlarm.h"
Expand All @@ -38,20 +40,21 @@
#include "supervisor/port.h"
#include "supervisor/shared/workflow.h"

#include "common-hal/alarm/__init__.h"

#include "esp_sleep.h"

#include "components/soc/soc/esp32s2/include/soc/rtc_cntl_reg.h"
#include "components/driver/include/driver/uart.h"

// Singleton instance of SleepMemory.
const alarm_sleep_memory_obj_t alarm_sleep_memory_obj = {
.base = {
.type = &alarm_sleep_memory_type,
},
};


void alarm_reset(void) {
alarm_time_timealarm_reset();
alarm_pin_pinalarm_reset();
alarm_sleep_memory_reset();
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);
}
Expand All @@ -60,6 +63,9 @@ STATIC esp_sleep_wakeup_cause_t _get_wakeup_cause(void) {
if (alarm_time_timealarm_woke_us_up()) {
return ESP_SLEEP_WAKEUP_TIMER;
}
if (alarm_pin_pinalarm_woke_us_up()) {
return ESP_SLEEP_WAKEUP_GPIO;
}

return esp_sleep_get_wakeup_cause();
}
Expand All @@ -69,14 +75,16 @@ bool alarm_woken_from_sleep(void) {
}

STATIC mp_obj_t _get_wake_alarm(size_t n_alarms, const mp_obj_t *alarms) {
switch (_get_wakeup_cause()) {
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);
}

case ESP_SLEEP_WAKEUP_EXT0: {
// TODO: implement pin alarm wake.
break;
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);
}

case ESP_SLEEP_WAKEUP_TOUCHPAD:
Expand All @@ -98,24 +106,8 @@ mp_obj_t common_hal_alarm_get_wake_alarm(void) {

// 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) {
bool time_alarm_set = false;
alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_NULL;

for (size_t i = 0; i < n_alarms; i++) {
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
mp_raise_NotImplementedError(translate("PinAlarm not yet implemented"));
} else if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) {
if (time_alarm_set) {
mp_raise_ValueError(translate("Only one alarm.time alarm can be set."));
}
time_alarm = MP_OBJ_TO_PTR(alarms[i]);
time_alarm_set = true;
}
}

if (time_alarm_set) {
alarm_time_timealarm_set_alarm(time_alarm);
}
alarm_pin_pinalarm_set_alarms(deep_sleep, n_alarms, alarms);
alarm_time_timealarm_set_alarms(deep_sleep, n_alarms, alarms);
tannewt marked this conversation as resolved.
Show resolved Hide resolved
}

STATIC void _idle_until_alarm(void) {
Expand All @@ -131,21 +123,16 @@ STATIC void _idle_until_alarm(void) {
}
}

// Is it safe to do a light sleep? Check whether WiFi is on or there are
// other ongoing tasks that should not be shut down.
STATIC bool _light_sleep_ok(void) {
return !common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) && !supervisor_workflow_active();
}

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);

// Light sleep can break some functionality so only do it when possible. Otherwise we idle.
if (_light_sleep_ok()) {
esp_light_sleep_start();
} else {
_idle_until_alarm();
// We cannot esp_light_sleep_start() here because it shuts down all non-RTC peripherals.
_idle_until_alarm();

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;
Expand All @@ -156,7 +143,12 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala
}

void NORETURN alarm_enter_deep_sleep(void) {
alarm_pin_pinalarm_prepare_for_deep_sleep();
// The ESP-IDF caches the deep sleep settings and applies them before sleep.
// We don't need to worry about resetting them in the interim.
esp_deep_sleep_start();
}

void common_hal_alarm_gc_collect(void) {
gc_collect_ptr(alarm_get_wake_alarm());
}
Loading