From 104a089677d62de3554deea7850796dfbb29b1fc Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 26 Nov 2020 22:06:37 -0500 Subject: [PATCH] deep sleep working; deep sleep delay when connected --- main.c | 82 +++---------------- .../common-hal/microcontroller/__init__.c | 4 - .../common-hal/microcontroller/__init__.c | 4 - ports/esp32s2/common-hal/alarm/__init__.c | 54 ++++++------ .../common-hal/microcontroller/__init__.c | 6 -- .../common-hal/microcontroller/__init__.c | 4 - .../common-hal/microcontroller/__init__.c | 4 - .../nrf/common-hal/microcontroller/__init__.c | 4 - .../stm/common-hal/microcontroller/__init__.c | 4 - shared-bindings/_typing/__init__.pyi | 4 +- shared-bindings/alarm/__init__.c | 43 ++++++++-- shared-bindings/alarm/__init__.h | 3 +- shared-bindings/alarm/pin/PinAlarm.c | 2 +- shared-bindings/alarm/time/TimeAlarm.c | 78 ++++++++++++++---- shared-bindings/microcontroller/__init__.h | 2 - 15 files changed, 143 insertions(+), 155 deletions(-) diff --git a/main.c b/main.c index a9dbb1b7c3..dda439d6de 100755 --- a/main.c +++ b/main.c @@ -66,9 +66,6 @@ #include "boards/board.h" -// REMOVE *********** -#include "esp_log.h" - #if CIRCUITPY_ALARM #include "shared-bindings/alarm/__init__.h" #endif @@ -98,12 +95,6 @@ #include "common-hal/canio/CAN.h" #endif -// How long to wait for host to start connecting.. -#define CIRCUITPY_USB_CONNECTING_DELAY 1 - -// How long to flash errors on the RGB status LED before going to sleep (secs) -#define CIRCUITPY_FLASH_ERROR_PERIOD 10 - #if MICROPY_ENABLE_PYSTACK static size_t PLACE_IN_DTCM_BSS(_pystack[CIRCUITPY_PYSTACK_SIZE / sizeof(size_t)]); #endif @@ -259,17 +250,6 @@ STATIC void print_code_py_status_message(safe_mode_t safe_mode) { } } -// Should we go into deep sleep when program finishes? -// Normally we won't deep sleep if there was an error or if we are connected to a host -// but either of those can be enabled. -// It's ok to deep sleep if we're not connected to a host, but we need to make sure -// we're giving enough time for USB to start to connect -STATIC bool deep_sleep_allowed(void) { - return - (ok || supervisor_workflow_get_allow_deep_sleep_on_error()) && - !supervisor_workflow_connecting() - (supervisor_ticks_ms64() > CIRCUITPY_USB_CONNECTING_DELAY * 1024); - STATIC bool run_code_py(safe_mode_t safe_mode) { bool serial_connected_at_start = serial_connected(); #if CIRCUITPY_AUTORELOAD_DELAY_MS > 0 @@ -290,10 +270,12 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { if (safe_mode == NO_SAFE_MODE) { new_status_color(MAIN_RUNNING); - static const char * const supported_filenames[] = STRING_LIST("code.txt", "code.py", "main.py", "main.txt"); + static const char * const supported_filenames[] = STRING_LIST( + "code.txt", "code.py", "main.py", "main.txt"); #if CIRCUITPY_FULL_BUILD - static const char * const double_extension_filenames[] = STRING_LIST("code.txt.py", "code.py.txt", "code.txt.txt","code.py.py", - "main.txt.py", "main.py.txt", "main.txt.txt","main.py.py"); + static const char * const double_extension_filenames[] = STRING_LIST( + "code.txt.py", "code.py.txt", "code.txt.txt","code.py.py", + "main.txt.py", "main.py.txt", "main.txt.txt","main.py.py"); #endif stack_resize(); @@ -319,7 +301,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { // Program has finished running. // Display a different completion message if the user has no USB attached (cannot save files) - if (!serial_connected_at_start && !deep_sleep_allowed()) { + if (!serial_connected_at_start) { serial_write_compressed(translate("\nCode done running. Waiting for reload.\n")); } @@ -327,16 +309,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { #if CIRCUITPY_DISPLAYIO bool refreshed_epaper_display = false; #endif + rgb_status_animation_t animation; - bool ok = result.return_code != PYEXEC_EXCEPTION; - - #if CIRCUITPY_ALARM - // Enable pin or time alarms before sleeping. - // If immediate_wake is true, then there's an alarm that would trigger immediately, - // so don't sleep. - bool immediate_wake = !common_hal_alarm_enable_deep_sleep_alarms(); - #endif - prep_rgb_status_animation(&result, found_main, safe_mode, &animation); while (true) { @@ -360,12 +334,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { if (!serial_connected_at_start) { print_code_py_status_message(safe_mode); } - // We won't be going into the REPL if we're going to sleep. - if (!deep_sleep_allowed()) { - print_safe_mode_message(safe_mode); - serial_write("\n"); - serial_write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload.")); - } + + print_safe_mode_message(safe_mode); + serial_write("\n"); + serial_write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload.")); } if (serial_connected_before_animation && !serial_connected()) { serial_connected_at_start = false; @@ -379,37 +351,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) { } #endif - bool animation_done = false; - - if (deep_sleep_allowed() && ok) { - // Skip animation if everything is OK. - animation_done = true; - } else { - animation_done = tick_rgb_status_animation(&animation); - } - // Do an error animation only once before deep-sleeping. - if (animation_done) { - if (immediate_wake) { - // Don't sleep, we are already supposed to wake up. - return true; - } - if (deep_sleep_allowed()) { - common_hal_mcu_deep_sleep(); - // Does not return. - } - - // Wake up every so often to flash the error code. - if (!ok) { - port_interrupt_after_ticks(CIRCUITPY_FLASH_ERROR_PERIOD * 1024); - } else { - int64_t remaining_connecting_wait = - CIRCUITPY_USB_CONNECTING_DELAY * 1024 - supervisor_ticks_ms64(); - if (remaining_connecting_wait > 0) { - port_interrupt_after_ticks(remaining_connecting_wait); - } - port_sleep_until_interrupt(); - } - } + tick_rgb_status_animation(&animation); } } diff --git a/ports/atmel-samd/common-hal/microcontroller/__init__.c b/ports/atmel-samd/common-hal/microcontroller/__init__.c index ca39f28386..50a1ec038e 100644 --- a/ports/atmel-samd/common-hal/microcontroller/__init__.c +++ b/ports/atmel-samd/common-hal/microcontroller/__init__.c @@ -84,10 +84,6 @@ void common_hal_mcu_reset(void) { reset(); } -void common_hal_mcu_deep_sleep(void) { - //deep sleep call here -} - // The singleton microcontroller.Processor object, bound to microcontroller.cpu // It currently only has properties, and no state. const mcu_processor_obj_t common_hal_mcu_processor_obj = { diff --git a/ports/cxd56/common-hal/microcontroller/__init__.c b/ports/cxd56/common-hal/microcontroller/__init__.c index 57140dec70..7aa3b839d7 100644 --- a/ports/cxd56/common-hal/microcontroller/__init__.c +++ b/ports/cxd56/common-hal/microcontroller/__init__.c @@ -81,10 +81,6 @@ void common_hal_mcu_reset(void) { boardctl(BOARDIOC_RESET, 0); } -void common_hal_mcu_deep_sleep(void) { - //deep sleep call here -} - STATIC const mp_rom_map_elem_t mcu_pin_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_UART2_RXD), MP_ROM_PTR(&pin_UART2_RXD) }, { MP_ROM_QSTR(MP_QSTR_UART2_TXD), MP_ROM_PTR(&pin_UART2_TXD) }, diff --git a/ports/esp32s2/common-hal/alarm/__init__.c b/ports/esp32s2/common-hal/alarm/__init__.c index 7cf74a0efc..767b0de70e 100644 --- a/ports/esp32s2/common-hal/alarm/__init__.c +++ b/ports/esp32s2/common-hal/alarm/__init__.c @@ -1,4 +1,4 @@ -/* + /* * This file is part of the MicroPython project, http://micropython.org/ * * The MIT License (MIT) @@ -77,12 +77,10 @@ mp_obj_t common_hal_alarm_get_wake_alarm(void) { return mp_const_none; } -mp_obj_t common_hal_alarm_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) { - mp_raise_NotImplementedError(NULL); -} - -void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) { +STATIC void setup_alarms(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 deep sleep not yet implemented")); @@ -91,32 +89,32 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala 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; } } - _deep_sleep_alarms = mp_obj_new_tuple(n_alarms, alarms); + if (time_alarm != MP_OBJ_NULL) { + // Compute how long to actually sleep, considering the time now. + mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f; + mp_float_t wakeup_in_secs = MAX(0.0f, time_alarm->monotonic_time - now_secs); + esp_sleep_enable_timer_wakeup((uint64_t) (wakeup_in_secs * 1000000)); + } } -// Return false if we should wake up immediately because a time alarm is in the past -// or otherwise already triggered. -bool common_hal_alarm_enable_deep_sleep_alarms(void) { - for (size_t i = 0; i < _deep_sleep_alarms->len; i++) { - mp_obj_t alarm = _deep_sleep_alarms->items[i]; - if (MP_OBJ_IS_TYPE(alarm, &alarm_pin_pin_alarm_type)) { - // TODO: handle pin alarms - mp_raise_NotImplementedError(translate("PinAlarm deep sleep not yet implemented")); - } - else if (MP_OBJ_IS_TYPE(alarm, &alarm_time_time_alarm_type)) { - alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_TO_PTR(alarm); - mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f; - // Compute how long to actually sleep, considering hte time now. - mp_float_t wakeup_in_secs = time_alarm->monotonic_time - now_secs; - if (wakeup_in_secs <= 0.0f) { - return false; - } - esp_sleep_enable_timer_wakeup((uint64_t) (wakeup_in_secs * 1000000)); - } - } - return true; +mp_obj_t common_hal_alarm_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) { + setup_alarms(n_alarms, alarms); + + // Shut down wifi cleanly. + esp_wifi_stop(); + esp_light_sleep_start(); + return common_hal_alarm_get_wake_alarm(); +} + +void common_hal_alarm_exit_and_deep_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) { + setup_alarms(n_alarms, alarms); + + // Shut down wifi cleanly. + esp_wifi_stop(); + esp_deep_sleep_start(); } diff --git a/ports/esp32s2/common-hal/microcontroller/__init__.c b/ports/esp32s2/common-hal/microcontroller/__init__.c index 3578b86d02..184f5be696 100644 --- a/ports/esp32s2/common-hal/microcontroller/__init__.c +++ b/ports/esp32s2/common-hal/microcontroller/__init__.c @@ -81,12 +81,6 @@ void common_hal_mcu_reset(void) { while(1); } -void NORETURN common_hal_mcu_deep_sleep(void) { - // Shut down wifi cleanly. - esp_wifi_stop(); - esp_deep_sleep_start(); -} - // The singleton microcontroller.Processor object, bound to microcontroller.cpu // It currently only has properties, and no state. const mcu_processor_obj_t common_hal_mcu_processor_obj = { diff --git a/ports/litex/common-hal/microcontroller/__init__.c b/ports/litex/common-hal/microcontroller/__init__.c index e6f50ed5a6..3c91661144 100644 --- a/ports/litex/common-hal/microcontroller/__init__.c +++ b/ports/litex/common-hal/microcontroller/__init__.c @@ -89,10 +89,6 @@ void common_hal_mcu_reset(void) { while(1); } -void common_hal_mcu_deep_sleep(void) { - //deep sleep call here -} - // The singleton microcontroller.Processor object, bound to microcontroller.cpu // It currently only has properties, and no state. const mcu_processor_obj_t common_hal_mcu_processor_obj = { diff --git a/ports/mimxrt10xx/common-hal/microcontroller/__init__.c b/ports/mimxrt10xx/common-hal/microcontroller/__init__.c index 0329ced69b..6a8537e2da 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/__init__.c +++ b/ports/mimxrt10xx/common-hal/microcontroller/__init__.c @@ -86,10 +86,6 @@ void common_hal_mcu_reset(void) { NVIC_SystemReset(); } -void common_hal_mcu_deep_sleep(void) { - //deep sleep call here -} - // The singleton microcontroller.Processor object, bound to microcontroller.cpu // It currently only has properties, and no state. const mcu_processor_obj_t common_hal_mcu_processor_obj = { diff --git a/ports/nrf/common-hal/microcontroller/__init__.c b/ports/nrf/common-hal/microcontroller/__init__.c index 9911896bff..06aac9409d 100644 --- a/ports/nrf/common-hal/microcontroller/__init__.c +++ b/ports/nrf/common-hal/microcontroller/__init__.c @@ -95,10 +95,6 @@ void common_hal_mcu_reset(void) { reset_cpu(); } -void common_hal_mcu_deep_sleep(void) { - //deep sleep call here -} - // The singleton microcontroller.Processor object, bound to microcontroller.cpu // It currently only has properties, and no state. const mcu_processor_obj_t common_hal_mcu_processor_obj = { diff --git a/ports/stm/common-hal/microcontroller/__init__.c b/ports/stm/common-hal/microcontroller/__init__.c index bc81b0e4f5..a827399ccb 100644 --- a/ports/stm/common-hal/microcontroller/__init__.c +++ b/ports/stm/common-hal/microcontroller/__init__.c @@ -81,10 +81,6 @@ void common_hal_mcu_reset(void) { NVIC_SystemReset(); } -void common_hal_mcu_deep_sleep(void) { - //deep sleep call here -} - // The singleton microcontroller.Processor object, bound to microcontroller.cpu // It currently only has properties, and no state. const mcu_processor_obj_t common_hal_mcu_processor_obj = { diff --git a/shared-bindings/_typing/__init__.pyi b/shared-bindings/_typing/__init__.pyi index 02839ab477..2716936860 100644 --- a/shared-bindings/_typing/__init__.pyi +++ b/shared-bindings/_typing/__init__.pyi @@ -54,12 +54,12 @@ FrameBuffer = Union[rgbmatrix.RGBMatrix] """ Alarm = Union[ - alarm.pin.PinAlarm, alarm.time.DurationAlarm + alarm.pin.PinAlarm, alarm.time.TimeAlarm ] """Classes that implement alarms for sleeping and asynchronous notification. - `alarm.pin.PinAlarm` - - `alarm.time.DurationAlarm` + - `alarm.time.TimeAlarm` You can use these alarms to wake from light or deep sleep. """ diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index 4aa6c8457d..4c2189c0d0 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -30,6 +30,15 @@ #include "shared-bindings/alarm/__init__.h" #include "shared-bindings/alarm/pin/PinAlarm.h" #include "shared-bindings/alarm/time/TimeAlarm.h" +#include "shared-bindings/time/__init__.h" +#include "supervisor/shared/rgb_led_status.h" +#include "supervisor/shared/workflow.h" + +// Wait this long to see if USB is being connected (enumeration starting). +#define CIRCUITPY_USB_CONNECTING_DELAY 1 +// Wait this long before going into deep sleep if connected. This +// allows the user to ctrl-C before deep sleep starts. +#define CIRCUITPY_USB_CONNECTED_DEEP_SLEEP_DELAY 5 //| """Power-saving light and deep sleep. Alarms can be set to wake up from sleep. //| @@ -44,16 +53,12 @@ //| Deep sleep shuts down power to nearly all of the chip including the CPU and RAM. This can save //| a more significant amount of power, but CircuitPython must start ``code.py`` from the beginning when //| awakened. +//| """ -//| -//| An error includes an uncaught exception, or sys.exit() called with a non-zero argument -//| -//| To set alarms for deep sleep use `alarm.set_deep_sleep_alarms()` they will apply to next deep sleep only.""" //| //| wake_alarm: Alarm //| """The most recent alarm to wake us up from a sleep (light or deep.)""" //| - void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) { for (size_t i = 0; i < n_args; i++) { if (MP_OBJ_IS_TYPE(objs[i], &alarm_pin_pin_alarm_type) || @@ -88,12 +93,38 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ //| For time-base alarms, currently, an `alarm.time.TimeAlarm()` is created. //| //| If no alarms are specified, the microcontroller will deep sleep until reset. +//| +//| If CircuitPython is unconnected to a host computer, go into deep sleep immediately. +//| But if it already connected or in the process of connecting to a host computer, wait at least +//| five seconds after starting code.py before entering deep sleep. +//| This allows interrupting a program that would otherwise go into deep sleep too quickly +//| to interrupt from the keyboard. //| """ //| ... //| STATIC mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_obj_t *args) { validate_objs_are_alarms(n_args, args); - common_hal_exit_and_deep_sleep_until_alarms(n_args, args); + + int64_t connecting_delay_msec = CIRCUITPY_USB_CONNECTING_DELAY * 1024 - supervisor_ticks_ms64(); + if (connecting_delay_msec > 0) { + common_hal_time_delay_ms(connecting_delay_msec * 1000 / 1024); + } + + // If connected, wait for the program to be running at least as long as + // CIRCUITPY_USB_CONNECTED_DEEP_SLEEP_DELAY. This allows a user to ctrl-C the running + // program in case it is in a tight deep sleep loop that would otherwise be difficult + // or impossible to interrupt. + // Indicate that we're delaying with the SAFE_MODE color. + int64_t delay_before_sleeping_msec = + supervisor_ticks_ms64() - CIRCUITPY_USB_CONNECTED_DEEP_SLEEP_DELAY * 1000; + if (supervisor_workflow_connecting() && delay_before_sleeping_msec > 0) { + temp_status_color(SAFE_MODE); + common_hal_time_delay_ms(delay_before_sleeping_msec); + clear_temp_status(); + } + + common_hal_alarm_exit_and_deep_sleep_until_alarms(n_args, args); + // Does not return. return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_exit_and_deep_sleep_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_exit_and_deep_sleep_until_alarms); diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h index 0f084c78e8..968136345c 100644 --- a/shared-bindings/alarm/__init__.h +++ b/shared-bindings/alarm/__init__.h @@ -32,8 +32,7 @@ #include "common-hal/alarm/__init__.h" extern mp_obj_t common_hal_alarm_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms); -extern bool common_hal_alarm_enable_deep_sleep_alarms(void); -extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms); +extern void common_hal_alarm_exit_and_deep_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms); // Used by wake-up code. extern void common_hal_alarm_set_wake_alarm(mp_obj_t alarm); diff --git a/shared-bindings/alarm/pin/PinAlarm.c b/shared-bindings/alarm/pin/PinAlarm.c index ff7b19ca1f..fadd1b0d4a 100644 --- a/shared-bindings/alarm/pin/PinAlarm.c +++ b/shared-bindings/alarm/pin/PinAlarm.c @@ -41,7 +41,7 @@ //| def __init__(self, *pins: microcontroller.Pin, value: bool, all_same_value: bool = False, edge: bool = False, pull: bool = False) -> None: //| """Create an alarm triggered by a `microcontroller.Pin` level. The alarm is not active //| until it is passed to an `alarm`-enabling function, such as `alarm.sleep_until_alarms()` or -//| `alarm.set_deep_sleep_alarms()`. +//| `alarm.exit_and_deep_sleep_until_alarms()`. //| //| :param microcontroller.Pin \*pins: The pins to monitor. On some ports, the choice of pins //| may be limited due to hardware restrictions, particularly for deep-sleep alarms. diff --git a/shared-bindings/alarm/time/TimeAlarm.c b/shared-bindings/alarm/time/TimeAlarm.c index 864ece284e..6339b850c6 100644 --- a/shared-bindings/alarm/time/TimeAlarm.c +++ b/shared-bindings/alarm/time/TimeAlarm.c @@ -24,25 +24,32 @@ * THE SOFTWARE. */ -#include "shared-bindings/board/__init__.h" -#include "shared-bindings/microcontroller/__init__.h" -#include "shared-bindings/alarm/time/TimeAlarm.h" - #include "py/nlr.h" #include "py/obj.h" #include "py/objproperty.h" #include "py/runtime.h" + +#include "shared-bindings/time/__init__.h" +#include "shared-bindings/alarm/time/TimeAlarm.h" + #include "supervisor/shared/translate.h" +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE +mp_obj_t MP_WEAK rtc_get_time_source_time(void) { + mp_raise_RuntimeError(translate("RTC is not supported on this board")); +} +#endif + //| class TimeAlarm: -//| """Trigger an alarm when `time.monotonic()` reaches the given value.""" +//| """Trigger an alarm when the specified time is reached.""" //| -//| def __init__(self, monotonic_time: float) -> None: +//| def __init__(self, monotonic_time: Optional[Float] = None, epoch_time: Optional[int] = None) -> None: //| """Create an alarm that will be triggered when `time.monotonic()` would equal -//| ``monotonic_time``. +//| ``monotonic_time``, or when `time.time()` would equal ``epoch_time``. +//| Only one of the two arguments can be given. //| The alarm is not active until it is passed to an //| `alarm`-enabling function, such as `alarm.sleep_until_alarms()` or -//| `alarm.set_deep_sleep_alarms()`. +//| `alarm.exit_and_deep_sleep_until_alarms()`. //| //| If the given time is in the past when sleep occurs, the alarm will be triggered //| immediately. @@ -50,21 +57,64 @@ //| ... //| STATIC mp_obj_t alarm_time_time_alarm_make_new(const mp_obj_type_t *type, - mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { - mp_arg_check_num(n_args, kw_args, 1, 1, false); - + mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { alarm_time_time_alarm_obj_t *self = m_new_obj(alarm_time_time_alarm_obj_t); self->base.type = &alarm_time_time_alarm_type; - mp_float_t secs = mp_obj_get_float(args[0]); + enum { ARG_monotonic_time, ARG_epoch_time }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_monotonic_time, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_epoch_time, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; - common_hal_alarm_time_time_alarm_construct(self, secs); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + bool have_monotonic = args[ARG_monotonic_time].u_obj != mp_const_none; + bool have_epoch = args[ARG_epoch_time].u_obj != mp_const_none; + + if (!(have_monotonic ^ have_epoch)) { + mp_raise_ValueError(translate("Supply one of monotonic_time or epoch_time")); + } + + mp_float_t monotonic_time = 0; // To avoid compiler warning. + if (have_monotonic) { + monotonic_time = mp_obj_get_float(args[ARG_monotonic_time].u_obj); + } + + mp_float_t monotonic_time_now = common_hal_time_monotonic_ms() / 1000.0; + + if (have_epoch) { +#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_NONE + mp_raise_ValueError(translate("epoch_time not supported on this board")); +#else + mp_uint_t epoch_time_secs = mp_obj_int_get_checked(args[ARG_epoch_time].u_obj); + + timeutils_struct_time_t tm; + struct_time_to_tm(rtc_get_time_source_time(), &tm); + mp_uint_t epoch_secs_now = timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + // How far in the future (in secs) is the requested time? + mp_int_t epoch_diff = epoch_time_secs - epoch_secs_now; + // Convert it to a future monotonic time. + monotonic_time = monotonic_time_now + epoch_diff; +#endif + } + + if (monotonic_time < monotonic_time_now) { + mp_raise_ValueError(translate("Time is in the past.")); + } + + common_hal_alarm_time_time_alarm_construct(self, monotonic_time); return MP_OBJ_FROM_PTR(self); } //| monotonic_time: float -//| """The time at which to trigger, based on the `time.monotonic()` clock.""" +//| """When this time is reached, the alarm will trigger, based on the `time.monotonic()` clock. +//| The time may be given as ``epoch_time`` in the constructor, but it is returned +//| by this property only as a `time.monotonic()` time. +//| """ //| STATIC mp_obj_t alarm_time_time_alarm_obj_get_monotonic_time(mp_obj_t self_in) { alarm_time_time_alarm_obj_t *self = MP_OBJ_TO_PTR(self_in); diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index 87284fc2e5..ac71de4247 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -43,8 +43,6 @@ extern void common_hal_mcu_enable_interrupts(void); extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode); extern void common_hal_mcu_reset(void); -extern void NORETURN common_hal_mcu_deep_sleep(void); - extern const mp_obj_dict_t mcu_pin_globals; extern const mcu_processor_obj_t common_hal_mcu_processor_obj;