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 ) {
@@ -286,8 +283,6 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
286
283
bool found_main = false;
287
284
288
285
if (safe_mode == NO_SAFE_MODE ) {
289
- new_status_color (MAIN_RUNNING );
290
-
291
286
static const char * const supported_filenames [] = STRING_LIST (
292
287
"code.txt" , "code.py" , "main.py" , "main.txt" );
293
288
#if CIRCUITPY_FULL_BUILD
@@ -317,6 +312,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
317
312
serial_write_compressed (translate ("WARNING: Your code filename has two extensions\n" ));
318
313
}
319
314
}
315
+ #else
316
+ (void ) found_main ;
320
317
#endif
321
318
322
319
// Finished executing python code. Cleanup includes a board reset.
@@ -334,42 +331,62 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
334
331
}
335
332
336
333
// Program has finished running.
337
-
338
334
bool printed_press_any_key = false;
339
335
#if CIRCUITPY_DISPLAYIO
340
- bool refreshed_epaper_display = false ;
336
+ size_t time_to_epaper_refresh = 1 ;
341
337
#endif
342
338
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
345
369
bool fake_sleeping = false;
370
+ #endif
371
+ bool skip_repl = false;
346
372
while (true) {
347
373
RUN_BACKGROUND_TASKS ;
348
374
349
375
// If a reload was requested by the supervisor or autoreload, return
350
376
if (reload_requested ) {
351
- #if CIRCUITPY_ALARM
352
- if (fake_sleeping ) {
353
- board_init ();
354
- }
355
- #endif
356
377
reload_requested = false;
357
- return true;
378
+ skip_repl = true;
379
+ break ;
358
380
}
359
381
360
382
// If interrupted by keyboard, return
361
383
if (serial_connected () && serial_bytes_available ()) {
362
- #if CIRCUITPY_ALARM
363
- if (fake_sleeping ) {
364
- board_init ();
365
- }
366
- #endif
367
384
// 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 ) {
370
387
supervisor_set_run_reason (RUN_REASON_REPL_RELOAD );
371
388
}
372
- return ctrl_d ;
389
+ break ;
373
390
}
374
391
375
392
// 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) {
378
395
#if CIRCUITPY_ALARM
379
396
if (fake_sleeping && common_hal_alarm_woken_from_sleep ()) {
380
397
serial_write_compressed (translate ("Woken up by alarm.\n" ));
381
- board_init ();
382
398
supervisor_set_run_reason (RUN_REASON_STARTUP );
383
- return true;
399
+ skip_repl = true;
400
+ break ;
384
401
}
385
402
#endif
386
403
@@ -403,26 +420,21 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
403
420
printed_press_any_key = false;
404
421
}
405
422
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
-
417
423
// Sleep until our next interrupt.
418
424
#if CIRCUITPY_ALARM
419
425
if (result .return_code & PYEXEC_DEEP_SLEEP ) {
420
426
// Make sure we have been awake long enough for USB to connect (enumeration delay).
421
427
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.)
426
438
board_deinit ();
427
439
if (!supervisor_workflow_active ()) {
428
440
// 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) {
431
443
// Does not return.
432
444
} else {
433
445
serial_write_compressed (translate ("Pretending to deep sleep until alarm, CTRL-C or file write.\n" ));
446
+ fake_sleeping = true;
434
447
}
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.
435
451
}
436
- }
452
+ } else
437
453
#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
+ }
438
460
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
447
465
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 );
452
507
#endif
508
+ port_idle_until_interrupt ();
453
509
}
454
510
}
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 ;
455
525
}
456
526
457
527
FIL * boot_output_file ;
@@ -468,7 +538,6 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
468
538
bool skip_boot_output = false;
469
539
470
540
if (ok_to_run ) {
471
- new_status_color (BOOT_RUNNING );
472
541
473
542
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
474
543
FIL file_pointer ;
@@ -578,13 +647,27 @@ STATIC int run_repl(void) {
578
647
#endif
579
648
580
649
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 ();
581
657
new_status_color (REPL_RUNNING );
658
+ status_led_deinit ();
659
+ #endif
582
660
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL ) {
583
661
exit_code = pyexec_raw_repl ();
584
662
} else {
585
663
exit_code = pyexec_friendly_repl ();
586
664
}
587
665
cleanup_after_vm (heap );
666
+ #if CIRCUITPY_STATUS_LED
667
+ status_led_init ();
668
+ new_status_color (BLACK );
669
+ status_led_deinit ();
670
+ #endif
588
671
autoreload_resume ();
589
672
return exit_code ;
590
673
}
@@ -593,9 +676,8 @@ int __attribute__((used)) main(void) {
593
676
// initialise the cpu and peripherals
594
677
safe_mode_t safe_mode = port_init ();
595
678
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 ();
599
681
600
682
// Wait briefly to give a reset window where we'll enter safe mode after the reset.
601
683
if (safe_mode == NO_SAFE_MODE ) {
0 commit comments