deep sleep working; deep sleep delay when connected

This commit is contained in:
Dan Halbert 2020-11-26 22:06:37 -05:00
parent ef0830bfe2
commit 104a089677
15 changed files with 143 additions and 155 deletions

82
main.c
View File

@ -66,9 +66,6 @@
#include "boards/board.h" #include "boards/board.h"
// REMOVE ***********
#include "esp_log.h"
#if CIRCUITPY_ALARM #if CIRCUITPY_ALARM
#include "shared-bindings/alarm/__init__.h" #include "shared-bindings/alarm/__init__.h"
#endif #endif
@ -98,12 +95,6 @@
#include "common-hal/canio/CAN.h" #include "common-hal/canio/CAN.h"
#endif #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 #if MICROPY_ENABLE_PYSTACK
static size_t PLACE_IN_DTCM_BSS(_pystack[CIRCUITPY_PYSTACK_SIZE / sizeof(size_t)]); static size_t PLACE_IN_DTCM_BSS(_pystack[CIRCUITPY_PYSTACK_SIZE / sizeof(size_t)]);
#endif #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) { STATIC bool run_code_py(safe_mode_t safe_mode) {
bool serial_connected_at_start = serial_connected(); bool serial_connected_at_start = serial_connected();
#if CIRCUITPY_AUTORELOAD_DELAY_MS > 0 #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) { if (safe_mode == NO_SAFE_MODE) {
new_status_color(MAIN_RUNNING); 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 #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", static const char * const double_extension_filenames[] = STRING_LIST(
"main.txt.py", "main.py.txt", "main.txt.txt","main.py.py"); "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 #endif
stack_resize(); stack_resize();
@ -319,7 +301,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
// Program has finished running. // Program has finished running.
// Display a different completion message if the user has no USB attached (cannot save files) // 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")); 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 #if CIRCUITPY_DISPLAYIO
bool refreshed_epaper_display = false; bool refreshed_epaper_display = false;
#endif #endif
rgb_status_animation_t animation; 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); prep_rgb_status_animation(&result, found_main, safe_mode, &animation);
while (true) { while (true) {
@ -360,12 +334,10 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
if (!serial_connected_at_start) { if (!serial_connected_at_start) {
print_code_py_status_message(safe_mode); 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);
print_safe_mode_message(safe_mode); serial_write("\n");
serial_write("\n"); serial_write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload."));
serial_write_compressed(translate("Press any key to enter the REPL. Use CTRL-D to reload."));
}
} }
if (serial_connected_before_animation && !serial_connected()) { if (serial_connected_before_animation && !serial_connected()) {
serial_connected_at_start = false; serial_connected_at_start = false;
@ -379,37 +351,7 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
} }
#endif #endif
bool animation_done = false; tick_rgb_status_animation(&animation);
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();
}
}
} }
} }

View File

@ -84,10 +84,6 @@ void common_hal_mcu_reset(void) {
reset(); reset();
} }
void common_hal_mcu_deep_sleep(void) {
//deep sleep call here
}
// The singleton microcontroller.Processor object, bound to microcontroller.cpu // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
const mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {

View File

@ -81,10 +81,6 @@ void common_hal_mcu_reset(void) {
boardctl(BOARDIOC_RESET, 0); 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[] = { 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_RXD), MP_ROM_PTR(&pin_UART2_RXD) },
{ MP_ROM_QSTR(MP_QSTR_UART2_TXD), MP_ROM_PTR(&pin_UART2_TXD) }, { MP_ROM_QSTR(MP_QSTR_UART2_TXD), MP_ROM_PTR(&pin_UART2_TXD) },

View File

@ -1,4 +1,4 @@
/* /*
* This file is part of the MicroPython project, http://micropython.org/ * This file is part of the MicroPython project, http://micropython.org/
* *
* The MIT License (MIT) * The MIT License (MIT)
@ -77,12 +77,10 @@ mp_obj_t common_hal_alarm_get_wake_alarm(void) {
return mp_const_none; return mp_const_none;
} }
mp_obj_t common_hal_alarm_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) { STATIC void setup_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) {
bool time_alarm_set = false; 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++) { for (size_t i = 0; i < n_alarms; i++) {
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) { if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
mp_raise_NotImplementedError(translate("PinAlarm deep sleep not yet implemented")); 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) { if (time_alarm_set) {
mp_raise_ValueError(translate("Only one alarm.time alarm can be 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; 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 mp_obj_t common_hal_alarm_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
// or otherwise already triggered. setup_alarms(n_alarms, alarms);
bool common_hal_alarm_enable_deep_sleep_alarms(void) {
for (size_t i = 0; i < _deep_sleep_alarms->len; i++) { // Shut down wifi cleanly.
mp_obj_t alarm = _deep_sleep_alarms->items[i]; esp_wifi_stop();
if (MP_OBJ_IS_TYPE(alarm, &alarm_pin_pin_alarm_type)) { esp_light_sleep_start();
// TODO: handle pin alarms return common_hal_alarm_get_wake_alarm();
mp_raise_NotImplementedError(translate("PinAlarm deep sleep not yet implemented")); }
}
else if (MP_OBJ_IS_TYPE(alarm, &alarm_time_time_alarm_type)) { void common_hal_alarm_exit_and_deep_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_TO_PTR(alarm); setup_alarms(n_alarms, alarms);
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. // Shut down wifi cleanly.
mp_float_t wakeup_in_secs = time_alarm->monotonic_time - now_secs; esp_wifi_stop();
if (wakeup_in_secs <= 0.0f) { esp_deep_sleep_start();
return false;
}
esp_sleep_enable_timer_wakeup((uint64_t) (wakeup_in_secs * 1000000));
}
}
return true;
} }

View File

@ -81,12 +81,6 @@ void common_hal_mcu_reset(void) {
while(1); 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 // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
const mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {

View File

@ -89,10 +89,6 @@ void common_hal_mcu_reset(void) {
while(1); while(1);
} }
void common_hal_mcu_deep_sleep(void) {
//deep sleep call here
}
// The singleton microcontroller.Processor object, bound to microcontroller.cpu // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
const mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {

View File

@ -86,10 +86,6 @@ void common_hal_mcu_reset(void) {
NVIC_SystemReset(); NVIC_SystemReset();
} }
void common_hal_mcu_deep_sleep(void) {
//deep sleep call here
}
// The singleton microcontroller.Processor object, bound to microcontroller.cpu // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
const mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {

View File

@ -95,10 +95,6 @@ void common_hal_mcu_reset(void) {
reset_cpu(); reset_cpu();
} }
void common_hal_mcu_deep_sleep(void) {
//deep sleep call here
}
// The singleton microcontroller.Processor object, bound to microcontroller.cpu // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
const mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {

View File

@ -81,10 +81,6 @@ void common_hal_mcu_reset(void) {
NVIC_SystemReset(); NVIC_SystemReset();
} }
void common_hal_mcu_deep_sleep(void) {
//deep sleep call here
}
// The singleton microcontroller.Processor object, bound to microcontroller.cpu // The singleton microcontroller.Processor object, bound to microcontroller.cpu
// It currently only has properties, and no state. // It currently only has properties, and no state.
const mcu_processor_obj_t common_hal_mcu_processor_obj = { const mcu_processor_obj_t common_hal_mcu_processor_obj = {

View File

@ -54,12 +54,12 @@ FrameBuffer = Union[rgbmatrix.RGBMatrix]
""" """
Alarm = Union[ Alarm = Union[
alarm.pin.PinAlarm, alarm.time.DurationAlarm alarm.pin.PinAlarm, alarm.time.TimeAlarm
] ]
"""Classes that implement alarms for sleeping and asynchronous notification. """Classes that implement alarms for sleeping and asynchronous notification.
- `alarm.pin.PinAlarm` - `alarm.pin.PinAlarm`
- `alarm.time.DurationAlarm` - `alarm.time.TimeAlarm`
You can use these alarms to wake from light or deep sleep. You can use these alarms to wake from light or deep sleep.
""" """

View File

@ -30,6 +30,15 @@
#include "shared-bindings/alarm/__init__.h" #include "shared-bindings/alarm/__init__.h"
#include "shared-bindings/alarm/pin/PinAlarm.h" #include "shared-bindings/alarm/pin/PinAlarm.h"
#include "shared-bindings/alarm/time/TimeAlarm.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. //| """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 //| 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 //| a more significant amount of power, but CircuitPython must start ``code.py`` from the beginning when
//| awakened. //| 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 //| wake_alarm: Alarm
//| """The most recent alarm to wake us up from a sleep (light or deep.)""" //| """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) { void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) {
for (size_t i = 0; i < n_args; i++) { for (size_t i = 0; i < n_args; i++) {
if (MP_OBJ_IS_TYPE(objs[i], &alarm_pin_pin_alarm_type) || 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. //| For time-base alarms, currently, an `alarm.time.TimeAlarm()` is created.
//| //|
//| If no alarms are specified, the microcontroller will deep sleep until reset. //| 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) { 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); 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; 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); 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);

View File

@ -32,8 +32,7 @@
#include "common-hal/alarm/__init__.h" #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 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_exit_and_deep_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms);
extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms);
// Used by wake-up code. // Used by wake-up code.
extern void common_hal_alarm_set_wake_alarm(mp_obj_t alarm); extern void common_hal_alarm_set_wake_alarm(mp_obj_t alarm);

View File

@ -41,7 +41,7 @@
//| def __init__(self, *pins: microcontroller.Pin, value: bool, all_same_value: bool = False, edge: bool = False, pull: bool = False) -> None: //| 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 //| """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 //| 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 //| :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. //| may be limited due to hardware restrictions, particularly for deep-sleep alarms.

View File

@ -24,25 +24,32 @@
* THE SOFTWARE. * 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/nlr.h"
#include "py/obj.h" #include "py/obj.h"
#include "py/objproperty.h" #include "py/objproperty.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "shared-bindings/time/__init__.h"
#include "shared-bindings/alarm/time/TimeAlarm.h"
#include "supervisor/shared/translate.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: //| 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 //| """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 //| The alarm is not active until it is passed to an
//| `alarm`-enabling function, such as `alarm.sleep_until_alarms()` or //| `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 //| If the given time is in the past when sleep occurs, the alarm will be triggered
//| immediately. //| immediately.
@ -50,21 +57,64 @@
//| ... //| ...
//| //|
STATIC mp_obj_t alarm_time_time_alarm_make_new(const mp_obj_type_t *type, 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_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_arg_check_num(n_args, kw_args, 1, 1, false);
alarm_time_time_alarm_obj_t *self = m_new_obj(alarm_time_time_alarm_obj_t); alarm_time_time_alarm_obj_t *self = m_new_obj(alarm_time_time_alarm_obj_t);
self->base.type = &alarm_time_time_alarm_type; 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); return MP_OBJ_FROM_PTR(self);
} }
//| monotonic_time: float //| 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) { 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); alarm_time_time_alarm_obj_t *self = MP_OBJ_TO_PTR(self_in);

View File

@ -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_on_next_reset(mcu_runmode_t runmode);
extern void common_hal_mcu_reset(void); 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 mp_obj_dict_t mcu_pin_globals;
extern const mcu_processor_obj_t common_hal_mcu_processor_obj; extern const mcu_processor_obj_t common_hal_mcu_processor_obj;