diff --git a/CMakeLists.txt b/CMakeLists.txt index 10a9b50..2979175 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ idf_component_register( SRCS "blk_box.cpp" INCLUDE_DIRS "include" "." + REQUIRES led_strip PRIV_REQUIRES esp_driver_gpio esp_driver_i2c diff --git a/blk_box.cpp b/blk_box.cpp index c681332..dd67d49 100644 --- a/blk_box.cpp +++ b/blk_box.cpp @@ -2,8 +2,10 @@ #include "blk_box_drivers/i2c.h" #include "blk_box_drivers/inputs.hpp" +#include "blk_box_drivers/leds.hpp" void init_blk_box(BlkBoxInitConfig cfg) { init_main_i2c(); init_expander(); + init_leds(); } diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 955d6b7..7bd8d59 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -1,6 +1,7 @@ set(SOURCES "inputs.cpp" "i2c.cpp" + "leds.cpp" ) target_sources(${COMPONENT_LIB} PRIVATE ${SOURCES}) diff --git a/drivers/leds.cpp b/drivers/leds.cpp new file mode 100644 index 0000000..2e44d85 --- /dev/null +++ b/drivers/leds.cpp @@ -0,0 +1,64 @@ +#include "blk_box_drivers/leds.hpp" +#include "pins.h" +#include "esp_log.h" +#include "esp_err.h" +#include "led_strip.h" + +const LEDColor LEDColor::OFF = LEDColor::from_rgb(0x00, 0x00, 0x00); +const LEDColor LEDColor::RED = LEDColor::from_rgb(0x17, 0x00, 0x00); +const LEDColor LEDColor::RED_STRONG = LEDColor::from_rgb(0xFF, 0x00, 0x00); +const LEDColor LEDColor::ORANGE = LEDColor::from_rgb(0x17, 0x02, 0x00); +const LEDColor LEDColor::ORANGE_STRONG = LEDColor::from_rgb(0xFF, 0x20, 0x00); +const LEDColor LEDColor::YELLOW = LEDColor::from_rgb(0x07, 0x07, 0x00); +const LEDColor LEDColor::YELLOW_STRONG = LEDColor::from_rgb(0xFF, 0xFF, 0x00); +const LEDColor LEDColor::GREEN = LEDColor::from_rgb(0x00, 0x07, 0x00); +const LEDColor LEDColor::GREEN_STRONG = LEDColor::from_rgb(0x00, 0xFF, 0x00); +const LEDColor LEDColor::BLUE = LEDColor::from_rgb(0x00, 0x00, 0x17); +const LEDColor LEDColor::BLUE_STRONG = LEDColor::from_rgb(0x00, 0x00, 0xFF); +const LEDColor LEDColor::PINK = LEDColor::from_rgb(0x10, 0x00, 0x04); +const LEDColor LEDColor::PINK_STRONG = LEDColor::from_rgb(0xFF, 0x00, 0x80); +const LEDColor LEDColor::WHITE = LEDColor::from_rgb(0x04, 0x04, 0x04); +const LEDColor LEDColor::WHITE_STRONG = LEDColor::from_rgb(0xFF, 0xFF, 0xFF); + +const static char* TAG = "leds"; + +static led_strip_handle_t led_strip = NULL; + +void init_leds() { + /// LED strip common configuration + led_strip_config_t strip_config = { + .strip_gpio_num = PIN_NEOPIXEL, + .max_leds = LED_COUNT, + // TODO: switch this over when we switch to the different LEDs + .led_model = LED_MODEL_WS2812, + .color_component_format = LED_STRIP_COLOR_COMPONENT_FMT_GRB, + .flags = { + .invert_out = false, + } + }; + + /// RMT backend specific configuration + led_strip_rmt_config_t rmt_config = { + .clk_src = RMT_CLK_SRC_DEFAULT, + .resolution_hz = LED_STRIP_RMT_RES_HZ, + .mem_block_symbols = RMT_LED_SYMBOLS * RMT_SYMBOLS_PER_LED, + .flags = { + .with_dma = false, + } + }; + + /// Create the LED strip object + ESP_ERROR_CHECK(led_strip_new_rmt_device(&strip_config, &rmt_config, &led_strip)); +} + +void LEDController::set_led(uint32_t led, uint32_t color) { + ESP_ERROR_CHECK(led_strip_set_pixel(led_strip, led, color >> 16 & 0xFF, color >> 8 & 0xFF, color & 0xFF)); +} + +void LEDController::flush() { + ESP_ERROR_CHECK(led_strip_refresh(led_strip)); +} + +void LEDController::clear() { + ESP_ERROR_CHECK(led_strip_clear(led_strip)); +} diff --git a/idf_component.yml b/idf_component.yml index 2c6790e..de891c8 100644 --- a/idf_component.yml +++ b/idf_component.yml @@ -2,7 +2,7 @@ dependencies: ## Required IDF version idf: - version: ">=6.0.0" + version: '>=6.0.0' # # Put list of dependencies here # # For components maintained by Espressif: # component: "~1.0.0" diff --git a/include/blk_box_drivers/leds.hpp b/include/blk_box_drivers/leds.hpp new file mode 100644 index 0000000..bd33a1b --- /dev/null +++ b/include/blk_box_drivers/leds.hpp @@ -0,0 +1,112 @@ +#ifndef LEDS_H +#define LEDS_H + +#include + +const uint32_t LED_COUNT = 21; +const uint32_t LED_SHAPE_COUNT = 4; +const uint32_t LED_INDICATOR_COUNT = 17; + +// We will store 7 LEDs worth of data in the RMT peripheral, +// so we can update all the LEDs in 3 transactions. +#define RMT_LED_SYMBOLS 7 +// Each LED requires 24 RMT symbols (1 for each bit) +#define RMT_SYMBOLS_PER_LED 24 + +// 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) +#define LED_STRIP_RMT_RES_HZ (10 * 1000 * 1000) + +class LEDColor { +private: + uint32_t color; + constexpr LEDColor(uint32_t color) : color(color) {} +public: + constexpr LEDColor(uint8_t r, uint8_t g, uint8_t b) + : color((static_cast(r) << 16) + | (static_cast(g) << 8) + | static_cast(b)) {} + + constexpr static LEDColor from_rgb(uint8_t r, uint8_t g, uint8_t b) { + return LEDColor(r, g, b); + } + + static const LEDColor OFF; + static const LEDColor RED; + static const LEDColor RED_STRONG; + static const LEDColor ORANGE; + static const LEDColor ORANGE_STRONG; + static const LEDColor YELLOW; + static const LEDColor YELLOW_STRONG; + static const LEDColor GREEN; + static const LEDColor GREEN_STRONG; + static const LEDColor BLUE; + static const LEDColor BLUE_STRONG; + static const LEDColor PINK; + static const LEDColor PINK_STRONG; + static const LEDColor WHITE; + static const LEDColor WHITE_STRONG; + + inline constexpr uint32_t value() const { return color; } +}; + +/// One of the shapes on the shape display. +enum class ShapeLed { + Shape1Led = 0, + Shape2Led = 1, + Shape3Led = 2, + Shape4Led = 3, +}; + +/// One of the indicator LEDs. +enum class IndicatorLED { + MODULE_SSEG = 4, + GAME_SSEG = 5, + TFT = 6, + MIC = 7, + IR_LED = 8, + SPEAKER = 9, + RFID = 10, + KEYPAD = 11, + LCD = 12, + S4 = 13, + S3 = 14, + S2 = 15, + S1 = 16, + B4 = 17, + B3 = 18, + B2 = 19, + B1 = 20, +}; + +/// @brief Initializes the indicator LEDs +void init_leds(); + +class LEDController { +private: + uint32_t led_colors[LED_COUNT]; + + static void set_led(uint32_t led, uint32_t color); +public: + /// Sets the color of an indicator LED. + /// + /// Call `flush()` to send the data to the LEDs. + static void set_indicator(IndicatorLED led, LEDColor color) { + set_led(static_cast(led), color.value()); + } + + /// Sets the color of an indicator LED. + /// + /// Call `flush()` to send the data to the LEDs. + static void set_shape(ShapeLed led, LEDColor color) { + set_led(static_cast(led), color.value()); + } + + /// Outputs the data to the leds. + static void flush(); + + /// Clears the LEDs + static void clear(); +}; + + +#endif // LEDS_H \ No newline at end of file diff --git a/include/pins.h b/include/pins.h index 876204b..32a629c 100644 --- a/include/pins.h +++ b/include/pins.h @@ -27,7 +27,8 @@ #define PIN_IR_RCV (GPIO_NUM_14) -#define PIN_NEOPIXEL (GPIO_NUM_21) +// #define PIN_NEOPIXEL (GPIO_NUM_21) // Rev 2.1 +#define PIN_NEOPIXEL (GPIO_NUM_0) // Rev 2.0 #define PIN_SD_DAT0 (GPIO_NUM_38) #define PIN_SD_DAT1 (GPIO_NUM_47)