summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Halbert <halbert@halwitz.org>2020-11-26 22:06:37 -0500
committerDan Halbert <halbert@halwitz.org>2020-11-26 22:06:37 -0500
commit104a089677d62de3554deea7850796dfbb29b1fc (patch)
tree35580c830283fc5eaea1e01623892eb24224b444
parentef0830bfe241b544b05bd3081f5bba03af57fe0d (diff)
deep sleep working; deep sleep delay when connected
-rwxr-xr-xmain.c82
-rw-r--r--ports/atmel-samd/common-hal/microcontroller/__init__.c4
-rw-r--r--ports/cxd56/common-hal/microcontroller/__init__.c4
-rw-r--r--ports/esp32s2/common-hal/alarm/__init__.c54
-rw-r--r--ports/esp32s2/common-hal/microcontroller/__init__.c6
-rw-r--r--ports/litex/common-hal/microcontroller/__init__.c4
-rw-r--r--ports/mimxrt10xx/common-hal/microcontroller/__init__.c4
-rw-r--r--ports/nrf/common-hal/microcontroller/__init__.c4
-rw-r--r--ports/stm/common-hal/microcontroller/__init__.c4
-rw-r--r--shared-bindings/_typing/__init__.pyi4
-rw-r--r--shared-bindings/alarm/__init__.c43
-rw-r--r--shared-bindings/alarm/__init__.h3
-rw-r--r--shared-bindings/alarm/pin/PinAlarm.c2
-rw-r--r--shared-bindings/alarm/time/TimeAlarm.c78
-rw-r--r--shared-bindings/microcontroller/__init__.h2
15 files changed, 143 insertions, 155 deletions
diff --git a/main.c b/main.c
index a9dbb1b7c..dda439d6d 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
+ rgb_status_animation_t animation;
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 ca39f2838..50a1ec038 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 57140dec7..7aa3b839d 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 7cf74a0ef..767b0de70 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 3578b86d0..184f5be69 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 e6f50ed5a..3c9166114 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 0329ced69..6a8537e2d 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 9911896bf..06aac9409 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 bc81b0e4f..a827399cc 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 02839ab47..271693686 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 4aa6c8457..4c2189c0d 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 0f084c78e..968136345 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 ff7b19ca1..fadd1b0d4 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 864ece284..6339b850c 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} },
+ };
+
+ 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, secs);
+ 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 87284fc2e..ac71de424 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;