diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile index 1b38503fe4..5a1226e1a8 100644 --- a/atmel-samd/Makefile +++ b/atmel-samd/Makefile @@ -178,7 +178,7 @@ SRC_C = \ moduos.c \ mphalport.c \ samd21_pins.c \ - neopixel_status.c \ + rgb_led_status.c \ tick.c \ $(FLASH_IMPL) \ asf/common/services/sleepmgr/samd/sleepmgr.c \ diff --git a/atmel-samd/boards/gemma_m0/mpconfigboard.h b/atmel-samd/boards/gemma_m0/mpconfigboard.h index 998e895ff6..dff412b6e7 100644 --- a/atmel-samd/boards/gemma_m0/mpconfigboard.h +++ b/atmel-samd/boards/gemma_m0/mpconfigboard.h @@ -3,7 +3,6 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Gemma M0 (Experimental)" #define MICROPY_HW_MCU_NAME "samd21e18" -#define MICROPY_HW_APA102_SERCOM SERCOM0 #define MICROPY_HW_APA102_MOSI &pin_PA04 #define MICROPY_HW_APA102_SCK &pin_PA05 diff --git a/atmel-samd/boards/trinket_m0/mpconfigboard.h b/atmel-samd/boards/trinket_m0/mpconfigboard.h index e7282c3a6e..f270441739 100644 --- a/atmel-samd/boards/trinket_m0/mpconfigboard.h +++ b/atmel-samd/boards/trinket_m0/mpconfigboard.h @@ -3,7 +3,6 @@ #define MICROPY_HW_BOARD_NAME "Adafruit Trinket M0 (Experimental)" #define MICROPY_HW_MCU_NAME "samd21e18" -#define MICROPY_HW_APA102_SERCOM SERCOM0 #define MICROPY_HW_APA102_MOSI &pin_PA04 #define MICROPY_HW_APA102_SCK &pin_PA05 diff --git a/atmel-samd/internal_flash.c b/atmel-samd/internal_flash.c index a4e205295d..d62b3a8ad1 100644 --- a/atmel-samd/internal_flash.c +++ b/atmel-samd/internal_flash.c @@ -37,7 +37,7 @@ #include "asf/sam0/drivers/nvm/nvm.h" #include "asf/sam0/drivers/port/port.h" -#include "neopixel_status.h" +#include "rgb_led_status.h" #define TOTAL_INTERNAL_FLASH_SIZE 0x010000 @@ -174,9 +174,7 @@ bool internal_flash_write_block(const uint8_t *src, uint32_t block) { #ifdef MICROPY_HW_LED_MSC port_pin_set_output_level(MICROPY_HW_LED_MSC, true); #endif - #ifdef MICROPY_HW_NEOPIXEL - temp_status_color(0x8f, 0x00, 0x00); - #endif + temp_status_color(ACTIVE_WRITE); // non-MBR block, copy to cache int32_t dest = convert_block_to_flash_addr(block); if (dest == -1) { @@ -214,9 +212,7 @@ bool internal_flash_write_block(const uint8_t *src, uint32_t block) { return false; } } - #ifdef MICROPY_HW_NEOPIXEL - clear_temp_status(); - #endif + clear_temp_status(); #ifdef MICROPY_HW_LED_MSC port_pin_set_output_level(MICROPY_HW_LED_MSC, false); #endif diff --git a/atmel-samd/main.c b/atmel-samd/main.c index c48f7e012a..64f36903dc 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); } - 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 (result.return_code & PYEXEC_FORCED_EXIT) { + return reset_next_character; + } + + // 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; } diff --git a/atmel-samd/mphalport.c b/atmel-samd/mphalport.c index de102ccc48..4ff4022ca5 100644 --- a/atmel-samd/mphalport.c +++ b/atmel-samd/mphalport.c @@ -30,9 +30,9 @@ static volatile uint8_t usb_rx_buf_head; static volatile uint8_t usb_rx_buf_tail; // Number of bytes in receive buffer -static volatile uint8_t usb_rx_count; +volatile uint8_t usb_rx_count; -static volatile bool mp_cdc_enabled = false; +volatile bool mp_cdc_enabled = false; void mp_keyboard_interrupt(void); int interrupt_char; diff --git a/atmel-samd/mphalport.h b/atmel-samd/mphalport.h index 6df09f9c71..e2185ae58d 100644 --- a/atmel-samd/mphalport.h +++ b/atmel-samd/mphalport.h @@ -37,6 +37,11 @@ extern volatile uint64_t ticks_ms; static inline mp_uint_t mp_hal_ticks_ms(void) { return ticks_ms; } +// Number of bytes in receive buffer +volatile uint8_t usb_rx_count; +volatile bool mp_cdc_enabled; + +int receive_usb(void); void mp_hal_set_interrupt_char(int c); diff --git a/atmel-samd/neopixel_status.c b/atmel-samd/neopixel_status.c deleted file mode 100644 index 86dd2cb282..0000000000 --- a/atmel-samd/neopixel_status.c +++ /dev/null @@ -1,43 +0,0 @@ -#include "asf/common2/services/delay/delay.h" -#include "asf/sam0/drivers/port/port.h" - -#include "mphalport.h" - -#include "shared-bindings/nativeio/DigitalInOut.h" -#include "shared-bindings/neopixel_write/__init__.h" -#include "neopixel_status.h" -#include "samd21_pins.h" - -#ifdef MICROPY_HW_NEOPIXEL -static uint8_t status_neopixel_color[3]; -static nativeio_digitalinout_obj_t status_neopixel; -#endif - -void neopixel_status_init() { - #ifdef MICROPY_HW_NEOPIXEL - common_hal_nativeio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL); - common_hal_nativeio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL); - #endif -} - -void new_status_color(uint8_t r, uint8_t g, uint8_t b) { - #ifdef MICROPY_HW_NEOPIXEL - status_neopixel_color[0] = g; - status_neopixel_color[1] = r; - status_neopixel_color[2] = b; - common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true); - #endif -} - -void temp_status_color(uint8_t r, uint8_t g, uint8_t b) { - #ifdef MICROPY_HW_NEOPIXEL - uint8_t colors[3] = {g, r, b}; - common_hal_neopixel_write(&status_neopixel, colors, 3, true); - #endif -} - -void clear_temp_status() { - #ifdef MICROPY_HW_NEOPIXEL - common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true); - #endif -} diff --git a/atmel-samd/neopixel_status.h b/atmel-samd/neopixel_status.h deleted file mode 100644 index a09fd7b918..0000000000 --- a/atmel-samd/neopixel_status.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_NEOPIXEL_STATUS_H -#define __MICROPY_INCLUDED_ATMEL_SAMD_NEOPIXEL_STATUS_H - -#include -#include - -extern void neopixel_status_init(void); -extern void new_status_color(uint8_t r, uint8_t g, uint8_t b); -extern void temp_status_color(uint8_t r, uint8_t g, uint8_t b); -extern void clear_temp_status(void); - -#endif // __MICROPY_INCLUDED_ATMEL_SAMD_NEOPIXEL_STATUS_H diff --git a/atmel-samd/rgb_led_colors.h b/atmel-samd/rgb_led_colors.h new file mode 100644 index 0000000000..cfdb93690e --- /dev/null +++ b/atmel-samd/rgb_led_colors.h @@ -0,0 +1,32 @@ +#define BLACK 0x000000 +#define GREEN 0x003f00 +#define BLUE 0x00003f +#define CYAN 0x003f3f +#define RED 0x3f0000 +#define ORANGE 0x3f1f00 +#define YELLOW 0x3f3f00 +#define PURPLE 0x3f003f +#define WHITE 0x3f3f3f + +#define BOOT_RUNNING BLUE +#define MAIN_RUNNING GREEN +#define ALL_DONE GREEN +#define REPL_RUNNING WHITE + +#define ACTIVE_WRITE 0x8f0000 + +#define ALL_GOOD_CYCLE_MS 2000u + +#define LINE_NUMBER_TOGGLE_LENGTH 300u +#define EXCEPTION_TYPE_LENGTH_MS 1000u + +#define THOUSANDS WHITE +#define HUNDREDS BLUE +#define TENS YELLOW +#define ONES CYAN + +#define INDENTATION_ERROR GREEN +#define SYNTAX_ERROR CYAN +#define NAME_ERROR WHITE +#define OS_ERROR ORANGE +#define OTHER_ERROR YELLOW diff --git a/atmel-samd/rgb_led_status.c b/atmel-samd/rgb_led_status.c new file mode 100644 index 0000000000..a46c01f27d --- /dev/null +++ b/atmel-samd/rgb_led_status.c @@ -0,0 +1,93 @@ +#include "asf/common2/services/delay/delay.h" +#include "asf/sam0/drivers/port/port.h" + +#include "mphalport.h" + +#include "shared-bindings/bitbangio/SPI.h" +#include "shared-bindings/nativeio/DigitalInOut.h" +#include "shared-bindings/neopixel_write/__init__.h" +#include "shared-module/bitbangio/types.h" +#include "rgb_led_status.h" +#include "samd21_pins.h" + +#ifdef MICROPY_HW_NEOPIXEL +static uint8_t status_neopixel_color[3]; +static nativeio_digitalinout_obj_t status_neopixel; +#endif + +#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) +static uint8_t status_apa102_color[12] = {0, 0, 0, 0, 0xff, 0, 0, 0}; +static bitbangio_spi_obj_t status_apa102; +#endif + +#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) +static uint32_t current_status_color = 0; +#endif + +void rgb_led_status_init() { + #ifdef MICROPY_HW_NEOPIXEL + common_hal_nativeio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL); + common_hal_nativeio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL); + #endif + #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) + shared_module_bitbangio_spi_construct(&status_apa102, + MICROPY_HW_APA102_SCK, + MICROPY_HW_APA102_MOSI, + NULL); + shared_module_bitbangio_spi_try_lock(&status_apa102); + shared_module_bitbangio_spi_configure(&status_apa102, 100000, 0, 1, 8); + #endif +} + +void new_status_color(uint32_t rgb) { + #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) + if (current_status_color == rgb) { + return; + } + current_status_color = rgb; + #endif + + #ifdef MICROPY_HW_NEOPIXEL + status_neopixel_color[0] = (rgb >> 8) & 0xff; + status_neopixel_color[1] = (rgb >> 16) & 0xff; + status_neopixel_color[2] = rgb & 0xff; + common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true); + #endif + #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) + status_apa102_color[5] = rgb & 0xff; + status_apa102_color[6] = (rgb >> 8) & 0xff; + status_apa102_color[7] = (rgb >> 16) & 0xff; + shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, 8); + #endif +} + +void temp_status_color(uint32_t rgb) { + #ifdef MICROPY_HW_NEOPIXEL + uint8_t colors[3] = {(rgb >> 8) & 0xff, (rgb >> 16) & 0xff, rgb & 0xff}; + common_hal_neopixel_write(&status_neopixel, colors, 3, true); + #endif + #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) + uint8_t colors[12] = {0, 0, 0, 0, 0xff, rgb & 0xff, (rgb >> 8) & 0xff, (rgb >> 16) & 0xff, 0x0, 0x0, 0x0, 0x0}; + shared_module_bitbangio_spi_write(&status_apa102, colors, 8); + #endif +} + +void clear_temp_status() { + #ifdef MICROPY_HW_NEOPIXEL + common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3, true); + #endif + #if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) + shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, 12); + #endif +} + +uint32_t color_brightness(uint32_t color, uint8_t brightness) { + #if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) + uint32_t result = ((color & 0xff0000) * brightness / 255) & 0xff0000; + result += ((color & 0xff00) * brightness / 255) & 0xff00; + result += ((color & 0xff) * brightness / 255) & 0xff; + return result; + #else + return color; + #endif +} diff --git a/atmel-samd/rgb_led_status.h b/atmel-samd/rgb_led_status.h new file mode 100644 index 0000000000..be1227e9f5 --- /dev/null +++ b/atmel-samd/rgb_led_status.h @@ -0,0 +1,16 @@ +#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_RGB_LED_STATUS_H +#define __MICROPY_INCLUDED_ATMEL_SAMD_RGB_LED_STATUS_H + +#include +#include + +#include "rgb_led_colors.h" + +extern void rgb_led_status_init(void); +extern void new_status_color(uint32_t rgb); +extern void temp_status_color(uint32_t rgb); +extern void clear_temp_status(void); + +uint32_t color_brightness(uint32_t color, uint8_t brightness); + +#endif // __MICROPY_INCLUDED_ATMEL_SAMD_RGB_LED_STATUS_H diff --git a/atmel-samd/spi_flash.c b/atmel-samd/spi_flash.c index e87c11f0da..6ed8e0cf81 100644 --- a/atmel-samd/spi_flash.c +++ b/atmel-samd/spi_flash.c @@ -36,7 +36,7 @@ #include "lib/fatfs/ff.h" #include "extmod/fsusermount.h" -#include "neopixel_status.h" +#include "rgb_led_status.h" #define SPI_FLASH_PART1_START_BLOCK (0x1) @@ -384,9 +384,7 @@ static void spi_flash_flush_keep_cache(bool keep_cache) { #ifdef MICROPY_HW_LED_MSC port_pin_set_output_level(MICROPY_HW_LED_MSC, true); #endif - #ifdef MICROPY_HW_NEOPIXEL - temp_status_color(0x8f, 0x00, 0x00); - #endif + temp_status_color(ACTIVE_WRITE); // If we've cached to the flash itself flush from there. if (MP_STATE_VM(flash_ram_cache) == NULL) { flush_scratch_flash(); @@ -394,9 +392,7 @@ static void spi_flash_flush_keep_cache(bool keep_cache) { flush_ram_cache(keep_cache); } current_sector = NO_SECTOR_LOADED; - #ifdef MICROPY_HW_NEOPIXEL - clear_temp_status(); - #endif + clear_temp_status(); #ifdef MICROPY_HW_LED_MSC port_pin_set_output_level(MICROPY_HW_LED_MSC, false); #endif diff --git a/lib/utils/pyexec.c b/lib/utils/pyexec.c index 7737d137f9..63797158ff 100644 --- a/lib/utils/pyexec.c +++ b/lib/utils/pyexec.c @@ -58,7 +58,7 @@ STATIC bool repl_display_debugging_info = 0; // EXEC_FLAG_PRINT_EOF prints 2 EOF chars: 1 after normal output, 1 after exception output // EXEC_FLAG_ALLOW_DEBUGGING allows debugging info to be printed after executing the code // EXEC_FLAG_IS_REPL is used for REPL inputs (flag passed on to mp_compile) -STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, int exec_flags) { +STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, int exec_flags, pyexec_result_t *result) { int ret = 0; uint32_t start = 0; @@ -88,7 +88,7 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, mp_call_function_0(module_fun); mp_hal_set_interrupt_char(-1); // disable interrupt nlr_pop(); - ret = 1; + ret = 0; if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } @@ -108,7 +108,21 @@ STATIC int parse_compile_execute(void *source, mp_parse_input_kind_t input_kind, ret = PYEXEC_FORCED_EXIT; } else { mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val); - ret = 0; + ret = PYEXEC_EXCEPTION; + } + } + if (result != NULL) { + result->return_code = ret; + if (ret != 0) { + mp_obj_t return_value = (mp_obj_t)nlr.ret_val; + result->exception_type = mp_obj_get_type(return_value); + result->exception_line = -1; + + if (mp_obj_is_exception_instance(return_value)) { + size_t n, *values; + mp_obj_exception_get_traceback(return_value, &n, &values); + result->exception_line = values[n - 2]; + } } } @@ -203,7 +217,7 @@ STATIC int pyexec_raw_repl_process_char(int c) { if (lex == NULL) { mp_hal_stdout_tx_str("\x04MemoryError\r\n\x04"); } else { - int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF); + int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF, NULL); if (ret & PYEXEC_FORCED_EXIT) { return ret; } @@ -285,7 +299,7 @@ exec: ; if (lex == NULL) { printf("MemoryError\n"); } else { - int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL); + int ret = parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL, NULL); if (ret & PYEXEC_FORCED_EXIT) { return ret; } @@ -361,7 +375,7 @@ raw_repl_reset: if (lex == NULL) { printf("\x04MemoryError\n\x04"); } else { - int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF); + int ret = parse_compile_execute(lex, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF, NULL); if (ret & PYEXEC_FORCED_EXIT) { return ret; } @@ -380,7 +394,7 @@ int pyexec_friendly_repl(void) { #endif friendly_repl_reset: - mp_hal_stdout_tx_str("Adafruit MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); + mp_hal_stdout_tx_str("\r\nAdafruit MicroPython " MICROPY_GIT_TAG " on " MICROPY_BUILD_DATE "; " MICROPY_HW_BOARD_NAME " with " MICROPY_HW_MCU_NAME "\r\n"); // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); // to test ctrl-C @@ -487,7 +501,7 @@ friendly_repl_reset: if (lex == NULL) { printf("MemoryError\n"); } else { - ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL); + ret = parse_compile_execute(lex, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL, NULL); if (ret & PYEXEC_FORCED_EXIT) { return ret; } @@ -497,7 +511,7 @@ friendly_repl_reset: #endif // MICROPY_REPL_EVENT_DRIVEN -int pyexec_file(const char *filename) { +int pyexec_file(const char *filename, pyexec_result_t *exec_result) { mp_lexer_t *lex = mp_lexer_new_from_file(filename); if (lex == NULL) { @@ -505,7 +519,7 @@ int pyexec_file(const char *filename) { return false; } - return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0); + return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, 0, exec_result); } #if MICROPY_MODULE_FROZEN @@ -516,12 +530,12 @@ int pyexec_frozen_module(const char *name) { switch (frozen_type) { #if MICROPY_MODULE_FROZEN_STR case MP_FROZEN_STR: - return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0); + return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, 0, NULL); #endif #if MICROPY_MODULE_FROZEN_MPY case MP_FROZEN_MPY: - return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE); + return parse_compile_execute(frozen_data, MP_PARSE_FILE_INPUT, EXEC_FLAG_SOURCE_IS_RAW_CODE, NULL); #endif default: diff --git a/lib/utils/pyexec.h b/lib/utils/pyexec.h index 0c7567e273..276e9a45a5 100644 --- a/lib/utils/pyexec.h +++ b/lib/utils/pyexec.h @@ -31,6 +31,12 @@ typedef enum { PYEXEC_MODE_FRIENDLY_REPL, } pyexec_mode_kind_t; +typedef struct { + int return_code; + const mp_obj_type_t * exception_type; + int exception_line; +} pyexec_result_t; + extern pyexec_mode_kind_t pyexec_mode_kind; // Set this to the value (eg PYEXEC_FORCED_EXIT) that will be propagated through @@ -40,10 +46,11 @@ extern int pyexec_system_exit; #define PYEXEC_FORCED_EXIT (0x100) #define PYEXEC_SWITCH_MODE (0x200) +#define PYEXEC_EXCEPTION (0x400) int pyexec_raw_repl(void); int pyexec_friendly_repl(void); -int pyexec_file(const char *filename); +int pyexec_file(const char *filename, pyexec_result_t *result); int pyexec_frozen_module(const char *name); void pyexec_event_repl_init(void); int pyexec_event_repl_process_char(int c); diff --git a/shared-module/bitbangio/SPI.c b/shared-module/bitbangio/SPI.c index e1a5f7c27a..5e8d73122d 100644 --- a/shared-module/bitbangio/SPI.c +++ b/shared-module/bitbangio/SPI.c @@ -38,7 +38,7 @@ void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self, const mcu_pin_obj_t * clock, const mcu_pin_obj_t * mosi, - const mcu_pin_obj_t * miso, uint32_t baudrate) { + const mcu_pin_obj_t * miso) { digitalinout_result_t result = common_hal_nativeio_digitalinout_construct(&self->clock, clock); if (result != DIGITALINOUT_OK) { nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, @@ -81,7 +81,7 @@ void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) { } void shared_module_bitbangio_spi_configure(bitbangio_spi_obj_t *self, - uint32_t baudrate, uint8_t polarity, uint8_t phase) { + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { self->delay_half = 500000 / baudrate; // round delay_half up so that: actual_baudrate <= requested_baudrate if (500000 % baudrate != 0) { @@ -148,14 +148,11 @@ bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); - } else { - common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); - common_hal_mcu_delay_us(delay_half); - } - if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); } else { + common_hal_nativeio_digitalinout_set_value(&self->clock, 1 - self->polarity); + common_hal_mcu_delay_us(delay_half); common_hal_nativeio_digitalinout_set_value(&self->clock, self->polarity); common_hal_mcu_delay_us(delay_half); }