5353#include "supervisor/port.h"
5454#include "supervisor/serial.h"
5555#include "supervisor/shared/autoreload.h"
56- #include "supervisor/shared/rgb_led_status.h"
5756#include "supervisor/shared/safe_mode.h"
5857#include "supervisor/shared/stack.h"
5958#include "supervisor/shared/status_leds.h"
@@ -114,7 +113,6 @@ static void reset_devices(void) {
114113}
115114
116115STATIC void start_mp (supervisor_allocation * heap ) {
117- reset_status_led ();
118116 autoreload_stop ();
119117 supervisor_workflow_reset ();
120118
@@ -251,7 +249,6 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) {
251249 #endif
252250 reset_port ();
253251 reset_board ();
254- reset_status_led ();
255252}
256253
257254STATIC void print_code_py_status_message (safe_mode_t safe_mode ) {
@@ -286,8 +283,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
286283 bool found_main = false;
287284
288285 if (safe_mode == NO_SAFE_MODE ) {
289- new_status_color (MAIN_RUNNING );
290-
291286 static const char * const supported_filenames [] = STRING_LIST (
292287 "code.txt" , "code.py" , "main.py" , "main.txt" );
293288 #if CIRCUITPY_FULL_BUILD
@@ -317,6 +312,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
317312 serial_write_compressed (translate ("WARNING: Your code filename has two extensions\n" ));
318313 }
319314 }
315+ #else
316+ (void ) found_main ;
320317 #endif
321318
322319 // Finished executing python code. Cleanup includes a board reset.
@@ -334,42 +331,62 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
334331 }
335332
336333 // Program has finished running.
337-
338334 bool printed_press_any_key = false;
339335 #if CIRCUITPY_DISPLAYIO
340- bool refreshed_epaper_display = false ;
336+ size_t time_to_epaper_refresh = 1 ;
341337 #endif
342338
343- rgb_status_animation_t animation ;
344- prep_rgb_status_animation (& result , found_main , safe_mode , & animation );
339+ // Setup LED blinks.
340+ #if CIRCUITPY_STATUS_LED
341+ uint32_t color ;
342+ uint8_t blink_count ;
343+ bool led_active = false;
344+ #if CIRCUITPY_ALARM
345+ if (result .return_code & PYEXEC_DEEP_SLEEP ) {
346+ color = BLACK ;
347+ blink_count = 0 ;
348+ } else
349+ #endif
350+ if (result .return_code != PYEXEC_EXCEPTION ) {
351+ if (safe_mode == NO_SAFE_MODE ) {
352+ color = ALL_DONE ;
353+ blink_count = ALL_DONE_BLINKS ;
354+ } else {
355+ color = SAFE_MODE ;
356+ blink_count = SAFE_MODE_BLINKS ;
357+ }
358+ } else {
359+ color = EXCEPTION ;
360+ blink_count = EXCEPTION_BLINKS ;
361+ }
362+ size_t pattern_start = supervisor_ticks_ms32 ();
363+ size_t single_blink_time = (OFF_ON_RATIO + 1 ) * BLINK_TIME_MS ;
364+ size_t blink_time = single_blink_time * blink_count ;
365+ size_t total_time = blink_time + LED_SLEEP_TIME_MS ;
366+ #endif
367+
368+ #if CIRCUITPY_ALARM
345369 bool fake_sleeping = false;
370+ #endif
371+ bool skip_repl = false;
346372 while (true) {
347373 RUN_BACKGROUND_TASKS ;
348374
349375 // If a reload was requested by the supervisor or autoreload, return
350376 if (reload_requested ) {
351- #if CIRCUITPY_ALARM
352- if (fake_sleeping ) {
353- board_init ();
354- }
355- #endif
356377 reload_requested = false;
357- return true;
378+ skip_repl = true;
379+ break ;
358380 }
359381
360382 // If interrupted by keyboard, return
361383 if (serial_connected () && serial_bytes_available ()) {
362- #if CIRCUITPY_ALARM
363- if (fake_sleeping ) {
364- board_init ();
365- }
366- #endif
367384 // Skip REPL if reload was requested.
368- bool ctrl_d = serial_read () == CHAR_CTRL_D ;
369- if (ctrl_d ) {
385+ skip_repl = serial_read () == CHAR_CTRL_D ;
386+ if (skip_repl ) {
370387 supervisor_set_run_reason (RUN_REASON_REPL_RELOAD );
371388 }
372- return ctrl_d ;
389+ break ;
373390 }
374391
375392 // Check for a deep sleep alarm and restart the VM. This can happen if
@@ -378,9 +395,9 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
378395 #if CIRCUITPY_ALARM
379396 if (fake_sleeping && common_hal_alarm_woken_from_sleep ()) {
380397 serial_write_compressed (translate ("Woken up by alarm.\n" ));
381- board_init ();
382398 supervisor_set_run_reason (RUN_REASON_STARTUP );
383- return true;
399+ skip_repl = true;
400+ break ;
384401 }
385402 #endif
386403
@@ -403,26 +420,21 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
403420 printed_press_any_key = false;
404421 }
405422
406- // Refresh the ePaper display if we have one. That way it'll show an error message.
407- #if CIRCUITPY_DISPLAYIO
408- // Don't refresh the display if we're about to deep sleep.
409- #if CIRCUITPY_ALARM
410- refreshed_epaper_display = refreshed_epaper_display || result .return_code & PYEXEC_DEEP_SLEEP ;
411- #endif
412- if (!refreshed_epaper_display ) {
413- refreshed_epaper_display = maybe_refresh_epaperdisplay ();
414- }
415- #endif
416-
417423 // Sleep until our next interrupt.
418424 #if CIRCUITPY_ALARM
419425 if (result .return_code & PYEXEC_DEEP_SLEEP ) {
420426 // Make sure we have been awake long enough for USB to connect (enumeration delay).
421427 int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks (NULL );
422- // Until it's safe to decide whether we're real/fake sleeping, just run the RGB
423- if (connecting_delay_ticks < 0 && !fake_sleeping ) {
424- fake_sleeping = true;
425- new_status_color (BLACK );
428+ // Until it's safe to decide whether we're real/fake sleeping
429+ if (fake_sleeping ) {
430+ // This waits until a pretend deep sleep alarm occurs. They are set
431+ // during common_hal_alarm_set_deep_sleep_alarms. On some platforms
432+ // it may also return due to another interrupt, that's why we check
433+ // for deep sleep alarms above. If it wasn't a deep sleep alarm,
434+ // then we'll idle here again.
435+ common_hal_alarm_pretending_deep_sleep ();
436+ } else if (connecting_delay_ticks < 0 ) {
437+ // Entering deep sleep (may be fake or real.)
426438 board_deinit ();
427439 if (!supervisor_workflow_active ()) {
428440 // Enter true deep sleep. When we wake up we'll be back at the
@@ -431,27 +443,85 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
431443 // Does not return.
432444 } else {
433445 serial_write_compressed (translate ("Pretending to deep sleep until alarm, CTRL-C or file write.\n" ));
446+ fake_sleeping = true;
434447 }
448+ } else {
449+ // Loop while checking the time. We can't idle because we don't want to override a
450+ // time alarm set for the deep sleep.
435451 }
436- }
452+ } else
437453 #endif
454+ {
455+ // Refresh the ePaper display if we have one. That way it'll show an error message.
456+ #if CIRCUITPY_DISPLAYIO
457+ if (time_to_epaper_refresh > 0 ) {
458+ time_to_epaper_refresh = maybe_refresh_epaperdisplay ();
459+ }
438460
439- if (!fake_sleeping ) {
440- tick_rgb_status_animation (& animation );
441- } else {
442- // This waits until a pretend deep sleep alarm occurs. They are set
443- // during common_hal_alarm_set_deep_sleep_alarms. On some platforms
444- // it may also return due to another interrupt, that's why we check
445- // for deep sleep alarms above. If it wasn't a deep sleep alarm,
446- // then we'll idle here again.
461+ #if !CIRCUITPY_STATUS_LED
462+ port_interrupt_after_ticks (time_to_epaper_refresh );
463+ #endif
464+ #endif
447465
448- #if CIRCUITPY_ALARM
449- common_hal_alarm_pretending_deep_sleep ();
450- #else
451- port_idle_until_interrupt ();
466+ #if CIRCUITPY_STATUS_LED
467+ uint32_t tick_diff = supervisor_ticks_ms32 () - pattern_start ;
468+
469+ // By default, don't sleep.
470+ size_t time_to_next_change = 0 ;
471+ if (tick_diff < blink_time ) {
472+ uint32_t blink_diff = tick_diff % (single_blink_time );
473+ if (blink_diff >= BLINK_TIME_MS ) {
474+ if (led_active ) {
475+ new_status_color (BLACK );
476+ status_led_deinit ();
477+ led_active = false;
478+ }
479+ time_to_next_change = single_blink_time - blink_diff ;
480+ } else {
481+ if (!led_active ) {
482+ status_led_init ();
483+ new_status_color (color );
484+ led_active = true;
485+ }
486+ time_to_next_change = BLINK_TIME_MS - blink_diff ;
487+ }
488+ } else if (tick_diff > total_time ) {
489+ pattern_start = supervisor_ticks_ms32 ();
490+ } else {
491+ if (led_active ) {
492+ new_status_color (BLACK );
493+ status_led_deinit ();
494+ led_active = false;
495+ }
496+ time_to_next_change = total_time - tick_diff ;
497+ }
498+ #if CIRCUITPY_DISPLAYIO
499+ if (time_to_epaper_refresh > 0 && time_to_next_change > 0 ) {
500+ time_to_next_change = MIN (time_to_next_change , time_to_epaper_refresh );
501+ }
502+ #endif
503+
504+ // time_to_next_change is in ms and ticks are slightly shorter so
505+ // we'll undersleep just a little. It shouldn't matter.
506+ port_interrupt_after_ticks (time_to_next_change );
452507 #endif
508+ port_idle_until_interrupt ();
453509 }
454510 }
511+ // Done waiting, start the board back up.
512+ #if CIRCUITPY_STATUS_LED
513+ if (led_active ) {
514+ new_status_color (BLACK );
515+ status_led_deinit ();
516+ }
517+ #endif
518+
519+ #if CIRCUITPY_ALARM
520+ if (fake_sleeping ) {
521+ board_init ();
522+ }
523+ #endif
524+ return skip_repl ;
455525}
456526
457527FIL * boot_output_file ;
@@ -468,7 +538,6 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
468538 bool skip_boot_output = false;
469539
470540 if (ok_to_run ) {
471- new_status_color (BOOT_RUNNING );
472541
473542 #ifdef CIRCUITPY_BOOT_OUTPUT_FILE
474543 FIL file_pointer ;
@@ -578,13 +647,27 @@ STATIC int run_repl(void) {
578647 #endif
579648
580649 autoreload_suspend ();
650+
651+ // Set the status LED to the REPL color before running the REPL. For
652+ // NeoPixels and DotStars this will be sticky but for PWM or single LED it
653+ // won't. This simplifies pin sharing because they won't be in use when
654+ // actually in the REPL.
655+ #if CIRCUITPY_STATUS_LED
656+ status_led_init ();
581657 new_status_color (REPL_RUNNING );
658+ status_led_deinit ();
659+ #endif
582660 if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL ) {
583661 exit_code = pyexec_raw_repl ();
584662 } else {
585663 exit_code = pyexec_friendly_repl ();
586664 }
587665 cleanup_after_vm (heap );
666+ #if CIRCUITPY_STATUS_LED
667+ status_led_init ();
668+ new_status_color (BLACK );
669+ status_led_deinit ();
670+ #endif
588671 autoreload_resume ();
589672 return exit_code ;
590673}
@@ -593,9 +676,8 @@ int __attribute__((used)) main(void) {
593676 // initialise the cpu and peripherals
594677 safe_mode_t safe_mode = port_init ();
595678
596- // Turn on LEDs
597- init_status_leds ();
598- rgb_led_status_init ();
679+ // Turn on RX and TX LEDs if we have them.
680+ init_rxtx_leds ();
599681
600682 // Wait briefly to give a reset window where we'll enter safe mode after the reset.
601683 if (safe_mode == NO_SAFE_MODE ) {
0 commit comments