Skip to content

Commit e308a9e

Browse files
committed
working! PinAlarm not implemented yet.
1 parent 104a089 commit e308a9e

File tree

7 files changed

+175
-57
lines changed

7 files changed

+175
-57
lines changed

locale/circuitpython.pot

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PACKAGE VERSION\n"
1010
"Report-Msgid-Bugs-To: \n"
11-
<<<<<<< HEAD
12-
"POT-Creation-Date: 2020-11-25 15:08-0500\n"
13-
=======
14-
"POT-Creation-Date: 2020-11-11 16:30+0530\n"
15-
>>>>>>> adafruit/main
11+
"POT-Creation-Date: 2020-11-27 16:03-0500\n"
1612
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1713
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1814
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -301,6 +297,7 @@ msgid "All I2C peripherals are in use"
301297
msgstr ""
302298

303299
#: ports/esp32s2/common-hal/countio/Counter.c
300+
#: ports/esp32s2/common-hal/frequencyio/FrequencyIn.c
304301
#: ports/esp32s2/common-hal/rotaryio/IncrementalEncoder.c
305302
msgid "All PCNT units in use"
306303
msgstr ""
@@ -337,6 +334,7 @@ msgstr ""
337334
#: ports/atmel-samd/common-hal/pulseio/PulseIn.c
338335
#: ports/atmel-samd/common-hal/pulseio/PulseOut.c
339336
#: ports/cxd56/common-hal/pulseio/PulseOut.c
337+
#: ports/esp32s2/common-hal/frequencyio/FrequencyIn.c
340338
#: ports/esp32s2/common-hal/neopixel_write/__init__.c
341339
#: ports/esp32s2/common-hal/pulseio/PulseIn.c
342340
#: ports/esp32s2/common-hal/pulseio/PulseOut.c
@@ -1098,6 +1096,7 @@ msgid "Invalid byteorder string"
10981096
msgstr ""
10991097

11001098
#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
1099+
#: ports/esp32s2/common-hal/frequencyio/FrequencyIn.c
11011100
msgid "Invalid capture period. Valid range: 1 - 500"
11021101
msgstr ""
11031102

@@ -1511,7 +1510,7 @@ msgid "Pin number already reserved by EXTI"
15111510
msgstr ""
15121511

15131512
#: ports/esp32s2/common-hal/alarm/__init__.c
1514-
msgid "PinAlarm deep sleep not yet implemented"
1513+
msgid "PinAlarm not yet implemented"
15151514
msgstr ""
15161515

15171516
#: shared-bindings/rgbmatrix/RGBMatrix.c
@@ -1575,7 +1574,7 @@ msgstr ""
15751574
msgid "RTC calibration is not supported on this board"
15761575
msgstr ""
15771576

1578-
#: shared-bindings/time/__init__.c
1577+
#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c
15791578
msgid "RTC is not supported on this board"
15801579
msgstr ""
15811580

@@ -1721,6 +1720,10 @@ msgstr ""
17211720
msgid "Supply at least one UART pin"
17221721
msgstr ""
17231722

1723+
#: shared-bindings/alarm/time/TimeAlarm.c
1724+
msgid "Supply one of monotonic_time or epoch_time"
1725+
msgstr ""
1726+
17241727
#: shared-bindings/gnss/GNSS.c
17251728
msgid "System entry must be gnss.SatelliteSystem"
17261729
msgstr ""
@@ -1784,6 +1787,10 @@ msgstr ""
17841787
msgid "Tile width must exactly divide bitmap width"
17851788
msgstr ""
17861789

1790+
#: shared-bindings/alarm/time/TimeAlarm.c
1791+
msgid "Time is in the past."
1792+
msgstr ""
1793+
17871794
#: ports/nrf/common-hal/_bleio/Adapter.c
17881795
#, c-format
17891796
msgid "Timeout is too long: Maximum timeout length is %d seconds"
@@ -2498,6 +2505,10 @@ msgstr ""
24982505
msgid "end_x should be an int"
24992506
msgstr ""
25002507

2508+
#: shared-bindings/alarm/time/TimeAlarm.c
2509+
msgid "epoch_time not supported on this board"
2510+
msgstr ""
2511+
25012512
#: ports/nrf/common-hal/busio/UART.c
25022513
#, c-format
25032514
msgid "error = 0x%08lX"

ports/esp32s2/common-hal/alarm/__init__.c

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737

3838
#include "esp_log.h"
3939
#include "esp_sleep.h"
40+
#include "esp_wifi.h"
4041

4142
STATIC mp_obj_tuple_t *_deep_sleep_alarms;
4243

@@ -77,13 +78,14 @@ mp_obj_t common_hal_alarm_get_wake_alarm(void) {
7778
return mp_const_none;
7879
}
7980

80-
STATIC void setup_alarms(size_t n_alarms, const mp_obj_t *alarms) {
81+
// Set up light sleep or deep sleep alarms.
82+
STATIC void setup_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms) {
8183
bool time_alarm_set = false;
8284
alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_NULL;
8385

8486
for (size_t i = 0; i < n_alarms; i++) {
8587
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
86-
mp_raise_NotImplementedError(translate("PinAlarm deep sleep not yet implemented"));
88+
mp_raise_NotImplementedError(translate("PinAlarm not yet implemented"));
8789
}
8890
else if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) {
8991
if (time_alarm_set) {
@@ -98,23 +100,82 @@ STATIC void setup_alarms(size_t n_alarms, const mp_obj_t *alarms) {
98100
// Compute how long to actually sleep, considering the time now.
99101
mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f;
100102
mp_float_t wakeup_in_secs = MAX(0.0f, time_alarm->monotonic_time - now_secs);
101-
esp_sleep_enable_timer_wakeup((uint64_t) (wakeup_in_secs * 1000000));
103+
const uint64_t sleep_for_us = (uint64_t) (wakeup_in_secs * 1000000);
104+
ESP_LOGI("ALARM", "Sleep for us: %lld", sleep_for_us);
105+
esp_sleep_enable_timer_wakeup(sleep_for_us);
102106
}
103107
}
104108

109+
mp_obj_t common_hal_alarm_wait_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
110+
if (n_alarms == 0) {
111+
return mp_const_none;
112+
}
113+
114+
bool time_alarm_set = false;
115+
alarm_time_time_alarm_obj_t *time_alarm = MP_OBJ_NULL;
116+
117+
for (size_t i = 0; i < n_alarms; i++) {
118+
if (MP_OBJ_IS_TYPE(alarms[i], &alarm_pin_pin_alarm_type)) {
119+
mp_raise_NotImplementedError(translate("PinAlarm not yet implemented"));
120+
}
121+
else if (MP_OBJ_IS_TYPE(alarms[i], &alarm_time_time_alarm_type)) {
122+
if (time_alarm_set) {
123+
mp_raise_ValueError(translate("Only one alarm.time alarm can be set."));
124+
}
125+
time_alarm = MP_OBJ_TO_PTR(alarms[i]);
126+
time_alarm_set = true;
127+
}
128+
}
129+
130+
ESP_LOGI("ALARM", "waiting for alarms");
131+
132+
if (time_alarm_set && n_alarms == 1) {
133+
// If we're only checking time, avoid a polling loop, so maybe we can save some power.
134+
const mp_float_t now_secs = uint64_to_float(common_hal_time_monotonic_ms()) / 1000.0f;
135+
const mp_float_t wakeup_in_secs = MAX(0.0f, time_alarm->monotonic_time - now_secs);
136+
const uint32_t delay_ms = (uint32_t) (wakeup_in_secs * 1000.0f);
137+
ESP_LOGI("ALARM", "Delay for ms: %d", delay_ms);
138+
common_hal_time_delay_ms((uint32_t) delay_ms);
139+
} else {
140+
// Poll for alarms.
141+
while (true) {
142+
RUN_BACKGROUND_TASKS;
143+
// Allow ctrl-C interrupt.
144+
if (mp_hal_is_interrupted()) {
145+
return mp_const_none;
146+
}
147+
148+
// TODO: Check PinAlarms.
149+
150+
if (time_alarm != MP_OBJ_NULL &&
151+
common_hal_time_monotonic_ms() * 1000.f >= time_alarm->monotonic_time) {
152+
return time_alarm;
153+
}
154+
}
155+
}
156+
157+
return mp_const_none;
158+
}
159+
105160
mp_obj_t common_hal_alarm_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
106-
setup_alarms(n_alarms, alarms);
161+
if (n_alarms == 0) {
162+
return mp_const_none;
163+
}
164+
165+
setup_sleep_alarms(n_alarms, alarms);
107166

108167
// Shut down wifi cleanly.
109168
esp_wifi_stop();
169+
ESP_LOGI("ALARM", "start light sleep");
110170
esp_light_sleep_start();
111171
return common_hal_alarm_get_wake_alarm();
112172
}
113173

114174
void common_hal_alarm_exit_and_deep_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms) {
115-
setup_alarms(n_alarms, alarms);
175+
setup_sleep_alarms(n_alarms, alarms);
116176

117177
// Shut down wifi cleanly.
118178
esp_wifi_stop();
179+
ESP_LOGI("ALARM", "start deep sleep");
119180
esp_deep_sleep_start();
120181
}

ports/esp32s2/common-hal/microcontroller/__init__.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@
4242

4343
#include "freertos/FreeRTOS.h"
4444

45-
#include "esp_sleep.h"
46-
#include "esp_wifi.h"
47-
4845
void common_hal_mcu_delay_us(uint32_t delay) {
4946
mp_hal_delay_us(delay);
5047
}

shared-bindings/alarm/__init__.c

Lines changed: 84 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -25,40 +25,46 @@
2525
*/
2626

2727
#include "py/obj.h"
28+
#include "py/reload.h"
2829
#include "py/runtime.h"
2930

3031
#include "shared-bindings/alarm/__init__.h"
3132
#include "shared-bindings/alarm/pin/PinAlarm.h"
3233
#include "shared-bindings/alarm/time/TimeAlarm.h"
34+
#include "shared-bindings/supervisor/Runtime.h"
3335
#include "shared-bindings/time/__init__.h"
34-
#include "supervisor/shared/rgb_led_status.h"
36+
#include "supervisor/shared/autoreload.h"
3537
#include "supervisor/shared/workflow.h"
3638

37-
// Wait this long to see if USB is being connected (enumeration starting).
38-
#define CIRCUITPY_USB_CONNECTING_DELAY 1
39-
// Wait this long before going into deep sleep if connected. This
40-
// allows the user to ctrl-C before deep sleep starts.
41-
#define CIRCUITPY_USB_CONNECTED_DEEP_SLEEP_DELAY 5
39+
// Wait this long imediately after startup to see if we are connected to USB.
40+
#define CIRCUITPY_USB_CONNECTED_SLEEP_DELAY 5
4241

43-
//| """Power-saving light and deep sleep. Alarms can be set to wake up from sleep.
42+
//| """Alarms and sleep
4443
//|
45-
//| The `alarm` module provides sleep related functionality. There are two supported levels of
46-
//| sleep, light and deep.
44+
//| Provides alarms that trigger based on time intervals or on external events, such as pin
45+
//| changes.
46+
//| The program can simply wait for these alarms, or go into a sleep state and
47+
//| and be awoken when they trigger.
4748
//|
48-
//| Light sleep leaves the CPU and RAM powered so that CircuitPython can resume where it left off
49-
//| after being woken up. CircuitPython automatically goes into a light sleep when `time.sleep()` is
50-
//| called. To light sleep until a non-time alarm use `alarm.sleep_until_alarms()`. Any active
51-
//| peripherals, such as I2C, are left on.
49+
//| There are two supported levels of sleep: light sleep and deep sleep.
5250
//|
53-
//| Deep sleep shuts down power to nearly all of the chip including the CPU and RAM. This can save
54-
//| a more significant amount of power, but CircuitPython must start ``code.py`` from the beginning when
51+
//| Light sleep leaves the CPU and RAM powered so the program can resume after sleeping.
52+
//|
53+
//| *However, note that on some platforms, light sleep will shut down some communications, including
54+
//| WiFi and/or Bluetooth.*
55+
//|
56+
//| Deep sleep shuts down power to nearly all of the microcontroller including the CPU and RAM. This can save
57+
//| a more significant amount of power, but CircuitPython must restart ``code.py`` from the beginning when
5558
//| awakened.
5659
//| """
5760

5861
//|
5962
//| wake_alarm: Alarm
60-
//| """The most recent alarm to wake us up from a sleep (light or deep.)"""
63+
//| """The most recently triggered alarm. If CircuitPython was sleeping, the alarm the woke it from sleep."""
6164
//|
65+
66+
// wake_alarm is implemented as a dictionary entry, so there's no code here.
67+
6268
void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) {
6369
for (size_t i = 0; i < n_args; i++) {
6470
if (MP_OBJ_IS_TYPE(objs[i], &alarm_pin_pin_alarm_type) ||
@@ -69,9 +75,36 @@ void validate_objs_are_alarms(size_t n_args, const mp_obj_t *objs) {
6975
}
7076
}
7177

78+
//| def wait_until_alarms(*alarms: Alarm) -> Alarm:
79+
//| """Wait for one of the alarms to trigger. The triggering alarm is returned.
80+
//| is returned, and is also available as `alarm.wake_alarm`. Nothing is shut down
81+
//| or interrupted. Power consumption will be reduced if possible.
82+
//|
83+
//| If no alarms are specified, return immediately.
84+
//| """
85+
//| ...
86+
//|
87+
STATIC mp_obj_t alarm_wait_until_alarms(size_t n_args, const mp_obj_t *args) {
88+
validate_objs_are_alarms(n_args, args);
89+
common_hal_alarm_wait_until_alarms(n_args, args);
90+
return mp_const_none;
91+
}
92+
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_wait_until_alarms_obj, 1, MP_OBJ_FUN_ARGS_MAX, alarm_wait_until_alarms);
93+
7294
//| def sleep_until_alarms(*alarms: Alarm) -> Alarm:
7395
//| """Go into a light sleep until awakened one of the alarms. The alarm causing the wake-up
74-
//| is returned, and is also available as `alarm.wake_alarm`.
96+
//| is returned, and is also available as `alarm.wake_alarm`.
97+
//|
98+
//| Some functionality may be shut down during sleep. On ESP32-S2, WiFi is turned off,
99+
//| and existing connections are broken.
100+
//|
101+
//| If no alarms are specified, return immediately.
102+
//|
103+
//| **If CircuitPython is connected to a host computer,** `alarm.sleep_until_alarms()`
104+
//| **does not go into light sleep.**
105+
//| Instead, light sleep is simulated by doing `alarm.wait_until_alarms()`,
106+
//| This allows the user to interrupt an existing program with ctrl-C,
107+
//| and to edit the files in CIRCUITPY, which would not be possible in true light sleep
75108
//| """
76109
//| ...
77110
//|
@@ -84,47 +117,60 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_sleep_until_alarms_obj, 1, MP_OBJ_FUN_
84117

85118
//| def exit_and_deep_sleep_until_alarms(*alarms: Alarm) -> None:
86119
//| """Exit the program and go into a deep sleep, until awakened by one of the alarms.
120+
//| This function does not return.
87121
//|
88122
//| When awakened, the microcontroller will restart and will run ``boot.py`` and ``code.py``
89123
//| from the beginning.
90124
//|
91-
//| An alarm equivalent to the one that caused the wake-up is available as `alarm.wake_alarm`.
125+
//| After restart, an alarm *equivalent* to the one that caused the wake-up
126+
//| will be available as `alarm.wake_alarm`.
92127
//| Its type and/or attributes may not correspond exactly to the original alarm.
93128
//| For time-base alarms, currently, an `alarm.time.TimeAlarm()` is created.
94129
//|
95130
//| If no alarms are specified, the microcontroller will deep sleep until reset.
96131
//|
97-
//| If CircuitPython is unconnected to a host computer, go into deep sleep immediately.
98-
//| But if it already connected or in the process of connecting to a host computer, wait at least
99-
//| five seconds after starting code.py before entering deep sleep.
100-
//| This allows interrupting a program that would otherwise go into deep sleep too quickly
101-
//| to interrupt from the keyboard.
132+
//| **If CircuitPython is connected to a host computer, `alarm.exit_and_deep_sleep_until_alarms()`
133+
//| does not go into deep sleep.**
134+
//| Instead, deep sleep is simulated by first doing `alarm.wait_until_alarms()`,
135+
//| and then, when an alarm triggers, by restarting CircuitPython.
136+
//| This allows the user to interrupt an existing program with ctrl-C,
137+
//| and to edit the files in CIRCUITPY, which would not be possible in true deep sleep.
138+
//|
139+
//| Here is skeletal example that deep-sleeps and restarts every 60 seconds:
140+
//|
141+
//| .. code-block:: python
142+
//|
143+
//| import alarm
144+
//| import time
145+
//|
146+
//| print("Waking up")
147+
//|
148+
//| # Set an alarm for 60 seconds from now.
149+
//| time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + 60)
150+
//|
151+
//| # Deep sleep until the alarm goes off. Then restart the program.
152+
//| alarm.exit_and_deep_sleep_until_alarms(time_alarm)
102153
//| """
103154
//| ...
104155
//|
105156
STATIC mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_obj_t *args) {
106157
validate_objs_are_alarms(n_args, args);
107158

108-
int64_t connecting_delay_msec = CIRCUITPY_USB_CONNECTING_DELAY * 1024 - supervisor_ticks_ms64();
159+
// Make sure we have been awake long enough for USB to connect (enumeration delay).
160+
int64_t connecting_delay_msec = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - supervisor_ticks_ms64();
109161
if (connecting_delay_msec > 0) {
110162
common_hal_time_delay_ms(connecting_delay_msec * 1000 / 1024);
111163
}
112164

113-
// If connected, wait for the program to be running at least as long as
114-
// CIRCUITPY_USB_CONNECTED_DEEP_SLEEP_DELAY. This allows a user to ctrl-C the running
115-
// program in case it is in a tight deep sleep loop that would otherwise be difficult
116-
// or impossible to interrupt.
117-
// Indicate that we're delaying with the SAFE_MODE color.
118-
int64_t delay_before_sleeping_msec =
119-
supervisor_ticks_ms64() - CIRCUITPY_USB_CONNECTED_DEEP_SLEEP_DELAY * 1000;
120-
if (supervisor_workflow_connecting() && delay_before_sleeping_msec > 0) {
121-
temp_status_color(SAFE_MODE);
122-
common_hal_time_delay_ms(delay_before_sleeping_msec);
123-
clear_temp_status();
165+
if (supervisor_workflow_active()) {
166+
common_hal_alarm_wait_until_alarms(n_args, args);
167+
reload_requested = true;
168+
supervisor_set_run_reason(RUN_REASON_STARTUP);
169+
mp_raise_reload_exception();
170+
} else {
171+
common_hal_alarm_exit_and_deep_sleep_until_alarms(n_args, args);
172+
// Does not return.
124173
}
125-
126-
common_hal_alarm_exit_and_deep_sleep_until_alarms(n_args, args);
127-
// Does not return.
128174
return mp_const_none;
129175
}
130176
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);

shared-bindings/alarm/__init__.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

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

34+
extern mp_obj_t common_hal_alarm_wait_until_alarms(size_t n_alarms, const mp_obj_t *alarms);
3435
extern mp_obj_t common_hal_alarm_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms);
3536
extern void common_hal_alarm_exit_and_deep_sleep_until_alarms(size_t n_alarms, const mp_obj_t *alarms);
3637

0 commit comments

Comments
 (0)