From aa769002445efe6be0d4f52fb81a160d411b4c1f Mon Sep 17 00:00:00 2001 From: Martin Bauer Date: Fri, 19 Nov 2021 17:22:09 +0100 Subject: [PATCH] Alexa swipe effect --- espmusicmouse/.gitignore | 2 +- espmusicmouse/lib/leds/LedAnimation.h | 56 --- espmusicmouse/lib/leds/LedControl.cpp | 146 ------ espmusicmouse/lib/leds/LedControl.h | 37 -- .../lib/leds/esp32_digital_led_lib.cpp | 472 ------------------ .../lib/leds/esp32_digital_led_lib.h | 155 ------ espmusicmouse/lib/ledtl/Esp32DriverRGBW.cpp | 4 + .../lib/ledtl/containers/LedStripRGBW.h | 12 +- .../lib/ledtl/drivers/Esp32DriverRGBW.h | 4 + espmusicmouse/lib/ledtl/effects/AlexaSwipe.h | 142 ++++++ espmusicmouse/lib/ledtl/effects/Circular.h | 12 +- espmusicmouse/lib/ledtl/effects/Common.h | 4 +- espmusicmouse/lib/ledtl/helpers/BellCurve.h | 2 + .../lib/ledtl/helpers/ColorConversions.h | 114 +++++ espmusicmouse/lib/ledtl/helpers/ColorHSV.h | 8 + espmusicmouse/platformio.ini | 6 + espmusicmouse/src/TaskLed.h | 7 +- espmusicmouse/src/host_test.cpp | 40 ++ espmusicmouse/src/main.cpp | 9 +- pyaudioplayeralsa/plan.md | 4 +- 20 files changed, 342 insertions(+), 894 deletions(-) delete mode 100644 espmusicmouse/lib/leds/LedAnimation.h delete mode 100644 espmusicmouse/lib/leds/LedControl.cpp delete mode 100644 espmusicmouse/lib/leds/LedControl.h delete mode 100644 espmusicmouse/lib/leds/esp32_digital_led_lib.cpp delete mode 100644 espmusicmouse/lib/leds/esp32_digital_led_lib.h create mode 100644 espmusicmouse/lib/ledtl/effects/AlexaSwipe.h create mode 100644 espmusicmouse/lib/ledtl/helpers/ColorConversions.h create mode 100644 espmusicmouse/lib/ledtl/helpers/ColorHSV.h create mode 100644 espmusicmouse/src/host_test.cpp diff --git a/espmusicmouse/.gitignore b/espmusicmouse/.gitignore index 89cc49c..69107a2 100644 --- a/espmusicmouse/.gitignore +++ b/espmusicmouse/.gitignore @@ -2,4 +2,4 @@ .vscode/.browse.c_cpp.db* .vscode/c_cpp_properties.json .vscode/launch.json -.vscode/ipch +.vscode/ipch \ No newline at end of file diff --git a/espmusicmouse/lib/leds/LedAnimation.h b/espmusicmouse/lib/leds/LedAnimation.h deleted file mode 100644 index 9f9a881..0000000 --- a/espmusicmouse/lib/leds/LedAnimation.h +++ /dev/null @@ -1,56 +0,0 @@ -#include "LedControl.h" - -class LedAnimation -{ -public: - /// Sets leds in the strip and returns number of milliseconds to wait until it is called again - virtual int operator()(LedStrip &leds) = 0; -}; - -class SweepCircularAnimation : public LedAnimation -{ -public: - SweepCircularAnimation(const ColorRGB &color, int delayMs = 100, int numLedsHalfWidth = 3, float brightnessFallOff = 0.8) - : color_(color), delayMs_(delayMs), numLedsHalfWidth_(numLedsHalfWidth), brightnessFallOff_(brightnessFallOff), currentCenter_(0) - { - } - - int operator()(LedStrip &leds) override - { - for (int i = 0; i < leds.numLeds(); ++i) - leds.setColor(i, 0, 0, 0, 0); - - leds.setColor(currentCenter_, color_); - - ColorRGB currColor = color_; - for (int i = 1; i <= numLedsHalfWidth_; ++i) - { - currColor.r = uint8_t(float(currColor.r) * brightnessFallOff_); - currColor.g = uint8_t(float(currColor.g) * brightnessFallOff_); - currColor.b = uint8_t(float(currColor.b) * brightnessFallOff_); - leds.setColor(leds.normalizeLedIdx(currentCenter_ - i), currColor); - leds.setColor(leds.normalizeLedIdx(currentCenter_ + i), currColor); - } - currentCenter_ = leds.normalizeLedIdx(currentCenter_ + 1); - return delayMs_; - } - -private: - // parameters - ColorRGB color_; - int delayMs_; - int numLedsHalfWidth_; // number of leds on to the left and right of center - float brightnessFallOff_; - - // state - int currentCenter_; -}; - -// strategy: -// use queue to send animation pointers over -// task calls animate function and waits for new even in queue with timeout of next due call -// - -void setAnimation(LedAnimation *animation) -{ -} diff --git a/espmusicmouse/lib/leds/LedControl.cpp b/espmusicmouse/lib/leds/LedControl.cpp deleted file mode 100644 index b7ca9cb..0000000 --- a/espmusicmouse/lib/leds/LedControl.cpp +++ /dev/null @@ -1,146 +0,0 @@ -#include "LedControl.h" -#include "driver/rmt.h" -#include "esp32_digital_led_lib.h" -#include "Arduino.h" - -#define HSV_SECTION_6 (0x20) -#define HSV_SECTION_3 (0x40) - -static ColorRGB hsv2rgb(const ColorHSV &hsv) -{ - // Convert hue, saturation and brightness ( HSV/HSB ) to RGB - // "Dimming" is used on saturation and brightness to make - // the output more visually linear. - - // Apply dimming curves - uint8_t value = hsv.v; - uint8_t saturation = hsv.s; - - // The brightness floor is minimum number that all of - // R, G, and B will be set to. - uint8_t invsat = 255 - saturation; - uint8_t brightness_floor = (value * invsat) / 256; - - // The color amplitude is the maximum amount of R, G, and B - // that will be added on top of the brightness_floor to - // create the specific hue desired. - uint8_t color_amplitude = value - brightness_floor; - - // Figure out which section of the hue wheel we're in, - // and how far offset we are withing that section - uint8_t section = hsv.h / HSV_SECTION_3; // 0..2 - uint8_t offset = hsv.h % HSV_SECTION_3; // 0..63 - - uint8_t rampup = offset; // 0..63 - uint8_t rampdown = (HSV_SECTION_3 - 1) - offset; // 63..0 - - // We now scale rampup and rampdown to a 0-255 range -- at least - // in theory, but here's where architecture-specific decsions - // come in to play: - // To scale them up to 0-255, we'd want to multiply by 4. - // But in the very next step, we multiply the ramps by other - // values and then divide the resulting product by 256. - // So which is faster? - // ((ramp * 4) * othervalue) / 256 - // or - // ((ramp ) * othervalue) / 64 - // It depends on your processor architecture. - // On 8-bit AVR, the "/ 256" is just a one-cycle register move, - // but the "/ 64" might be a multicycle shift process. So on AVR - // it's faster do multiply the ramp values by four, and then - // divide by 256. - // On ARM, the "/ 256" and "/ 64" are one cycle each, so it's - // faster to NOT multiply the ramp values by four, and just to - // divide the resulting product by 64 (instead of 256). - // Moral of the story: trust your profiler, not your insticts. - - // Since there's an AVR assembly version elsewhere, we'll - // assume what we're on an architecture where any number of - // bit shifts has roughly the same cost, and we'll remove the - // redundant math at the source level: - - // // scale up to 255 range - // //rampup *= 4; // 0..252 - // //rampdown *= 4; // 0..252 - - // compute color-amplitude-scaled-down versions of rampup and rampdown - uint8_t rampup_amp_adj = (rampup * color_amplitude) / (256 / 4); - uint8_t rampdown_amp_adj = (rampdown * color_amplitude) / (256 / 4); - - // add brightness_floor offset to everything - uint8_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor; - uint8_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor; - - if (section) - { - if (section == 1) - return ColorRGB{brightness_floor, rampdown_adj_with_floor, rampup_adj_with_floor}; - else - return ColorRGB{rampup_adj_with_floor, brightness_floor, rampdown_adj_with_floor}; - } - else - return ColorRGB{rampdown_adj_with_floor, rampup_adj_with_floor, brightness_floor}; -} - -LedStrip::LedStrip(int numLeds, int pin) - : numLeds_(numLeds), pin_(pin) -{ - cfg = {.rmtChannel = 0, .gpioNum = pin, .ledType = LED_SK6812W_V1, .brightLimit = 24, .numPixels = numLeds}; - strands[0] = &cfg; -} - -void LedStrip::begin() -{ - digitalLeds_initDriver(); - gpioSetup(cfg.gpioNum, OUTPUT, LOW); - - int rc = digitalLeds_addStrands(strands, 1); - if (rc) - Serial.println("LEDs: Error during init"); -} - -void LedStrip::clear() -{ - digitalLeds_resetPixels(strands, 1); -} - -int LedStrip::normalizeLedIdx(int i) -{ - while (i < 0) - i += numLeds_; - while (i >= numLeds_) - i -= numLeds_; - return i; -} - -void LedStrip::setColor(int led, int r, int g, int b, int w) -{ - strands[0]->pixels[led] = pixelFromRGBW(r, g, b, w); -} - -void LedStrip::transmit() -{ - digitalLeds_drawPixels(strands, 1); -} - -void LedStrip::setAll(int r, int g, int b, int w) -{ - for (int i = 0; i < numLeds_; ++i) - setColor(i, r, g, b, w); -} - -void LedStrip::setRange(int begin, int end, int r, int g, int b, int w) -{ - for (int i = begin; i < min(end, numLeds_); ++i) - setColor(i, r, g, b, w); -} - -void LedStrip::setColor(int led, const ColorRGB &color) -{ - setColor(led, color.r, color.g, color.b, 0); -} - -void LedStrip::setColor(int led, const ColorHSV &color) -{ - setColor(led, hsv2rgb(color)); -} \ No newline at end of file diff --git a/espmusicmouse/lib/leds/LedControl.h b/espmusicmouse/lib/leds/LedControl.h deleted file mode 100644 index bc4d79f..0000000 --- a/espmusicmouse/lib/leds/LedControl.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once -#include "esp32_digital_led_lib.h" - -struct ColorRGB -{ - uint8_t r, g, b; -}; - -struct ColorHSV -{ - uint8_t h, s, v; -}; - -class LedStrip -{ -public: - LedStrip(int numLeds, int pin); - - void begin(); - - void setColor(int led, int r, int g, int b, int w); - void setColor(int led, const ColorRGB &color); - void setColor(int led, const ColorHSV &color); - void transmit(); - void clear(); - void setAll(int r, int g, int b, int w); - void setRange(int begin, int end, int r, int g, int b, int w); - int numLeds() const { return numLeds_; } - - int normalizeLedIdx(int i); - -private: - strand_t cfg; - strand_t *strands[1]; - int numLeds_; - int pin_; -}; \ No newline at end of file diff --git a/espmusicmouse/lib/leds/esp32_digital_led_lib.cpp b/espmusicmouse/lib/leds/esp32_digital_led_lib.cpp deleted file mode 100644 index 0e80bce..0000000 --- a/espmusicmouse/lib/leds/esp32_digital_led_lib.cpp +++ /dev/null @@ -1,472 +0,0 @@ -/* - * Library for driving digital RGB(W) LEDs using the ESP32's RMT peripheral - * - * Modifications Copyright (c) 2017-2019 Martin F. Falatic - * - * Portions modified using FastLED's ClocklessController as a reference - * Copyright (c) 2018 Samuel Z. Guyer - * Copyright (c) 2017 Thomas Basler - * - * Based on public domain code created 19 Nov 2016 by Chris Osborn - * http://insentricity.com - * - */ - -/* - * 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 "esp32_digital_led_lib.h" - - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(ARDUINO) - #include "esp32-hal.h" - #include "esp_intr.h" - #include "driver/gpio.h" - #include "driver/rmt.h" - #include "driver/periph_ctrl.h" - #include "freertos/semphr.h" - #include "soc/rmt_struct.h" -#elif defined(ESP_PLATFORM) - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include // memset, memcpy, etc. live here! -#endif - -#ifdef __cplusplus -} -#endif - -#define COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) - -#if DEBUG_ESP32_DIGITAL_LED_LIB -extern char * digitalLeds_debugBuffer; -extern int digitalLeds_debugBufferSz; -#endif - -static DRAM_ATTR const uint16_t MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass -static DRAM_ATTR const uint16_t DIVIDER = 4; // 8 still seems to work, but timings become marginal -static DRAM_ATTR const double RMT_DURATION_NS = 12.5; // Minimum time of a single RMT duration based on clock ns - - -// Considering the RMT_INT_RAW_REG (raw int status) and RMT_INT_ST_REG (masked int status) registers (each 32-bit): -// Where op = {raw, st, ena, clr} and n = {0..7} -// Every three bits = RMT.int_.ch_tx_end, RMT.int_.ch_rx_end, RMT.int_.ch_err -// The final 8 bits are RMT.int_.ch_tx_thr_event - -// LUT for mapping bits in RMT.int_.ch_tx_thr_event -static DRAM_ATTR const uint32_t tx_thr_event_offsets [] = { - static_cast(1) << (24 + 0), - static_cast(1) << (24 + 1), - static_cast(1) << (24 + 2), - static_cast(1) << (24 + 3), - static_cast(1) << (24 + 4), - static_cast(1) << (24 + 5), - static_cast(1) << (24 + 6), - static_cast(1) << (24 + 7), -}; - -// LUT for mapping bits in RMT.int_.ch_tx_end -static DRAM_ATTR const uint32_t tx_end_offsets [] = { - static_cast(1) << (0 + 0) * 3, - static_cast(1) << (0 + 1) * 3, - static_cast(1) << (0 + 2) * 3, - static_cast(1) << (0 + 3) * 3, - static_cast(1) << (0 + 4) * 3, - static_cast(1) << (0 + 5) * 3, - static_cast(1) << (0 + 6) * 3, - static_cast(1) << (0 + 7) * 3, -}; - -typedef union { - struct { - uint32_t duration0:15; - uint32_t level0:1; - uint32_t duration1:15; - uint32_t level1:1; - }; - uint32_t val; -} rmtPulsePair; - -typedef struct { - uint8_t * buf_data; - uint16_t buf_pos, buf_len, buf_half, buf_isDirty; - rmtPulsePair pulsePairMap[2]; - bool isProcessing; -} digitalLeds_stateData; - -double randDouble() -{ - return double(esp_random()>>16) / (UINT16_MAX + 1); -} - -pixelColor_t adjustByUniformFactor(pixelColor_t * color, double adjFactor) { - color->r = uint8_t(color->r * (1.0 - adjFactor)); - color->g = uint8_t(color->g * (1.0 - adjFactor)); - color->b = uint8_t(color->b * (1.0 - adjFactor)); - color->w = uint8_t(color->w * (1.0 - adjFactor)); - return *color; -} - - -const static int MAX_RMT_CHANNELS = 8; -static strand_t * strandDataPtrs[MAX_RMT_CHANNELS] = {nullptr}; // Indexed by RMT channel - -// Forward declarations of local functions -static void copyHalfBlockToRmt(strand_t * pStrand); -static void rmtInterruptHandler(void *arg); - - -static xSemaphoreHandle gRmtSem = nullptr; -static intr_handle_t gRmtIntrHandle = nullptr; - -static int gToProcess = 0; - - -#if defined(ARDUINO) && ARDUINO >= 100 - void espPinMode(int pinNum, int pinDir) { - // Enable GPIO32 or 33 as output. Device-dependent - // (only works if these aren't used for external XTAL). - // https://esp32.com/viewtopic.php?t=9151#p38282 - if (pinNum == 32 || pinNum == 33) { - uint64_t gpioBitMask = (pinNum == 32) ? 1ULL<= 100 - espPinMode(gpioNum, gpioMode); - digitalWrite (gpioNum, gpioVal); - #elif defined(ESP_PLATFORM) - gpio_num_t gpioNumNative = static_cast(gpioNum); - gpio_mode_t gpioModeNative = static_cast(gpioMode); - gpio_pad_select_gpio(gpioNumNative); - gpio_set_direction(gpioNumNative, gpioModeNative); - gpio_set_level(gpioNumNative, gpioVal); - #endif -} - - -int digitalLeds_initDriver() -{ - #if DEBUG_ESP32_DIGITAL_LED_LIB - snprintf(digitalLeds_debugBuffer, digitalLeds_debugBufferSz, "digitalLeds_initDriver\n"); - #endif - - esp_err_t rc = ESP_OK; - - if (gRmtIntrHandle == nullptr) { // Only on first run - // Sem is created here - gRmtSem = xSemaphoreCreateBinary(); - xSemaphoreGive(gRmtSem); - rc = esp_intr_alloc(ETS_RMT_INTR_SOURCE, 0, rmtInterruptHandler, nullptr, &gRmtIntrHandle); - } - - return rc; -} - - -int digitalLeds_addStrands(strand_t * strands [], int numStrands) -{ - for (int i = 0; i < numStrands; i++) { - int rmtChannel = strands[i]->rmtChannel; - strand_t * pStrand = strands[i]; - strandDataPtrs[rmtChannel] = pStrand; - - ledParams_t ledParams = ledParamsAll[pStrand->ledType]; - - pStrand->pixels = static_cast(malloc(pStrand->numPixels * sizeof(pixelColor_t))); - if (pStrand->pixels == nullptr) { - return -1; - } - - pStrand->_stateVars = static_cast(malloc(sizeof(digitalLeds_stateData))); - if (pStrand->_stateVars == nullptr) { - return -2; - } - digitalLeds_stateData * pState = static_cast(pStrand->_stateVars); - - pState->buf_len = (pStrand->numPixels * ledParams.bytesPerPixel); - pState->buf_data = static_cast(malloc(pState->buf_len)); - if (pState->buf_data == nullptr) { - return -3; - } - - // RMT configuration for transmission - rmt_config_t rmt_tx; - rmt_tx.channel = static_cast(rmtChannel); - rmt_tx.gpio_num = static_cast(pStrand->gpioNum); - rmt_tx.rmt_mode = RMT_MODE_TX; - rmt_tx.mem_block_num = 1; - rmt_tx.clk_div = DIVIDER; - rmt_tx.tx_config.loop_en = false; - rmt_tx.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; - rmt_tx.tx_config.carrier_en = false; - rmt_tx.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; - rmt_tx.tx_config.idle_output_en = true; - rmt_config(&rmt_tx); - - // RMT config for transmitting a '0' bit val to this LED strand - pState->pulsePairMap[0].level0 = 1; - pState->pulsePairMap[0].level1 = 0; - pState->pulsePairMap[0].duration0 = ledParams.T0H / (RMT_DURATION_NS * DIVIDER); - pState->pulsePairMap[0].duration1 = ledParams.T0L / (RMT_DURATION_NS * DIVIDER); - - // RMT config for transmitting a '0' bit val to this LED strand - pState->pulsePairMap[1].level0 = 1; - pState->pulsePairMap[1].level1 = 0; - pState->pulsePairMap[1].duration0 = ledParams.T1H / (RMT_DURATION_NS * DIVIDER); - pState->pulsePairMap[1].duration1 = ledParams.T1L / (RMT_DURATION_NS * DIVIDER); - - pState->isProcessing = false; - - // Set interrupts - rmt_set_tx_thr_intr_en(static_cast(rmtChannel), true, MAX_PULSES); // sets rmt_set_tx_wrap_en and RMT.tx_lim_ch.limit - } - - digitalLeds_resetPixels(strands, numStrands); - - return 0; -} - - -int digitalLeds_removeStrands(strand_t * strands [], int numStrands) -{ - digitalLeds_resetPixels(strands, numStrands); - - for (int i = 0; i < numStrands; i++) { - int rmtChannel = strands[i]->rmtChannel; - strand_t * pStrand = strandDataPtrs[rmtChannel]; - if (pStrand) { - strandDataPtrs[rmtChannel] = nullptr; - } - } - - return 0; -} - - -int digitalLeds_resetPixels(strand_t * strands [], int numStrands) -{ - // TODO: The input is strands for convenience - the point is to get indicies of strands to draw - // Could just pass the channel numbers, but would it be slower to construct that list? - - for (int i = 0; i < numStrands; i++) { - int rmtChannel = strands[i]->rmtChannel; - strand_t * pStrand = strandDataPtrs[rmtChannel]; - memset(pStrand->pixels, 0, pStrand->numPixels * sizeof(pixelColor_t)); - } - - digitalLeds_drawPixels(strands, numStrands); - - return 0; -} - - -int IRAM_ATTR digitalLeds_drawPixels(strand_t * strands [], int numStrands) -{ - // TODO: The input is strands for convenience - the point is to get indicies of strands to draw - // Could just pass the channel numbers, but would it be slower to construct that list? - - if (numStrands == 0) { - return 0; - } - - gToProcess = numStrands; - - xSemaphoreTake(gRmtSem, portMAX_DELAY); - - for (int i = 0; i < numStrands; i++) { - int rmtChannel = strands[i]->rmtChannel; - strand_t * pStrand = strandDataPtrs[rmtChannel]; - - digitalLeds_stateData * pState = static_cast(pStrand->_stateVars); - ledParams_t ledParams = ledParamsAll[pStrand->ledType]; - - pState->isProcessing = true; - - // Pack pixels into transmission buffer - if (ledParams.bytesPerPixel == 3) { - for (uint16_t i = 0; i < pStrand->numPixels; i++) { - // Color order is translated from RGB to GRB - pState->buf_data[0 + i * 3] = pStrand->pixels[i].g; - pState->buf_data[1 + i * 3] = pStrand->pixels[i].r; - pState->buf_data[2 + i * 3] = pStrand->pixels[i].b; - } - } - else if (ledParams.bytesPerPixel == 4) { - for (uint16_t i = 0; i < pStrand->numPixels; i++) { - // Color order is translated from RGBW to GRBW - pState->buf_data[0 + i * 4] = pStrand->pixels[i].g; - pState->buf_data[1 + i * 4] = pStrand->pixels[i].r; - pState->buf_data[2 + i * 4] = pStrand->pixels[i].b; - pState->buf_data[3 + i * 4] = pStrand->pixels[i].w; - } - } - else { - return -1; - } - - pState->buf_pos = 0; - pState->buf_half = 0; - - rmt_set_tx_intr_en(static_cast(rmtChannel), true); - - copyHalfBlockToRmt(pStrand); - if (pState->buf_pos < pState->buf_len) { // Fill the other half of the buffer block - copyHalfBlockToRmt(pStrand); - } - - // Starts RMT, which will end up giving us the semaphore back - // Immediately starts transmitting - rmt_set_tx_intr_en(static_cast(rmtChannel), true); - rmt_tx_start(static_cast(rmtChannel), true); - } - - // Give back semaphore after drawing is done - xSemaphoreTake(gRmtSem, portMAX_DELAY); - xSemaphoreGive(gRmtSem); - - return 0; -} - - -static IRAM_ATTR void copyHalfBlockToRmt(strand_t * pStrand) -{ - // This fills half an RMT block - // When wraparound is happening, we want to keep the inactive half of the RMT block filled - digitalLeds_stateData * pState = static_cast(pStrand->_stateVars); - ledParams_t ledParams = ledParamsAll[pStrand->ledType]; - - uint16_t i, j, offset, len, byteval; - - offset = pState->buf_half * MAX_PULSES; - pState->buf_half = !pState->buf_half; - - len = pState->buf_len - pState->buf_pos; - if (len > (MAX_PULSES / 8)) - len = (MAX_PULSES / 8); - - if (!len) { - if (!pState->buf_isDirty) { - return; - } - // Clear the channel's data block and return - for (i = 0; i < MAX_PULSES; i++) { - RMTMEM.chan[pStrand->rmtChannel].data32[i + offset].val = 0; - } - pState->buf_isDirty = 0; - return; - } - pState->buf_isDirty = 1; - - for (i = 0; i < len; i++) { - byteval = pState->buf_data[i + pState->buf_pos]; - - // Shift bits out, MSB first, setting RMTMEM.chan[n].data32[x] to - // the rmtPulsePair value corresponding to the buffered bit value - for (j = 0; j < 8; j++, byteval <<= 1) { - int bitval = (byteval >> 7) & 0x01; - int data32_idx = i * 8 + offset + j; - RMTMEM.chan[pStrand->rmtChannel].data32[data32_idx].val = pState->pulsePairMap[bitval].val; - } - - // Handle the reset bit by stretching duration1 for the final bit in the stream - if (i + pState->buf_pos == pState->buf_len - 1) { - RMTMEM.chan[pStrand->rmtChannel].data32[i * 8 + offset + 7].duration1 = - ledParams.TRS / (RMT_DURATION_NS * DIVIDER); - } - } - - // Clear the remainder of the channel's data not set above - for (i *= 8; i < MAX_PULSES; i++) { - RMTMEM.chan[pStrand->rmtChannel].data32[i + offset].val = 0; - } - - pState->buf_pos += len; - - return; -} - - -static IRAM_ATTR void rmtInterruptHandler(void *arg) -{ - portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - - for (int rmtChannel = 0; rmtChannel < MAX_RMT_CHANNELS; rmtChannel++) { - strand_t * pStrand = strandDataPtrs[rmtChannel]; - if (pStrand == nullptr) { - continue; - } - - digitalLeds_stateData * pState = static_cast(pStrand->_stateVars); - if (!pState->isProcessing) { - continue; - } - - if (RMT.int_st.val & tx_thr_event_offsets[rmtChannel]) { - // We got an RMT.int_st.ch_tx_thr_event interrupt because RMT.tx_lim_ch.limit was crossed - RMT.int_clr.val |= tx_thr_event_offsets[rmtChannel]; // set RMT.int_clr.ch_tx_thr_event (reset interrupt bit) - copyHalfBlockToRmt(pStrand); - } - else if (RMT.int_st.val & tx_end_offsets[rmtChannel]) { - // We got an RMT.int_st.ch_tx_end interrupt with a zero-length entry which means we're done - RMT.int_clr.val |= tx_end_offsets[rmtChannel]; // set RMT.int_clr.ch_tx_end (reset interrupt bit) - //gpio_matrix_out(static_cast(pStrand->gpioNum), 0x100, 0, 0); // only useful if rmt_config keeps getting called - pState->isProcessing = false; - gToProcess--; - if (gToProcess == 0) { - xSemaphoreGiveFromISR(gRmtSem, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken == pdTRUE) { // Perform cleanup if we're all done - portYIELD_FROM_ISR(); - } - } - } - - } - - return; -} - - -//**************************************************************************// diff --git a/espmusicmouse/lib/leds/esp32_digital_led_lib.h b/espmusicmouse/lib/leds/esp32_digital_led_lib.h deleted file mode 100644 index 338da85..0000000 --- a/espmusicmouse/lib/leds/esp32_digital_led_lib.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Library for driving digital RGB(W) LEDs using the ESP32's RMT peripheral - * - * Modifications Copyright (c) 2017-2019 Martin F. Falatic - * - * Portions modified using FastLED's ClocklessController as a reference - * Copyright (c) 2018 Samuel Z. Guyer - * Copyright (c) 2017 Thomas Basler - * - * Based on public domain code created 19 Nov 2016 by Chris Osborn - * http://insentricity.com - * - */ - -/* - * 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 ESP32_DIGITAL_LED_LIB_H -#define ESP32_DIGITAL_LED_LIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define DEBUG_ESP32_DIGITAL_LED_LIB 0 - -typedef union { - struct __attribute__ ((packed)) { - uint8_t b, g, r, w; // Little-endian ordered - }; - uint32_t raw32; -} pixelColor_t; - -inline pixelColor_t pixelFromRGB(uint8_t r, uint8_t g, uint8_t b) -{ - pixelColor_t v; - v.r = r; - v.g = g; - v.b = b; - v.w = 0; - return v; -} - -inline pixelColor_t pixelFromRGBhex(uint8_t r, uint8_t g, uint8_t b) -{ - pixelColor_t v; - v.r = r; - v.g = g; - v.b = b; - v.w = 0; - return v; -} - -inline pixelColor_t pixelFromRGBW(uint8_t r, uint8_t g, uint8_t b, uint8_t w) -{ - pixelColor_t v; - v.r = r; - v.g = g; - v.b = b; - v.w = w; - return v; -} - -inline pixelColor_t pixelFromRGBWhex(uint8_t r, uint8_t g, uint8_t b, uint8_t w) -{ - // The value is of the form 0xWWRRGGBB - pixelColor_t v; - v.r = r; - v.g = g; - v.b = b; - v.w = w; - return v; -} - -typedef struct { - int rmtChannel; - int gpioNum; - int ledType; - int brightLimit; - int numPixels; - pixelColor_t * pixels; - void * _stateVars; -} strand_t; - -typedef struct { - int bytesPerPixel; - uint32_t T0H; - uint32_t T1H; - uint32_t T0L; - uint32_t T1L; - uint32_t TRS; -} ledParams_t; - -enum led_types { - LED_WS2812_V1, - LED_WS2812B_V1, - LED_WS2812B_V2, - LED_WS2812B_V3, - LED_WS2813_V1, - LED_WS2813_V2, - LED_WS2813_V3, - LED_SK6812_V1, - LED_SK6812W_V1, -}; - -const ledParams_t ledParamsAll[] = { // Still must match order of `led_types` - [LED_WS2812_V1] = { .bytesPerPixel = 3, .T0H = 350, .T1H = 700, .T0L = 800, .T1L = 600, .TRS = 50000}, // Various - [LED_WS2812B_V1] = { .bytesPerPixel = 3, .T0H = 350, .T1H = 900, .T0L = 900, .T1L = 350, .TRS = 50000}, // Older datasheet - [LED_WS2812B_V2] = { .bytesPerPixel = 3, .T0H = 400, .T1H = 850, .T0L = 850, .T1L = 400, .TRS = 50000}, // 2016 datasheet - [LED_WS2812B_V3] = { .bytesPerPixel = 3, .T0H = 450, .T1H = 850, .T0L = 850, .T1L = 450, .TRS = 50000}, // cplcpu test - [LED_WS2813_V1] = { .bytesPerPixel = 3, .T0H = 350, .T1H = 800, .T0L = 350, .T1L = 350, .TRS = 300000}, // Older datasheet - [LED_WS2813_V2] = { .bytesPerPixel = 3, .T0H = 270, .T1H = 800, .T0L = 800, .T1L = 270, .TRS = 300000}, // 2016 datasheet - [LED_WS2813_V3] = { .bytesPerPixel = 3, .T0H = 270, .T1H = 630, .T0L = 630, .T1L = 270, .TRS = 300000}, // 2017-05 WS datasheet - [LED_SK6812_V1] = { .bytesPerPixel = 3, .T0H = 300, .T1H = 600, .T0L = 900, .T1L = 600, .TRS = 80000}, // Various, all consistent - [LED_SK6812W_V1] = { .bytesPerPixel = 4, .T0H = 300, .T1H = 600, .T0L = 900, .T1L = 600, .TRS = 80000}, // Various, all consistent -}; - -extern void espPinMode(int pinNum, int pinDir); -extern void gpioSetup(int gpioNum, int gpioMode, int gpioVal); -extern double randDouble(); -extern pixelColor_t adjustByUniformFactor(pixelColor_t * color, double adjFactor); - -extern int digitalLeds_initDriver(); -extern int digitalLeds_addStrands(strand_t * strands [], int numStrands); -extern int digitalLeds_removeStrands(strand_t * strands [], int numStrands); -extern int digitalLeds_drawPixels(strand_t * strands [], int numStrands); -extern int digitalLeds_resetPixels(strand_t * strands [], int numStrands); - -#ifdef __cplusplus -} -#endif - -#endif /* ESP32_DIGITAL_LED_LIB_H */ - - -//**************************************************************************// diff --git a/espmusicmouse/lib/ledtl/Esp32DriverRGBW.cpp b/espmusicmouse/lib/ledtl/Esp32DriverRGBW.cpp index 43f4cee..cb86513 100644 --- a/espmusicmouse/lib/ledtl/Esp32DriverRGBW.cpp +++ b/espmusicmouse/lib/ledtl/Esp32DriverRGBW.cpp @@ -1,3 +1,5 @@ +#ifndef PLATFORM_NATIVE + #include "drivers/Esp32DriverRGBW.h" #include @@ -103,3 +105,5 @@ bool Esp32DriverRGBW::waitForTransmissionToFinish(int waitMs) else return false; } + +#endif \ No newline at end of file diff --git a/espmusicmouse/lib/ledtl/containers/LedStripRGBW.h b/espmusicmouse/lib/ledtl/containers/LedStripRGBW.h index 4d39212..4420b92 100644 --- a/espmusicmouse/lib/ledtl/containers/LedStripRGBW.h +++ b/espmusicmouse/lib/ledtl/containers/LedStripRGBW.h @@ -3,7 +3,6 @@ #include "helpers/ColorRGBW.h" -#include "Arduino.h" // TODO #include template @@ -12,16 +11,19 @@ class LedStripRGBW public: static constexpr int NUM_LEDS = TNumLeds; + static constexpr int normalizeIdx(int idx) + { + return (idx < 0) ? (idx + NUM_LEDS) : (idx >= NUM_LEDS ? idx - NUM_LEDS : idx); + } + void set(int idx, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { // green: 0 // red: 8 // blue: 16 // white: 24 - if (idx < 0 || idx >= NUM_LEDS) - Serial.printf("Out of bounds idx %i\n", idx); - else - data_[idx] = (g << 0) | (r << 8) | (b << 16) | (w << 24); + idx = normalizeIdx(idx); + data_[idx] = (g << 0) | (r << 8) | (b << 16) | (w << 24); } const uint32_t *rawData() const { return data_; } diff --git a/espmusicmouse/lib/ledtl/drivers/Esp32DriverRGBW.h b/espmusicmouse/lib/ledtl/drivers/Esp32DriverRGBW.h index facfe16..dda9088 100644 --- a/espmusicmouse/lib/ledtl/drivers/Esp32DriverRGBW.h +++ b/espmusicmouse/lib/ledtl/drivers/Esp32DriverRGBW.h @@ -1,5 +1,7 @@ #pragma once +#ifndef PLATFORM_NATIVE + #include "containers/LedStripRGBW.h" class Esp32DriverRGBW @@ -17,3 +19,5 @@ private: int rmtChannel_; bool transmitting_; }; + +#endif \ No newline at end of file diff --git a/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h b/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h new file mode 100644 index 0000000..d21557b --- /dev/null +++ b/espmusicmouse/lib/ledtl/effects/AlexaSwipe.h @@ -0,0 +1,142 @@ +#pragma once + +#include "effects/Common.h" +#include "helpers/ColorRGBW.h" +#include "helpers/ColorHSV.h" +#include "helpers/ColorConversions.h" +#include "helpers/BellCurve.h" + +struct EffectAlexaSwipeConfig +{ + float primaryColorWidth; // in degrees + float transitionWidth; + float swipeSpeed; // in degrees per second + float bellCurveWidthInLeds; + float startPosition; + ColorRGBW primaryColor; + ColorRGBW secondaryColor; +}; + +template +class EffectAlexaSwipe +{ +public: + static constexpr auto NUM_LEDS = numLeds(); + static constexpr int DELAY_MS = 10; + + using ConfigType = EffectAlexaSwipeConfig; + + EffectAlexaSwipe(const EffectAlexaSwipeConfig &cfg, TLedStrip &ledStrip) + : ledStrip_(ledStrip), + currentPosition_(0), + transitionWidth_(cfg.transitionWidth / 360.0f * NUM_LEDS), + invTransitionWidth_(1.0f / transitionWidth_), + primaryColorWidth_(cfg.primaryColorWidth / 360.0f * NUM_LEDS + cfg.bellCurveWidthInLeds), + bellCurveWidth_(cfg.bellCurveWidthInLeds), + invBellCurveWidth_(1.0f / cfg.bellCurveWidthInLeds), + speed_(cfg.swipeSpeed / 360 / 1000 * NUM_LEDS * DELAY_MS), + startPosition_(cfg.startPosition / 360.0f * NUM_LEDS), + primaryColor_(rgb2hsv(cfg.primaryColor)), + secondaryColor_(rgb2hsv(cfg.secondaryColor)) + { + //#ifndef PLATFORM_NATIVE + // Serial.printf("Primary color %f, %f, %f\n", primaryColor_.h, primaryColor_.s, primaryColor_.v); + // Serial.printf("Secondary color %f, %f, %f\n", secondaryColor_.h, secondaryColor_.s, secondaryColor_.v); + //#endif + } + + int operator()() + { + clear(ledStrip_); + + const auto width = std::min(int(currentPosition_ + 1), int(NUM_LEDS / 2)); + + setLedRGBW(ledStrip_, startPosition_, getColor(currentPosition_)); + for (int i = 1; i < width; ++i) + { + const float x = currentPosition_ - float(i); + if (x > 0.0f) + { + const int led1 = startPosition_ + i; + const int led2 = startPosition_ - i; + const ColorRGBW color = getColor(x); + //#ifndef PLATFORM_NATIVE + // Serial.printf("Setting %d and %d to %d, %d, %d\n", led1, led2, color.r, color.g, color.b); + //#endif + setLedRGBW(ledStrip_, led1, color); + setLedRGBW(ledStrip_, led2, color); + } + } + currentPosition_ += speed_; + currentPosition_ = std::min(currentPosition_, float(NUM_LEDS) / 2.0f + bellCurveWidth_ / 2); + return DELAY_MS; + } + + //private: + void getParams(float x, float &interpFac, float &brightness) + { + brightness = (x < bellCurveWidth_) ? bellCurveApproximation(bellCurveWidth_ / 2 - x, invBellCurveWidth_) : 1.0f; + if (x < primaryColorWidth_) + interpFac = 0.0f; + else if (x > primaryColorWidth_ + transitionWidth_) + interpFac = 1.0f; + else + interpFac = (x - primaryColorWidth_) * invTransitionWidth_; + } + + // x is positive distance from running front + ColorRGBW getColor(float x) + { + float interpFac; + float brightness; + getParams(x, interpFac, brightness); + ColorHSV result{ + interpFac * secondaryColor_.h + (1.0f - interpFac) * primaryColor_.h, + interpFac * secondaryColor_.s + (1.0f - interpFac) * primaryColor_.s, + interpFac * secondaryColor_.v + (1.0f - interpFac) * primaryColor_.v}; + result.v *= brightness; + + const auto converted = hsv2rgb(result); + //#ifndef PLATFORM_NATIVE + // Serial.printf("Coord %f, interp %f, bright %f, h %f, s %f, v %f, r %d, g %d, b %d\n", x, + // interpFac, brightness, result.h, result.s, result.v, converted.r, + // converted.g, converted.b); + //#endif + return converted; + } + + TLedStrip &ledStrip_; + + // in number of leds + float currentPosition_; + float transitionWidth_; + float invTransitionWidth_; + float primaryColorWidth_; + float bellCurveWidth_; + float invBellCurveWidth_; + float speed_; + + int startPosition_; + + const ColorHSV primaryColor_; + const ColorHSV secondaryColor_; +}; + +// Traits +template <> +struct EffectIdToConfig +{ + using type = EffectAlexaSwipeConfig; +}; + +template <> +struct EffectConfigToId +{ + static constexpr auto id = EffectId::ALEXA_SWIPE; +}; + +template +struct EffectIdToClass +{ + using type = EffectAlexaSwipe; +}; \ No newline at end of file diff --git a/espmusicmouse/lib/ledtl/effects/Circular.h b/espmusicmouse/lib/ledtl/effects/Circular.h index 25a1528..aa484cb 100644 --- a/espmusicmouse/lib/ledtl/effects/Circular.h +++ b/espmusicmouse/lib/ledtl/effects/Circular.h @@ -28,11 +28,6 @@ public: { } - static constexpr int normalizeIdx(int idx) - { - return (idx < 0) ? (idx + NUM_LEDS) : (idx >= NUM_LEDS ? idx - NUM_LEDS : idx); - } - int operator()() { int startLed = int(currentPosition_); @@ -41,20 +36,20 @@ public: clear(ledStrip_); // center - setLedRGBW(ledStrip_, normalizeIdx(startLed), + setLedRGBW(ledStrip_, startLed, config_.color * bellCurveApproximation(distDown, invWidth_)); // down for (int i = 1; i < widthInLeds_ / 2 + 1; ++i) { - setLedRGBW(ledStrip_, normalizeIdx(startLed - i), + setLedRGBW(ledStrip_, startLed - i, config_.color * bellCurveApproximation(distDown + i, invWidth_)); } // up for (int i = 1; i < widthInLeds_ / 2 + 1; ++i) { - setLedRGBW(ledStrip_, normalizeIdx(startLed + i), + setLedRGBW(ledStrip_, startLed + i, config_.color * bellCurveApproximation(distUp + i - 1, invWidth_)); } @@ -62,7 +57,6 @@ public: if (currentPosition_ > NUM_LEDS) currentPosition_ -= NUM_LEDS; - //Serial.printf("Current pos %f led %d width %d\n", currentPosition_, normalizeIdx(startLed), widthInLeds_ / 2 + 1); return DELAY_MS; } diff --git a/espmusicmouse/lib/ledtl/effects/Common.h b/espmusicmouse/lib/ledtl/effects/Common.h index b4036cd..452e83c 100644 --- a/espmusicmouse/lib/ledtl/effects/Common.h +++ b/espmusicmouse/lib/ledtl/effects/Common.h @@ -4,9 +4,7 @@ enum class EffectId { STATIC, CIRCULAR, - CIRCLE_WAVE, - COLOR_FADE, - RAINBOW_FADE, + ALEXA_SWIPE, }; template diff --git a/espmusicmouse/lib/ledtl/helpers/BellCurve.h b/espmusicmouse/lib/ledtl/helpers/BellCurve.h index 8e18fb8..fcfbc36 100644 --- a/espmusicmouse/lib/ledtl/helpers/BellCurve.h +++ b/espmusicmouse/lib/ledtl/helpers/BellCurve.h @@ -1,3 +1,5 @@ +#pragma once + #include static inline float bellCurveApproximation(float x, float inverseWidth) diff --git a/espmusicmouse/lib/ledtl/helpers/ColorConversions.h b/espmusicmouse/lib/ledtl/helpers/ColorConversions.h new file mode 100644 index 0000000..4042636 --- /dev/null +++ b/espmusicmouse/lib/ledtl/helpers/ColorConversions.h @@ -0,0 +1,114 @@ +#include "helpers/ColorHSV.h" +#include "helpers/ColorRGBW.h" + +#include +#include +#include + +// https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both +inline ColorHSV rgb2hsv(const ColorRGBW &in) +{ + ColorHSV out; + + const float r = (float)(in.r) / 255.0f; + const float g = (float)(in.g) / 255.0f; + const float b = (float)(in.b) / 255.0f; + + const float min = std::min(r, std::min(g, b)); + const float max = std::max(r, std::max(g, b)); + + out.v = max; // v + const float delta = max - min; + if (delta < 0.00001f) + { + out.s = 0; + out.h = 0; // undefined, maybe nan? + return out; + } + if (max > 0.0f) + { // NOTE: if Max is == 0, this divide would cause a crash + out.s = (delta / max); // s + } + else + { + // if max is 0, then r = g = b = 0 + // s = 0, h is undefined + out.s = 0.0f; + out.h = 0.0f; //NAN; // its now undefined + return out; + } + if (r >= max) // > is bogus, just keeps compilor happy + out.h = (g - b) / delta; // between yellow & magenta + else if (g >= max) + out.h = 2.0f + (b - r) / delta; // between cyan & yellow + else + out.h = 4.0f + (r - g) / delta; // between magenta & cyan + + out.h *= 60.0f; // degrees + + if (out.h < 0.0f) + out.h += 360.0f; + + return out; +} + +ColorRGBW hsv2rgb(const ColorHSV &in) +{ + int i; + ColorRGBW out; + out.w = 0; + + if (in.s <= 0.0f) + { // < is bogus, just shuts up warnings + out.r = (uint8_t)(in.v * 255.0f); + out.g = (uint8_t)(in.v * 255.0f); + out.b = (uint8_t)(in.v * 255.0f); + return out; + } + float hh = in.h; + if (hh >= 360.0f) + hh = 0.0f; + hh /= 60.0f; + i = (long)hh; + auto ff = hh - i; + float p = in.v * (1.0f - in.s); + float q = in.v * (1.0f - (in.s * ff)); + float t = in.v * (1.0f - (in.s * (1.0f - ff))); + + switch (i) + { + case 0: + out.r = (uint8_t)(in.v * 255.0f); + out.g = (uint8_t)(t * 255.0f); + out.b = (uint8_t)(p * 255.0f); + break; + case 1: + out.r = (uint8_t)(q * 255.0f); + out.g = (uint8_t)(in.v * 255.0f); + out.b = (uint8_t)(p * 255.0f); + break; + case 2: + out.r = (uint8_t)(p * 255.0f); + out.g = (uint8_t)(in.v * 255.0f); + out.b = (uint8_t)(t * 255.0f); + break; + + case 3: + out.r = (uint8_t)(p * 255.0f); + out.g = (uint8_t)(q * 255.0f); + out.b = (uint8_t)(in.v * 255.0f); + break; + case 4: + out.r = (uint8_t)(t * 255.0f); + out.g = (uint8_t)(p * 255.0f); + out.b = (uint8_t)(in.v * 255.0f); + break; + case 5: + default: + out.r = (uint8_t)(in.v * 255.0f); + out.g = (uint8_t)(p * 255.0f); + out.b = (uint8_t)(q * 255.0f); + break; + } + return out; +} \ No newline at end of file diff --git a/espmusicmouse/lib/ledtl/helpers/ColorHSV.h b/espmusicmouse/lib/ledtl/helpers/ColorHSV.h new file mode 100644 index 0000000..10a353a --- /dev/null +++ b/espmusicmouse/lib/ledtl/helpers/ColorHSV.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +struct ColorHSV +{ + float h, s, v; +}; \ No newline at end of file diff --git a/espmusicmouse/platformio.ini b/espmusicmouse/platformio.ini index 3f62778..d507438 100644 --- a/espmusicmouse/platformio.ini +++ b/espmusicmouse/platformio.ini @@ -27,5 +27,11 @@ framework = arduino monitor_port = /dev/ttyUSB0 upload_port = /dev/ttyUSB0 monitor_speed = 115200 +src_filter = +<*> - lib_deps = miguelbalboa/MFRC522 + +[env:native] +platform=native +src_filter = +<*> - +build_flags=-Ilib/ledtl -g -DPLATFORM_NATIVE \ No newline at end of file diff --git a/espmusicmouse/src/TaskLed.h b/espmusicmouse/src/TaskLed.h index 43fa388..0da1c40 100644 --- a/espmusicmouse/src/TaskLed.h +++ b/espmusicmouse/src/TaskLed.h @@ -75,8 +75,9 @@ void _led_task_func(void *params) TLedStrip &ledStrip = *(task->ledStrip_); // clang-format off - if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed circular");} - else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed static");} + if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed circular");} + else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed static");} + else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Alexa swipe");} // clang-format on timeoutMsForEffect = 0; @@ -99,7 +100,7 @@ void LedTask::begin(TLedStrip &strip, Esp32DriverRGBW &driver) ledStrip_ = &strip; driver_ = &driver; - xTaskCreate(_led_task_func, "led task", MAX_EFFECT_CLASS_SIZE + MAX_EFFECT_CONFIG_SIZE + 2048, + xTaskCreate(_led_task_func, "led task", MAX_EFFECT_CLASS_SIZE + MAX_EFFECT_CONFIG_SIZE + 2048 * 2, (void *)(this), 1, nullptr); } diff --git a/espmusicmouse/src/host_test.cpp b/espmusicmouse/src/host_test.cpp new file mode 100644 index 0000000..a6d3b28 --- /dev/null +++ b/espmusicmouse/src/host_test.cpp @@ -0,0 +1,40 @@ + +#include "containers/LedStripRGBW.h" + +#include "effects/AlexaSwipe.h" + +#include +#include + +template +void printVec(const std::vector &vec) +{ + std::cout << "["; + for (const auto &e : vec) + std::cout << e << ","; + std::cout << "]\n"; +} + +int main(int argc, char **argv) +{ + auto cfg = EffectAlexaSwipeConfig{20, 20, 90, 5, 180, ColorRGBW{255, 0, 0, 0}, ColorRGBW{0, 0, 255, 0}}; + LedStripRGBW<51> strip; + + EffectAlexaSwipe effect(cfg, strip); + effect.currentPosition_ = 150; + + const auto numLeds = strip.numLeds() / 2; + + std::vector brightness(numLeds, 0); + std::vector interpolation(numLeds, 0); + + for (int i = 0; i < numLeds; ++i) + effect.getParams(float(i), interpolation[i], brightness[i]); + + printVec(brightness); + printVec(interpolation); + + effect(); + + return 0; +} \ No newline at end of file diff --git a/espmusicmouse/src/main.cpp b/espmusicmouse/src/main.cpp index 988a401..b31c25a 100644 --- a/espmusicmouse/src/main.cpp +++ b/espmusicmouse/src/main.cpp @@ -2,14 +2,13 @@ #include "rc522.h" #include "SPI.h" #include -#include "LedControl.h" #include "rotary_encoder.h" -#include "LedAnimation.h" #include "containers/LedStripRGBW.h" #include "drivers/Esp32DriverRGBW.h" #include "effects/Circular.h" #include "effects/Static.h" +#include "effects/AlexaSwipe.h" #include "TaskLed.h" @@ -34,12 +33,13 @@ void tag_handler(uint8_t *sn) if (sn[4] == 0x30) { Serial.println("Fuchs"); - ledTask.startEffect(EffectCircularConfig{2 * 360, 180, ColorRGBW{0, 0, 255, 0}}); + //ledTask.startEffect(EffectCircularConfig{2 * 360, 180, ColorRGBW{0, 0, 255, 0}}); + ledTask.startEffect(EffectAlexaSwipeConfig{20, 30, 3 * 360, 3, 180, ColorRGBW{0, 255, 0, 0}, ColorRGBW{0, 0, 255, 0}}); } if (sn[4] == 0xf0) { Serial.println("Eule"); - ledTask.startEffect(EffectCircularConfig{180, 180, ColorRGBW{0, 0, 0, 128}}); + ledTask.startEffect(EffectCircularConfig{360, 180, ColorRGBW{0, 0, 255, 0}}); } } else @@ -94,7 +94,6 @@ void setup() bool btn2state = true; -SweepCircularAnimation animation(ColorRGB{0, 0, 255}, 100, 15, 0.7); void loop() { /* diff --git a/pyaudioplayeralsa/plan.md b/pyaudioplayeralsa/plan.md index 816576d..7bf203a 100644 --- a/pyaudioplayeralsa/plan.md +++ b/pyaudioplayeralsa/plan.md @@ -1,5 +1,5 @@ -- play wav file - - read & parse wav file +- play wav file [ok] + - read & parse wav file [ok] - stop wave file in the middle, wait 2 secs and continue - fade in/out - mix second wave file on top (some effect)