summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott.shawcroft@gmail.com>2016-12-09 19:27:41 -0800
committerScott Shawcroft <scott.shawcroft@gmail.com>2016-12-09 19:35:56 -0800
commitb6f1eebab30b0e687e07cc3e42d9db9fd48aab05 (patch)
tree0cbd3edb2a81de4df6d33a5775d9f9cb99b48e91
parent6225b89c764f8e9e44fc03f9544e9d2162bb0659 (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
-rw-r--r--atmel-samd/Makefile2
-rw-r--r--atmel-samd/boards/gemma_m0/mpconfigboard.h1
-rw-r--r--atmel-samd/boards/trinket_m0/mpconfigboard.h1
-rw-r--r--atmel-samd/internal_flash.c10
-rw-r--r--atmel-samd/main.c211
-rw-r--r--atmel-samd/mphalport.c4
-rw-r--r--atmel-samd/mphalport.h5
-rw-r--r--atmel-samd/neopixel_status.c43
-rw-r--r--atmel-samd/neopixel_status.h12
-rw-r--r--atmel-samd/rgb_led_colors.h32
-rw-r--r--atmel-samd/rgb_led_status.c93
-rw-r--r--atmel-samd/rgb_led_status.h16
-rw-r--r--atmel-samd/spi_flash.c10
-rw-r--r--lib/utils/pyexec.c38
-rw-r--r--lib/utils/pyexec.h9
-rw-r--r--shared-module/bitbangio/SPI.c11
16 files changed, 371 insertions, 127 deletions
diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile
index 1b38503fe..5a1226e1a 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 998e895ff..dff412b6e 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 e7282c3a6..f27044173 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 a4e205295..d62b3a8ad 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 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;
}
diff --git a/atmel-samd/mphalport.c b/atmel-samd/mphalport.c
index de102ccc4..4ff4022ca 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 6df09f9c7..e2185ae58 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 86dd2cb28..000000000
--- 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 a09fd7b91..000000000
--- 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 <stdint.h>
-#include <stdbool.h>
-
-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 000000000..cfdb93690
--- /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 000000000..a46c01f27
--- /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 000000000..be1227e9f
--- /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 <stdint.h>
+#include <stdbool.h>
+
+#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 e87c11f0d..6ed8e0cf8 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 7737d137f..63797158f 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 0c7567e27..276e9a45a 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 e1a5f7c27..5e8d73122 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);
}