4646#include "background.h"
4747#include "mpconfigboard.h"
4848#include "supervisor/background_callback.h"
49+ #include "supervisor/board.h"
4950#include "supervisor/cpu.h"
5051#include "supervisor/filesystem.h"
5152#include "supervisor/memory.h"
6465#include "shared-bindings/microcontroller/Processor.h"
6566#include "shared-bindings/supervisor/Runtime.h"
6667
67- #include "boards/board.h"
68-
6968#if CIRCUITPY_ALARM
7069#include "shared-bindings/alarm/__init__.h"
7170#endif
@@ -303,13 +302,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
303302 if (result .return_code & PYEXEC_FORCED_EXIT ) {
304303 return reload_requested ;
305304 }
306-
307- #if CIRCUITPY_ALARM
308- if (result .return_code & PYEXEC_DEEP_SLEEP ) {
309- common_hal_alarm_enter_deep_sleep ();
310- // Does not return.
311- }
312- #endif
313305 }
314306
315307 // Program has finished running.
@@ -326,32 +318,55 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
326318
327319 rgb_status_animation_t animation ;
328320 prep_rgb_status_animation (& result , found_main , safe_mode , & animation );
321+ bool asleep = false;
329322 while (true) {
330-
331323 RUN_BACKGROUND_TASKS ;
332324 if (reload_requested ) {
325+ #if CIRCUITPY_ALARM
326+ if (asleep ) {
327+ board_init ();
328+ }
329+ #endif
333330 supervisor_set_run_reason (RUN_REASON_AUTO_RELOAD );
334331 reload_requested = false;
335332 return true;
336333 }
337334
338335 if (serial_connected () && serial_bytes_available ()) {
336+ #if CIRCUITPY_ALARM
337+ if (asleep ) {
338+ board_init ();
339+ }
340+ #endif
339341 // Skip REPL if reload was requested.
340342 bool ctrl_d = serial_read () == CHAR_CTRL_D ;
341343 if (ctrl_d ) {
342344 supervisor_set_run_reason (RUN_REASON_REPL_RELOAD );
343345 }
344- return ( ctrl_d ) ;
346+ return ctrl_d ;
345347 }
346348
349+ // Check for a deep sleep alarm and restart the VM. This can happen if
350+ // an alarm alerts faster than our USB delay or if we pretended to deep
351+ // sleep.
352+ #if CIRCUITPY_ALARM
353+ if (asleep && alarm_woken_from_sleep ()) {
354+ serial_write_compressed (translate ("Woken up by alarm.\n" ));
355+ board_init ();
356+ supervisor_set_run_reason (RUN_REASON_STARTUP );
357+ // TODO: Reset any volatile memory the user may have access to.
358+ return true;
359+ }
360+ #endif
361+
347362 if (!serial_connected_before_animation && serial_connected ()) {
348363 if (!serial_connected_at_start ) {
349364 print_code_py_status_message (safe_mode );
350365 }
351366
352367 print_safe_mode_message (safe_mode );
353368 serial_write ("\n" );
354- serial_write_compressed (translate ("Press any key to enter the REPL. Use CTRL-D to reload." ));
369+ serial_write_compressed (translate ("Press any key to enter the REPL. Use CTRL-D to reload.\n " ));
355370 }
356371 if (serial_connected_before_animation && !serial_connected ()) {
357372 serial_connected_at_start = false;
@@ -360,12 +375,52 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
360375
361376 // Refresh the ePaper display if we have one. That way it'll show an error message.
362377 #if CIRCUITPY_DISPLAYIO
378+ // Don't refresh the display if we're about to deep sleep.
379+ #if CIRCUITPY_ALARM
380+ refreshed_epaper_display = refreshed_epaper_display || result .return_code & PYEXEC_DEEP_SLEEP ;
381+ #endif
363382 if (!refreshed_epaper_display ) {
364383 refreshed_epaper_display = maybe_refresh_epaperdisplay ();
365384 }
366385 #endif
367386
368- tick_rgb_status_animation (& animation );
387+ // Sleep until our next interrupt.
388+ #if CIRCUITPY_ALARM
389+ if (result .return_code & PYEXEC_DEEP_SLEEP ) {
390+ // Make sure we have been awake long enough for USB to connect (enumeration delay).
391+ int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks (NULL );
392+ if (connecting_delay_ticks > 0 ) {
393+ // Set when we've waited long enough so that we wake up from the
394+ // port_idle_until_interrupt below and loop around to the real deep
395+ // sleep in the else clause.
396+ port_interrupt_after_ticks (connecting_delay_ticks );
397+ // Deep sleep if we're not connected to a host.
398+ } else if (!asleep ) {
399+ asleep = true;
400+ new_status_color (BLACK );
401+ board_deinit ();
402+ if (!supervisor_workflow_active ()) {
403+ // Enter true deep sleep. When we wake up we'll be back at the
404+ // top of main(), not in this loop.
405+ alarm_enter_deep_sleep ();
406+ // Does not return.
407+ } else {
408+ serial_write_compressed (translate ("Pretending to deep sleep until alarm, any key or file write.\n" ));
409+ }
410+ }
411+ }
412+ #endif
413+
414+ if (!asleep ) {
415+ tick_rgb_status_animation (& animation );
416+ } else {
417+ // This waits until a pretend deep sleep alarm occurs. They are set
418+ // during common_hal_alarm_set_deep_sleep_alarms. On some platforms
419+ // it may also return due to another interrupt, that's why we check
420+ // for deep sleep alarms above. If it wasn't a deep sleep alarm,
421+ // then we'll idle here again.
422+ port_idle_until_interrupt ();
423+ }
369424 }
370425}
371426
0 commit comments