New led control
This commit is contained in:
parent
6a5d4c463c
commit
c68114dc4c
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,56 @@
|
|||
#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)
|
||||
{
|
||||
}
|
|
@ -3,6 +3,85 @@
|
|||
#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)
|
||||
{
|
||||
|
@ -25,6 +104,15 @@ 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);
|
||||
|
@ -46,3 +134,13 @@ 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));
|
||||
}
|
|
@ -1,5 +1,15 @@
|
|||
#pragma once
|
||||
#include "esp32_digital_led_lib.h"
|
||||
|
||||
struct ColorRGB
|
||||
{
|
||||
uint8_t r, g, b;
|
||||
};
|
||||
|
||||
struct ColorHSV
|
||||
{
|
||||
uint8_t h, s, v;
|
||||
};
|
||||
|
||||
class LedStrip
|
||||
{
|
||||
|
@ -9,11 +19,16 @@ public:
|
|||
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];
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
#include "drivers/Esp32DriverRGBW.h"
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/rmt.h>
|
||||
|
||||
// Timing constants
|
||||
static constexpr uint16_t DIVIDER = 4;
|
||||
static constexpr double RMT_DURATION_NS = 12.5; // Minimum time of a single RMT duration based on clock ns
|
||||
static constexpr uint32_t T0H = 300;
|
||||
static constexpr uint32_t T0L = 900;
|
||||
static constexpr uint32_t T1H = 600;
|
||||
static constexpr uint32_t T1L = 600;
|
||||
static constexpr uint32_t TRS = 80000;
|
||||
static constexpr rmt_item32_t bit0Data = {uint32_t(T0H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T0L / (RMT_DURATION_NS * DIVIDER)), 0};
|
||||
static constexpr rmt_item32_t bit1Data = {uint32_t(T1H / (RMT_DURATION_NS * DIVIDER)), 1, uint32_t(T1L / (RMT_DURATION_NS * DIVIDER)), 0};
|
||||
|
||||
// Function registered at the RMT driver that converts regular uint8_t values containing r,g,b,w values
|
||||
// to rmt_item32_t for each bit. (8 bit -> 32 * 8 bit)
|
||||
static void IRAM_ATTR uint8ToRmtAdaptor(const void *src, rmt_item32_t *dest, size_t srcSize,
|
||||
size_t wantedNum, size_t *translatedSize, size_t *itemNum)
|
||||
{
|
||||
if (src == NULL || dest == NULL)
|
||||
{
|
||||
*translatedSize = 0;
|
||||
*itemNum = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
size_t num = 0;
|
||||
uint8_t *psrc = (uint8_t *)src;
|
||||
rmt_item32_t *pdest = dest;
|
||||
while (size < srcSize && num < wantedNum)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
// MSB first
|
||||
const bool isBitSet = *psrc & (1 << (7 - i));
|
||||
pdest->val = isBitSet ? bit1Data.val : bit0Data.val;
|
||||
num++;
|
||||
pdest++;
|
||||
}
|
||||
size++;
|
||||
psrc++;
|
||||
}
|
||||
*translatedSize = size;
|
||||
*itemNum = num;
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::begin(int gpio, int rmtChannel)
|
||||
{
|
||||
rmtChannel_ = rmtChannel;
|
||||
transmitting_ = false;
|
||||
|
||||
rmt_config_t rmt_tx;
|
||||
rmt_tx.channel = static_cast<rmt_channel_t>(rmtChannel);
|
||||
rmt_tx.gpio_num = static_cast<gpio_num_t>(gpio);
|
||||
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;
|
||||
|
||||
ESP_ERROR_CHECK(rmt_config(&rmt_tx));
|
||||
ESP_ERROR_CHECK(rmt_driver_install(rmt_tx.channel, 0, 0));
|
||||
|
||||
rmt_translator_init((rmt_channel_t)rmtChannel, uint8ToRmtAdaptor);
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::end()
|
||||
{
|
||||
ESP_ERROR_CHECK(rmt_driver_uninstall((rmt_channel_t)rmtChannel_));
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::writeSync(const uint32_t *rgbwData, int numLeds)
|
||||
{
|
||||
waitForTransmissionToFinish();
|
||||
auto data = reinterpret_cast<const uint8_t *>(rgbwData);
|
||||
ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, true));
|
||||
}
|
||||
|
||||
void Esp32DriverRGBW::writeAsync(const uint32_t *rgbwData, int numLeds)
|
||||
{
|
||||
waitForTransmissionToFinish();
|
||||
auto data = reinterpret_cast<const uint8_t *>(rgbwData);
|
||||
ESP_ERROR_CHECK(rmt_write_sample((rmt_channel_t)rmtChannel_, data, numLeds * 4, false));
|
||||
transmitting_ = true;
|
||||
}
|
||||
|
||||
bool Esp32DriverRGBW::waitForTransmissionToFinish(int waitMs)
|
||||
{
|
||||
if (!transmitting_)
|
||||
return true;
|
||||
auto ret = rmt_wait_tx_done((rmt_channel_t)rmtChannel_, waitMs / portTICK_PERIOD_MS);
|
||||
if (ret == ESP_OK)
|
||||
{
|
||||
transmitting_ = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
// 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
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/// a static array of red-green-blue-white values together with free functions to set them
|
||||
#pragma once
|
||||
|
||||
#include "helpers/ColorRGBW.h"
|
||||
|
||||
#include "Arduino.h" // TODO
|
||||
#include <cstdint>
|
||||
|
||||
template <int TNumLeds>
|
||||
class LedStripRGBW
|
||||
{
|
||||
public:
|
||||
static constexpr int NUM_LEDS = TNumLeds;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
const uint32_t *rawData() const { return data_; }
|
||||
constexpr static int numLeds() { return TNumLeds; }
|
||||
|
||||
private:
|
||||
uint32_t data_[TNumLeds];
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
constexpr int numLeds()
|
||||
{
|
||||
return TLedStrip::NUM_LEDS;
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
constexpr int numLeds(const LedStripRGBW<TNumLeds> &)
|
||||
{
|
||||
return TNumLeds;
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGB(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
for (int i = beginIdx; i < endIdx; ++i)
|
||||
s.set(i, r, g, b, 0);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGB(LedStripRGBW<TNumLeds> &s, int idx, uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
s.set(idx, r, g, b, 0);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int beginIdx, int endIdx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
|
||||
{
|
||||
for (int i = beginIdx; i < endIdx; ++i)
|
||||
s.set(i, r, g, b, w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
void setLedRGBW(LedStripRGBW<TNumLeds> &s, int idx, uint8_t r, uint8_t g, uint8_t b, uint8_t w)
|
||||
{
|
||||
s.set(idx, r, g, b, w);
|
||||
}
|
||||
|
||||
template <int TNumLeds>
|
||||
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 clear(LedStripRGBW<TNumLeds> &s)
|
||||
{
|
||||
for (int i = 0; i < TNumLeds; ++i)
|
||||
s.set(i, 0, 0, 0, 0);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "containers/LedStripRGBW.h"
|
||||
|
||||
class Esp32DriverRGBW
|
||||
{
|
||||
public:
|
||||
void begin(int gpio, int rmtChannel);
|
||||
void end();
|
||||
|
||||
void writeSync(const uint32_t *rgbwData, int numLeds);
|
||||
|
||||
void writeAsync(const uint32_t *rgbwData, int numLeds);
|
||||
bool waitForTransmissionToFinish(int waitMs = 1000);
|
||||
|
||||
private:
|
||||
int rmtChannel_;
|
||||
bool transmitting_;
|
||||
};
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include "effects/Common.h"
|
||||
#include "helpers/ColorRGBW.h"
|
||||
#include "helpers/BellCurve.h"
|
||||
|
||||
struct EffectCircularConfig
|
||||
{
|
||||
float speed; // in degrees per second
|
||||
float width; // width in degrees
|
||||
ColorRGBW color;
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
class EffectCircular
|
||||
{
|
||||
public:
|
||||
static constexpr auto NUM_LEDS = numLeds<TLedStrip>();
|
||||
static constexpr int DELAY_MS = 10;
|
||||
|
||||
EffectCircular(const EffectCircularConfig &cfg, TLedStrip &ledStrip)
|
||||
: config_(cfg),
|
||||
ledStrip_(ledStrip),
|
||||
currentPosition_(0),
|
||||
widthInLeds_((numLeds(ledStrip) * cfg.width / 360)),
|
||||
invWidth_(1.0f / widthInLeds_)
|
||||
{
|
||||
}
|
||||
|
||||
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_);
|
||||
float distDown = currentPosition_ - float(startLed);
|
||||
float distUp = 1.f - distDown;
|
||||
|
||||
clear(ledStrip_);
|
||||
// center
|
||||
setLedRGBW(ledStrip_, normalizeIdx(startLed),
|
||||
config_.color * bellCurveApproximation(distDown, invWidth_));
|
||||
|
||||
// down
|
||||
for (int i = 1; i < widthInLeds_ / 2 + 1; ++i)
|
||||
{
|
||||
setLedRGBW(ledStrip_, normalizeIdx(startLed - i),
|
||||
config_.color * bellCurveApproximation(distDown + i, invWidth_));
|
||||
}
|
||||
|
||||
// up
|
||||
for (int i = 1; i < widthInLeds_ / 2 + 1; ++i)
|
||||
{
|
||||
setLedRGBW(ledStrip_, normalizeIdx(startLed + i),
|
||||
config_.color * bellCurveApproximation(distUp + i - 1, invWidth_));
|
||||
}
|
||||
|
||||
currentPosition_ += config_.speed / 1000 / 360 * NUM_LEDS * DELAY_MS;
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
EffectCircularConfig config_;
|
||||
TLedStrip &ledStrip_;
|
||||
float currentPosition_; // between 0 and num leds
|
||||
int widthInLeds_;
|
||||
float invWidth_;
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
enum class EffectID
|
||||
{
|
||||
OFF,
|
||||
STATIC,
|
||||
CIRCULAR,
|
||||
CIRCLE_WAVE,
|
||||
COLOR_FADE,
|
||||
RAINBOW_FADE,
|
||||
};
|
||||
|
||||
template <typename TLedStrip>
|
||||
class AbstractEffect
|
||||
{
|
||||
public:
|
||||
virtual int operator()(TLedStrip &s) = 0;
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
#include <cstdint>
|
||||
|
||||
static inline float bellCurveApproximation(float x, float inverseWidth)
|
||||
{
|
||||
if (x < 0)
|
||||
x = -x;
|
||||
|
||||
const auto nx = x * inverseWidth * 4;
|
||||
if (nx > 2)
|
||||
return 0.0f;
|
||||
|
||||
const auto x2 = nx * nx;
|
||||
const auto x3 = x2 * nx;
|
||||
const auto res = 1.0f + 0.27606958941084f * x3 - 0.80213917882168f * x2;
|
||||
|
||||
return res < 0.0f ? 0.0f : res;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct ColorRGBW
|
||||
{
|
||||
uint8_t r, g, b, w;
|
||||
|
||||
ColorRGBW operator*(float s) const
|
||||
{
|
||||
return {uint8_t(s * r),
|
||||
uint8_t(s * g),
|
||||
uint8_t(s * b),
|
||||
uint8_t(s * w)};
|
||||
}
|
||||
};
|
|
@ -4,12 +4,28 @@
|
|||
#include <MFRC522.h>
|
||||
#include "LedControl.h"
|
||||
#include "rotary_encoder.h"
|
||||
#include "LedAnimation.h"
|
||||
|
||||
MFRC522 rfid(5); // Instance of the class
|
||||
#include "containers/LedStripRGBW.h"
|
||||
#include "drivers/Esp32DriverRGBW.h"
|
||||
#include "effects/Circular.h"
|
||||
|
||||
MFRC522 rfid; // Instance of the class
|
||||
|
||||
MFRC522::MIFARE_Key key;
|
||||
|
||||
LedStrip led(144, 13);
|
||||
//LedStrip led(46, 23);
|
||||
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;
|
||||
|
||||
void tag_handler(uint8_t *sn)
|
||||
{
|
||||
|
@ -22,22 +38,29 @@ void tag_handler(uint8_t *sn)
|
|||
if (sn[4] == 0x30)
|
||||
{
|
||||
Serial.println("Fuchs");
|
||||
////////////////////////////////////////////////////////////////////////////////////led.setAll(0, 0, 254, 0);
|
||||
led.setRange(led.numLeds() - 40, led.numLeds(), 0, 0, 243, 0);
|
||||
fox = true;
|
||||
owl = false;
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
//led.setRange(0, 50, 0, 0, 243, 0);
|
||||
//led.setRange(led.numLeds() - 40, led.numLeds(), 0, 0, 243, 0);
|
||||
}
|
||||
if (sn[4] == 0xf0)
|
||||
{
|
||||
Serial.println("Eule");
|
||||
//led.setAll(0, 0, 0, 254);
|
||||
led.setRange(led.numLeds() - 40, led.numLeds(), 0, 0, 0, 254);
|
||||
owl = true;
|
||||
fox = false;
|
||||
//led.setRange(0, 50, 0, 0, 0, 254);
|
||||
//led.setRange(led.numLeds() - 40, led.numLeds(), 0, 0, 0, 254);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
led.clear();
|
||||
//led.clear();
|
||||
owl = false;
|
||||
fox = false;
|
||||
Serial.println("Nichts");
|
||||
}
|
||||
led.transmit();
|
||||
//led.transmit();
|
||||
}
|
||||
QueueHandle_t event_queue;
|
||||
|
||||
|
@ -45,14 +68,15 @@ rotary_encoder_info_t info;
|
|||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
led.begin();
|
||||
digitalWrite(5, 1);
|
||||
|
||||
//led.begin();
|
||||
ledDriver.begin(23, 0);
|
||||
|
||||
const rc522_start_args_t start_args = {
|
||||
19, // MISO
|
||||
18, // MOSI
|
||||
22, // SCK
|
||||
23, // SDA
|
||||
21, // MISO
|
||||
5, // MOSI
|
||||
18, // SCK
|
||||
19, // SDA
|
||||
VSPI_HOST,
|
||||
&tag_handler,
|
||||
125, // scan_interval_ms
|
||||
|
@ -62,16 +86,26 @@ void setup()
|
|||
rc522_start(start_args);
|
||||
|
||||
ESP_ERROR_CHECK(gpio_install_isr_service(0));
|
||||
ESP_ERROR_CHECK(rotary_encoder_init(&info, GPIO_NUM_12, GPIO_NUM_14));
|
||||
ESP_ERROR_CHECK(rotary_encoder_init(&info, GPIO_NUM_26, GPIO_NUM_27));
|
||||
ESP_ERROR_CHECK(rotary_encoder_enable_half_steps(&info, false));
|
||||
event_queue = rotary_encoder_create_queue();
|
||||
ESP_ERROR_CHECK(rotary_encoder_set_queue(&info, event_queue));
|
||||
|
||||
pinMode (2, OUTPUT);
|
||||
digitalWrite(2, HIGH);
|
||||
//button leds
|
||||
//pinMode(33, OUTPUT);
|
||||
//digitalWrite(33, HIGH);
|
||||
//pinMode(12, OUTPUT);
|
||||
//digitalWrite(12, HIGH);
|
||||
|
||||
//// button in
|
||||
//pinMode(25, INPUT_PULLUP);
|
||||
//pinMode(14, INPUT_PULLUP);
|
||||
//pinMode(13, INPUT_PULLUP);
|
||||
}
|
||||
|
||||
bool btn2state = true;
|
||||
|
||||
SweepCircularAnimation animation(ColorRGB{0, 0, 255}, 100, 15, 0.7);
|
||||
void loop()
|
||||
{
|
||||
/*
|
||||
|
@ -82,7 +116,37 @@ void loop()
|
|||
event.state.direction ? (event.state.direction == ROTARY_ENCODER_DIRECTION_CLOCKWISE ? "CW" : "CCW") : "NOT_SET");
|
||||
}
|
||||
*/
|
||||
Serial.println(touchRead(15)); // get value of Touch 0 pin = GPIO 4
|
||||
|
||||
/*
|
||||
for (int i = 48; i < ledStrip.numLeds(); ++i)
|
||||
{
|
||||
clear(ledStrip);
|
||||
setLedRGBW(ledStrip, i, 0, 0, 255, 255);
|
||||
Serial.println(i);
|
||||
ledDriver.writeSync(ledStrip.rawData(), ledStrip.numLeds());
|
||||
delay(3000);
|
||||
}
|
||||
*/
|
||||
int delayVal;
|
||||
if (owl)
|
||||
delayVal = effectOwl();
|
||||
else if (fox)
|
||||
delayVal = effectFox();
|
||||
else
|
||||
clear(ledStrip);
|
||||
|
||||
ledDriver.writeSync(ledStrip.rawData(), ledStrip.numLeds());
|
||||
delay(delayVal);
|
||||
/*
|
||||
auto delayMs = animation(led);
|
||||
led.transmit();
|
||||
delay(delayMs);
|
||||
*/
|
||||
|
||||
/*
|
||||
Serial.printf("btn1 %d btn2 %d rot %d\n", digitalRead(25), digitalRead(14), digitalRead(13));
|
||||
delay(500);
|
||||
//digitalWrite(2, HIGH);
|
||||
btn2state = !btn2state;
|
||||
digitalWrite(12, btn2state);
|
||||
*/
|
||||
}
|
Loading…
Reference in New Issue