53
53
#include "supervisor/port.h"
54
54
#include "supervisor/serial.h"
55
55
#include "supervisor/shared/autoreload.h"
56
- #include "supervisor/shared/rgb_led_status.h"
57
56
#include "supervisor/shared/safe_mode.h"
58
57
#include "supervisor/shared/stack.h"
59
58
#include "supervisor/shared/status_leds.h"
@@ -114,7 +113,6 @@ static void reset_devices(void) {
114
113
}
115
114
116
115
STATIC void start_mp (supervisor_allocation * heap ) {
117
- reset_status_led ();
118
116
autoreload_stop ();
119
117
supervisor_workflow_reset ();
120
118
@@ -251,7 +249,6 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) {
251
249
#endif
252
250
reset_port ();
253
251
reset_board ();
254
- reset_status_led ();
255
252
}
256
253
257
254
STATIC void print_code_py_status_message (safe_mode_t safe_mode ) {
@@ -284,8 +281,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
284
281
bool found_main = false;
285
282
286
283
if (safe_mode == NO_SAFE_MODE ) {
287
- new_status_color (MAIN_RUNNING );
288
-
289
284
static const char * const supported_filenames [] = STRING_LIST (
290
285
"code.txt" , "code.py" , "main.py" , "main.txt" );
291
286
#if CIRCUITPY_FULL_BUILD
@@ -315,6 +310,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
315
310
serial_write_compressed (translate ("WARNING: Your code filename has two extensions\n" ));
316
311
}
317
312
}
313
+ #else
314
+ (void ) found_main ;
318
315
#endif
319
316
320
317
// Finished executing python code. Cleanup includes a board reset.
@@ -332,42 +329,64 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
332
329
}
333
330
334
331
// Program has finished running.
335
-
336
332
bool printed_press_any_key = false;
337
333
#if CIRCUITPY_DISPLAYIO
338
- bool refreshed_epaper_display = false ;
334
+ size_t time_to_epaper_refresh = 1 ;
339
335
#endif
340
336
341
- rgb_status_animation_t animation ;
342
- prep_rgb_status_animation (& result , found_main , safe_mode , & animation );
337
+ // Setup LED blinks.
338
+ #if CIRCUITPY_STATUS_LED
339
+ uint32_t color ;
340
+ uint8_t blink_count ;
341
+ #if CIRCUITPY_ALARM
342
+ if (result .return_code & PYEXEC_DEEP_SLEEP ) {
343
+ color = BLACK ;
344
+ blink_count = 0 ;
345
+ } else
346
+ #endif
347
+ if (result .return_code != PYEXEC_EXCEPTION ) {
348
+ if (safe_mode == NO_SAFE_MODE ) {
349
+ color = ALL_DONE ;
350
+ blink_count = ALL_DONE_BLINKS ;
351
+ } else {
352
+ color = SAFE_MODE ;
353
+ blink_count = SAFE_MODE_BLINKS ;
354
+ }
355
+ } else {
356
+ color = EXCEPTION ;
357
+ blink_count = EXCEPTION_BLINKS ;
358
+ }
359
+ size_t pattern_start = supervisor_ticks_ms32 ();
360
+ size_t single_blink_time = (OFF_ON_RATIO + 1 ) * BLINK_TIME_MS ;
361
+ size_t blink_time = single_blink_time * blink_count ;
362
+ size_t total_time = blink_time + LED_SLEEP_TIME_MS ;
363
+ if (blink_count > 0 ) {
364
+ status_led_init ();
365
+ }
366
+ #endif
367
+
368
+ #if CIRCUITPY_ALARM
343
369
bool fake_sleeping = false;
370
+ #endif
371
+ bool skip_repl = false;
344
372
while (true) {
345
373
RUN_BACKGROUND_TASKS ;
346
374
347
375
// If a reload was requested by the supervisor or autoreload, return
348
376
if (reload_requested ) {
349
- #if CIRCUITPY_ALARM
350
- if (fake_sleeping ) {
351
- board_init ();
352
- }
353
- #endif
354
377
reload_requested = false;
355
- return true;
378
+ skip_repl = true;
379
+ break ;
356
380
}
357
381
358
382
// If interrupted by keyboard, return
359
383
if (serial_connected () && serial_bytes_available ()) {
360
- #if CIRCUITPY_ALARM
361
- if (fake_sleeping ) {
362
- board_init ();
363
- }
364
- #endif
365
384
// Skip REPL if reload was requested.
366
- bool ctrl_d = serial_read () == CHAR_CTRL_D ;
367
- if (ctrl_d ) {
385
+ skip_repl = serial_read () == CHAR_CTRL_D ;
386
+ if (skip_repl ) {
368
387
supervisor_set_run_reason (RUN_REASON_REPL_RELOAD );
369
388
}
370
- return ctrl_d ;
389
+ break ;
371
390
}
372
391
373
392
// Check for a deep sleep alarm and restart the VM. This can happen if
@@ -376,9 +395,9 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
376
395
#if CIRCUITPY_ALARM
377
396
if (fake_sleeping && common_hal_alarm_woken_from_sleep ()) {
378
397
serial_write_compressed (translate ("Woken up by alarm.\n" ));
379
- board_init ();
380
398
supervisor_set_run_reason (RUN_REASON_STARTUP );
381
- return true;
399
+ skip_repl = true;
400
+ break ;
382
401
}
383
402
#endif
384
403
@@ -398,25 +417,21 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
398
417
printed_press_any_key = false;
399
418
}
400
419
401
- // Refresh the ePaper display if we have one. That way it'll show an error message.
402
- #if CIRCUITPY_DISPLAYIO
403
- // Don't refresh the display if we're about to deep sleep.
404
- #if CIRCUITPY_ALARM
405
- refreshed_epaper_display = refreshed_epaper_display || result .return_code & PYEXEC_DEEP_SLEEP ;
406
- #endif
407
- if (!refreshed_epaper_display ) {
408
- refreshed_epaper_display = maybe_refresh_epaperdisplay ();
409
- }
410
- #endif
411
-
412
420
// Sleep until our next interrupt.
413
421
#if CIRCUITPY_ALARM
414
422
if (result .return_code & PYEXEC_DEEP_SLEEP ) {
415
423
// Make sure we have been awake long enough for USB to connect (enumeration delay).
416
424
int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks (NULL );
417
- // Until it's safe to decide whether we're real/fake sleeping, just run the RGB
418
- if (connecting_delay_ticks < 0 && !fake_sleeping ) {
419
- fake_sleeping = true;
425
+ // Until it's safe to decide whether we're real/fake sleeping
426
+ if (fake_sleeping ) {
427
+ // This waits until a pretend deep sleep alarm occurs. They are set
428
+ // during common_hal_alarm_set_deep_sleep_alarms. On some platforms
429
+ // it may also return due to another interrupt, that's why we check
430
+ // for deep sleep alarms above. If it wasn't a deep sleep alarm,
431
+ // then we'll idle here again.
432
+ common_hal_alarm_pretending_deep_sleep ();
433
+ } else if (connecting_delay_ticks < 0 ) {
434
+ // Entering deep sleep (may be fake or real.)
420
435
new_status_color (BLACK );
421
436
board_deinit ();
422
437
if (!supervisor_workflow_active ()) {
@@ -426,27 +441,71 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
426
441
// Does not return.
427
442
} else {
428
443
serial_write_compressed (translate ("Pretending to deep sleep until alarm, CTRL-C or file write.\n" ));
444
+ fake_sleeping = true;
429
445
}
446
+ } else {
447
+ // Loop while checking the time. We can't idle because we don't want to override a
448
+ // time alarm set for the deep sleep.
430
449
}
431
- }
450
+ } else
432
451
#endif
452
+ {
453
+ // Refresh the ePaper display if we have one. That way it'll show an error message.
454
+ #if CIRCUITPY_DISPLAYIO
455
+ if (time_to_epaper_refresh > 0 ) {
456
+ time_to_epaper_refresh = maybe_refresh_epaperdisplay ();
457
+ }
433
458
434
- if (!fake_sleeping ) {
435
- tick_rgb_status_animation (& animation );
436
- } else {
437
- // This waits until a pretend deep sleep alarm occurs. They are set
438
- // during common_hal_alarm_set_deep_sleep_alarms. On some platforms
439
- // it may also return due to another interrupt, that's why we check
440
- // for deep sleep alarms above. If it wasn't a deep sleep alarm,
441
- // then we'll idle here again.
459
+ #if !CIRCUITPY_STATUS_LED
460
+ port_interrupt_after_ticks (time_to_epaper_refresh );
461
+ #endif
462
+ #endif
442
463
443
- #if CIRCUITPY_ALARM
444
- common_hal_alarm_pretending_deep_sleep ();
445
- #else
446
- port_idle_until_interrupt ();
464
+ #if CIRCUITPY_STATUS_LED
465
+ uint32_t tick_diff = supervisor_ticks_ms32 () - pattern_start ;
466
+
467
+ // By default, don't sleep.
468
+ size_t time_to_next_change = 0 ;
469
+ if (tick_diff < blink_time ) {
470
+ uint32_t blink_diff = tick_diff % (single_blink_time );
471
+ if (blink_diff >= BLINK_TIME_MS ) {
472
+ new_status_color (BLACK );
473
+ time_to_next_change = single_blink_time - blink_diff ;
474
+ } else {
475
+ new_status_color (color );
476
+ time_to_next_change = BLINK_TIME_MS - blink_diff ;
477
+ }
478
+ } else if (tick_diff > total_time ) {
479
+ pattern_start = supervisor_ticks_ms32 ();
480
+ } else {
481
+ time_to_next_change = total_time - tick_diff ;
482
+ }
483
+ #if CIRCUITPY_DISPLAYIO
484
+ if (time_to_epaper_refresh > 0 && time_to_next_change > 0 ) {
485
+ time_to_next_change = MIN (time_to_next_change , time_to_epaper_refresh );
486
+ }
447
487
#endif
488
+ if (time_to_next_change > 0 ) {
489
+ // time_to_next_change is in ms and ticks are slightly shorter so
490
+ // we'll undersleep just a little. It shouldn't matter.
491
+ port_interrupt_after_ticks (time_to_next_change );
492
+ }
493
+ #endif
494
+ port_idle_until_interrupt ();
448
495
}
449
496
}
497
+ // Done waiting, start the board back up.
498
+ #if CIRCUITPY_STATUS_LED
499
+ new_status_color (BLACK );
500
+ status_led_deinit ();
501
+ #endif
502
+
503
+ #if CIRCUITPY_ALARM
504
+ if (fake_sleeping ) {
505
+ board_init ();
506
+ }
507
+ #endif
508
+ return skip_repl ;
450
509
}
451
510
452
511
FIL * boot_output_file ;
@@ -463,7 +522,6 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
463
522
bool skip_boot_output = false;
464
523
465
524
if (ok_to_run ) {
466
- new_status_color (BOOT_RUNNING );
467
525
468
526
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
469
527
FIL file_pointer ;
@@ -574,7 +632,16 @@ STATIC int run_repl(void) {
574
632
#endif
575
633
576
634
autoreload_suspend ();
635
+
636
+ // Set the status LED to the REPL color before running the REPL. For
637
+ // NeoPixels and DotStars this will be sticky but for PWM or single LED it
638
+ // won't. This simplifies pin sharing because they won't be in use when
639
+ // actually in the REPL.
640
+ #if CIRCUITPY_STATUS_LED
641
+ status_led_init ();
577
642
new_status_color (REPL_RUNNING );
643
+ status_led_deinit ();
644
+ #endif
578
645
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL ) {
579
646
exit_code = pyexec_raw_repl ();
580
647
} else {
@@ -589,9 +656,8 @@ int __attribute__((used)) main(void) {
589
656
// initialise the cpu and peripherals
590
657
safe_mode_t safe_mode = port_init ();
591
658
592
- // Turn on LEDs
593
- init_status_leds ();
594
- rgb_led_status_init ();
659
+ // Turn on RX and TX LEDs if we have them.
660
+ init_rxtx_leds ();
595
661
596
662
// Wait briefly to give a reset window where we'll enter safe mode after the reset.
597
663
if (safe_mode == NO_SAFE_MODE ) {
0 commit comments