17ed2a6898
- disable_ble_workflow - set_next_stack_limit - set_rgb_status_brightness
375 lines
13 KiB
C
375 lines
13 KiB
C
/*
|
|
* This file is part of the MicroPython project, http://micropython.org/
|
|
*
|
|
* The MIT License (MIT)
|
|
*
|
|
* 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
|
|
* 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 "supervisor/shared/status_leds.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "mphalport.h"
|
|
#include "shared-bindings/microcontroller/Pin.h"
|
|
#include "supervisor/shared/tick.h"
|
|
#include "py/obj.h"
|
|
|
|
|
|
#ifdef CIRCUITPY_STATUS_LED_POWER
|
|
#include "shared-bindings/digitalio/DigitalInOut.h"
|
|
static digitalio_digitalinout_obj_t _status_power;
|
|
#endif
|
|
|
|
#ifdef MICROPY_HW_NEOPIXEL
|
|
uint8_t rgb_status_brightness = 63;
|
|
#include "shared-bindings/digitalio/DigitalInOut.h"
|
|
#include "shared-bindings/neopixel_write/__init__.h"
|
|
|
|
#ifndef MICROPY_HW_NEOPIXEL_COUNT
|
|
#define MICROPY_HW_NEOPIXEL_COUNT (1)
|
|
#endif
|
|
|
|
static uint64_t next_start_raw_ticks;
|
|
static uint8_t status_neopixel_color[3 * MICROPY_HW_NEOPIXEL_COUNT];
|
|
static digitalio_digitalinout_obj_t status_neopixel;
|
|
|
|
#elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
|
|
uint8_t rgb_status_brightness = 50;
|
|
|
|
#ifndef MICROPY_HW_APA102_COUNT
|
|
#define MICROPY_HW_APA102_COUNT (1)
|
|
#endif
|
|
|
|
#define APA102_BUFFER_LENGTH (4 + 4 * MICROPY_HW_APA102_COUNT + 4)
|
|
static uint8_t status_apa102_color[APA102_BUFFER_LENGTH];
|
|
|
|
#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;
|
|
|
|
#ifndef MICROPY_HW_LED_STATUS_INVERTED
|
|
#define MICROPY_HW_LED_STATUS_INVERTED (0)
|
|
#endif
|
|
|
|
#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
|
|
|
|
#ifdef MICROPY_HW_LED_TX
|
|
digitalio_digitalinout_obj_t tx_led;
|
|
#endif
|
|
#endif
|
|
|
|
#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 CIRCUITPY_STATUS_LED_POWER
|
|
common_hal_digitalio_digitalinout_construct(&_status_power, CIRCUITPY_STATUS_LED_POWER);
|
|
common_hal_digitalio_digitalinout_switch_to_output(&_status_power,
|
|
CIRCUITPY_STATUS_LED_POWER_INVERTED == 0, DRIVE_MODE_PUSH_PULL);
|
|
#endif
|
|
|
|
#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)
|
|
// Set every byte to 0xff except the start 4 bytes that make up the header.
|
|
memset(status_apa102_color + 4, 0xff, APA102_BUFFER_LENGTH - 4);
|
|
#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,
|
|
false);
|
|
#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, MICROPY_HW_LED_STATUS_INVERTED == 0, 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
|
|
// Make sure the pin stays low for the reset period. The pin reset may pull
|
|
// it up and stop the reset period.
|
|
while (port_get_raw_ticks(NULL) < next_start_raw_ticks) {
|
|
}
|
|
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
|
|
|
|
#ifdef CIRCUITPY_STATUS_LED_POWER
|
|
common_hal_digitalio_digitalinout_deinit(&_status_power);
|
|
#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
|
|
for (size_t i = 0; i < MICROPY_HW_NEOPIXEL_COUNT; i++) {
|
|
status_neopixel_color[3 * i + 0] = (rgb_adjusted >> 8) & 0xff;
|
|
status_neopixel_color[3 * i + 1] = (rgb_adjusted >> 16) & 0xff;
|
|
status_neopixel_color[3 * i + 2] = rgb_adjusted & 0xff;
|
|
}
|
|
common_hal_neopixel_write(&status_neopixel, status_neopixel_color, 3 * MICROPY_HW_NEOPIXEL_COUNT);
|
|
next_start_raw_ticks = port_get_raw_ticks(NULL) + 2;
|
|
#elif defined(MICROPY_HW_APA102_MOSI) && defined(MICROPY_HW_APA102_SCK)
|
|
for (size_t i = 0; i < MICROPY_HW_APA102_COUNT; i++) {
|
|
// Skip 4 + offset to skip the header bytes too.
|
|
status_apa102_color[4 * i + 4 + 1] = rgb_adjusted & 0xff;
|
|
status_apa102_color[4 * i + 4 + 2] = (rgb_adjusted >> 8) & 0xff;
|
|
status_apa102_color[4 * i + 4 + 3] = (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) ^ MICROPY_HW_LED_STATUS_INVERTED);
|
|
#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;
|
|
// This is only called by user code and we're never controlling the status
|
|
// LED when user code is running. So, we don't need to update the current
|
|
// state (there is none.)
|
|
#endif
|
|
}
|
|
|
|
uint8_t get_status_brightness(void) {
|
|
#if CIRCUITPY_STATUS_LED
|
|
return rgb_status_brightness;
|
|
#else
|
|
return 0;
|
|
#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);
|
|
common_hal_digitalio_digitalinout_never_reset(&rx_led);
|
|
#endif
|
|
#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);
|
|
common_hal_digitalio_digitalinout_never_reset(&tx_led);
|
|
#endif
|
|
}
|
|
|
|
void deinit_rxtx_leds(void) {
|
|
#if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_RX)
|
|
common_hal_digitalio_digitalinout_deinit(&rx_led);
|
|
#endif
|
|
#if CIRCUITPY_DIGITALIO && defined(MICROPY_HW_LED_TX)
|
|
common_hal_digitalio_digitalinout_deinit(&tx_led);
|
|
#endif
|
|
}
|
|
|
|
void toggle_rx_led(void) {
|
|
#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) {
|
|
#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
|
|
}
|