#pragma once #include "effects/Circular.h" #include "effects/Common.h" #include "drivers/Esp32DriverRGBW.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include #include static constexpr int MAX_EFFECT_CONFIG_SIZE = 128; static constexpr int MAX_EFFECT_CLASS_SIZE = 8 * 1024; template class LedTask { public: void begin(TLedStrip &strip, Esp32DriverRGBW &driver); template void startEffect(const TEffectConfig &cfg); private: template friend void _led_task_func(void *); QueueHandle_t queue_ = nullptr; TLedStrip *ledStrip_ = nullptr; Esp32DriverRGBW *driver_ = nullptr; }; // ----------------------------------------------------------------------------------------------- template bool dispatchEffectId(EffectId dynamicEffectId, std::function &effectFunction, TLedStrip &ledStrip, unsigned char *msgBuffer, unsigned char *effectStorage) { if (staticEffectId == dynamicEffectId) { typename EffectIdToConfig::type cfg; memcpy(&cfg, msgBuffer + sizeof(EffectId), sizeof(decltype(cfg))); using TEffect = typename EffectIdToClass::type; static_assert(sizeof(TEffect) < MAX_EFFECT_CLASS_SIZE, "Effect to big for effectStorage, increase MAX_EFFECT_CLASS_SIZE"); TEffect *effect = new (effectStorage) TEffect(cfg, ledStrip); effectFunction = [effect]() { return (*effect)(); }; return true; } else return false; } template void _led_task_func(void *params) { LedTask *task = reinterpret_cast *>(params); unsigned char msgBuffer[MAX_EFFECT_CONFIG_SIZE]; unsigned char effectStorage[MAX_EFFECT_CLASS_SIZE]; std::function effectFunction = []() -> int { return 100000; }; int timeoutMsForEffect = 100000; // huge timeout since there is no effect in the beginning while (true) { if (xQueueReceive(task->queue_, msgBuffer, (TickType_t)(timeoutMsForEffect / portTICK_PERIOD_MS)) == pdTRUE) { // Read and parse effect from queue EffectId id; memcpy(&id, msgBuffer, sizeof(EffectId)); TLedStrip &ledStrip = *(task->ledStrip_); // clang-format off if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} else if (dispatchEffectId(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {} // clang-format on timeoutMsForEffect = 0; } else { timeoutMsForEffect = effectFunction(); task->driver_->writeSync(task->ledStrip_->rawData(), task->ledStrip_->numLeds()); } } } template void LedTask::begin(TLedStrip &strip, Esp32DriverRGBW &driver) { queue_ = xQueueCreate(4, MAX_EFFECT_CONFIG_SIZE); if (!queue_) Serial.println("Failed to create LED effect queue"); ledStrip_ = &strip; driver_ = &driver; xTaskCreate(_led_task_func, "led task", MAX_EFFECT_CLASS_SIZE + MAX_EFFECT_CONFIG_SIZE + 2048 * 2, (void *)(this), 1, nullptr); } template template void LedTask::startEffect(const TEffectConfig &cfg) { static constexpr auto msgSize = sizeof(TEffectConfig) + sizeof(EffectId); static_assert(msgSize < MAX_EFFECT_CONFIG_SIZE, "Effect config too large, increase MAX_EFFECT_CONFIG_SIZE"); unsigned char buffer[MAX_EFFECT_CONFIG_SIZE]; if (queue_ == nullptr) { Serial.println("Trying to start effect before queue was set up!"); return; } EffectId id = EffectConfigToId::id; memcpy(buffer, &id, sizeof(EffectId)); memcpy(buffer + sizeof(EffectId), &cfg, sizeof(TEffectConfig)); xQueueSend(queue_, (void *)buffer, (TickType_t)10); }