musicmouse/espmusicmouse/lib/leds/LedControl.cpp

146 lines
4.4 KiB
C++
Raw Normal View History

2021-10-27 16:40:18 +02:00
#include "LedControl.h"
#include "driver/rmt.h"
#include "esp32_digital_led_lib.h"
#include "Arduino.h"
2021-11-16 22:04:22 +01:00
#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};
}
2021-10-27 16:40:18 +02:00
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);
}
2021-11-16 22:04:22 +01:00
int LedStrip::normalizeLedIdx(int i)
{
while (i < 0)
i += numLeds_;
while (i >= numLeds_)
i -= numLeds_;
return i;
}
2021-10-27 16:40:18 +02:00
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);
2021-11-16 22:04:22 +01:00
}
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));
2021-10-27 16:40:18 +02:00
}