From 28714963d5b22519dba8b9c6366f536ec078dc1c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 17 Feb 2022 15:24:31 -0500 Subject: [PATCH] don't wait for USB or BLE workflow after true deep sleep --- main.c | 30 +++++++++++++++++++++--------- py/circuitpy_mpconfig.h | 6 +++--- shared-bindings/alarm/__init__.c | 10 +++++++--- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/main.c b/main.c index b4537b1d69..3e6a34843f 100644 --- a/main.c +++ b/main.c @@ -301,7 +301,8 @@ STATIC void cleanup_after_vm(supervisor_allocation *heap, mp_obj_t exception) { STATIC void print_code_py_status_message(safe_mode_t safe_mode) { if (autoreload_is_enabled()) { - serial_write_compressed(translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n")); + serial_write_compressed( + translate("Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.\n")); } else { serial_write_compressed(translate("Auto-reload is off.\n")); } @@ -401,7 +402,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re // the options because it can be treated like any other reason-for-stickiness bit. The // source is different though: it comes from the options that will apply to the next run, // while the rest of next_code_options is what applied to this run. - if (next_code_allocation != NULL && (((next_code_info_t *)next_code_allocation->ptr)->options & SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET)) { + if (next_code_allocation != NULL && + (((next_code_info_t *)next_code_allocation->ptr)->options & SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET)) { next_code_options |= SUPERVISOR_NEXT_CODE_OPT_NEWLY_SET; } @@ -527,9 +529,9 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re // Sleep until our next interrupt. #if CIRCUITPY_ALARM if (result.return_code & PYEXEC_DEEP_SLEEP) { - // Make sure we have been awake long enough for USB to connect (enumeration delay). - int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks(NULL); - // Until it's safe to decide whether we're real/fake sleeping + const bool awoke_from_true_deep_sleep = + common_hal_mcu_processor_get_reset_reason() == RESET_REASON_DEEP_SLEEP_ALARM; + if (fake_sleeping) { // This waits until a pretend deep sleep alarm occurs. They are set // during common_hal_alarm_set_deep_sleep_alarms. On some platforms @@ -537,18 +539,28 @@ STATIC bool run_code_py(safe_mode_t safe_mode, bool first_run, bool *simulate_re // for deep sleep alarms above. If it wasn't a deep sleep alarm, // then we'll idle here again. common_hal_alarm_pretending_deep_sleep(); - } else if (connecting_delay_ticks < 0) { - // Entering deep sleep (may be fake or real.) + } + // The first time we go into a deep sleep, make sure we have been awake long enough + // for USB to connect (enumeration delay), or for the BLE workflow to start. + // We wait CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY seconds after a restart. + // But if we woke up from a real deep sleep, don't wait for connection. The user will need to + // do a hard reset to get out of the real deep sleep. + else if (awoke_from_true_deep_sleep || + port_get_raw_ticks(NULL) > CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY * 1024) { + // OK to start sleeping, real or fake. status_led_deinit(); deinit_rxtx_leds(); board_deinit(); - if (!supervisor_workflow_active()) { + + // Continue with true deep sleep even if workflow is available. + if (awoke_from_true_deep_sleep || !supervisor_workflow_active()) { // Enter true deep sleep. When we wake up we'll be back at the // top of main(), not in this loop. common_hal_alarm_enter_deep_sleep(); // Does not return. } else { - serial_write_compressed(translate("Pretending to deep sleep until alarm, CTRL-C or file write.\n")); + serial_write_compressed( + translate("Pretending to deep sleep until alarm, CTRL-C or file write.\n")); fake_sleeping = true; } } else { diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 2893df46ec..070403877f 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -447,9 +447,9 @@ void supervisor_run_background_tasks_if_tick(void); #define CIRCUITPY_PYSTACK_SIZE 1536 #endif -// Wait this long imediately after startup to see if we are connected to USB. -#ifndef CIRCUITPY_USB_CONNECTED_SLEEP_DELAY -#define CIRCUITPY_USB_CONNECTED_SLEEP_DELAY 5 +// Wait this long before sleeping immediately after startup, to see if we are connected via USB or BLE. +#ifndef CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY +#define CIRCUITPY_WORKFLOW_CONNECTION_SLEEP_DELAY 5 #endif #ifndef CIRCUITPY_PROCESSOR_COUNT diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index 9f9e01885a..340a4ea679 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -125,11 +125,15 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OB //| //| If no alarms are specified, the microcontroller will deep sleep until reset. //| -//| **If CircuitPython is connected to a host computer, the connection will be maintained, -//| and the system will not go into deep sleep.** +//| **If CircuitPython is connected to a host computer via USB or BLE +//| the first time a deep sleep is requested, +//| the connection will be maintained and the system will not go into deep sleep.** //| This allows the user to interrupt an existing program with ctrl-C, //| and to edit the files in CIRCUITPY, which would not be possible in true deep sleep. -//| Thus, to use deep sleep and save significant power, you will need to disconnect from the host. +//| +//| If CircuitPython goes into a true deep sleep, and USB or BLE is reconnected, +//| the next deep sleep will still be a true deep sleep. You must do a hard reset +//| or power-cycle to exit a true deep sleep loop. //| //| Here is skeletal example that deep-sleeps and restarts every 60 seconds: //|