Simplify the status LED to save power

This also removes the need to pin share because we don't use the
status LED while user code is running.

The status flashes fallback to the HW_STATUS LED if no RGB LED is
present. Each status has a unique blink pattern as well.

One caveat is the REPL state. In order to not pin share, we set the
RGB color once. PWM and single color will be shutoff immediately but
DotStars and NeoPixels will hold the color until the user overrides
it.

Fixes #4133
This commit is contained in:
Scott Shawcroft 2021-04-16 16:18:01 -07:00
parent 35ee4add63
commit 1a0b4193b7
No known key found for this signature in database
GPG Key ID: 0DFD512649C052DA
33 changed files with 464 additions and 1148 deletions

180
main.c
View File

@ -53,7 +53,6 @@
#include "supervisor/port.h"
#include "supervisor/serial.h"
#include "supervisor/shared/autoreload.h"
#include "supervisor/shared/rgb_led_status.h"
#include "supervisor/shared/safe_mode.h"
#include "supervisor/shared/stack.h"
#include "supervisor/shared/status_leds.h"
@ -114,7 +113,6 @@ static void reset_devices(void) {
}
STATIC void start_mp(supervisor_allocation* heap) {
reset_status_led();
autoreload_stop();
supervisor_workflow_reset();
@ -251,7 +249,6 @@ STATIC void cleanup_after_vm(supervisor_allocation* heap) {
#endif
reset_port();
reset_board();
reset_status_led();
}
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) {
bool found_main = false;
if (safe_mode == NO_SAFE_MODE) {
new_status_color(MAIN_RUNNING);
static const char * const supported_filenames[] = STRING_LIST(
"code.txt", "code.py", "main.py", "main.txt");
#if CIRCUITPY_FULL_BUILD
@ -315,6 +310,8 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
serial_write_compressed(translate("WARNING: Your code filename has two extensions\n"));
}
}
#else
(void) found_main;
#endif
// Finished executing python code. Cleanup includes a board reset.
@ -332,42 +329,64 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
}
// Program has finished running.
bool printed_press_any_key = false;
#if CIRCUITPY_DISPLAYIO
bool refreshed_epaper_display = false;
size_t time_to_epaper_refresh = 1;
#endif
rgb_status_animation_t animation;
prep_rgb_status_animation(&result, found_main, safe_mode, &animation);
// Setup LED blinks.
#if CIRCUITPY_STATUS_LED
uint32_t color;
uint8_t blink_count;
#if CIRCUITPY_ALARM
if (result.return_code & PYEXEC_DEEP_SLEEP) {
color = BLACK;
blink_count = 0;
} else
#endif
if (result.return_code != PYEXEC_EXCEPTION) {
if (safe_mode == NO_SAFE_MODE) {
color = ALL_DONE;
blink_count = ALL_DONE_BLINKS;
} else {
color = SAFE_MODE;
blink_count = SAFE_MODE_BLINKS;
}
} else {
color = EXCEPTION;
blink_count = EXCEPTION_BLINKS;
}
size_t pattern_start = supervisor_ticks_ms32();
size_t single_blink_time = (OFF_ON_RATIO + 1) * BLINK_TIME_MS;
size_t blink_time = single_blink_time * blink_count;
size_t total_time = blink_time + LED_SLEEP_TIME_MS;
if (blink_count > 0) {
status_led_init();
}
#endif
#if CIRCUITPY_ALARM
bool fake_sleeping = false;
#endif
bool skip_repl = false;
while (true) {
RUN_BACKGROUND_TASKS;
// If a reload was requested by the supervisor or autoreload, return
if (reload_requested) {
#if CIRCUITPY_ALARM
if (fake_sleeping) {
board_init();
}
#endif
reload_requested = false;
return true;
skip_repl = true;
break;
}
// If interrupted by keyboard, return
if (serial_connected() && serial_bytes_available()) {
#if CIRCUITPY_ALARM
if (fake_sleeping) {
board_init();
}
#endif
// Skip REPL if reload was requested.
bool ctrl_d = serial_read() == CHAR_CTRL_D;
if (ctrl_d) {
skip_repl = serial_read() == CHAR_CTRL_D;
if (skip_repl) {
supervisor_set_run_reason(RUN_REASON_REPL_RELOAD);
}
return ctrl_d;
break;
}
// 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) {
#if CIRCUITPY_ALARM
if (fake_sleeping && common_hal_alarm_woken_from_sleep()) {
serial_write_compressed(translate("Woken up by alarm.\n"));
board_init();
supervisor_set_run_reason(RUN_REASON_STARTUP);
return true;
skip_repl = true;
break;
}
#endif
@ -398,25 +417,21 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
printed_press_any_key = false;
}
// Refresh the ePaper display if we have one. That way it'll show an error message.
#if CIRCUITPY_DISPLAYIO
// Don't refresh the display if we're about to deep sleep.
#if CIRCUITPY_ALARM
refreshed_epaper_display = refreshed_epaper_display || result.return_code & PYEXEC_DEEP_SLEEP;
#endif
if (!refreshed_epaper_display) {
refreshed_epaper_display = maybe_refresh_epaperdisplay();
}
#endif
// Sleep until our next interrupt.
#if CIRCUITPY_ALARM
if (result.return_code & PYEXEC_DEEP_SLEEP) {
// Make sure we have been awake long enough for USB to connect (enumeration delay).
int64_t connecting_delay_ticks = CIRCUITPY_USB_CONNECTED_SLEEP_DELAY * 1024 - port_get_raw_ticks(NULL);
// Until it's safe to decide whether we're real/fake sleeping, just run the RGB
if (connecting_delay_ticks < 0 && !fake_sleeping) {
fake_sleeping = true;
// Until it's safe to decide whether we're real/fake sleeping
if (fake_sleeping) {
// This waits until a pretend deep sleep alarm occurs. They are set
// during common_hal_alarm_set_deep_sleep_alarms. On some platforms
// it may also return due to another interrupt, that's why we check
// for deep sleep alarms above. If it wasn't a deep sleep alarm,
// then we'll idle here again.
common_hal_alarm_pretending_deep_sleep();
} else if (connecting_delay_ticks < 0) {
// Entering deep sleep (may be fake or real.)
new_status_color(BLACK);
board_deinit();
if (!supervisor_workflow_active()) {
@ -426,27 +441,71 @@ STATIC bool run_code_py(safe_mode_t safe_mode) {
// Does not return.
} else {
serial_write_compressed(translate("Pretending to deep sleep until alarm, CTRL-C or file write.\n"));
fake_sleeping = true;
}
} else {
// Loop while checking the time. We can't idle because we don't want to override a
// time alarm set for the deep sleep.
}
}
} else
#endif
{
// Refresh the ePaper display if we have one. That way it'll show an error message.
#if CIRCUITPY_DISPLAYIO
if (time_to_epaper_refresh > 0) {
time_to_epaper_refresh = maybe_refresh_epaperdisplay();
}
if (!fake_sleeping) {
tick_rgb_status_animation(&animation);
} else {
// This waits until a pretend deep sleep alarm occurs. They are set
// during common_hal_alarm_set_deep_sleep_alarms. On some platforms
// it may also return due to another interrupt, that's why we check
// for deep sleep alarms above. If it wasn't a deep sleep alarm,
// then we'll idle here again.
#if CIRCUITPY_ALARM
common_hal_alarm_pretending_deep_sleep();
#else
port_idle_until_interrupt();
#if !CIRCUITPY_STATUS_LED
port_interrupt_after_ticks(time_to_epaper_refresh);
#endif
#endif
#if CIRCUITPY_STATUS_LED
uint32_t tick_diff = supervisor_ticks_ms32() - pattern_start;
// By default, don't sleep.
size_t time_to_next_change = 0;
if (tick_diff < blink_time) {
uint32_t blink_diff = tick_diff % (single_blink_time);
if (blink_diff >= BLINK_TIME_MS) {
new_status_color(BLACK);
time_to_next_change = single_blink_time - blink_diff;
} else {
new_status_color(color);
time_to_next_change = BLINK_TIME_MS - blink_diff;
}
} else if (tick_diff > total_time) {
pattern_start = supervisor_ticks_ms32();
} else {
time_to_next_change = total_time - tick_diff;
}
#if CIRCUITPY_DISPLAYIO
if (time_to_epaper_refresh > 0 && time_to_next_change > 0) {
time_to_next_change = MIN(time_to_next_change, time_to_epaper_refresh);
}
#endif
if (time_to_next_change > 0) {
// time_to_next_change is in ms and ticks are slightly shorter so
// we'll undersleep just a little. It shouldn't matter.
port_interrupt_after_ticks(time_to_next_change);
}
#endif
port_idle_until_interrupt();
}
}
// Done waiting, start the board back up.
#if CIRCUITPY_STATUS_LED
new_status_color(BLACK);
status_led_deinit();
#endif
#if CIRCUITPY_ALARM
if (fake_sleeping) {
board_init();
}
#endif
return skip_repl;
}
FIL* boot_output_file;
@ -463,7 +522,6 @@ STATIC void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) {
bool skip_boot_output = false;
if (ok_to_run) {
new_status_color(BOOT_RUNNING);
#ifdef CIRCUITPY_BOOT_OUTPUT_FILE
FIL file_pointer;
@ -574,7 +632,16 @@ STATIC int run_repl(void) {
#endif
autoreload_suspend();
// Set the status LED to the REPL color before running the REPL. For
// NeoPixels and DotStars this will be sticky but for PWM or single LED it
// won't. This simplifies pin sharing because they won't be in use when
// actually in the REPL.
#if CIRCUITPY_STATUS_LED
status_led_init();
new_status_color(REPL_RUNNING);
status_led_deinit();
#endif
if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
exit_code = pyexec_raw_repl();
} else {
@ -589,9 +656,8 @@ int __attribute__((used)) main(void) {
// initialise the cpu and peripherals
safe_mode_t safe_mode = port_init();
// Turn on LEDs
init_status_leds();
rgb_led_status_init();
// Turn on RX and TX LEDs if we have them.
init_rxtx_leds();
// Wait briefly to give a reset window where we'll enter safe mode after the reset.
if (safe_mode == NO_SAFE_MODE) {

View File

@ -33,10 +33,9 @@
#define DEFAULT_SPI_BUS_SCK (&pin_PA17)
#define DEFAULT_SPI_BUS_MOSI (&pin_PA16)
// #define CP_RGB_STATUS_R (&pin_PA06)
// #define CP_RGB_STATUS_G (&pin_PA05)
// #define CP_RGB_STATUS_B (&pin_PA07)
// #define CP_RGB_STATUS_INVERTED_PWM
// #define CP_RGB_STATUS_LED
// #define CIRCUITPY_RGB_STATUS_R (&pin_PA06)
// #define CIRCUITPY_RGB_STATUS_G (&pin_PA05)
// #define CIRCUITPY_RGB_STATUS_B (&pin_PA07)
// #define CIRCUITPY_RGB_STATUS_INVERTED_PWM
#define MICROPY_HW_LED_STATUS (&pin_PA06)

View File

@ -36,7 +36,6 @@
#include "hal/include/hal_gpio.h"
#include "hal/include/hal_spi_m_sync.h"
#include "hal/include/hpl_spi_m_sync.h"
#include "supervisor/shared/rgb_led_status.h"
#include "samd/dma.h"
#include "samd/sercom.h"
@ -72,11 +71,6 @@ void reset_sercoms(void) {
if (never_reset_sercoms[i]) {
continue;
}
#ifdef MICROPY_HW_APA102_SERCOM
if (sercom_instances[i] == MICROPY_HW_APA102_SERCOM) {
continue;
}
#endif
// SWRST is same for all modes of SERCOMs.
sercom_instances[i]->SPI.CTRLA.bit.SWRST = 1;
}
@ -122,15 +116,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
continue;
}
Sercom *potential_sercom = sercom_insts[sercom_index];
if (
#if defined(MICROPY_HW_APA102_SCK) && defined(MICROPY_HW_APA102_MOSI) && !CIRCUITPY_BITBANG_APA102
(potential_sercom->SPI.CTRLA.bit.ENABLE != 0 &&
potential_sercom != status_apa102.spi_desc.dev.prvt &&
!apa102_sck_in_use)
#else
potential_sercom->SPI.CTRLA.bit.ENABLE != 0
#endif
) {
if (potential_sercom->SPI.CTRLA.bit.ENABLE != 0) {
continue;
}
clock_pinmux = PINMUX(clock->number, (i == 0) ? MUX_C : MUX_D);
@ -181,10 +167,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
// Set up SPI clocks on SERCOM.
samd_peripherals_sercom_clock_init(sercom, sercom_index);
#if defined(MICROPY_HW_APA102_SCK) && defined(MICROPY_HW_APA102_MOSI) && !CIRCUITPY_BITBANG_APA102
// if we're re-using the dotstar sercom, make sure it is disabled or the init will fail out
hri_sercomspi_clear_CTRLA_ENABLE_bit(sercom);
#endif
if (spi_m_sync_init(&self->spi_desc, sercom) != ERR_NONE) {
mp_raise_OSError(MP_EIO);
}

View File

@ -32,15 +32,7 @@
#include "hal/include/hal_gpio.h"
#include "samd/pins.h"
#include "supervisor/shared/rgb_led_status.h"
#ifdef MICROPY_HW_NEOPIXEL
bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
bool apa102_sck_in_use;
bool apa102_mosi_in_use;
#endif
#ifdef SPEAKER_ENABLE_PIN
bool speaker_enable_in_use;
#endif
@ -90,14 +82,6 @@ void reset_all_pins(void) {
gpio_set_pin_function(PIN_PA31, GPIO_PIN_FUNCTION_G);
#endif
#ifdef MICROPY_HW_NEOPIXEL
neopixel_in_use = false;
#endif
#ifdef MICROPY_HW_APA102_MOSI
apa102_sck_in_use = false;
apa102_mosi_in_use = false;
#endif
// After configuring SWD because it may be shared.
#ifdef SPEAKER_ENABLE_PIN
speaker_enable_in_use = false;
@ -122,25 +106,6 @@ void reset_pin_number(uint8_t pin_number) {
never_reset_pins[GPIO_PORT(pin_number)] &= ~(1 << GPIO_PIN(pin_number));
#ifdef MICROPY_HW_NEOPIXEL
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
neopixel_in_use = false;
rgb_led_status_init();
return;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin_number == MICROPY_HW_APA102_MOSI->number ||
pin_number == MICROPY_HW_APA102_SCK->number) {
apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number;
apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number;
if (!apa102_sck_in_use && !apa102_mosi_in_use) {
rgb_led_status_init();
}
return;
}
#endif
if (pin_number == PIN_PA30
#ifdef SAM_D5X_E5X
) {
@ -176,20 +141,6 @@ void common_hal_reset_pin(const mcu_pin_obj_t* pin) {
}
void claim_pin(const mcu_pin_obj_t* pin) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
neopixel_in_use = true;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
apa102_mosi_in_use = true;
}
if (pin == MICROPY_HW_APA102_SCK) {
apa102_sck_in_use = true;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin == SPEAKER_ENABLE_PIN) {
speaker_enable_in_use = true;
@ -223,26 +174,6 @@ bool pin_number_is_free(uint8_t pin_number) {
}
bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
// Special case for Metro M0 where the NeoPixel is also SWCLK
#ifndef IGNORE_PIN_PA30
if (MICROPY_HW_NEOPIXEL == &pin_PA30 && DSU->STATUSB.bit.DBGPRES == 1) {
return false;
}
#endif
return !neopixel_in_use;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
return !apa102_mosi_in_use;
}
if (pin == MICROPY_HW_APA102_SCK) {
return !apa102_sck_in_use;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin == SPEAKER_ENABLE_PIN) {
return !speaker_enable_in_use;

View File

@ -31,14 +31,6 @@
#include "peripherals/samd/pins.h"
#ifdef MICROPY_HW_NEOPIXEL
extern bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
extern bool apa102_sck_in_use;
extern bool apa102_mosi_in_use;
#endif
void reset_all_pins(void);
// reset_pin_number takes the pin number instead of the pointer so that objects don't
// need to store a full pointer.

View File

@ -51,21 +51,10 @@
#include "hal/include/hal_flash.h"
#include "supervisor/flash.h"
#include "supervisor/shared/rgb_led_status.h"
static struct flash_descriptor supervisor_flash_desc;
void supervisor_flash_init(void) {
// Activity LED for flash writes.
#ifdef MICROPY_HW_LED_MSC
struct port_config pin_conf;
port_get_config_defaults(&pin_conf);
pin_conf.direction = PORT_PIN_DIR_OUTPUT;
port_pin_set_config(MICROPY_HW_LED_MSC, &pin_conf);
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
#endif
#ifdef SAM_D5X_E5X
hri_mclk_set_AHBMASK_NVMCTRL_bit(MCLK);
#endif
@ -114,10 +103,6 @@ bool supervisor_flash_read_block(uint8_t *dest, uint32_t block) {
}
bool supervisor_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
temp_status_color(ACTIVE_WRITE);
// non-MBR block, copy to cache
int32_t dest = convert_block_to_flash_addr(block);
if (dest == -1) {
@ -136,10 +121,6 @@ bool supervisor_flash_write_block(const uint8_t *src, uint32_t block) {
if (error_code != ERR_NONE) {
return false;
}
clear_temp_status();
#ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
#endif
return true;
}

View File

@ -29,7 +29,6 @@
#include "py/runtime.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "supervisor/shared/rgb_led_status.h"
static bool spi_never_reset[SOC_SPI_PERIPH_NUM];

View File

@ -27,23 +27,15 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "supervisor/shared/rgb_led_status.h"
#include "py/mphal.h"
#include "components/driver/include/driver/gpio.h"
#include "components/soc/include/hal/gpio_hal.h"
#ifdef MICROPY_HW_NEOPIXEL
bool neopixel_in_use;
#endif
STATIC uint32_t never_reset_pins[2];
STATIC uint32_t in_use[2];
bool apa102_mosi_in_use;
bool apa102_sck_in_use;
STATIC void floating_gpio_reset(gpio_num_t pin_number) {
// This is the same as gpio_reset_pin(), but without the pullup.
// Note that gpio_config resets the iomatrix to GPIO_FUNC as well.
@ -78,14 +70,6 @@ void reset_pin_number(gpio_num_t pin_number) {
in_use[pin_number / 32] &= ~(1 << pin_number % 32);
floating_gpio_reset(pin_number);
#ifdef MICROPY_HW_NEOPIXEL
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
neopixel_in_use = false;
rgb_led_status_init();
return;
}
#endif
}
void common_hal_reset_pin(const mcu_pin_obj_t *pin) {
@ -106,19 +90,10 @@ void reset_all_pins(void) {
}
in_use[0] = 0;
in_use[1] = 0;
#ifdef MICROPY_HW_NEOPIXEL
neopixel_in_use = false;
#endif
}
void claim_pin(const mcu_pin_obj_t *pin) {
in_use[pin->number / 32] |= (1 << (pin->number % 32));
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
neopixel_in_use = true;
}
#endif
}
void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) {
@ -126,12 +101,6 @@ void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) {
}
bool pin_number_is_free(gpio_num_t pin_number) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
return !neopixel_in_use;
}
#endif
uint8_t offset = pin_number / 32;
uint32_t mask = 1 << (pin_number % 32);
return (in_use[offset] & mask) == 0;

View File

@ -31,13 +31,6 @@
#include "peripherals/pins.h"
extern bool apa102_mosi_in_use;
extern bool apa102_sck_in_use;
#ifdef MICROPY_HW_NEOPIXEL
extern bool neopixel_in_use;
#endif
void reset_all_pins(void);
// reset_pin_number takes the pin number instead of the pointer so that objects don't
// need to store a full pointer.

View File

@ -27,15 +27,6 @@
*/
#include "shared-bindings/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "supervisor/shared/rgb_led_status.h"
#ifdef MICROPY_HW_NEOPIXEL
bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
bool apa102_sck_in_use;
bool apa102_mosi_in_use;
#endif
STATIC bool claimed_pins[IOMUXC_SW_PAD_CTL_PAD_COUNT];
STATIC bool never_reset_pins[IOMUXC_SW_PAD_CTL_PAD_COUNT];
@ -54,14 +45,6 @@ void reset_all_pins(void) {
IOMUXC->SW_PAD_CTL_PAD[i] = ((mcu_pin_obj_t *)(mcu_pin_globals.map.table[i].value))->pad_reset;
}
}
#ifdef MICROPY_HW_NEOPIXEL
neopixel_in_use = false;
#endif
#ifdef MICROPY_HW_APA102_MOSI
apa102_sck_in_use = false;
apa102_mosi_in_use = false;
#endif
}
// Since i.MX pins need extra register and reset information to reset properly,
@ -74,25 +57,6 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) {
claimed_pins[pin->mux_idx] = false;
*(uint32_t *)pin->mux_reg = pin->mux_reset;
*(uint32_t *)pin->cfg_reg = pin->pad_reset;
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
neopixel_in_use = false;
rgb_led_status_init();
return;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin->mux_idx == MICROPY_HW_APA102_MOSI->mux_idx ||
pin->mux_idx == MICROPY_HW_APA102_SCK->mux_idx) {
apa102_mosi_in_use = apa102_mosi_in_use && pin->mux_idx != MICROPY_HW_APA102_MOSI->mux_idx;
apa102_sck_in_use = apa102_sck_in_use && pin->mux_idx != MICROPY_HW_APA102_SCK->mux_idx;
if (!apa102_sck_in_use && !apa102_mosi_in_use) {
rgb_led_status_init();
}
return;
}
#endif
}
void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) {
@ -100,20 +64,6 @@ void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) {
}
bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
return !neopixel_in_use;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
return !apa102_mosi_in_use;
}
if (pin == MICROPY_HW_APA102_SCK) {
return !apa102_sck_in_use;
}
#endif
return !claimed_pins[pin->mux_idx];
}
@ -123,20 +73,6 @@ uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t *pin) {
void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) {
claimed_pins[pin->mux_idx] = true;
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
neopixel_in_use = true;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
apa102_mosi_in_use = true;
}
if (pin == MICROPY_HW_APA102_SCK) {
apa102_sck_in_use = true;
}
#endif
}
void claim_pin(const mcu_pin_obj_t *pin) {

View File

@ -32,14 +32,6 @@
#include "pins.h"
#ifdef MICROPY_HW_NEOPIXEL
extern bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
extern bool apa102_sck_in_use;
extern bool apa102_mosi_in_use;
#endif
void reset_all_pins(void);
void claim_pin(const mcu_pin_obj_t *pin);

View File

@ -30,7 +30,7 @@
#define MICROPY_HW_BOARD_NAME "Adafruit Feather nRF52840 Express"
#define MICROPY_HW_MCU_NAME "nRF52840"
#define MICROPY_HW_NEOPIXEL (&pin_P0_16)
// #define MICROPY_HW_NEOPIXEL (&pin_P0_16)
#define MICROPY_HW_LED_STATUS (&pin_P1_15)

View File

@ -31,9 +31,9 @@
#define MICROPY_HW_MCU_NAME "nRF52840"
// RGB LEDs use PWM peripheral, avoid using them to save energy
// #define CP_RGB_STATUS_R (&pin_P0_30)
// #define CP_RGB_STATUS_G (&pin_P0_29)
// #define CP_RGB_STATUS_B (&pin_P0_31)
#define CIRCUITPY_RGB_STATUS_R (&pin_P0_30)
#define CIRCUITPY_RGB_STATUS_G (&pin_P0_29)
#define CIRCUITPY_RGB_STATUS_B (&pin_P0_31)
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(1, 10)
#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(1, 14)

View File

@ -32,10 +32,10 @@
#define MICROPY_HW_LED_STATUS (&pin_P1_07)
#define CP_RGB_STATUS_INVERTED_PWM
#define CP_RGB_STATUS_R (&pin_P0_30)
#define CP_RGB_STATUS_G (&pin_P0_29)
#define CP_RGB_STATUS_B (&pin_P0_31)
#define CIRCUITPY_RGB_STATUS_INVERTED_PWM
#define CIRCUITPY_RGB_STATUS_R (&pin_P0_30)
#define CIRCUITPY_RGB_STATUS_G (&pin_P0_29)
#define CIRCUITPY_RGB_STATUS_B (&pin_P0_31)
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(1, 10)
#define MICROPY_QSPI_DATA1 NRF_GPIO_PIN_MAP(1, 14)

View File

@ -32,9 +32,9 @@
#define MICROPY_HW_LED_STATUS (&pin_P1_12)
#define CP_RGB_STATUS_R (&pin_P0_13)
#define CP_RGB_STATUS_G (&pin_P0_14)
#define CP_RGB_STATUS_B (&pin_P0_15)
#define CIRCUITPY_RGB_STATUS_R (&pin_P0_13)
#define CIRCUITPY_RGB_STATUS_G (&pin_P0_14)
#define CIRCUITPY_RGB_STATUS_B (&pin_P0_15)
#if QSPI_FLASH_FILESYSTEM
#define MICROPY_QSPI_DATA0 NRF_GPIO_PIN_MAP(0, 20)

View File

@ -31,15 +31,7 @@
#include "py/mphal.h"
#include "nrf/pins.h"
#include "supervisor/shared/rgb_led_status.h"
#ifdef MICROPY_HW_NEOPIXEL
bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
bool apa102_sck_in_use;
bool apa102_mosi_in_use;
#endif
#ifdef SPEAKER_ENABLE_PIN
bool speaker_enable_in_use;
#endif
@ -73,14 +65,6 @@ void reset_all_pins(void) {
nrf_gpio_cfg_default(pin);
}
#ifdef MICROPY_HW_NEOPIXEL
neopixel_in_use = false;
#endif
#ifdef MICROPY_HW_APA102_MOSI
apa102_sck_in_use = false;
apa102_mosi_in_use = false;
#endif
// After configuring SWD because it may be shared.
reset_speaker_enable_pin();
}
@ -95,25 +79,6 @@ void reset_pin_number(uint8_t pin_number) {
claimed_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number));
never_reset_pins[nrf_pin_port(pin_number)] &= ~(1 << nrf_relative_pin_number(pin_number));
#ifdef MICROPY_HW_NEOPIXEL
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
neopixel_in_use = false;
rgb_led_status_init();
return;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin_number == MICROPY_HW_APA102_MOSI->number ||
pin_number == MICROPY_HW_APA102_SCK->number) {
apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number;
apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number;
if (!apa102_sck_in_use && !apa102_mosi_in_use) {
rgb_led_status_init();
}
return;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin_number == SPEAKER_ENABLE_PIN->number) {
reset_speaker_enable_pin();
@ -144,20 +109,6 @@ void claim_pin(const mcu_pin_obj_t *pin) {
// Set bit in claimed_pins bitmask.
claimed_pins[nrf_pin_port(pin->number)] |= 1 << nrf_relative_pin_number(pin->number);
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
neopixel_in_use = true;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
apa102_mosi_in_use = true;
}
if (pin == MICROPY_HW_APA102_SCK) {
apa102_sck_in_use = true;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin == SPEAKER_ENABLE_PIN) {
speaker_enable_in_use = true;
@ -171,20 +122,6 @@ bool pin_number_is_free(uint8_t pin_number) {
}
bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
return !neopixel_in_use;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
return !apa102_mosi_in_use;
}
if (pin == MICROPY_HW_APA102_SCK) {
return !apa102_sck_in_use;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin == SPEAKER_ENABLE_PIN) {
return !speaker_enable_in_use;

View File

@ -31,14 +31,6 @@
#include "peripherals/nrf/pins.h"
#ifdef MICROPY_HW_NEOPIXEL
extern bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
extern bool apa102_sck_in_use;
extern bool apa102_mosi_in_use;
#endif
void reset_all_pins(void);
// reset_pin_number takes the pin number instead of the pointer so that objects don't
// need to store a full pointer.

View File

@ -32,7 +32,6 @@
#include "supervisor/board.h"
#include "common-hal/microcontroller/Pin.h"
#include "supervisor/shared/rgb_led_status.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "src/rp2_common/hardware_dma/include/hardware/dma.h"

View File

@ -29,21 +29,8 @@
#include "common-hal/microcontroller/__init__.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "supervisor/shared/rgb_led_status.h"
#include "src/rp2_common/hardware_gpio/include/hardware/gpio.h"
#ifdef MICROPY_HW_NEOPIXEL
bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
bool apa102_sck_in_use;
bool apa102_mosi_in_use;
#endif
#ifdef SPEAKER_ENABLE_PIN
bool speaker_enable_in_use;
#endif
STATIC uint32_t never_reset_pins;
void reset_all_pins(void) {
@ -77,31 +64,6 @@ void reset_pin_number(uint8_t pin_number) {
PADS_BANK0_GPIO0_PUE_BITS |
PADS_BANK0_GPIO0_PDE_BITS);
hw_set_bits(&padsbank0_hw->io[pin_number], PADS_BANK0_GPIO0_OD_BITS);
#ifdef MICROPY_HW_NEOPIXEL
if (pin_number == MICROPY_HW_NEOPIXEL->number) {
neopixel_in_use = false;
rgb_led_status_init();
return;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin_number == MICROPY_HW_APA102_MOSI->number ||
pin_number == MICROPY_HW_APA102_SCK->number) {
apa102_mosi_in_use = apa102_mosi_in_use && pin_number != MICROPY_HW_APA102_MOSI->number;
apa102_sck_in_use = apa102_sck_in_use && pin_number != MICROPY_HW_APA102_SCK->number;
if (!apa102_sck_in_use && !apa102_mosi_in_use) {
rgb_led_status_init();
}
return;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin_number == SPEAKER_ENABLE_PIN->number) {
speaker_enable_in_use = false;
}
#endif
}
void common_hal_never_reset_pin(const mcu_pin_obj_t *pin) {
@ -113,25 +75,7 @@ void common_hal_reset_pin(const mcu_pin_obj_t *pin) {
}
void claim_pin(const mcu_pin_obj_t *pin) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
neopixel_in_use = true;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
apa102_mosi_in_use = true;
}
if (pin == MICROPY_HW_APA102_SCK) {
apa102_sck_in_use = true;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin == SPEAKER_ENABLE_PIN) {
speaker_enable_in_use = true;
}
#endif
// Nothing to do because all changes will set the GPIO settings.
}
bool pin_number_is_free(uint8_t pin_number) {
@ -145,26 +89,6 @@ bool pin_number_is_free(uint8_t pin_number) {
}
bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
return !neopixel_in_use;
}
#endif
#ifdef MICROPY_HW_APA102_MOSI
if (pin == MICROPY_HW_APA102_MOSI) {
return !apa102_mosi_in_use;
}
if (pin == MICROPY_HW_APA102_SCK) {
return !apa102_sck_in_use;
}
#endif
#ifdef SPEAKER_ENABLE_PIN
if (pin == SPEAKER_ENABLE_PIN) {
return !speaker_enable_in_use;
}
#endif
return pin_number_is_free(pin->number);
}

View File

@ -34,14 +34,6 @@
#include "peripherals/pins.h"
#ifdef MICROPY_HW_NEOPIXEL
extern bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
extern bool apa102_sck_in_use;
extern bool apa102_mosi_in_use;
#endif
void reset_all_pins(void);
// reset_pin_number takes the pin number instead of the pointer so that objects don't
// need to store a full pointer.

View File

@ -27,19 +27,10 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "supervisor/shared/rgb_led_status.h"
#include "py/mphal.h"
#include "pins.h"
#ifdef MICROPY_HW_NEOPIXEL
bool neopixel_in_use;
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
bool apa102_sck_in_use;
bool apa102_mosi_in_use;
#endif
#if defined(TFBGA216)
GPIO_TypeDef *ports[] = {GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH, GPIOI, GPIOJ, GPIOK};
#elif defined(LQFP144)
@ -66,14 +57,6 @@ void reset_all_pins(void) {
for (uint8_t i = 0; i < GPIO_PORT_COUNT; i++) {
HAL_GPIO_DeInit(ports[i], ~never_reset_pins[i]);
}
#ifdef MICROPY_HW_NEOPIXEL
neopixel_in_use = false;
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
apa102_sck_in_use = false;
apa102_mosi_in_use = false;
#endif
}
// Mark pin as free and return it to a quiescent state.
@ -89,25 +72,6 @@ void reset_pin_number(uint8_t pin_port, uint8_t pin_number) {
claimed_pins[pin_port] &= ~(1 << pin_number);
never_reset_pins[pin_port] &= ~(1 << pin_number);
HAL_GPIO_DeInit(ports[pin_port], 1 << pin_number);
#ifdef MICROPY_HW_NEOPIXEL
if (pin_port == MICROPY_HW_NEOPIXEL->port && pin_number == MICROPY_HW_NEOPIXEL->number) {
neopixel_in_use = false;
rgb_led_status_init();
return;
}
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
if (
(pin_port == MICROPY_HW_APA102_MOSI->port && pin_number == MICROPY_HW_APA102_MOSI->number)
|| (pin_port == MICROPY_HW_APA102_SCK->port && pin_number == MICROPY_HW_APA102_MOSI->number)
) {
apa102_mosi_in_use = false;
apa102_sck_in_use = false;
rgb_led_status_init();
return;
}
#endif
}
void never_reset_pin_number(uint8_t pin_port, uint8_t pin_number) {
@ -140,20 +104,6 @@ bool pin_number_is_free(uint8_t pin_port, uint8_t pin_number) {
}
bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t *pin) {
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
return !neopixel_in_use;
}
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
if (pin == MICROPY_HW_APA102_MOSI) {
return !apa102_mosi_in_use;
}
if (pin == MICROPY_HW_APA102_SCK) {
return !apa102_sck_in_use;
}
#endif
return pin_number_is_free(pin->port, pin->number);
}
@ -171,19 +121,6 @@ uint8_t common_hal_mcu_pin_number(const mcu_pin_obj_t *pin) {
void common_hal_mcu_pin_claim(const mcu_pin_obj_t *pin) {
claim_pin(pin->port, pin->number);
#ifdef MICROPY_HW_NEOPIXEL
if (pin == MICROPY_HW_NEOPIXEL) {
neopixel_in_use = true;
}
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
if (pin == MICROPY_HW_APA102_MOSI) {
apa102_mosi_in_use = true;
}
if (pin == MICROPY_HW_APA102_SCK) {
apa102_sck_in_use = true;
}
#endif
}
void common_hal_mcu_pin_reset_number(uint8_t pin_no) {

View File

@ -31,14 +31,6 @@
#include "peripherals/pins.h"
#ifdef MICROPY_HW_NEOPIXEL
extern bool neopixel_in_use;
#endif
#ifdef MICROPY_HW_APA102_MOSI
extern bool apa102_sck_in_use;
extern bool apa102_mosi_in_use;
#endif
void reset_all_pins(void);
// reset_pin_number takes the pin number instead of the pointer so that objects don't
// need to store a full pointer.

View File

@ -29,7 +29,7 @@
#include "lib/utils/interrupt_char.h"
#include "supervisor/shared/autoreload.h"
#include "supervisor/shared/rgb_led_status.h"
#include "supervisor/shared/status_leds.h"
#include "supervisor/shared/stack.h"
#include "supervisor/shared/translate.h"
#include "supervisor/shared/workflow.h"
@ -79,7 +79,7 @@ STATIC mp_obj_t supervisor_set_rgb_status_brightness(mp_obj_t lvl) {
if (brightness_int < 0 || brightness_int > 255) {
mp_raise_ValueError(translate("Brightness must be between 0 and 255"));
}
set_rgb_status_brightness((uint8_t)brightness_int);
set_status_brightness((uint8_t)brightness_int);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(supervisor_set_rgb_status_brightness_obj, supervisor_set_rgb_status_brightness);

View File

@ -409,7 +409,7 @@ void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t *self) {
gc_collect_ptr((void *)self->stop_sequence);
}
bool maybe_refresh_epaperdisplay(void) {
size_t maybe_refresh_epaperdisplay(void) {
for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) {
if (displays[i].epaper_display.base.type != &displayio_epaperdisplay_type ||
displays[i].epaper_display.core.current_group != &circuitpython_splash) {
@ -417,11 +417,16 @@ bool maybe_refresh_epaperdisplay(void) {
continue;
}
displayio_epaperdisplay_obj_t *display = &displays[i].epaper_display;
if (common_hal_displayio_epaperdisplay_get_time_to_refresh(display) != 0) {
return false;
size_t time_to_refresh = common_hal_displayio_epaperdisplay_get_time_to_refresh(display);
if (time_to_refresh > 0) {
return time_to_refresh;
}
return common_hal_displayio_epaperdisplay_refresh(display);
if (common_hal_displayio_epaperdisplay_refresh(display)) {
return 0;
}
// If we could refresh but it failed, then we want to retry.
return 1;
}
// Return true if no ePaper displays are available to pretend it was updated.
return true;
// Return 0 if no ePaper displays are available to pretend it was updated.
return 0;
}

View File

@ -61,7 +61,7 @@ typedef struct {
void displayio_epaperdisplay_background(displayio_epaperdisplay_obj_t *self);
void release_epaperdisplay(displayio_epaperdisplay_obj_t *self);
bool maybe_refresh_epaperdisplay(void);
size_t maybe_refresh_epaperdisplay(void);
void displayio_epaperdisplay_collect_ptrs(displayio_epaperdisplay_obj_t *self);

View File

@ -39,7 +39,6 @@
#include "lib/oofatfs/ff.h"
#include "shared-bindings/microcontroller/__init__.h"
#include "supervisor/memory.h"
#include "supervisor/shared/rgb_led_status.h"
#define NO_SECTOR_LOADED 0xFFFFFFFF
@ -467,7 +466,6 @@ 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
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();
@ -475,7 +473,6 @@ static void spi_flash_flush_keep_cache(bool keep_cache) {
flush_ram_cache(keep_cache);
}
current_sector = NO_SECTOR_LOADED;
clear_temp_status();
#ifdef MICROPY_HW_LED_MSC
port_pin_set_output_level(MICROPY_HW_LED_MSC, false);
#endif

View File

@ -14,28 +14,17 @@
#define PURPLE COLOR(INTENSITY, 0, INTENSITY)
#define WHITE COLOR(INTENSITY, INTENSITY, INTENSITY)
#define BOOT_RUNNING BLUE
#define MAIN_RUNNING GREEN
#define SAFE_MODE YELLOW
#define ALL_DONE GREEN
#define EXCEPTION RED
#define SAFE_MODE YELLOW
#define REPL_RUNNING WHITE
#define ACTIVE_WRITE 0x200000
#define ALL_DONE_BLINKS 1
#define EXCEPTION_BLINKS 2
#define SAFE_MODE_BLINKS 3
#define ALL_GOOD_CYCLE_MS 2000u
#define OFF_ON_RATIO 3
#define LINE_NUMBER_TOGGLE_LENGTH 300u
#define EXCEPTION_TYPE_LENGTH_MS 1000u
#define LED_SLEEP_TIME_MS 5000u
#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 VALUE_ERROR PURPLE
#define MPY_ERROR BLUE
#define OTHER_ERROR YELLOW
#define BLINK_TIME_MS 100u

View File

@ -1,486 +0,0 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "mphalport.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "rgb_led_status.h"
#include "supervisor/shared/tick.h"
#include "py/obj.h"
#ifdef MICROPY_HW_NEOPIXEL
uint8_t rgb_status_brightness = 63;
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-bindings/neopixel_write/__init__.h"
static uint8_t status_neopixel_color[3];
static digitalio_digitalinout_obj_t status_neopixel;
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
uint8_t rgb_status_brightness = 50;
#define APA102_BUFFER_LENGTH 12
static uint8_t status_apa102_color[APA102_BUFFER_LENGTH] = {0, 0, 0, 0, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff};
#if CIRCUITPY_BITBANG_APA102
#include "shared-bindings/bitbangio/SPI.h"
static bitbangio_spi_obj_t status_apa102 = {
.base = {
.type = &bitbangio_spi_type,
},
};
#else
#include "shared-bindings/busio/SPI.h"
busio_spi_obj_t status_apa102 = {
.base = {
.type = &busio_spi_type,
},
};
#endif
#endif
#if defined(CP_RGB_STATUS_R) || defined(CP_RGB_STATUS_G) || defined(CP_RGB_STATUS_B)
#define CP_RGB_STATUS_LED
#include "shared-bindings/pwmio/PWMOut.h"
#include "shared-bindings/microcontroller/Pin.h"
pwmio_pwmout_obj_t rgb_status_r = {
.base = {
.type = &pwmio_pwmout_type,
},
};
pwmio_pwmout_obj_t rgb_status_g = {
.base = {
.type = &pwmio_pwmout_type,
},
};
pwmio_pwmout_obj_t rgb_status_b = {
.base = {
.type = &pwmio_pwmout_type,
},
};
uint8_t rgb_status_brightness = 0xFF;
uint16_t status_rgb_color[3] = {
0 /* red */, 0 /* green */, 0 /* blue */
};
#endif
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
static uint32_t current_status_color = 0;
#endif
static bool rgb_led_status_init_in_progress = false;
void rgb_led_status_init() {
if (rgb_led_status_init_in_progress) {
// Avoid recursion.
return;
}
rgb_led_status_init_in_progress = true;
#ifdef MICROPY_HW_NEOPIXEL
common_hal_digitalio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL);
// Pretend we aren't using the pins. digitalio.DigitalInOut
// will mark them as used.
neopixel_in_use = false;
common_hal_digitalio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL);
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_construct(&status_apa102,
MICROPY_HW_APA102_SCK,
MICROPY_HW_APA102_MOSI,
NULL);
#else
if (!common_hal_busio_spi_deinited(&status_apa102)) {
// This may call us recursively if common_hal_reset_pin() is called,
// The rgb_led_status_init_in_progress guard will prevent further recursion.
common_hal_busio_spi_deinit(&status_apa102);
}
common_hal_busio_spi_construct(&status_apa102,
MICROPY_HW_APA102_SCK,
MICROPY_HW_APA102_MOSI,
NULL);
common_hal_busio_spi_never_reset(&status_apa102);
#endif
// Pretend we aren't using the pins. bitbangio.SPI will
// mark them as used.
apa102_mosi_in_use = false;
apa102_sck_in_use = false;
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_try_lock(&status_apa102);
// Use 1MHz for clock rate. Some APA102's are spec'd 800kHz-1200kHz,
// though many can run much faster. bitbang will probably run slower.
shared_module_bitbangio_spi_configure(&status_apa102, 1000000, 0, 0, 8);
#else
common_hal_busio_spi_try_lock(&status_apa102);
common_hal_busio_spi_configure(&status_apa102, 1000000, 0, 0, 8);
#endif
#endif
#if defined(CP_RGB_STATUS_LED)
if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_R)) {
pwmout_result_t red_result = common_hal_pwmio_pwmout_construct(&rgb_status_r, CP_RGB_STATUS_R, 0, 50000, false);
if (PWMOUT_OK == red_result) {
common_hal_pwmio_pwmout_never_reset(&rgb_status_r);
}
}
if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_G)) {
pwmout_result_t green_result = common_hal_pwmio_pwmout_construct(&rgb_status_g, CP_RGB_STATUS_G, 0, 50000, false);
if (PWMOUT_OK == green_result) {
common_hal_pwmio_pwmout_never_reset(&rgb_status_g);
}
}
if (common_hal_mcu_pin_is_free(CP_RGB_STATUS_B)) {
pwmout_result_t blue_result = common_hal_pwmio_pwmout_construct(&rgb_status_b, CP_RGB_STATUS_B, 0, 50000, false);
if (PWMOUT_OK == blue_result) {
common_hal_pwmio_pwmout_never_reset(&rgb_status_b);
}
}
#endif
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
// Force a write of the current status color.
uint32_t rgb = current_status_color;
current_status_color = 0x1000000; // Not a valid color
new_status_color(rgb);
#endif
rgb_led_status_init_in_progress = false;
}
void reset_status_led() {
#ifdef MICROPY_HW_NEOPIXEL
common_hal_reset_pin(MICROPY_HW_NEOPIXEL);
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
common_hal_reset_pin(MICROPY_HW_APA102_MOSI);
common_hal_reset_pin(MICROPY_HW_APA102_SCK);
#endif
#if defined(CP_RGB_STATUS_LED)
// TODO: Support sharing status LED with user.
#endif
}
void new_status_color(uint32_t rgb) {
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
if (current_status_color == rgb) {
return;
}
uint32_t rgb_adjusted = color_brightness(rgb, rgb_status_brightness);
current_status_color = rgb;
#endif
#ifdef MICROPY_HW_NEOPIXEL
if (neopixel_in_use) {
return;
}
status_neopixel_color[0] = (rgb_adjusted >> 8) & 0xff;
status_neopixel_color[1] = (rgb_adjusted >> 16) & 0xff;
status_neopixel_color[2] = rgb_adjusted & 0xff;
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3);
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
if (apa102_mosi_in_use || apa102_sck_in_use) {
return;
}
status_apa102_color[5] = rgb_adjusted & 0xff;
status_apa102_color[6] = (rgb_adjusted >> 8) & 0xff;
status_apa102_color[7] = (rgb_adjusted >> 16) & 0xff;
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH);
#else
common_hal_busio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH);
#endif
#endif
#if defined(CP_RGB_STATUS_LED)
uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF;
uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF;
uint8_t blue_u8 = rgb_adjusted & 0xFF;
#if defined(CP_RGB_STATUS_INVERTED_PWM)
status_rgb_color[0] = (1 << 16) - 1 - ((uint16_t)(red_u8 << 8) + red_u8);
status_rgb_color[1] = (1 << 16) - 1 - ((uint16_t)(green_u8 << 8) + green_u8);
status_rgb_color[2] = (1 << 16) - 1 - ((uint16_t)(blue_u8 << 8) + blue_u8);
#else
status_rgb_color[0] = (uint16_t)(red_u8 << 8) + red_u8;
status_rgb_color[1] = (uint16_t)(green_u8 << 8) + green_u8;
status_rgb_color[2] = (uint16_t)(blue_u8 << 8) + blue_u8;
#endif
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, status_rgb_color[0]);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, status_rgb_color[1]);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, status_rgb_color[2]);
#endif
}
void temp_status_color(uint32_t rgb) {
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
uint32_t rgb_adjusted = rgb;
rgb_adjusted = color_brightness(rgb, rgb_status_brightness);
#endif
#ifdef MICROPY_HW_NEOPIXEL
if (neopixel_in_use) {
return;
}
uint8_t colors[3] = {(rgb_adjusted >> 8) & 0xff, (rgb_adjusted >> 16) & 0xff, rgb_adjusted & 0xff};
common_hal_neopixel_write(&status_neopixel, colors, 3);
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
if (apa102_mosi_in_use || apa102_sck_in_use) {
return;
}
uint8_t colors[APA102_BUFFER_LENGTH] = {0, 0, 0, 0, 0xff, rgb_adjusted & 0xff, (rgb_adjusted >> 8) & 0xff, (rgb_adjusted >> 16) & 0xff, 0xff, 0xff, 0xff, 0xff};
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_write(&status_apa102, colors, APA102_BUFFER_LENGTH);
#else
common_hal_busio_spi_write(&status_apa102, colors, APA102_BUFFER_LENGTH);
#endif
#endif
#if defined(CP_RGB_STATUS_LED)
uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF;
uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF;
uint8_t blue_u8 = rgb_adjusted & 0xFF;
uint16_t temp_status_color_rgb[3] = {0};
#if defined(CP_RGB_STATUS_INVERTED_PWM)
temp_status_color_rgb[0] = (1 << 16) - 1 - ((uint16_t)(red_u8 << 8) + red_u8);
temp_status_color_rgb[1] = (1 << 16) - 1 - ((uint16_t)(green_u8 << 8) + green_u8);
temp_status_color_rgb[2] = (1 << 16) - 1 - ((uint16_t)(blue_u8 << 8) + blue_u8);
#else
temp_status_color_rgb[0] = (uint16_t)(red_u8 << 8) + red_u8;
temp_status_color_rgb[1] = (uint16_t)(green_u8 << 8) + green_u8;
temp_status_color_rgb[2] = (uint16_t)(blue_u8 << 8) + blue_u8;
#endif
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, temp_status_color_rgb[0]);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, temp_status_color_rgb[1]);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, temp_status_color_rgb[2]);
#endif
}
void clear_temp_status() {
#ifdef MICROPY_HW_NEOPIXEL
if (neopixel_in_use) {
return;
}
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3);
#endif
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
if (apa102_mosi_in_use || apa102_sck_in_use) {
return;
}
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH);
#else
common_hal_busio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH);
#endif
#endif
#if defined(CP_RGB_STATUS_LED)
uint16_t red = 0;
uint16_t green = 0;
uint16_t blue = 0;
#if defined(CP_RGB_STATUS_INVERTED_PWM)
red = (1 << 16) - 1 - status_rgb_color[0];
green = (1 << 16) - 1 - status_rgb_color[1];
blue = (1 << 16) - 1 - status_rgb_color[2];
#else
red = status_rgb_color[0];
green = status_rgb_color[1];
blue = status_rgb_color[2];
#endif
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, red);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, green);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, blue);
#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)) || (defined(CP_RGB_STATUS_LED))
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
}
void set_rgb_status_brightness(uint8_t level) {
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
rgb_status_brightness = level;
uint32_t current_color = current_status_color;
// Temporarily change the current color global to force the new_status_color call to update the
// LED. Usually duplicate calls of the same color are ignored without regard to brightness
// changes.
current_status_color = 0;
new_status_color(current_color);
#endif
}
void prep_rgb_status_animation(const pyexec_result_t *result,
bool found_main,
safe_mode_t safe_mode,
rgb_status_animation_t *status) {
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
new_status_color(ALL_DONE);
status->pattern_start = supervisor_ticks_ms32();
status->safe_mode = safe_mode;
status->found_main = found_main;
status->total_exception_cycle = 0;
status->ok = result->return_code != PYEXEC_EXCEPTION;
if (status->ok) {
// If this isn't an exception, skip exception sorting and handling
return;
}
status->ones = result->exception_line % 10;
status->ones += status->ones > 0 ? 1 : 0;
status->tens = (result->exception_line / 10) % 10;
status->tens += status->tens > 0 ? 1 : 0;
status->hundreds = (result->exception_line / 100) % 10;
status->hundreds += status->hundreds > 0 ? 1 : 0;
status->thousands = (result->exception_line / 1000) % 10;
status->thousands += status->thousands > 0 ? 1 : 0;
status->digit_sum = status->ones + status->tens + status->hundreds + status->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 (!status->ok) {
status->total_exception_cycle = EXCEPTION_TYPE_LENGTH_MS * 3 + LINE_NUMBER_TOGGLE_LENGTH * status->digit_sum + LINE_NUMBER_TOGGLE_LENGTH * num_places;
}
if (!result->exception_type) {
status->exception_color = OTHER_ERROR;
} else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_IndentationError)) {
status->exception_color = INDENTATION_ERROR;
} else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_SyntaxError)) {
status->exception_color = SYNTAX_ERROR;
} else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_NameError)) {
status->exception_color = NAME_ERROR;
} else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_OSError)) {
status->exception_color = OS_ERROR;
} else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_ValueError)) {
status->exception_color = VALUE_ERROR;
} else if (mp_obj_is_subclass_fast(result->exception_type, &mp_type_MpyError)) {
status->exception_color = MPY_ERROR;
} else {
status->exception_color = OTHER_ERROR;
}
#endif
}
bool tick_rgb_status_animation(rgb_status_animation_t *status) {
#if defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || (defined(CP_RGB_STATUS_LED))
uint32_t tick_diff = supervisor_ticks_ms32() - status->pattern_start;
if (status->ok) {
// All is good. Ramp ALL_DONE up and down.
if (tick_diff > ALL_GOOD_CYCLE_MS) {
status->pattern_start = supervisor_ticks_ms32();
new_status_color(BLACK);
return true;
}
uint16_t brightness = tick_diff * 255 / (ALL_GOOD_CYCLE_MS / 2);
if (brightness > 255) {
brightness = 511 - brightness;
}
if (status->safe_mode == NO_SAFE_MODE) {
new_status_color(color_brightness(ALL_DONE, brightness));
} else {
new_status_color(color_brightness(SAFE_MODE, brightness));
}
} else {
if (tick_diff > status->total_exception_cycle) {
status->pattern_start = supervisor_ticks_ms32();
return true;
}
// First flash the file color.
if (tick_diff < EXCEPTION_TYPE_LENGTH_MS) {
if (status->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) {
new_status_color(status->exception_color);
// 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 * status->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 * status->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 * (status->thousands + status->hundreds)) {
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + 1)) {
new_status_color(BLACK);
} else {
new_status_color(HUNDREDS);
}
} else if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + status->tens)) {
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + 1)) {
new_status_color(BLACK);
} else {
new_status_color(TENS);
}
} else {
if (digit_diff < LINE_NUMBER_TOGGLE_LENGTH * (status->thousands + status->hundreds + status->tens + 1)) {
new_status_color(BLACK);
} else {
new_status_color(ONES);
}
}
} else {
new_status_color(BLACK);
}
}
#endif
return false; // Animation is not finished.
}

View File

@ -1,81 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef MICROPY_INCLUDED_SUPERVISOR_RGB_LED_STATUS_H
#define MICROPY_INCLUDED_SUPERVISOR_RGB_LED_STATUS_H
#include <stdint.h>
#include <stdbool.h>
#include "lib/utils/pyexec.h"
#include "supervisor/port.h"
#include "py/mpconfig.h"
#include "rgb_led_colors.h"
#include "supervisor/shared/safe_mode.h"
// Overall, the time module must be implemented.
// To work with a DotStar, one must have MICROPY_HW_APA102_SCK and
// MICROPY_HW_APA102_MOSI defined and bitbangio.SPI or busio.SPI implemented.
// To work with a NeoPixel, one must have MICROPY_HW_NEOPIXEL defined and
// neopixel_write implemented.
#if defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK) && !CIRCUITPY_BITBANG_APA102
#include "common-hal/busio/SPI.h"
extern busio_spi_obj_t status_apa102;
#endif
void rgb_led_status_init(void);
void reset_status_led(void);
void new_status_color(uint32_t rgb);
void temp_status_color(uint32_t rgb);
void clear_temp_status(void);
uint32_t color_brightness(uint32_t color, uint8_t brightness);
void set_rgb_status_brightness(uint8_t level);
typedef struct {
bool ok;
uint32_t pattern_start;
uint32_t total_exception_cycle;
safe_mode_t safe_mode;
uint8_t digit_sum;
uint8_t ones;
uint8_t tens;
uint8_t hundreds;
uint8_t thousands;
uint32_t exception_color;
bool found_main;
} rgb_status_animation_t;
void prep_rgb_status_animation(const pyexec_result_t *result,
bool found_main,
safe_mode_t safe_mode,
rgb_status_animation_t *status);
bool tick_rgb_status_animation(rgb_status_animation_t *status);
#endif // MICROPY_INCLUDED_SUPERVISOR_RGB_LED_STATUS_H

View File

@ -36,7 +36,7 @@
#include "supervisor/serial.h"
#include "supervisor/shared/rgb_led_colors.h"
#include "supervisor/shared/rgb_led_status.h"
#include "supervisor/shared/status_leds.h"
#include "supervisor/shared/translate.h"
#include "supervisor/shared/tick.h"
@ -65,11 +65,9 @@ safe_mode_t wait_for_safe_mode_reset(void) {
}
port_set_saved_word(SAFE_MODE_DATA_GUARD | (MANUAL_SAFE_MODE << 8));
// Wait for a while to allow for reset.
temp_status_color(SAFE_MODE);
#ifdef MICROPY_HW_LED_STATUS
digitalio_digitalinout_obj_t status_led;
common_hal_digitalio_digitalinout_construct(&status_led, MICROPY_HW_LED_STATUS);
common_hal_digitalio_digitalinout_switch_to_output(&status_led, true, DRIVE_MODE_PUSH_PULL);
#if CIRCUITPY_STATUS_LED
status_led_init();
#endif
#ifdef CIRCUITPY_BOOT_BUTTON
digitalio_digitalinout_obj_t boot_button;
@ -78,22 +76,32 @@ safe_mode_t wait_for_safe_mode_reset(void) {
#endif
uint64_t start_ticks = supervisor_ticks_ms64();
uint64_t diff = 0;
bool boot_in_safe_mode = false;
while (diff < 700) {
#ifdef MICROPY_HW_LED_STATUS
#ifdef CIRCUITPY_STATUS_LED
// Blink on for 100, off for 100, on for 100, off for 100 and on for 200
common_hal_digitalio_digitalinout_set_value(&status_led, diff > 100 && diff / 100 != 2 && diff / 100 != 4);
bool led_on = diff > 100 && diff / 100 != 2 && diff / 100 != 4;
if (led_on) {
new_status_color(SAFE_MODE);
} else {
new_status_color(BLACK);
}
#endif
#ifdef CIRCUITPY_BOOT_BUTTON
if (!common_hal_digitalio_digitalinout_get_value(&boot_button)) {
return USER_SAFE_MODE;
boot_in_safe_mode = true;
break;
}
#endif
diff = supervisor_ticks_ms64() - start_ticks;
}
#ifdef MICROPY_HW_LED_STATUS
common_hal_digitalio_digitalinout_deinit(&status_led);
#if CIRCUITPY_STATUS_LED
new_status_color(BLACK);
status_led_deinit();
#endif
clear_temp_status();
if (boot_in_safe_mode) {
return USER_SAFE_MODE;
}
port_set_saved_word(SAFE_MODE_DATA_GUARD);
return NO_SAFE_MODE;
}

View File

@ -3,7 +3,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Scott Shawcroft for Adafruit Industries
* Copyright (c) 2017-2021 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -26,11 +26,75 @@
#include "supervisor/shared/status_leds.h"
#if CIRCUITPY_DIGITALIO
#include "common-hal/digitalio/DigitalInOut.h"
#include "mphalport.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "supervisor/shared/tick.h"
#include "py/obj.h"
#ifdef MICROPY_HW_NEOPIXEL
uint8_t rgb_status_brightness = 63;
#include "shared-bindings/digitalio/DigitalInOut.h"
#include "shared-bindings/neopixel_write/__init__.h"
static uint8_t status_neopixel_color[3];
static digitalio_digitalinout_obj_t status_neopixel;
#elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
uint8_t rgb_status_brightness = 50;
#define APA102_BUFFER_LENGTH 12
static uint8_t status_apa102_color[APA102_BUFFER_LENGTH] = {0, 0, 0, 0, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff};
#if CIRCUITPY_BITBANG_APA102
#include "shared-bindings/bitbangio/SPI.h"
static bitbangio_spi_obj_t status_apa102 = {
.base = {
.type = &bitbangio_spi_type,
},
};
#else
#include "shared-bindings/busio/SPI.h"
busio_spi_obj_t status_apa102 = {
.base = {
.type = &busio_spi_type,
},
};
#endif
#elif CIRCUITPY_PWM_RGB_LED
#include "shared-bindings/pwmio/PWMOut.h"
#include "shared-bindings/microcontroller/Pin.h"
pwmio_pwmout_obj_t rgb_status_r = {
.base = {
.type = &pwmio_pwmout_type,
},
};
pwmio_pwmout_obj_t rgb_status_g = {
.base = {
.type = &pwmio_pwmout_type,
},
};
pwmio_pwmout_obj_t rgb_status_b = {
.base = {
.type = &pwmio_pwmout_type,
},
};
uint8_t rgb_status_brightness = 0xFF;
uint16_t status_rgb_color[3] = {
0 /* red */, 0 /* green */, 0 /* blue */
};
#elif CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS)
#include "shared-bindings/digitalio/DigitalInOut.h"
digitalio_digitalinout_obj_t single_color_led;
uint8_t rgb_status_brightness = 0xff;
#endif
#if CIRCUITPY_DIGITALIO && (defined(MICROPY_HW_LED_RX) || defined(MICROPY_HW_LED_TX))
#include "shared-bindings/digitalio/DigitalInOut.h"
#ifdef MICROPY_HW_LED_RX
digitalio_digitalinout_obj_t rx_led;
#endif
@ -38,27 +102,210 @@ digitalio_digitalinout_obj_t rx_led;
#ifdef MICROPY_HW_LED_TX
digitalio_digitalinout_obj_t tx_led;
#endif
#endif
void init_status_leds(void) {
#ifdef MICROPY_HW_LED_RX
#if CIRCUITPY_STATUS_LED
static uint32_t current_status_color = 0;
#endif
static bool status_led_init_in_progress = false;
void status_led_init() {
if (status_led_init_in_progress) {
// Avoid recursion.
return;
}
status_led_init_in_progress = true;
#ifdef MICROPY_HW_NEOPIXEL
common_hal_digitalio_digitalinout_construct(&status_neopixel, MICROPY_HW_NEOPIXEL);
common_hal_digitalio_digitalinout_switch_to_output(&status_neopixel, false, DRIVE_MODE_PUSH_PULL);
#elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_construct(&status_apa102,
MICROPY_HW_APA102_SCK,
MICROPY_HW_APA102_MOSI,
NULL);
#else
if (!common_hal_busio_spi_deinited(&status_apa102)) {
common_hal_busio_spi_deinit(&status_apa102);
}
common_hal_busio_spi_construct(&status_apa102,
MICROPY_HW_APA102_SCK,
MICROPY_HW_APA102_MOSI,
NULL);
#endif
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_try_lock(&status_apa102);
// Use 1MHz for clock rate. Some APA102's are spec'd 800kHz-1200kHz,
// though many can run much faster. bitbang will probably run slower.
shared_module_bitbangio_spi_configure(&status_apa102, 1000000, 0, 0, 8);
#else
common_hal_busio_spi_try_lock(&status_apa102);
common_hal_busio_spi_configure(&status_apa102, 1000000, 0, 0, 8);
#endif
#elif CIRCUITPY_PWM_RGB_LED
if (common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_R)) {
pwmout_result_t red_result = common_hal_pwmio_pwmout_construct(&rgb_status_r, CIRCUITPY_RGB_STATUS_R, 0, 50000, false);
if (PWMOUT_OK == red_result) {
common_hal_pwmio_pwmout_never_reset(&rgb_status_r);
}
}
if (common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_G)) {
pwmout_result_t green_result = common_hal_pwmio_pwmout_construct(&rgb_status_g, CIRCUITPY_RGB_STATUS_G, 0, 50000, false);
if (PWMOUT_OK == green_result) {
common_hal_pwmio_pwmout_never_reset(&rgb_status_g);
}
}
if (common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_B)) {
pwmout_result_t blue_result = common_hal_pwmio_pwmout_construct(&rgb_status_b, CIRCUITPY_RGB_STATUS_B, 0, 50000, false);
if (PWMOUT_OK == blue_result) {
common_hal_pwmio_pwmout_never_reset(&rgb_status_b);
}
}
#elif defined(MICROPY_HW_LED_STATUS)
common_hal_digitalio_digitalinout_construct(&single_color_led, MICROPY_HW_LED_STATUS);
common_hal_digitalio_digitalinout_switch_to_output(&single_color_led, true, DRIVE_MODE_PUSH_PULL);
#endif
#if CIRCUITPY_DIGITALIO && CIRCUITPY_STATUS_LED
// Force a write of the current status color.
uint32_t rgb = current_status_color;
current_status_color = 0x1000000; // Not a valid color
new_status_color(rgb);
#endif
status_led_init_in_progress = false;
}
void status_led_deinit() {
#ifdef MICROPY_HW_NEOPIXEL
common_hal_reset_pin(MICROPY_HW_NEOPIXEL);
#elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_deinit(&status_apa102);
#else
common_hal_busio_spi_deinit(&status_apa102);
#endif
#elif CIRCUITPY_PWM_RGB_LED
if (!common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_R)) {
common_hal_pwmio_pwmout_deinit(&rgb_status_r);
}
if (!common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_G)) {
common_hal_pwmio_pwmout_deinit(&rgb_status_g);
}
if (!common_hal_mcu_pin_is_free(CIRCUITPY_RGB_STATUS_B)) {
common_hal_pwmio_pwmout_deinit(&rgb_status_b);
}
#elif defined(MICROPY_HW_LED_STATUS)
common_hal_digitalio_digitalinout_deinit(&single_color_led);
#endif
}
void new_status_color(uint32_t rgb) {
#if CIRCUITPY_STATUS_LED
if (current_status_color == rgb) {
return;
}
uint32_t rgb_adjusted = color_brightness(rgb, rgb_status_brightness);
current_status_color = rgb;
#endif
#ifdef MICROPY_HW_NEOPIXEL
status_neopixel_color[0] = (rgb_adjusted >> 8) & 0xff;
status_neopixel_color[1] = (rgb_adjusted >> 16) & 0xff;
status_neopixel_color[2] = rgb_adjusted & 0xff;
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3);
#elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
status_apa102_color[5] = rgb_adjusted & 0xff;
status_apa102_color[6] = (rgb_adjusted >> 8) & 0xff;
status_apa102_color[7] = (rgb_adjusted >> 16) & 0xff;
#if CIRCUITPY_BITBANG_APA102
shared_module_bitbangio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH);
#else
common_hal_busio_spi_write(&status_apa102, status_apa102_color, APA102_BUFFER_LENGTH);
#endif
#elif CIRCUITPY_PWM_RGB_LED
uint8_t red_u8 = (rgb_adjusted >> 16) & 0xFF;
uint8_t green_u8 = (rgb_adjusted >> 8) & 0xFF;
uint8_t blue_u8 = rgb_adjusted & 0xFF;
#ifdef CIRCUITPY_RGB_STATUS_INVERTED_PWM
status_rgb_color[0] = (1 << 16) - 1 - ((uint16_t)(red_u8 << 8) + red_u8);
status_rgb_color[1] = (1 << 16) - 1 - ((uint16_t)(green_u8 << 8) + green_u8);
status_rgb_color[2] = (1 << 16) - 1 - ((uint16_t)(blue_u8 << 8) + blue_u8);
#else
status_rgb_color[0] = (uint16_t)(red_u8 << 8) + red_u8;
status_rgb_color[1] = (uint16_t)(green_u8 << 8) + green_u8;
status_rgb_color[2] = (uint16_t)(blue_u8 << 8) + blue_u8;
#endif
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_r, status_rgb_color[0]);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_g, status_rgb_color[1]);
common_hal_pwmio_pwmout_set_duty_cycle(&rgb_status_b, status_rgb_color[2]);
#elif CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS)
common_hal_digitalio_digitalinout_set_value(&single_color_led, rgb_adjusted > 0);
#endif
}
uint32_t color_brightness(uint32_t color, uint8_t brightness) {
#if CIRCUITPY_STATUS_LED
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
}
void set_status_brightness(uint8_t level) {
#if CIRCUITPY_STATUS_LED
rgb_status_brightness = level;
uint32_t current_color = current_status_color;
// Temporarily change the current color global to force the new_status_color call to update the
// LED. Usually duplicate calls of the same color are ignored without regard to brightness
// changes.
current_status_color = 0;
new_status_color(current_color);
#endif
}
void init_rxtx_leds(void) {
#if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_RX)
common_hal_digitalio_digitalinout_construct(&rx_led, MICROPY_HW_LED_RX);
common_hal_digitalio_digitalinout_switch_to_output(&rx_led, true, DRIVE_MODE_PUSH_PULL);
#endif
#ifdef MICROPY_HW_LED_TX
#if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_TX)
common_hal_digitalio_digitalinout_construct(&tx_led, MICROPY_HW_LED_TX);
common_hal_digitalio_digitalinout_switch_to_output(&tx_led, true, DRIVE_MODE_PUSH_PULL);
#endif
}
void toggle_rx_led(void) {
#ifdef MICROPY_HW_LED_RX
#if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_RX)
common_hal_digitalio_digitalinout_set_value(&rx_led, !common_hal_digitalio_digitalinout_get_value(&rx_led));
#endif
}
void toggle_tx_led(void) {
#ifdef MICROPY_HW_LED_TX
#if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_TX)
common_hal_digitalio_digitalinout_set_value(&tx_led, !common_hal_digitalio_digitalinout_get_value(&tx_led));
#endif
}

View File

@ -27,10 +27,35 @@
#ifndef MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H
#define MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H
void init_status_leds(void);
#include <stdint.h>
#include <stdbool.h>
#include "lib/utils/pyexec.h"
#include "supervisor/port.h"
#include "py/mpconfig.h"
#include "rgb_led_colors.h"
#include "supervisor/shared/safe_mode.h"
// Overall, the time module must be implemented.
// To work with a DotStar, one must have MICROPY_HW_APA102_SCK and
// MICROPY_HW_APA102_MOSI defined and bitbangio.SPI or busio.SPI implemented.
// To work with a NeoPixel, one must have MICROPY_HW_NEOPIXEL defined and
// neopixel_write implemented.
#define CIRCUITPY_PWM_RGB_LED defined(CIRCUITPY_RGB_STATUS_R) || defined(CIRCUITPY_RGB_STATUS_G) || defined(CIRCUITPY_RGB_STATUS_B)
#define CIRCUITPY_STATUS_LED (CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_STATUS)) || defined(MICROPY_HW_NEOPIXEL) || (defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)) || CIRCUITPY_PWM_RGB_LED
void status_led_init(void);
void status_led_deinit(void);
void new_status_color(uint32_t rgb);
uint32_t color_brightness(uint32_t color, uint8_t brightness);
void set_status_brightness(uint8_t level);
void init_rxtx_leds(void);
void toggle_rx_led(void);
void toggle_tx_led(void);
#endif // MICROPY_INCLUDED_SUPERVISOR_STATUS_LEDS_H

View File

@ -9,7 +9,6 @@ SRC_SUPERVISOR = \
supervisor/shared/flash.c \
supervisor/shared/memory.c \
supervisor/shared/micropython.c \
supervisor/shared/rgb_led_status.c \
supervisor/shared/safe_mode.c \
supervisor/shared/stack.c \
supervisor/shared/status_leds.c \