Grouping and Spacing

This commit is contained in:
cschwinne 2020-01-14 10:57:23 +01:00
parent 6bc927c535
commit ae6ba79f1e
4 changed files with 318 additions and 300 deletions

File diff suppressed because it is too large Load Diff

View File

@ -59,7 +59,7 @@
#define SEGMENT _segments[_segment_index]
#define SEGCOLOR(x) gamma32(_segments[_segment_index].colors[x])
#define SEGENV _segment_runtimes[_segment_index]
#define SEGLEN SEGMENT.length()
#define SEGLEN _virtualSegmentLength
#define SEGACT SEGMENT.stop
#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGLEN
#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes))
@ -199,16 +199,15 @@ class WS2812FX {
// segment parameters
public:
typedef struct Segment { // 25 bytes
typedef struct Segment { // 24 bytes
uint16_t start;
uint16_t stop; //segment invalid if stop == 0
uint16_t rawLength;
uint8_t speed;
uint8_t intensity;
uint8_t palette;
uint8_t mode;
uint8_t options; //bit pattern: msb first: transitional tbd tbd tbd tbd paused reverse selected
uint8_t group, spacing;
uint8_t grouping, spacing;
uint8_t opacity;
uint32_t colors[NUM_COLORS];
void setOption(uint8_t n, bool val)
@ -236,8 +235,14 @@ class WS2812FX {
{
return stop - start;
}
uint16_t ledGroup() {
return group + spacing;
uint16_t groupLength()
{
return grouping + spacing;
}
uint16_t virtualLength()
{
uint16_t groupLen = groupLength();
return (length() + groupLen -1) / groupLen;
}
} segment;
@ -381,7 +386,7 @@ class WS2812FX {
}
void
init(bool supportWhite, uint16_t countPixels, uint8_t group, uint8_t spacing, bool skipFirst),
init(bool supportWhite, uint16_t countPixels, bool skipFirst),
service(void),
blur(uint8_t),
fade_out(uint8_t r),
@ -396,7 +401,7 @@ class WS2812FX {
setShowCallback(show_callback cb),
setTransitionMode(bool t),
trigger(void),
setSegment(uint8_t n, uint16_t start, uint16_t length, uint8_t group, uint8_t spacing),
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0),
resetSegments(),
setPixelColor(uint16_t n, uint32_t c),
setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0),
@ -416,8 +421,6 @@ class WS2812FX {
paletteBlend = 0,
colorOrder = 0,
milliampsPerLed = 55,
_spacing = 0,
_group = 1,
getBrightness(void),
getMode(void),
getSpeed(void),
@ -432,8 +435,7 @@ class WS2812FX {
uint16_t
ablMilliampsMax,
currentMilliamps,
triwave16(uint16_t),
getUsableCount();
triwave16(uint16_t);
uint32_t
timebase,
@ -564,7 +566,7 @@ class WS2812FX {
CRGBPalette16 targetPalette;
uint32_t now;
uint16_t _length;
uint16_t _length, _lengthRaw, _virtualSegmentLength;
uint16_t _rand16seed;
uint8_t _brightness;
static uint16_t _usedSegmentData;
@ -610,14 +612,13 @@ class WS2812FX {
uint8_t _segment_index = 0;
uint8_t _segment_index_palette_last = 99;
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 25 bytes per element
// start, stop, length, speed, intensity, palette, mode, options, group, spacing, opacity (unused), color[]
{ 0, 7, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 24 bytes per element
// start, stop, speed, intensity, palette, mode, options, grouping, spacing, opacity (unused), color[]
{ 0, 7, DEFAULT_SPEED, 128, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}}
};
segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element
friend class Segment_runtime;
uint16_t realPixelIndex(uint16_t i);
};

View File

@ -30,37 +30,29 @@
#define LED_SKIP_AMOUNT 1
#define MIN_SHOW_DELAY 15
void WS2812FX::init(bool supportWhite, uint16_t countPixels, uint8_t group, uint8_t spacing, bool skipFirst)
void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst)
{
if (supportWhite == _rgbwMode && countPixels == _length && disableNLeds == _disableNLeds) return;
if (supportWhite == _rgbwMode && countPixels == _length) return;
RESET_RUNTIME;
_rgbwMode = supportWhite;
_skipFirstMode = skipFirst;
_length = countPixels;
_group = group;
_spacing = spacing;
uint8_t ty = 1;
if (supportWhite) ty =2;
uint16_t lengthRaw = _length + (_skipFirstMode ? LED_SKIP_AMOUNT : 0);
if (supportWhite) ty = 2;
_lengthRaw = _length;
if (_skipFirstMode) {
_lengthRaw += LED_SKIP_AMOUNT;
}
bus->Begin((NeoPixelType)ty, lengthRaw);
bus->Begin((NeoPixelType)ty, _lengthRaw);
_segments[0].start = 0;
_segments[0].group = _group;
_segments[0].spacing = _spacing;
_segments[0].stop = getUsableCount();
_segments[0].rawLength = _length;
_segments[0].stop = _length;
setBrightness(_brightness);
}
uint16_t WS2812FX::getUsableCount() {
uint16_t ledGroup = _group + _spacing;
return (_length + ledGroup -1) / ledGroup;
}
void WS2812FX::service() {
uint32_t nowUp = millis(); // Be aware, millis() rolls over every 49 days
now = nowUp + timebase;
@ -73,6 +65,7 @@ void WS2812FX::service() {
{
if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary
{
_virtualSegmentLength = SEGMENT.virtualLength();
doShow = true;
handle_palette();
uint16_t delay = (this->*_mode[SEGMENT.mode])();
@ -81,6 +74,7 @@ void WS2812FX::service() {
}
}
}
_virtualSegmentLength = 0;
if(doShow) {
yield();
show();
@ -97,82 +91,90 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) {
}
uint16_t WS2812FX::realPixelIndex(uint16_t i) {
int16_t iGroup = (i - SEGMENT.start) * SEGMENT.ledGroup();
int16_t iGroup = i * SEGMENT.groupLength();
/* reverse just an individual segment */
int16_t realIndex;
if IS_REVERSE
realIndex = SEGMENT.rawLength + SEGMENT.start - iGroup -1;
else
realIndex = SEGMENT.start + iGroup;
/* Reverse the whole string */
if (reverseMode) realIndex = _length - 1 - realIndex;
/* reverse just an individual segment */
int16_t realIndex = iGroup;
if (IS_REVERSE) realIndex = SEGMENT.length() -iGroup -1;
return realIndex;
realIndex += SEGMENT.start;
/* Reverse the whole string */
if (reverseMode) realIndex = _length - 1 - realIndex;
return realIndex;
}
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
{
RgbwColor color;
color.W = w;
switch (colorOrder) //0 = Grb, default
RgbwColor col;
switch (colorOrder)
{
case 0: color.G = g; color.R = r; color.B = b; break; // 0 = GRB
case 1: color.G = r; color.R = g; color.B = b; break; // 1 = RGB, common for WS2811
case 2: color.G = b; color.R = r; color.B = g; break; // 2 = BRG
case 3: color.G = r; color.R = b; color.B = g; break; // 3 = RBG
case 0: col.G = g; col.R = r; col.B = b; break; //0 = GRB, default
case 1: col.G = r; col.R = g; col.B = b; break; //1 = RGB, common for WS2811
case 2: col.G = b; col.R = r; col.B = g; break; //2 = BRG
case 3: col.G = r; col.R = b; col.B = g; break; //3 = RBG
case 4: col.G = b; col.R = g; col.B = r; break; //4 = BGR
default: col.G = g; col.R = b; col.B = r; break; //5 = GBR
}
col.W = w;
if (!_cronixieMode)
{
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */
bool reversed = reverseMode ^ IS_REVERSE;
uint16_t realIndex = realPixelIndex(i);
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
for (uint16_t l = 0; l < SEGMENT.ledGroup(); l++) {
int16_t indexSet = realIndex + (reversed ? -l : l);
if (indexSet >= SEGMENT.start && (indexSet < SEGMENT.start + SEGMENT.rawLength))
bus->SetPixelColor(indexSet + skip, l < SEGMENT.group ? color : RgbwColor(0, 0, 0, 0));
for (uint16_t l = 0; indexSet == 0 && l < skip; l++) {// Clear the skipped pixels
bus->SetPixelColor(l, RgbwColor(0, 0, 0, 0));
if (SEGLEN) {//from segment
/* Set all the pixels in the group, ensuring _skipFirstMode is honored */
bool reversed = reverseMode ^ IS_REVERSE;
uint16_t realIndex = realPixelIndex(i);
for (uint16_t j = 0; j < SEGMENT.grouping; j++) {
int16_t indexSet = realIndex + (reversed ? -j : j);
if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) bus->SetPixelColor(indexSet + skip, col);
}
} else { //live data, etc.
if (reverseMode) i = _length - 1 - i;
bus->SetPixelColor(i + skip, col);
}
if (skip && i == 0) {
for (uint16_t j = 0; j < skip; j++) {
bus->SetPixelColor(j, RgbwColor(0, 0, 0, 0));
}
}
} else {
if(i>6)return;
byte o = 10*i;
if (_cronixieBacklightEnabled && _cronixieDigits[i] <11)
return;
}
//CRONIXIE
if(i>6)return;
byte o = 10*i;
if (_cronixieBacklightEnabled && _cronixieDigits[i] <11)
{
byte r2 = _segments[0].colors[1] >>16;
byte g2 = _segments[0].colors[1] >> 8;
byte b2 = _segments[0].colors[1];
byte w2 = _segments[0].colors[1] >>24;
for (int j=o; j< o+19; j++)
{
byte r2 = _segments[0].colors[1] >>16;
byte g2 = _segments[0].colors[1] >> 8;
byte b2 = _segments[0].colors[1];
byte w2 = _segments[0].colors[1] >>24;
for (int j=o; j< o+19; j++)
{
bus->SetPixelColor(j, RgbwColor(r2,g2,b2,w2));
}
} else
{
for (int j=o; j< o+19; j++)
{
bus->SetPixelColor(j, RgbwColor(0,0,0,0));
}
bus->SetPixelColor(j, RgbwColor(r2,g2,b2,w2));
}
if (_skipFirstMode) o += LED_SKIP_AMOUNT;
switch(_cronixieDigits[i])
} else
{
for (int j=o; j< o+19; j++)
{
case 0: bus->SetPixelColor(o+5, color); break;
case 1: bus->SetPixelColor(o+0, color); break;
case 2: bus->SetPixelColor(o+6, color); break;
case 3: bus->SetPixelColor(o+1, color); break;
case 4: bus->SetPixelColor(o+7, color); break;
case 5: bus->SetPixelColor(o+2, color); break;
case 6: bus->SetPixelColor(o+8, color); break;
case 7: bus->SetPixelColor(o+3, color); break;
case 8: bus->SetPixelColor(o+9, color); break;
case 9: bus->SetPixelColor(o+4, color); break;
bus->SetPixelColor(j, RgbwColor(0,0,0,0));
}
}
if (_skipFirstMode) o += LED_SKIP_AMOUNT;
switch(_cronixieDigits[i])
{
case 0: bus->SetPixelColor(o+5, col); break;
case 1: bus->SetPixelColor(o+0, col); break;
case 2: bus->SetPixelColor(o+6, col); break;
case 3: bus->SetPixelColor(o+1, col); break;
case 4: bus->SetPixelColor(o+7, col); break;
case 5: bus->SetPixelColor(o+2, col); break;
case 6: bus->SetPixelColor(o+8, col); break;
case 7: bus->SetPixelColor(o+3, col); break;
case 8: bus->SetPixelColor(o+9, col); break;
case 9: bus->SetPixelColor(o+4, col); break;
}
}
void WS2812FX::driverModeCronixie(bool b)
@ -387,6 +389,7 @@ uint32_t WS2812FX::getColor(void) {
uint32_t WS2812FX::getPixelColor(uint16_t i)
{
i = realPixelIndex(i) + (_skipFirstMode ? LED_SKIP_AMOUNT : 0);
if (_cronixieMode)
{
if(i>6)return 0;
@ -406,18 +409,20 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
default: return 0;
}
}
uint16_t skip = _skipFirstMode ? LED_SKIP_AMOUNT : 0;
if (i >= (_length + skip)) return 0;
RgbwColor lColor = bus->GetPixelColorRgbw(i);
byte r = lColor.R, g = lColor.G, b = lColor.B;
if (i >= _lengthRaw) return 0;
RgbwColor col = bus->GetPixelColorRgbw(i);
switch (colorOrder)
{
case 0: break; //0 = Grb
case 1: r = lColor.G; g = lColor.R; break; //1 = Rgb, common for WS2811
case 2: g = lColor.B; b = lColor.G; break; //2 = Brg
case 3: r = lColor.B; g = lColor.R; b = lColor.G; //3 = Rbg
// W G R B
case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default
case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811
case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG
case 3: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //3 = RBG
case 4: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //4 = BGR
case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR
}
return ( (lColor.W << 24) | (r << 16) | (g << 8) | (b) );
return 0;
}
WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) {
@ -437,26 +442,26 @@ uint32_t WS2812FX::getLastShow(void) {
return _lastShow;
}
void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t length, uint8_t group, uint8_t spacing) {
void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing) {
if (n >= MAX_NUM_SEGMENTS) return;
Segment& seg = _segments[n];
if (seg.start == start && seg.rawLength == length && seg.group == group && seg.spacing == spacing) return;
//return if neither bounds nor grouping have changed
if (seg.start == i1 && seg.stop == i2 && (!grouping || (seg.grouping == grouping && seg.spacing == spacing))) return;
_segment_index = n; fill(0); //turn old segment range off
seg.rawLength = min(_length - start, length);
seg.spacing = spacing;
seg.group = group;
seg.start = start;
uint16_t ledGroup = seg.ledGroup();
seg.stop = (seg.rawLength - seg.start + ledGroup -1) / ledGroup + seg.start;
if (seg.start >= seg.stop) {
seg.stop = 0;
if (seg.stop) setRange(seg.start, seg.stop -1, 0); //turn old segment range off
if (i2 <= i1) //disable segment
{
seg.stop = 0; return;
}
else {
_segment_runtimes[n].reset();
if (i1 < _length) seg.start = i1;
seg.stop = i2;
if (i2 > _length) seg.stop = _length;
if (grouping) {
seg.grouping = grouping;
seg.spacing = spacing;
}
_segment_runtimes[n].reset();
}
void WS2812FX::resetSegments() {
@ -467,16 +472,13 @@ void WS2812FX::resetSegments() {
_segments[0].colors[0] = DEFAULT_COLOR;
_segments[0].start = 0;
_segments[0].speed = DEFAULT_SPEED;
_segments[0].stop = getUsableCount();
_segments[0].rawLength = _length;
_segments[0].stop = _length;
_segments[0].grouping = 1;
_segments[0].setOption(0, 1); //select
_segments[0].group = _group;
_segments[0].spacing = _spacing;
for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++)
{
_segments[i].colors[0] = color_wheel(i*51);
_segments[i].grouping = 1;
_segment_runtimes[i].reset();
}
_segment_runtimes[0].reset();
@ -536,7 +538,7 @@ uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend)
* Fills segment with color
*/
void WS2812FX::fill(uint32_t c) {
for(uint16_t i=SEGMENT.start; i < SEGMENT.stop; i++) {
for(uint16_t i = 0; i < SEGLEN; i++) {
setPixelColor(i, c);
}
}
@ -554,7 +556,7 @@ void WS2812FX::fade_out(uint8_t rate) {
int g2 = (color >> 8) & 0xff;
int b2 = color & 0xff;
for(uint16_t i=SEGMENT.start; i < SEGMENT.stop; i++) {
for(uint16_t i = 0; i < SEGLEN; i++) {
color = getPixelColor(i);
int w1 = (color >> 24) & 0xff;
int r1 = (color >> 16) & 0xff;
@ -584,14 +586,14 @@ void WS2812FX::blur(uint8_t blur_amount)
uint8_t keep = 255 - blur_amount;
uint8_t seep = blur_amount >> 1;
CRGB carryover = CRGB::Black;
for(uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++)
for(uint16_t i = 0; i < SEGLEN; i++)
{
CRGB cur = col_to_crgb(getPixelColor(i));
CRGB part = cur;
part.nscale8(seep);
cur.nscale8(keep);
cur += carryover;
if(i > SEGMENT.start) {
if(i > 0) {
uint32_t c = getPixelColor(i-1);
uint8_t r = (c >> 16 & 0xFF);
uint8_t g = (c >> 8 & 0xFF);
@ -756,7 +758,7 @@ uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8
{
if (SEGMENT.palette == 0 && mcol < 3) return SEGCOLOR(mcol); //WS2812FX default
uint8_t paletteIndex = i;
if (mapping) paletteIndex = map(i,SEGMENT.start,SEGMENT.stop-1,0,255);
if (mapping) paletteIndex = (i*255)/(SEGLEN -1);
if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
CRGB fastled_col;
fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND);

View File

@ -8,12 +8,16 @@ void deserializeSegment(JsonObject elem, byte it)
if (id < strip.getMaxSegments())
{
WS2812FX::Segment& seg = strip.getSegment(id);
uint16_t start = elem.containsKey("start") ? elem["start"] : seg.start;
uint16_t len = elem.containsKey("len") ? elem["len"] : seg.rawLength;
uint8_t group = max(1, elem["grp"] | seg.group);
uint8_t spacing = elem.containsKey("spc") ? elem["spc"] : seg.spacing;
uint16_t start = elem["start"] | seg.start;
int stop = elem["stop"] | -1;
strip.setSegment(id, start, len, group, spacing);
if (stop < 0) {
uint16_t len = elem["len"];
stop = (len > 0) ? start + len : seg.stop;
}
uint16_t grp = elem["grp"] | seg.grouping;
uint16_t spc = elem["spc"] | seg.spacing;
strip.setSegment(id, start, stop, grp, spc);
JsonArray colarr = elem["col"];
if (!colarr.isNull())
@ -163,7 +167,9 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
root["id"] = id;
root["start"] = seg.start;
root["stop"] = seg.stop;
root["len"] = seg.rawLength;
root["len"] = seg.stop - seg.start;
root["grp"] = seg.grouping;
root["spc"] = seg.spacing;
JsonArray colarr = root.createNestedArray("col");
@ -182,8 +188,6 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
root["ix"] = seg.intensity;
root["pal"] = seg.palette;
root["sel"] = seg.isSelected();
root["grp"] = seg.group;
root["spc"] = seg.spacing;
root["rev"] = seg.getOption(1);
}
@ -257,7 +261,9 @@ void serializeInfo(JsonObject root)
JsonObject wifi_info = root.createNestedObject("wifi");
wifi_info["bssid"] = WiFi.BSSIDstr();
wifi_info["signal"] = getSignalQuality(WiFi.RSSI());
int qrssi = WiFi.RSSI();
wifi_info["rssi"] = qrssi;
wifi_info["signal"] = getSignalQuality(qrssi);
wifi_info["channel"] = WiFi.channel();
#ifdef ARDUINO_ARCH_ESP32
@ -357,7 +363,7 @@ void serveJson(AsyncWebServerRequest* request)
void serveLiveLeds(AsyncWebServerRequest* request)
{
byte used = strip.getUsableCount();
byte used = ledCount;
byte n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS
char buffer[2000] = "{\"leds\":[";
olen = 9;