Files
musicmouse/esp-firmware/src/TaskLed.h
Martin Bauer bd8925a278 Cleaned up repository
- only moving files around
2026-08-25 17:06:53 +02:00

130 lines
4.6 KiB
C++

#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 <functional>
#include <cstring>
static constexpr int MAX_EFFECT_CONFIG_SIZE = 128;
static constexpr int MAX_EFFECT_CLASS_SIZE = 8 * 1024;
template <typename TLedStrip>
class LedTask
{
public:
void begin(TLedStrip &strip, Esp32DriverRGBW &driver);
template <typename TEffectConfig>
void startEffect(const TEffectConfig &cfg);
private:
template <typename T>
friend void _led_task_func(void *);
QueueHandle_t queue_ = nullptr;
TLedStrip *ledStrip_ = nullptr;
Esp32DriverRGBW *driver_ = nullptr;
};
// -----------------------------------------------------------------------------------------------
template <EffectId staticEffectId, typename TLedStrip>
bool dispatchEffectId(EffectId dynamicEffectId, std::function<int()> &effectFunction, TLedStrip &ledStrip,
unsigned char *msgBuffer, unsigned char *effectStorage)
{
if (staticEffectId == dynamicEffectId)
{
typename EffectIdToConfig<staticEffectId>::type cfg;
memcpy(&cfg, msgBuffer + sizeof(EffectId), sizeof(decltype(cfg)));
using TEffect = typename EffectIdToClass<staticEffectId, TLedStrip>::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 <typename TLedStrip>
void _led_task_func(void *params)
{
LedTask<TLedStrip> *task = reinterpret_cast<LedTask<TLedStrip> *>(params);
unsigned char msgBuffer[MAX_EFFECT_CONFIG_SIZE];
unsigned char effectStorage[MAX_EFFECT_CLASS_SIZE];
std::function<int()> 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<EffectId::CIRCULAR >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::STATIC >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::STATIC_DETAILED >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::ALEXA_SWIPE >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::RANDOM_TWO_COLOR_INTERPOLATION>(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::SWIPE_AND_CHANGE >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
else if (dispatchEffectId<EffectId::REVERSE_SWIPE >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) {}
// clang-format on
timeoutMsForEffect = 0;
}
else
{
timeoutMsForEffect = effectFunction();
task->driver_->writeSync(task->ledStrip_->rawData(), task->ledStrip_->numLeds());
}
}
}
template <typename TLedStrip>
void LedTask<TLedStrip>::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<TLedStrip>, "led task", MAX_EFFECT_CLASS_SIZE + MAX_EFFECT_CONFIG_SIZE + 2048 * 2,
(void *)(this), 1, nullptr);
}
template <typename TLedStrip>
template <typename TEffectConfig>
void LedTask<TLedStrip>::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<TEffectConfig>::id;
memcpy(buffer, &id, sizeof(EffectId));
memcpy(buffer + sizeof(EffectId), &cfg, sizeof(TEffectConfig));
xQueueSend(queue_, (void *)buffer, (TickType_t)10);
}