| @@ -3,6 +3,8 @@ | |||
| cmake_minimum_required(VERSION 3.16) | |||
| include($ENV{IDF_PATH}/tools/cmake/project.cmake) | |||
| include($ENV{IOT_SOLUTION_PATH}/component.cmake) | |||
| project(blinky) | |||
| target_add_binary_data(blinky.elf "main/broker.pem" TEXT) | |||
| @@ -11,6 +11,8 @@ idf_component_register( | |||
| "leds.cpp" | |||
| "presets.cpp" | |||
| "spi_leds.cpp" | |||
| "screen_leds.cpp" | |||
| "display.cpp" | |||
| "patterns/gradient.cpp" | |||
| "patterns/random.cpp" | |||
| "patterns/sparkle.cpp" | |||
| @@ -0,0 +1,80 @@ | |||
| static const char *TAG = "display"; | |||
| #include <esp_log.h> | |||
| #include "display.hpp" | |||
| Display::Display(size_t w, size_t h) : | |||
| width(w), height(h), pitch(w), buffer(NULL), | |||
| bus(NULL), iface_drv(NULL), driver{.deinit = NULL} | |||
| { | |||
| esp_err_t ret; | |||
| spi_config_t bus_cfg = { | |||
| .miso_io_num = GPIO_NUM_4, | |||
| .mosi_io_num = GPIO_NUM_35, | |||
| .sclk_io_num = GPIO_NUM_36, | |||
| .max_transfer_sz = (int)(height * width * sizeof(*buffer) + 8), | |||
| }; | |||
| bus = spi_bus_create(SPI2_HOST, &bus_cfg); | |||
| if (NULL == bus) { | |||
| ESP_LOGE(TAG, "Failed to acquire bus"); | |||
| return; | |||
| } | |||
| scr_interface_spi_config_t spi_dev_cfg = { | |||
| .spi_bus = bus, | |||
| .pin_num_cs = 34, | |||
| .pin_num_dc = 37, | |||
| .clk_freq = 40 * 1000 * 1000, | |||
| .swap_data = 1, | |||
| }; | |||
| ret = scr_interface_create(SCREEN_IFACE_SPI, &spi_dev_cfg, &iface_drv); | |||
| if (ESP_OK != ret) { | |||
| ESP_LOGE(TAG, "Failed to create interface"); | |||
| return; | |||
| } | |||
| ret = scr_find_driver(SCREEN_CONTROLLER_ST7789, &driver); | |||
| if (ESP_OK != ret) { | |||
| ESP_LOGE(TAG, "Failed to find driver"); | |||
| return; | |||
| } | |||
| scr_controller_config_t lcd_cfg = { | |||
| .interface_drv = iface_drv, | |||
| .pin_num_rst = 38, | |||
| .pin_num_bckl = 33, | |||
| .rst_active_level = 0, | |||
| .bckl_active_level = 1, | |||
| .width = (uint16_t)width, | |||
| .height = (uint16_t)height, | |||
| .offset_hor = 52, | |||
| .offset_ver = 40, | |||
| .rotate = SCR_DIR_LRTB, | |||
| }; | |||
| ret = driver.init(&lcd_cfg); | |||
| if (ESP_OK != ret) { | |||
| ESP_LOGE(TAG, "Failed to initialize driver"); | |||
| return; | |||
| } | |||
| buffer = new uint16_t[height * pitch](); | |||
| refresh(); | |||
| } | |||
| Display::~Display() { | |||
| if (buffer) delete[] buffer; | |||
| if (driver.deinit) driver.deinit(); | |||
| if (iface_drv) scr_interface_delete(iface_drv); | |||
| if (bus) spi_bus_delete(&bus); | |||
| } | |||
| void Display::refresh() { | |||
| driver.draw_bitmap(0, 0, width, height, buffer); | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| #pragma once | |||
| #include <screen_driver.h> | |||
| class Display { | |||
| public: | |||
| Display(size_t w, size_t h); | |||
| ~Display(); | |||
| void refresh(); | |||
| size_t get_width() const { return width; } | |||
| size_t get_height() const { return height; } | |||
| size_t get_pitch() const { return pitch; } | |||
| size_t get_stride() const { return pitch * sizeof(*buffer); } | |||
| uint16_t* get_buffer() const { return buffer; } | |||
| private: | |||
| size_t width; | |||
| size_t height; | |||
| size_t pitch; | |||
| uint16_t *buffer; | |||
| spi_bus_handle_t bus; | |||
| scr_interface_driver_t *iface_drv; | |||
| scr_driver_t driver; | |||
| }; | |||
| @@ -16,6 +16,7 @@ static const char *TAG = "blinky"; | |||
| #include "presets.hpp" | |||
| #include "utils.hpp" | |||
| #include "spi_leds.hpp" | |||
| #include "screen_leds.hpp" | |||
| // mDNS / NetBIOS | |||
| @@ -176,7 +177,7 @@ extern "C" void app_main(void) { | |||
| } else { | |||
| ESP_LOGI(TAG, "Starting animation"); | |||
| int period_us = 1000000 / 60; | |||
| int period_us = 1000000 / 30; | |||
| int64_t target_us = time_us(); | |||
| int64_t profile_start = target_us; | |||
| #ifdef PROFILE_PERF | |||
| @@ -0,0 +1,79 @@ | |||
| static const char *TAG = "screen_leds"; | |||
| #include <esp_log.h> | |||
| #include "screen_leds.hpp" | |||
| static inline void fill(uint16_t *buffer, uint16_t value, int w, int h, int p = -1) { | |||
| if (p <= 0) p = w; | |||
| uint16_t *line = buffer; | |||
| while (--h >= 0) { | |||
| uint16_t *pixel = line; | |||
| for (int _w = w; _w > 0; --_w) { | |||
| *pixel = value; | |||
| ++pixel; | |||
| } | |||
| line += p; | |||
| } | |||
| } | |||
| static inline void box(uint16_t *buffer, uint16_t value, int x, int y, int w, int h, int p = -1) { | |||
| if (p <= 0) p = w; | |||
| fill(buffer + x + (y * p), value, w, h, p); | |||
| } | |||
| static inline uint16_t rgb16(int r, int g, int b) { | |||
| return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((uint8_t)b >> 3); | |||
| } | |||
| static inline uint16_t color_to_565(Color c) { | |||
| return rgb16(c.r, c.g, c.b); | |||
| } | |||
| ScreenLEDs::ScreenLEDs(int length) : LEDStrip(length), display(135, 240) {} | |||
| void ScreenLEDs::length_changing(int length) { | |||
| fill(display.get_buffer(), COLOR_BLACK, display.get_width(), display.get_height()); | |||
| } | |||
| void ScreenLEDs::show() { | |||
| const int width = display.get_width(); | |||
| const int height = display.get_height(); | |||
| const int pitch = display.get_pitch(); | |||
| auto buffer = display.get_buffer(); | |||
| const size_t size = ((width + height) * 2) / (length + 4); | |||
| int lx = 0, ly = 0; | |||
| int dx = 0, dy = size; | |||
| for (size_t l = 0; l < length; ++l) { | |||
| if (ly + dy > height) { | |||
| ly -= dy; | |||
| dx = size; | |||
| dy = 0; | |||
| lx += dx; | |||
| } else if (ly < 0) { | |||
| ly -= dy; | |||
| dx = -size; | |||
| dy = 0; | |||
| lx += dx; | |||
| } else if (lx + dx > width) { | |||
| lx -= dx; | |||
| dx = 0; | |||
| dy = -size; | |||
| ly += dy; | |||
| } else if (lx < 0) { | |||
| lx -= dx; | |||
| dx = 0; | |||
| dy = size; | |||
| ly += dy; | |||
| } | |||
| box(buffer, color_to_565(pixels[l]), lx, ly, size, size, pitch); | |||
| lx += dx; | |||
| ly += dy; | |||
| } | |||
| display.refresh(); | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| #pragma once | |||
| #include "leds.hpp" | |||
| #include "display.hpp" | |||
| class ScreenLEDs : public LEDStrip { | |||
| public: | |||
| ScreenLEDs(int length = 0); | |||
| void show(); | |||
| void length_changing(int length); | |||
| private: | |||
| Display display; | |||
| }; | |||