diff options
| author | Scott Shawcroft <scott.shawcroft@gmail.com> | 2016-12-09 19:27:41 -0800 |
|---|---|---|
| committer | Scott Shawcroft <scott.shawcroft@gmail.com> | 2016-12-09 19:35:56 -0800 |
| commit | b6f1eebab30b0e687e07cc3e42d9db9fd48aab05 (patch) | |
| tree | 0cbd3edb2a81de4df6d33a5775d9f9cb99b48e91 /atmel-samd/main.c | |
| parent | 6225b89c764f8e9e44fc03f9544e9d2162bb0659 (diff) | |
atmel-samd: Add APA102 support and flash more advanced status.
The new sequence is as follows:
* Solid blue during the boot/settings script.
* Solid green during the main/code script.
* After main while waiting to enter repl or reset:
* Fading green once main is done successfully.
* On error produce a series of flashes:
* Long flash color of script.
* Long flash color of error:
* Green = IndentationError
* Cyan = SyntaxError
* White = NameError
* Orange = OSError
* Yellow = Other error
* Line number of the exception by digit. Number of flashes represents value.
* Thousands = White
* Hundreds = Blue
* Tens = Yellow
* Ones = Cyan
* Off for a period and then repeats.
At any point a write to the flash storage will flicker red.
Fixes #63
Diffstat (limited to 'atmel-samd/main.c')
| -rw-r--r-- | atmel-samd/main.c | 211 |
1 files changed, 178 insertions, 33 deletions
diff --git a/atmel-samd/main.c b/atmel-samd/main.c index c48f7e012..64f36903d 100644 --- a/atmel-samd/main.c +++ b/atmel-samd/main.c @@ -10,6 +10,7 @@ #include "lib/fatfs/ff.h" #include "lib/fatfs/diskio.h" +#include "lib/mp-readline/readline.h" #include "lib/utils/pyexec.h" #include "extmod/fsusermount.h" @@ -23,7 +24,7 @@ #include "autoreset.h" #include "mpconfigboard.h" -#include "neopixel_status.h" +#include "rgb_led_status.h" #include "tick.h" fs_user_mount_t fs_user_mount_flash; @@ -131,7 +132,7 @@ static char *stack_top; static char heap[16384]; void reset_mp(void) { - new_status_color(0x8f, 0x00, 0x8f); + new_status_color(0x8f008f); autoreset_stop(); autoreset_enable(); @@ -181,7 +182,7 @@ void reset_samd21(void) { system_pinmux_group_set_config(&(PORT->Group[1]), pin_mask[1] & ~MICROPY_PORT_B, &config); } -bool maybe_run(const char* filename, int* ret) { +bool maybe_run(const char* filename, pyexec_result_t* exec_result) { FILINFO fno; #if _USE_LFN fno.lfname = NULL; @@ -193,32 +194,171 @@ bool maybe_run(const char* filename, int* ret) { } mp_hal_stdout_tx_str(filename); mp_hal_stdout_tx_str(" output:\r\n"); - *ret = pyexec_file(filename); + pyexec_file(filename, exec_result); return true; } -void start_mp(void) { +bool start_mp(void) { + bool cdc_enabled_at_start = mp_cdc_enabled; #ifdef AUTORESET_DELAY_MS + if (cdc_enabled_at_start) { mp_hal_stdout_tx_str("\r\n"); mp_hal_stdout_tx_str("Auto-soft reset is on. Simply save files over USB to run them.\r\n"); - mp_hal_stdout_tx_str("Type anything into the REPL to disable and manually reset (CTRL-D) to re-enable.\r\n"); + } #endif - new_status_color(0x00, 0x00, 0x8f); - int ret = 0; - bool found_boot = maybe_run("settings.txt", &ret) || - maybe_run("settings.py", &ret) || - maybe_run("boot.py", &ret) || - maybe_run("boot.txt", &ret); - if (found_boot && ret & PYEXEC_FORCED_EXIT) { - return; + new_status_color(BOOT_RUNNING); + pyexec_result_t result; + bool found_boot = maybe_run("settings.txt", &result) || + maybe_run("settings.py", &result) || + maybe_run("boot.py", &result) || + maybe_run("boot.txt", &result); + bool found_main = false; + if (!found_boot || !(result.return_code & PYEXEC_FORCED_EXIT)) { + new_status_color(MAIN_RUNNING); + found_main = maybe_run("code.txt", &result) || + maybe_run("code.py", &result) || + maybe_run("main.py", &result) || + maybe_run("main.txt", &result); + } + + if (result.return_code & PYEXEC_FORCED_EXIT) { + return reset_next_character; } - new_status_color(0x00, 0x8f, 0x00); - maybe_run("code.txt", &ret) || - maybe_run("code.py", &ret) || - maybe_run("main.py", &ret) || - maybe_run("main.txt", &ret); + // If not is USB mode then do not skip the repl. + #ifndef USB_REPL + return false; + #endif + + // Wait for connection or character. + new_status_color(ALL_DONE); + bool cdc_enabled_before = false; + uint32_t pattern_start = ticks_ms; + + printf("result code %d %d.\r\n", result.return_code, result.exception_line); + uint32_t total_exception_cycle = 0; + uint8_t ones = result.exception_line % 10; + ones += ones > 0 ? 1 : 0; + uint8_t tens = (result.exception_line / 10) % 10; + tens += tens > 0 ? 1 : 0; + uint8_t hundreds = (result.exception_line / 100) % 10; + hundreds += hundreds > 0 ? 1 : 0; + uint8_t thousands = (result.exception_line / 1000) % 10; + thousands += thousands > 0 ? 1 : 0; + uint8_t digit_sum = ones + tens + hundreds + thousands; + uint8_t num_places = 0; + uint16_t line = result.exception_line; + for (int i = 0; i < 4; i++) { + if ((line % 10) > 0) { + num_places++; + } + line /= 10; + } + if (result.return_code == PYEXEC_EXCEPTION) { + total_exception_cycle = EXCEPTION_TYPE_LENGTH_MS * 3 + LINE_NUMBER_TOGGLE_LENGTH * digit_sum + LINE_NUMBER_TOGGLE_LENGTH * num_places; + } + while (true) { + #ifdef MICROPY_VM_HOOK_LOOP + MICROPY_VM_HOOK_LOOP + #endif + if (reset_next_character) { + return true; + } + if (usb_rx_count > 0) { + // Skip REPL if reset was requested. + return receive_usb() == CHAR_CTRL_D; + } + + if (!cdc_enabled_before && mp_cdc_enabled) { + if (cdc_enabled_at_start) { + mp_hal_stdout_tx_str("\r\n\r\n"); + } else { + printf("result code %d %d.\r\n", result.return_code, result.exception_line); + mp_hal_stdout_tx_str("Auto-soft reset is on. Simply save files over USB to run them.\r\n"); + } + mp_hal_stdout_tx_str("Press any key to enter the REPL and disable auto-reset. Use CTRL-D to soft reset.\r\n"); + } + if (cdc_enabled_before && !mp_cdc_enabled) { + cdc_enabled_at_start = false; + } + cdc_enabled_before = mp_cdc_enabled; + + uint32_t tick_diff = ticks_ms - pattern_start; + if (result.return_code != PYEXEC_EXCEPTION) { + // All is good. Ramp ALL_DONE up and down. + if (tick_diff > ALL_GOOD_CYCLE_MS) { + pattern_start = ticks_ms; + tick_diff = 0; + } + + uint16_t brightness = tick_diff * 255 / (ALL_GOOD_CYCLE_MS / 2); + if (brightness > 255) { + brightness = 511 - brightness; + } + new_status_color(color_brightness(ALL_DONE, brightness)); + } else { + if (tick_diff > total_exception_cycle) { + pattern_start = ticks_ms; + tick_diff = 0; + } + // First flash the file color. + if (tick_diff < EXCEPTION_TYPE_LENGTH_MS) { + if (found_main) { + new_status_color(MAIN_RUNNING); + } else { + new_status_color(BOOT_RUNNING); + } + // Next flash the exception color. + } else if (tick_diff < EXCEPTION_TYPE_LENGTH_MS * 2) { + if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_IndentationError)) { + new_status_color(INDENTATION_ERROR); + } else if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_SyntaxError)) { + new_status_color(SYNTAX_ERROR); + } else if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_NameError)) { + new_status_color(NAME_ERROR); + } else if (mp_obj_is_subclass_fast(result.exception_type, &mp_type_OSError)) { + new_status_color(OS_ERROR); + } else { + new_status_color(OTHER_ERROR); + } + // Finally flash the line number digits from highest to lowest. + // Zeroes will not produce a flash but can be read by the absence of + // a color from the sequence. + } else if (tick_diff < (EXCEPTION_TYPE_LENGTH_MS * 2 + LINE_NUMBER_TOGGLE_LENGTH * digit_sum)) { + uint32_t digit_diff = tick_diff - EXCEPTION_TYPE_LENGTH_MS * 2; + if ((digit_diff % LINE_NUMBER_TOGGLE_LENGTH) < (LINE_NUMBER_TOGGLE_LENGTH / 2)) { + new_status_color(BLACK); + } else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * thousands) { + if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH) { + new_status_color(BLACK); + } else { + new_status_color(THOUSANDS); + } + } else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds)) { + if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + 1)) { + new_status_color(BLACK); + } else { + new_status_color(HUNDREDS); + } + } else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds + tens)) { + if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds + 1)) { + new_status_color(BLACK); + } else { + new_status_color(TENS); + } + } else { + if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (thousands + hundreds + tens + 1)) { + new_status_color(BLACK); + } else { + new_status_color(ONES); + } + } + } else { + new_status_color(BLACK); + } + } + } } #ifdef UART_REPL @@ -283,7 +423,7 @@ void samd21_init(void) { // port_pin_set_config(MICROPY_HW_LED1, &pin_conf); // port_pin_set_output_level(MICROPY_HW_LED1, false); - neopixel_status_init(); + rgb_led_status_init(); } int main(int argc, char **argv) { @@ -307,24 +447,29 @@ int main(int argc, char **argv) { udc_start(); #endif - // Run boot and main. - start_mp(); - // Main script is finished, so now go into REPL mode. // The REPL mode can change, or it can request a soft reset. - int exit_code = 0; + int exit_code = PYEXEC_FORCED_EXIT; + bool skip_repl = true; + bool first_run = true; for (;;) { - new_status_color(0x3f, 0x3f, 0x3f); - if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { - exit_code = pyexec_raw_repl(); - } else { - exit_code = pyexec_friendly_repl(); + if (!skip_repl) { + autoreset_disable(); + new_status_color(REPL_RUNNING); + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + exit_code = pyexec_raw_repl(); + } else { + exit_code = pyexec_friendly_repl(); + } } if (exit_code == PYEXEC_FORCED_EXIT) { - mp_hal_stdout_tx_str("soft reboot\r\n"); - reset_samd21(); - reset_mp(); - start_mp(); + if (!first_run) { + mp_hal_stdout_tx_str("soft reboot\r\n"); + reset_samd21(); + reset_mp(); + } + first_run = false; + skip_repl = start_mp(); } else if (exit_code != 0) { break; } |
