Separate FreeRTOS task for LED
This commit is contained in:
parent
c68114dc4c
commit
5a41c03e8e
|
@ -1,11 +1,74 @@
|
|||
Connections
|
||||
-----------
|
||||
|
||||
- SDA purple 23
|
||||
- SCK green 22
|
||||
- MOSI orange 18
|
||||
- MISO yellow 19
|
||||
- IRQ grey
|
||||
Reader
|
||||
----------
|
||||
|
||||
- GND black
|
||||
- RST blue 5
|
||||
- 3.3V red
|
||||
- RST blue 3.3V
|
||||
- 3.3V red
|
||||
- MISO brown 21
|
||||
- SDA green 19
|
||||
- SCK yellow 18
|
||||
- MOSI orange 5
|
||||
- IRQ green single cable not connected
|
||||
|
||||
|
||||
Button Board:
|
||||
-------------
|
||||
|
||||
- rot in | white 13
|
||||
- btn2 led | grey 12
|
||||
- btn2 in | purple 14
|
||||
- rotB | blue 27
|
||||
- rotA | green 26
|
||||
- btn1 in | yellow 25
|
||||
- btn1 led | orange 33
|
||||
|
||||
rot="rotary encoder"
|
||||
in=button sense in
|
||||
led = 5V pwm
|
||||
|
||||
|
||||
|
||||
Firmware Planning
|
||||
-----------------
|
||||
|
||||
- input commands:
|
||||
- led: effect + parameters
|
||||
- off
|
||||
- single color
|
||||
- multiple color HSV fade, list of colors with timings
|
||||
- circular motion (already exists)
|
||||
- chained events? e.g. circle two times then fade
|
||||
- effects:
|
||||
- welle fuer an und aus
|
||||
- breathe waehrend an, oder farbgradient
|
||||
-
|
||||
- output infos:
|
||||
- nfc read: with id
|
||||
- nfc remove
|
||||
- button presses, (possible also long press, double click, etc)
|
||||
- rotary encoder up down + current numeric state
|
||||
- on led effect end?
|
||||
|
||||
|
||||
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
1) case redesign
|
||||
- slightly smaller led ring (10mm -> 9mm) [ok]
|
||||
- thicker top of inner ring, but cutouts for reader [ok]
|
||||
- adjust reader stands position [ok]
|
||||
- bottom for led ring snap-in [ok]
|
||||
- bottom for inner ring [ok]
|
||||
- stands for own "pcb" [ok]
|
||||
- 2 cutouts for cables [ok]
|
||||
- checks, compared to existing print
|
||||
- same diameter, very slightly smaller
|
||||
- larger overlap of LED ring
|
||||
- minimal wall thickness for led ring top and side
|
||||
- check total height - compare to existing
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
|
||||
// overall layout:
|
||||
// queue for each led stripe
|
||||
//
|
||||
|
||||
enum class EffectID
|
||||
{
|
||||
OFF,
|
||||
STATIC,
|
||||
CIRCLE,
|
||||
CIRCLE_WAVE,
|
||||
COLOR_FADE,
|
||||
RAINBOW_FADE,
|
||||
};
|
||||
|
||||
struct EffectCircularConfig
|
||||
{
|
||||
float speed; // in degrees per second
|
||||
float width; // width in degrees
|
||||
float brightnessFalloffFactor;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
class AbstractEffect
|
||||
{
|
||||
public:
|
||||
virtual int operator()(TLedStrip &s) = 0;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectCircle : public AbstractEffect<TLedStrip>
|
||||
{
|
||||
public:
|
||||
EffectCircle(const EffectCircularConfig &cfg) : config_(cfg) {}
|
||||
int operator()(TLedStrip &s) override;
|
||||
|
||||
private:
|
||||
EffectCircularConfig config_;
|
||||
float currentPosition_; // between 0 and 1
|
||||
};
|
||||
|
||||
unsigned char effectStorage[128];
|
||||
|
||||
template <typename TLedStrip>
|
||||
AbstractEffect<TLedStrip> *makeEffect(const char *buffer)
|
||||
{
|
||||
const EffectID &effectId = *reinterpret_cast<const EffectID *>(buffer);
|
||||
if (effectId == EffectID::CIRCLE)
|
||||
{
|
||||
auto cfg = reinterpret_cast<const EffectCircularConfig *>(buffer + sizeof(EffectID));
|
||||
return new (effectStorage) EffectCircle<TLedStrip>(*cfg);
|
||||
}
|
||||
// read effect id code from buffer
|
||||
// read config from buffer
|
||||
}
|
|
@ -75,6 +75,13 @@ void setLedRGBW(LedStripRGBW<TNumLeds> &s, int idx, const ColorRGBW &c)
|
|||
s.set(idx, c.r, c.g, c.b, c.w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, const ColorRGBW &c)
|
||||
{
|
||||
for (int i = beginIdx; i < endIdx; ++i)
|
||||
s.set(i, c.r, c.g, c.b, c.w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void clear(LedStripRGBW<TNumLeds> &s)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@ class EffectCircular
|
|||
public:
|
||||
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||
static constexpr int DELAY_MS = 10;
|
||||
using ConfigType = EffectCircularConfig;
|
||||
|
||||
EffectCircular(const EffectCircularConfig &cfg, TLedStrip &ledStrip)
|
||||
: config_(cfg),
|
||||
|
@ -72,3 +73,22 @@ private:
|
|||
int widthInLeds_;
|
||||
float invWidth_;
|
||||
};
|
||||
|
||||
// Traits
|
||||
template <>
|
||||
struct EffectIdToConfig<EffectId::CIRCULAR>
|
||||
{
|
||||
using type = EffectCircularConfig;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EffectConfigToId<EffectCircularConfig>
|
||||
{
|
||||
static constexpr auto id = EffectId::CIRCULAR;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
struct EffectIdToClass<EffectId::CIRCULAR, TLedStrip>
|
||||
{
|
||||
using type = EffectCircular<TLedStrip>;
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
enum class EffectID
|
||||
enum class EffectId
|
||||
{
|
||||
OFF,
|
||||
STATIC,
|
||||
CIRCULAR,
|
||||
CIRCLE_WAVE,
|
||||
|
@ -9,9 +9,17 @@ enum class EffectID
|
|||
RAINBOW_FADE,
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
class AbstractEffect
|
||||
template <EffectId id>
|
||||
struct EffectIdToConfig
|
||||
{
|
||||
};
|
||||
|
||||
template <typename EffectConfig>
|
||||
struct EffectConfigToId
|
||||
{
|
||||
};
|
||||
|
||||
template <EffectId id, typename TLedStrip>
|
||||
struct EffectIdToClass
|
||||
{
|
||||
public:
|
||||
virtual int operator()(TLedStrip &s) = 0;
|
||||
};
|
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
|
||||
struct EffectStaticConfig
|
||||
{
|
||||
ColorRGBW color;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectStatic
|
||||
{
|
||||
public:
|
||||
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||
|
||||
EffectStatic(const EffectStaticConfig &cfg, TLedStrip &ledStrip)
|
||||
: config_(cfg),
|
||||
ledStrip_(ledStrip)
|
||||
{
|
||||
}
|
||||
|
||||
int operator()()
|
||||
{
|
||||
setLedRGBW(ledStrip_, 0, NUM_LEDS, config_.color);
|
||||
return 10000; // nothing changing, return some large time to sleep
|
||||
}
|
||||
|
||||
private:
|
||||
EffectStaticConfig config_;
|
||||
TLedStrip &ledStrip_;
|
||||
};
|
||||
|
||||
// Traits
|
||||
template <>
|
||||
struct EffectIdToConfig<EffectId::STATIC>
|
||||
{
|
||||
using type = EffectStaticConfig;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct EffectConfigToId<EffectStaticConfig>
|
||||
{
|
||||
static constexpr auto id = EffectId::STATIC;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
struct EffectIdToClass<EffectId::STATIC, TLedStrip>
|
||||
{
|
||||
using type = EffectStatic<TLedStrip>;
|
||||
};
|
|
@ -0,0 +1,124 @@
|
|||
#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 = 128;
|
||||
|
||||
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)) { Serial.println("Parsed circular");}
|
||||
else if (dispatchEffectId<EffectId::STATIC >(id, effectFunction, ledStrip, msgBuffer, effectStorage)) { Serial.println("Parsed static");}
|
||||
// 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,
|
||||
(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);
|
||||
}
|
|
@ -9,6 +9,9 @@
|
|||
#include "containers/LedStripRGBW.h"
|
||||
#include "drivers/Esp32DriverRGBW.h"
|
||||
#include "effects/Circular.h"
|
||||
#include "effects/Static.h"
|
||||
|
||||
#include "TaskLed.h"
|
||||
|
||||
MFRC522 rfid; // Instance of the class
|
||||
|
||||
|
@ -18,14 +21,7 @@ MFRC522::MIFARE_Key key;
|
|||
LedStripRGBW<51> ledStrip;
|
||||
Esp32DriverRGBW ledDriver;
|
||||
|
||||
EffectCircular<decltype(ledStrip)> effectFox(EffectCircularConfig{60.0f, 180.0f, ColorRGBW{15, 230, 230, 0} * 0.2f},
|
||||
ledStrip);
|
||||
|
||||
EffectCircular<decltype(ledStrip)> effectOwl(EffectCircularConfig{360.0f, 180.0f, ColorRGBW{0, 0, 0, 150} * 0.2f},
|
||||
ledStrip);
|
||||
|
||||
bool owl = false;
|
||||
bool fox = false;
|
||||
LedTask<decltype(ledStrip)> ledTask;
|
||||
|
||||
void tag_handler(uint8_t *sn)
|
||||
{
|
||||
|
@ -38,27 +34,18 @@ void tag_handler(uint8_t *sn)
|
|||
if (sn[4] == 0x30)
|
||||
{
|
||||
Serial.println("Fuchs");
|
||||
fox = true;
|
||||
owl = false;
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
//led.setRange(0, 50, 0, 0, 243, 0);
|
||||
//led.setRange(led.numLeds() - 40, led.numLeds(), 0, 0, 243, 0);
|
||||
ledTask.startEffect(EffectCircularConfig{2 * 360, 180, ColorRGBW{0, 0, 255, 0}});
|
||||
}
|
||||
if (sn[4] == 0xf0)
|
||||
{
|
||||
Serial.println("Eule");
|
||||
owl = true;
|
||||
fox = false;
|
||||
//led.setRange(0, 50, 0, 0, 0, 254);
|
||||
//led.setRange(led.numLeds() - 40, led.numLeds(), 0, 0, 0, 254);
|
||||
ledTask.startEffect(EffectCircularConfig{180, 180, ColorRGBW{0, 0, 0, 128}});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//led.clear();
|
||||
owl = false;
|
||||
fox = false;
|
||||
Serial.println("Nichts");
|
||||
ledTask.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}});
|
||||
}
|
||||
//led.transmit();
|
||||
}
|
||||
|
@ -101,6 +88,8 @@ void setup()
|
|||
//pinMode(25, INPUT_PULLUP);
|
||||
//pinMode(14, INPUT_PULLUP);
|
||||
//pinMode(13, INPUT_PULLUP);
|
||||
ledTask.begin(ledStrip, ledDriver);
|
||||
ledTask.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}});
|
||||
}
|
||||
|
||||
bool btn2state = true;
|
||||
|
@ -127,7 +116,9 @@ void loop()
|
|||
delay(3000);
|
||||
}
|
||||
*/
|
||||
int delayVal;
|
||||
|
||||
#if 0
|
||||
int delayVal = 100;
|
||||
if (owl)
|
||||
delayVal = effectOwl();
|
||||
else if (fox)
|
||||
|
@ -137,6 +128,8 @@ void loop()
|
|||
|
||||
ledDriver.writeSync(ledStrip.rawData(), ledStrip.numLeds());
|
||||
delay(delayVal);
|
||||
#endif
|
||||
|
||||
/*
|
||||
auto delayMs = animation(led);
|
||||
led.transmit();
|
||||
|
|
Loading…
Reference in New Issue