mirror of
https://github.com/wled/WLED.git
synced 2025-04-24 06:47:18 +00:00
Merge branch 'main' into waterfall-fix
This commit is contained in:
commit
f001846e00
7
package-lock.json
generated
7
package-lock.json
generated
@ -1,18 +1,21 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b7",
|
||||
"version": "0.16.0-dev",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wled",
|
||||
"version": "0.15.0-b7",
|
||||
"version": "0.16.0-dev",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"clean-css": "^5.3.3",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"inliner": "^1.13.1",
|
||||
"nodemon": "^3.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wled",
|
||||
"version": "0.15.0-dev",
|
||||
"version": "0.16.0-dev",
|
||||
"description": "Tools for WLED project",
|
||||
"main": "tools/cdata.js",
|
||||
"directories": {
|
||||
|
@ -49,7 +49,7 @@ private:
|
||||
|
||||
void setColor(int r, int g, int b)
|
||||
{
|
||||
strip.setColor(0, r, g, b);
|
||||
strip.getMainSegment().setColor(0, RGBW32(r, g, b, 0));
|
||||
stateUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
char msg[18] {};
|
||||
sprintf(msg, "rgb(%d,%d,%d)", r, g, b);
|
||||
|
@ -31,14 +31,14 @@ public:
|
||||
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||
|
||||
//select first two segments (background color + FX settable)
|
||||
WS2812FX::Segment &seg = strip.getSegment(0);
|
||||
Segment &seg = strip.getSegment(0);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
|
||||
strip.getSegment(0).setOption(0, false);
|
||||
strip.getSegment(0).setOption(2, false);
|
||||
//other segments are text
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
WS2812FX::Segment &seg = strip.getSegment(i);
|
||||
Segment &seg = strip.getSegment(i);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
|
||||
strip.getSegment(i).setOption(0, true);
|
||||
strip.setBrightness(64);
|
||||
@ -80,61 +80,61 @@ public:
|
||||
void displayTime(byte hour, byte minute)
|
||||
{
|
||||
bool isToHour = false; //true if minute > 30
|
||||
strip.setSegment(0, 0, 64); // background
|
||||
strip.setSegment(1, 0, 2); //It is
|
||||
strip.getSegment(0).setGeometry(0, 64); // background
|
||||
strip.getSegment(1).setGeometry(0, 2); //It is
|
||||
|
||||
strip.setSegment(2, 0, 0);
|
||||
strip.setSegment(3, 0, 0); //disable minutes
|
||||
strip.setSegment(4, 0, 0); //past
|
||||
strip.setSegment(6, 0, 0); //to
|
||||
strip.setSegment(8, 0, 0); //disable o'clock
|
||||
strip.getSegment(2).setGeometry(0, 0);
|
||||
strip.getSegment(3).setGeometry(0, 0); //disable minutes
|
||||
strip.getSegment(4).setGeometry(0, 0); //past
|
||||
strip.getSegment(6).setGeometry(0, 0); //to
|
||||
strip.getSegment(8).setGeometry(0, 0); //disable o'clock
|
||||
|
||||
if (hour < 24) //valid time, display
|
||||
{
|
||||
if (minute == 30)
|
||||
{
|
||||
strip.setSegment(2, 3, 6); //half
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.getSegment(2).setGeometry(3, 6); //half
|
||||
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||
}
|
||||
else if (minute == 15 || minute == 45)
|
||||
{
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||
}
|
||||
else if (minute == 10)
|
||||
{
|
||||
//strip.setSegment(5, 6, 8); //ten
|
||||
//strip.getSegment(5).setGeometry(6, 8); //ten
|
||||
}
|
||||
else if (minute == 5)
|
||||
{
|
||||
//strip.setSegment(5, 16, 18); //five
|
||||
//strip.getSegment(5).setGeometry(16, 18); //five
|
||||
}
|
||||
else if (minute == 0)
|
||||
{
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||
//hourChime();
|
||||
}
|
||||
else
|
||||
{
|
||||
strip.setSegment(3, 18, 22); //minutes
|
||||
strip.getSegment(3).setGeometry(18, 22); //minutes
|
||||
}
|
||||
|
||||
//past or to?
|
||||
if (minute == 0)
|
||||
{ //full hour
|
||||
strip.setSegment(3, 0, 0); //disable minutes
|
||||
strip.setSegment(4, 0, 0); //disable past
|
||||
strip.setSegment(6, 0, 0); //disable to
|
||||
strip.setSegment(8, 60, 64); //o'clock
|
||||
strip.getSegment(3).setGeometry(0, 0); //disable minutes
|
||||
strip.getSegment(4).setGeometry(0, 0); //disable past
|
||||
strip.getSegment(6).setGeometry(0, 0); //disable to
|
||||
strip.getSegment(8).setGeometry(60, 64); //o'clock
|
||||
}
|
||||
else if (minute > 34)
|
||||
{
|
||||
//strip.setSegment(6, 22, 24); //to
|
||||
//strip.getSegment(6).setGeometry(22, 24); //to
|
||||
//minute = 60 - minute;
|
||||
isToHour = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//strip.setSegment(4, 24, 27); //past
|
||||
//strip.getSegment(4).setGeometry(24, 27); //past
|
||||
//isToHour = false;
|
||||
}
|
||||
}
|
||||
@ -143,68 +143,68 @@ public:
|
||||
|
||||
if (minute <= 4)
|
||||
{
|
||||
strip.setSegment(3, 0, 0); //nothing
|
||||
strip.setSegment(5, 0, 0); //nothing
|
||||
strip.setSegment(6, 0, 0); //nothing
|
||||
strip.setSegment(8, 60, 64); //o'clock
|
||||
strip.getSegment(3).setGeometry(0, 0); //nothing
|
||||
strip.getSegment(5).setGeometry(0, 0); //nothing
|
||||
strip.getSegment(6).setGeometry(0, 0); //nothing
|
||||
strip.getSegment(8).setGeometry(60, 64); //o'clock
|
||||
}
|
||||
else if (minute <= 9)
|
||||
{
|
||||
strip.setSegment(5, 16, 18); // five past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
strip.getSegment(5).setGeometry(16, 18); // five past
|
||||
strip.getSegment(4).setGeometry(24, 27); //past
|
||||
}
|
||||
else if (minute <= 14)
|
||||
{
|
||||
strip.setSegment(5, 6, 8); // ten past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
strip.getSegment(5).setGeometry(6, 8); // ten past
|
||||
strip.getSegment(4).setGeometry(24, 27); //past
|
||||
}
|
||||
else if (minute <= 19)
|
||||
{
|
||||
strip.setSegment(5, 8, 12); // quarter past
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
strip.getSegment(5).setGeometry(8, 12); // quarter past
|
||||
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||
strip.getSegment(4).setGeometry(24, 27); //past
|
||||
}
|
||||
else if (minute <= 24)
|
||||
{
|
||||
strip.setSegment(5, 12, 16); // twenty past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
strip.getSegment(5).setGeometry(12, 16); // twenty past
|
||||
strip.getSegment(4).setGeometry(24, 27); //past
|
||||
}
|
||||
else if (minute <= 29)
|
||||
{
|
||||
strip.setSegment(5, 12, 18); // twenty-five past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
strip.getSegment(5).setGeometry(12, 18); // twenty-five past
|
||||
strip.getSegment(4).setGeometry(24, 27); //past
|
||||
}
|
||||
else if (minute <= 34)
|
||||
{
|
||||
strip.setSegment(5, 3, 6); // half past
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
strip.getSegment(5).setGeometry(3, 6); // half past
|
||||
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||
strip.getSegment(4).setGeometry(24, 27); //past
|
||||
}
|
||||
else if (minute <= 39)
|
||||
{
|
||||
strip.setSegment(5, 12, 18); // twenty-five to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
strip.getSegment(5).setGeometry(12, 18); // twenty-five to
|
||||
strip.getSegment(6).setGeometry(22, 24); //to
|
||||
}
|
||||
else if (minute <= 44)
|
||||
{
|
||||
strip.setSegment(5, 12, 16); // twenty to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
strip.getSegment(5).setGeometry(12, 16); // twenty to
|
||||
strip.getSegment(6).setGeometry(22, 24); //to
|
||||
}
|
||||
else if (minute <= 49)
|
||||
{
|
||||
strip.setSegment(5, 8, 12); // quarter to
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
strip.getSegment(5).setGeometry(8, 12); // quarter to
|
||||
strip.getSegment(3).setGeometry(0, 0); //minutes
|
||||
strip.getSegment(6).setGeometry(22, 24); //to
|
||||
}
|
||||
else if (minute <= 54)
|
||||
{
|
||||
strip.setSegment(5, 6, 8); // ten to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
strip.getSegment(5).setGeometry(6, 8); // ten to
|
||||
strip.getSegment(6).setGeometry(22, 24); //to
|
||||
}
|
||||
else if (minute <= 59)
|
||||
{
|
||||
strip.setSegment(5, 16, 18); // five to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
strip.getSegment(5).setGeometry(16, 18); // five to
|
||||
strip.getSegment(6).setGeometry(22, 24); //to
|
||||
}
|
||||
|
||||
//hours
|
||||
@ -220,45 +220,45 @@ public:
|
||||
switch (hour)
|
||||
{
|
||||
case 1:
|
||||
strip.setSegment(7, 27, 29);
|
||||
strip.getSegment(7).setGeometry(27, 29);
|
||||
break; //one
|
||||
case 2:
|
||||
strip.setSegment(7, 35, 37);
|
||||
strip.getSegment(7).setGeometry(35, 37);
|
||||
break; //two
|
||||
case 3:
|
||||
strip.setSegment(7, 29, 32);
|
||||
strip.getSegment(7).setGeometry(29, 32);
|
||||
break; //three
|
||||
case 4:
|
||||
strip.setSegment(7, 32, 35);
|
||||
strip.getSegment(7).setGeometry(32, 35);
|
||||
break; //four
|
||||
case 5:
|
||||
strip.setSegment(7, 37, 40);
|
||||
strip.getSegment(7).setGeometry(37, 40);
|
||||
break; //five
|
||||
case 6:
|
||||
strip.setSegment(7, 43, 45);
|
||||
strip.getSegment(7).setGeometry(43, 45);
|
||||
break; //six
|
||||
case 7:
|
||||
strip.setSegment(7, 40, 43);
|
||||
strip.getSegment(7).setGeometry(40, 43);
|
||||
break; //seven
|
||||
case 8:
|
||||
strip.setSegment(7, 45, 48);
|
||||
strip.getSegment(7).setGeometry(45, 48);
|
||||
break; //eight
|
||||
case 9:
|
||||
strip.setSegment(7, 48, 50);
|
||||
strip.getSegment(7).setGeometry(48, 50);
|
||||
break; //nine
|
||||
case 10:
|
||||
strip.setSegment(7, 54, 56);
|
||||
strip.getSegment(7).setGeometry(54, 56);
|
||||
break; //ten
|
||||
case 11:
|
||||
strip.setSegment(7, 50, 54);
|
||||
strip.getSegment(7).setGeometry(50, 54);
|
||||
break; //eleven
|
||||
case 12:
|
||||
strip.setSegment(7, 56, 60);
|
||||
strip.getSegment(7).setGeometry(56, 60);
|
||||
break; //twelve
|
||||
}
|
||||
|
||||
selectWordSegments(true);
|
||||
applyMacro(1);
|
||||
applyPreset(1);
|
||||
}
|
||||
|
||||
void timeOfDay()
|
||||
|
@ -1,305 +0,0 @@
|
||||
#include "wled.h"
|
||||
/*
|
||||
* This v1 usermod file allows you to add own functionality to WLED more easily
|
||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
||||
* If you just need 8 bytes, use 2551-2559 (you do not need to increase EEPSIZE)
|
||||
*
|
||||
* Consider the v2 usermod API if you need a more advanced feature set!
|
||||
*/
|
||||
|
||||
|
||||
uint8_t minuteLast = 99;
|
||||
int dayBrightness = 128;
|
||||
int nightBrightness = 16;
|
||||
|
||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
||||
|
||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
||||
void userSetup()
|
||||
{
|
||||
saveMacro(14, "A=128", false);
|
||||
saveMacro(15, "A=64", false);
|
||||
saveMacro(16, "A=16", false);
|
||||
|
||||
saveMacro(1, "&FX=0&R=255&G=255&B=255", false);
|
||||
|
||||
//strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||
|
||||
//select first two segments (background color + FX settable)
|
||||
Segment &seg = strip.getSegment(0);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((0 & 0xFF) << 8) | ((0 & 0xFF)));
|
||||
strip.getSegment(0).setOption(0, false);
|
||||
strip.getSegment(0).setOption(2, false);
|
||||
//other segments are text
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
Segment &seg = strip.getSegment(i);
|
||||
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
|
||||
strip.getSegment(i).setOption(0, true);
|
||||
strip.setBrightness(128);
|
||||
}
|
||||
}
|
||||
|
||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
||||
void userConnected()
|
||||
{
|
||||
}
|
||||
|
||||
void selectWordSegments(bool state)
|
||||
{
|
||||
for (int i = 1; i < 10; i++)
|
||||
{
|
||||
//Segment &seg = strip.getSegment(i);
|
||||
strip.getSegment(i).setOption(0, state);
|
||||
// strip.getSegment(1).setOption(SEG_OPTION_SELECTED, true);
|
||||
//seg.mode = 12;
|
||||
//seg.palette = 1;
|
||||
//strip.setBrightness(255);
|
||||
}
|
||||
strip.getSegment(0).setOption(0, !state);
|
||||
}
|
||||
|
||||
void hourChime()
|
||||
{
|
||||
//strip.resetSegments();
|
||||
selectWordSegments(true);
|
||||
colorUpdated(CALL_MODE_FX_CHANGED);
|
||||
//savePreset(255);
|
||||
selectWordSegments(false);
|
||||
//strip.getSegment(0).setOption(0, true);
|
||||
strip.getSegment(0).setOption(2, true);
|
||||
applyPreset(12);
|
||||
colorUpdated(CALL_MODE_FX_CHANGED);
|
||||
}
|
||||
|
||||
void displayTime(byte hour, byte minute)
|
||||
{
|
||||
bool isToHour = false; //true if minute > 30
|
||||
strip.setSegment(0, 0, 64); // background
|
||||
strip.setSegment(1, 0, 2); //It is
|
||||
|
||||
strip.setSegment(2, 0, 0);
|
||||
strip.setSegment(3, 0, 0); //disable minutes
|
||||
strip.setSegment(4, 0, 0); //past
|
||||
strip.setSegment(6, 0, 0); //to
|
||||
strip.setSegment(8, 0, 0); //disable o'clock
|
||||
|
||||
if (hour < 24) //valid time, display
|
||||
{
|
||||
if (minute == 30)
|
||||
{
|
||||
strip.setSegment(2, 3, 6); //half
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
}
|
||||
else if (minute == 15 || minute == 45)
|
||||
{
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
}
|
||||
else if (minute == 10)
|
||||
{
|
||||
//strip.setSegment(5, 6, 8); //ten
|
||||
}
|
||||
else if (minute == 5)
|
||||
{
|
||||
//strip.setSegment(5, 16, 18); //five
|
||||
}
|
||||
else if (minute == 0)
|
||||
{
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
//hourChime();
|
||||
}
|
||||
else
|
||||
{
|
||||
strip.setSegment(3, 18, 22); //minutes
|
||||
}
|
||||
|
||||
//past or to?
|
||||
if (minute == 0)
|
||||
{ //full hour
|
||||
strip.setSegment(3, 0, 0); //disable minutes
|
||||
strip.setSegment(4, 0, 0); //disable past
|
||||
strip.setSegment(6, 0, 0); //disable to
|
||||
strip.setSegment(8, 60, 64); //o'clock
|
||||
}
|
||||
else if (minute > 34)
|
||||
{
|
||||
//strip.setSegment(6, 22, 24); //to
|
||||
//minute = 60 - minute;
|
||||
isToHour = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//strip.setSegment(4, 24, 27); //past
|
||||
//isToHour = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ //temperature display
|
||||
}
|
||||
|
||||
//byte minuteRem = minute %10;
|
||||
|
||||
if (minute <= 4)
|
||||
{
|
||||
strip.setSegment(3, 0, 0); //nothing
|
||||
strip.setSegment(5, 0, 0); //nothing
|
||||
strip.setSegment(6, 0, 0); //nothing
|
||||
strip.setSegment(8, 60, 64); //o'clock
|
||||
}
|
||||
else if (minute <= 9)
|
||||
{
|
||||
strip.setSegment(5, 16, 18); // five past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
}
|
||||
else if (minute <= 14)
|
||||
{
|
||||
strip.setSegment(5, 6, 8); // ten past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
}
|
||||
else if (minute <= 19)
|
||||
{
|
||||
strip.setSegment(5, 8, 12); // quarter past
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
}
|
||||
else if (minute <= 24)
|
||||
{
|
||||
strip.setSegment(5, 12, 16); // twenty past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
}
|
||||
else if (minute <= 29)
|
||||
{
|
||||
strip.setSegment(5, 12, 18); // twenty-five past
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
}
|
||||
else if (minute <= 34)
|
||||
{
|
||||
strip.setSegment(5, 3, 6); // half past
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.setSegment(4, 24, 27); //past
|
||||
}
|
||||
else if (minute <= 39)
|
||||
{
|
||||
strip.setSegment(5, 12, 18); // twenty-five to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
}
|
||||
else if (minute <= 44)
|
||||
{
|
||||
strip.setSegment(5, 12, 16); // twenty to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
}
|
||||
else if (minute <= 49)
|
||||
{
|
||||
strip.setSegment(5, 8, 12); // quarter to
|
||||
strip.setSegment(3, 0, 0); //minutes
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
}
|
||||
else if (minute <= 54)
|
||||
{
|
||||
strip.setSegment(5, 6, 8); // ten to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
}
|
||||
else if (minute <= 59)
|
||||
{
|
||||
strip.setSegment(5, 16, 18); // five to
|
||||
strip.setSegment(6, 22, 24); //to
|
||||
}
|
||||
|
||||
//hours
|
||||
if (hour > 23)
|
||||
return;
|
||||
if (isToHour)
|
||||
hour++;
|
||||
if (hour > 12)
|
||||
hour -= 12;
|
||||
if (hour == 0)
|
||||
hour = 12;
|
||||
|
||||
switch (hour)
|
||||
{
|
||||
case 1:
|
||||
strip.setSegment(7, 27, 29);
|
||||
break; //one
|
||||
case 2:
|
||||
strip.setSegment(7, 35, 37);
|
||||
break; //two
|
||||
case 3:
|
||||
strip.setSegment(7, 29, 32);
|
||||
break; //three
|
||||
case 4:
|
||||
strip.setSegment(7, 32, 35);
|
||||
break; //four
|
||||
case 5:
|
||||
strip.setSegment(7, 37, 40);
|
||||
break; //five
|
||||
case 6:
|
||||
strip.setSegment(7, 43, 45);
|
||||
break; //six
|
||||
case 7:
|
||||
strip.setSegment(7, 40, 43);
|
||||
break; //seven
|
||||
case 8:
|
||||
strip.setSegment(7, 45, 48);
|
||||
break; //eight
|
||||
case 9:
|
||||
strip.setSegment(7, 48, 50);
|
||||
break; //nine
|
||||
case 10:
|
||||
strip.setSegment(7, 54, 56);
|
||||
break; //ten
|
||||
case 11:
|
||||
strip.setSegment(7, 50, 54);
|
||||
break; //eleven
|
||||
case 12:
|
||||
strip.setSegment(7, 56, 60);
|
||||
break; //twelve
|
||||
}
|
||||
|
||||
selectWordSegments(true);
|
||||
applyMacro(1);
|
||||
}
|
||||
|
||||
void timeOfDay() {
|
||||
// NOT USED: use timed macros instead
|
||||
//Used to set brightness dependant of time of day - lights dimmed at night
|
||||
|
||||
//monday to thursday and sunday
|
||||
|
||||
if ((weekday(localTime) == 6) | (weekday(localTime) == 7)) {
|
||||
if (hour(localTime) > 0 | hour(localTime) < 8) {
|
||||
strip.setBrightness(nightBrightness);
|
||||
}
|
||||
else {
|
||||
strip.setBrightness(dayBrightness);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (hour(localTime) < 6 | hour(localTime) >= 22) {
|
||||
strip.setBrightness(nightBrightness);
|
||||
}
|
||||
else {
|
||||
strip.setBrightness(dayBrightness);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
||||
void userLoop()
|
||||
{
|
||||
if (minute(localTime) != minuteLast)
|
||||
{
|
||||
updateLocalTime();
|
||||
//timeOfDay();
|
||||
minuteLast = minute(localTime);
|
||||
displayTime(hour(localTime), minute(localTime));
|
||||
if (minute(localTime) == 0){
|
||||
hourChime();
|
||||
}
|
||||
if (minute(localTime) == 1){
|
||||
//turn off background segment;
|
||||
strip.getSegment(0).setOption(2, false);
|
||||
//applyPreset(255);
|
||||
}
|
||||
}
|
||||
}
|
1544
wled00/FX.cpp
1544
wled00/FX.cpp
File diff suppressed because it is too large
Load Diff
155
wled00/FX.h
155
wled00/FX.h
@ -16,6 +16,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "const.h"
|
||||
#include "bus_manager.h"
|
||||
|
||||
#define FASTLED_INTERNAL //remove annoying pragma messages
|
||||
#define USE_GET_MILLISECOND_TIMER
|
||||
@ -42,6 +43,9 @@
|
||||
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
||||
#endif
|
||||
|
||||
extern bool realtimeRespectLedMaps; // used in getMappedPixelIndex()
|
||||
extern byte realtimeMode; // used in getMappedPixelIndex()
|
||||
|
||||
/* Not used in all effects yet */
|
||||
#define WLED_FPS 42
|
||||
#define FRAMETIME_FIXED (1000/WLED_FPS)
|
||||
@ -88,11 +92,11 @@
|
||||
#define NUM_COLORS 3 /* number of colors per segment */
|
||||
#define SEGMENT strip._segments[strip.getCurrSegmentId()]
|
||||
#define SEGENV strip._segments[strip.getCurrSegmentId()]
|
||||
//#define SEGCOLOR(x) strip._segments[strip.getCurrSegmentId()].currentColor(x, strip._segments[strip.getCurrSegmentId()].colors[x])
|
||||
//#define SEGLEN strip._segments[strip.getCurrSegmentId()].virtualLength()
|
||||
#define SEGCOLOR(x) strip.segColor(x) /* saves us a few kbytes of code */
|
||||
#define SEGCOLOR(x) Segment::getCurrentColor(x)
|
||||
#define SEGPALETTE Segment::getCurrentPalette()
|
||||
#define SEGLEN strip._virtualSegmentLength /* saves us a few kbytes of code */
|
||||
#define SEGLEN Segment::vLength()
|
||||
#define SEG_W Segment::vWidth()
|
||||
#define SEG_H Segment::vHeight()
|
||||
#define SPEED_FORMULA_L (5U + (50U*(255U - SEGMENT.speed))/SEGLEN)
|
||||
|
||||
// some common colors
|
||||
@ -204,7 +208,7 @@
|
||||
#define FX_MODE_COLORTWINKLE 74
|
||||
#define FX_MODE_LAKE 75
|
||||
#define FX_MODE_METEOR 76
|
||||
#define FX_MODE_METEOR_SMOOTH 77
|
||||
//#define FX_MODE_METEOR_SMOOTH 77 // merged with meteor
|
||||
#define FX_MODE_RAILWAY 78
|
||||
#define FX_MODE_RIPPLE 79
|
||||
#define FX_MODE_TWINKLEFOX 80
|
||||
@ -398,7 +402,7 @@ typedef struct Segment {
|
||||
uint32_t _stepT;
|
||||
uint32_t _callT;
|
||||
uint8_t *_dataT;
|
||||
uint16_t _dataLenT;
|
||||
unsigned _dataLenT;
|
||||
TemporarySegmentData()
|
||||
: _dataT(nullptr) // just in case...
|
||||
, _dataLenT(0)
|
||||
@ -416,10 +420,14 @@ typedef struct Segment {
|
||||
uint8_t _reserved : 4;
|
||||
};
|
||||
};
|
||||
uint16_t _dataLen;
|
||||
static uint16_t _usedSegmentData;
|
||||
|
||||
// perhaps this should be per segment, not static
|
||||
uint8_t _default_palette; // palette number that gets assigned to pal0
|
||||
unsigned _dataLen;
|
||||
static unsigned _usedSegmentData;
|
||||
static uint8_t _segBri; // brightness of segment for current effect
|
||||
static unsigned _vLength; // 1D dimension used for current effect
|
||||
static unsigned _vWidth, _vHeight; // 2D dimensions used for current effect
|
||||
static uint32_t _currentColors[NUM_COLORS]; // colors used for current effect
|
||||
static bool _colorScaled; // color has been scaled prior to setPixelColor() call
|
||||
static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette())
|
||||
static CRGBPalette16 _randomPalette; // actual random palette
|
||||
static CRGBPalette16 _newRandomPalette; // target random palette
|
||||
@ -452,6 +460,8 @@ typedef struct Segment {
|
||||
{}
|
||||
} *_t;
|
||||
|
||||
[[gnu::hot]] void _setPixelColorXY_raw(int& x, int& y, uint32_t& col); // set pixel without mapping (internal use only)
|
||||
|
||||
public:
|
||||
|
||||
Segment(uint16_t sStart=0, uint16_t sStop=30) :
|
||||
@ -484,6 +494,7 @@ typedef struct Segment {
|
||||
aux1(0),
|
||||
data(nullptr),
|
||||
_capabilities(0),
|
||||
_default_palette(0),
|
||||
_dataLen(0),
|
||||
_t(nullptr)
|
||||
{
|
||||
@ -532,23 +543,30 @@ typedef struct Segment {
|
||||
inline uint16_t length() const { return width() * height(); } // segment length (count) in physical pixels
|
||||
inline uint16_t groupLength() const { return grouping + spacing; }
|
||||
inline uint8_t getLightCapabilities() const { return _capabilities; }
|
||||
inline void deactivate() { setGeometry(0,0); }
|
||||
|
||||
inline static uint16_t getUsedSegmentData() { return _usedSegmentData; }
|
||||
inline static void addUsedSegmentData(int len) { _usedSegmentData += len; }
|
||||
inline static unsigned getUsedSegmentData() { return Segment::_usedSegmentData; }
|
||||
inline static void addUsedSegmentData(int len) { Segment::_usedSegmentData += len; }
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
inline static void modeBlend(bool blend) { _modeBlend = blend; }
|
||||
inline static void modeBlend(bool blend) { _modeBlend = blend; }
|
||||
#endif
|
||||
static void handleRandomPalette();
|
||||
inline static unsigned vLength() { return Segment::_vLength; }
|
||||
inline static unsigned vWidth() { return Segment::_vWidth; }
|
||||
inline static unsigned vHeight() { return Segment::_vHeight; }
|
||||
inline static uint32_t getCurrentColor(unsigned i) { return Segment::_currentColors[i]; } // { return i < 3 ? Segment::_currentColors[i] : 0; }
|
||||
inline static const CRGBPalette16 &getCurrentPalette() { return Segment::_currentPalette; }
|
||||
inline static uint8_t getCurrentBrightness() { return Segment::_segBri; }
|
||||
static void handleRandomPalette();
|
||||
|
||||
void setUp(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1);
|
||||
void beginDraw(); // set up parameters for current effect
|
||||
void setGeometry(uint16_t i1, uint16_t i2, uint8_t grp=1, uint8_t spc=0, uint16_t ofs=UINT16_MAX, uint16_t i1Y=0, uint16_t i2Y=1, uint8_t m12=0);
|
||||
Segment &setColor(uint8_t slot, uint32_t c);
|
||||
Segment &setCCT(uint16_t k);
|
||||
Segment &setOpacity(uint8_t o);
|
||||
Segment &setOption(uint8_t n, bool val);
|
||||
Segment &setMode(uint8_t fx, bool loadDefaults = false);
|
||||
Segment &setPalette(uint8_t pal);
|
||||
uint8_t differs(Segment& b) const;
|
||||
uint8_t differs(const Segment& b) const;
|
||||
void refreshLightCapabilities();
|
||||
|
||||
// runtime data functions
|
||||
@ -578,7 +596,6 @@ typedef struct Segment {
|
||||
uint8_t currentMode() const; // currently active effect/mode (while in transition)
|
||||
[[gnu::hot]] uint32_t currentColor(uint8_t slot) const; // currently active segment color (blended while in transition)
|
||||
CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal);
|
||||
void setCurrentPalette();
|
||||
|
||||
// 1D strip
|
||||
[[gnu::hot]] uint16_t virtualLength() const;
|
||||
@ -599,21 +616,19 @@ typedef struct Segment {
|
||||
void fadeToBlackBy(uint8_t fadeBy);
|
||||
inline void blendPixelColor(int n, uint32_t color, uint8_t blend) { setPixelColor(n, color_blend(getPixelColor(n), color, blend)); }
|
||||
inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
inline void addPixelColor(int n, uint32_t color, bool fast = false) { setPixelColor(n, color_add(getPixelColor(n), color, fast)); }
|
||||
inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); }
|
||||
inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); }
|
||||
inline void addPixelColor(int n, uint32_t color, bool preserveCR = true) { setPixelColor(n, color_add(getPixelColor(n), color, preserveCR)); }
|
||||
inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColor(n, RGBW32(r,g,b,w), preserveCR); }
|
||||
inline void addPixelColor(int n, CRGB c, bool preserveCR = true) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), preserveCR); }
|
||||
inline void fadePixelColor(uint16_t n, uint8_t fade) { setPixelColor(n, color_fade(getPixelColor(n), fade, true)); }
|
||||
[[gnu::hot]] uint32_t color_from_palette(uint16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255) const;
|
||||
[[gnu::hot]] uint32_t color_wheel(uint8_t pos) const;
|
||||
|
||||
// 2D Blur: shortcuts for bluring columns or rows only (50% faster than full 2D blur)
|
||||
inline void blurCols(fract8 blur_amount, bool smear = false) { // blur all columns
|
||||
const unsigned cols = virtualWidth();
|
||||
for (unsigned k = 0; k < cols; k++) blurCol(k, blur_amount, smear);
|
||||
blur2D(0, blur_amount, smear);
|
||||
}
|
||||
inline void blurRows(fract8 blur_amount, bool smear = false) { // blur all rows
|
||||
const unsigned rows = virtualHeight();
|
||||
for ( unsigned i = 0; i < rows; i++) blurRow(i, blur_amount, smear);
|
||||
blur2D(blur_amount, 0, smear);
|
||||
}
|
||||
|
||||
// 2D matrix
|
||||
@ -642,31 +657,28 @@ typedef struct Segment {
|
||||
// 2D support functions
|
||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend) { setPixelColorXY(x, y, color_blend(getPixelColorXY(x,y), color, blend)); }
|
||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, fast)); }
|
||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); }
|
||||
inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); }
|
||||
inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); }
|
||||
void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur
|
||||
void blur2D(uint8_t blur_amount, bool smear = false);
|
||||
void blurRow(uint32_t row, fract8 blur_amount, bool smear = false);
|
||||
void blurCol(uint32_t col, fract8 blur_amount, bool smear = false);
|
||||
void moveX(int8_t delta, bool wrap = false);
|
||||
void moveY(int8_t delta, bool wrap = false);
|
||||
void move(uint8_t dir, uint8_t delta, bool wrap = false);
|
||||
inline void addPixelColorXY(int x, int y, uint32_t color, bool preserveCR = true) { setPixelColorXY(x, y, color_add(getPixelColorXY(x,y), color, preserveCR)); }
|
||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(r,g,b,w), preserveCR); }
|
||||
inline void addPixelColorXY(int x, int y, CRGB c, bool preserveCR = true) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), preserveCR); }
|
||||
inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), fade, true)); }
|
||||
//void box_blur(unsigned r = 1U, bool smear = false); // 2D box blur
|
||||
void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false);
|
||||
void moveX(int delta, bool wrap = false);
|
||||
void moveY(int delta, bool wrap = false);
|
||||
void move(unsigned dir, unsigned delta, bool wrap = false);
|
||||
void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
||||
void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false);
|
||||
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); }
|
||||
void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false);
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0);
|
||||
void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0, int8_t rotate = 0, bool usePalGrad = false);
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0)); } // automatic inline
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate); } // automatic inline
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0), rotate, usePalGrad); } // automatic inline
|
||||
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
||||
inline void blur2d(fract8 blur_amount) { blur(blur_amount); }
|
||||
inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); }
|
||||
#else
|
||||
inline uint16_t XY(uint16_t x, uint16_t y) { return x; }
|
||||
inline uint16_t XY(int x, int y) { return x; }
|
||||
inline void setPixelColorXY(int x, int y, uint32_t c) { setPixelColor(x, c); }
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); }
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); }
|
||||
@ -680,16 +692,16 @@ typedef struct Segment {
|
||||
inline uint32_t getPixelColorXY(int x, int y) { return getPixelColor(x); }
|
||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t c, uint8_t blend) { blendPixelColor(x, c, blend); }
|
||||
inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColor(x, RGBW32(c.r,c.g,c.b,0), blend); }
|
||||
inline void addPixelColorXY(int x, int y, uint32_t color, bool fast = false) { addPixelColor(x, color, fast); }
|
||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(x, RGBW32(r,g,b,w), fast); }
|
||||
inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), fast); }
|
||||
inline void addPixelColorXY(int x, int y, uint32_t color, bool saturate = false) { addPixelColor(x, color, saturate); }
|
||||
inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool saturate = false) { addPixelColor(x, RGBW32(r,g,b,w), saturate); }
|
||||
inline void addPixelColorXY(int x, int y, CRGB c, bool saturate = false) { addPixelColor(x, RGBW32(c.r,c.g,c.b,0), saturate); }
|
||||
inline void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) { fadePixelColor(x, fade); }
|
||||
inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {}
|
||||
inline void blur2D(uint8_t blur_amount, bool smear = false) {}
|
||||
inline void blurRow(uint32_t row, fract8 blur_amount, bool smear = false) {}
|
||||
inline void blurCol(uint32_t col, fract8 blur_amount, bool smear = false) {}
|
||||
inline void moveX(int8_t delta, bool wrap = false) {}
|
||||
inline void moveY(int8_t delta, bool wrap = false) {}
|
||||
//inline void box_blur(unsigned i, bool vertical, fract8 blur_amount) {}
|
||||
inline void blur2D(uint8_t blur_x, uint8_t blur_y, bool smear = false) {}
|
||||
inline void blurRow(int row, fract8 blur_amount, bool smear = false) {}
|
||||
inline void blurCol(int col, fract8 blur_amount, bool smear = false) {}
|
||||
inline void moveX(int delta, bool wrap = false) {}
|
||||
inline void moveY(int delta, bool wrap = false) {}
|
||||
inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {}
|
||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {}
|
||||
inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
||||
@ -697,9 +709,9 @@ typedef struct Segment {
|
||||
inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {}
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {}
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0, bool = false) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) {}
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0, bool usePalGrad = false) {}
|
||||
inline void wu_pixel(uint32_t x, uint32_t y, CRGB c) {}
|
||||
#endif
|
||||
} segment;
|
||||
@ -737,9 +749,6 @@ class WS2812FX { // 96 bytes
|
||||
#endif
|
||||
correctWB(false),
|
||||
cctFromRgb(false),
|
||||
// semi-private (just obscured) used in effect functions through macros
|
||||
_colors_t{0,0,0},
|
||||
_virtualSegmentLength(0),
|
||||
// true private variables
|
||||
_suspend(false),
|
||||
_length(DEFAULT_LED_COUNT),
|
||||
@ -787,26 +796,22 @@ class WS2812FX { // 96 bytes
|
||||
#endif
|
||||
finalizeInit(), // initialises strip components
|
||||
service(), // executes effect functions when due and calls strip.show()
|
||||
setMode(uint8_t segid, uint8_t m), // sets effect/mode for given segment (high level API)
|
||||
setColor(uint8_t slot, uint32_t c), // sets color (in slot) for given segment (high level API)
|
||||
setCCT(uint16_t k), // sets global CCT (either in relative 0-255 value or in K)
|
||||
setBrightness(uint8_t b, bool direct = false), // sets strip brightness
|
||||
setRange(uint16_t i, uint16_t i2, uint32_t col), // used for clock overlay
|
||||
purgeSegments(), // removes inactive segments from RAM (may incure penalty and memory fragmentation but reduces vector footprint)
|
||||
setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 1, uint8_t spacing = 0, uint16_t offset = UINT16_MAX, uint16_t startY=0, uint16_t stopY=1),
|
||||
setMainSegmentId(uint8_t n),
|
||||
setMainSegmentId(unsigned n = 0),
|
||||
resetSegments(), // marks all segments for reset
|
||||
makeAutoSegments(bool forceReset = false), // will create segments based on configured outputs
|
||||
fixInvalidSegments(), // fixes incorrect segment configuration
|
||||
setPixelColor(unsigned n, uint32_t c), // paints absolute strip pixel with index n and color c
|
||||
show(), // initiates LED output
|
||||
setTargetFps(uint8_t fps),
|
||||
setTargetFps(unsigned fps),
|
||||
setupEffectData(); // add default effects to the list; defined in FX.cpp
|
||||
|
||||
inline void resetTimebase() { timebase = 0UL - millis(); }
|
||||
inline void restartRuntime() { for (Segment &seg : _segments) { seg.markForReset().resetIfRequired(); } }
|
||||
inline void setTransitionMode(bool t) { for (Segment &seg : _segments) seg.startTransition(t ? _transitionDur : 0); }
|
||||
inline void setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setColor(slot, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColor(unsigned n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColor(unsigned n, CRGB c) { setPixelColor(n, c.red, c.green, c.blue); }
|
||||
inline void fill(uint32_t c) { for (unsigned i = 0; i < getLengthTotal(); i++) setPixelColor(i, c); } // fill whole strip with color (inline)
|
||||
@ -822,9 +827,9 @@ class WS2812FX { // 96 bytes
|
||||
checkSegmentAlignment(),
|
||||
hasRGBWBus() const,
|
||||
hasCCTBus() const,
|
||||
isUpdating() const, // return true if the strip is being sent pixel updates
|
||||
deserializeMap(uint8_t n=0);
|
||||
deserializeMap(unsigned n = 0);
|
||||
|
||||
inline bool isUpdating() const { return !BusManager::canAllShow(); } // return true if the strip is being sent pixel updates
|
||||
inline bool isServicing() const { return _isServicing; } // returns true if strip.service() is executing
|
||||
inline bool hasWhiteChannel() const { return _hasWhiteChannel; } // returns true if strip contains separate white chanel
|
||||
inline bool isOffRefreshRequired() const { return _isOffRefreshRequired; } // returns true if strip requires regular updates (i.e. TM1814 chipset)
|
||||
@ -841,7 +846,7 @@ class WS2812FX { // 96 bytes
|
||||
addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name); // add effect to the list; defined in FX.cpp;
|
||||
|
||||
inline uint8_t getBrightness() const { return _brightness; } // returns current strip brightness
|
||||
inline uint8_t getMaxSegments() const { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline static constexpr unsigned getMaxSegments() { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline uint8_t getSegmentsNum() const { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId() const { return _segment_index; } // returns current segment index (only valid while strip.isServicing())
|
||||
inline uint8_t getMainSegmentId() const { return _mainSegment; } // returns main segment index
|
||||
@ -851,28 +856,27 @@ class WS2812FX { // 96 bytes
|
||||
|
||||
uint16_t
|
||||
getLengthPhysical() const,
|
||||
getLengthTotal() const, // will include virtual/nonexistent pixels in matrix
|
||||
getFps() const,
|
||||
getMappedPixelIndex(uint16_t index) const;
|
||||
getLengthTotal() const; // will include virtual/nonexistent pixels in matrix
|
||||
|
||||
inline uint16_t getFps() const { return (millis() - _lastShow > 2000) ? 0 : (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; } // Returns the refresh rate of the LED strip (_cumulativeFps is stored in fixed point)
|
||||
inline uint16_t getFrameTime() const { return _frametime; } // returns amount of time a frame should take (in ms)
|
||||
inline uint16_t getMinShowDelay() const { return MIN_FRAME_DELAY; } // returns minimum amount of time strip.service() can be delayed (constant)
|
||||
inline uint16_t getLength() const { return _length; } // returns actual amount of LEDs on a strip (2D matrix may have less LEDs than W*H)
|
||||
inline uint16_t getTransition() const { return _transitionDur; } // returns currently set transition time (in ms)
|
||||
inline uint16_t getMappedPixelIndex(uint16_t index) const { // convert logical address to physical
|
||||
if (index < customMappingSize && (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index];
|
||||
return index;
|
||||
};
|
||||
|
||||
unsigned long now, timebase;
|
||||
uint32_t getPixelColor(unsigned) const;
|
||||
|
||||
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||
inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; } // returns currently valid color (for slot i) AKA SEGCOLOR(); may be blended between two colors while in transition
|
||||
inline uint32_t getLastShow() const { return _lastShow; } // returns millis() timestamp of last strip.show() call
|
||||
|
||||
const char *
|
||||
getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||
const char *getModeData(unsigned id = 0) const { return (id && id < _modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||
inline const char **getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data
|
||||
|
||||
const char **
|
||||
getModeDataSrc() { return &(_modeData[0]); } // vectors use arrays for underlying data
|
||||
|
||||
Segment& getSegment(uint8_t id);
|
||||
Segment& getSegment(unsigned id);
|
||||
inline Segment& getFirstSelectedSeg() { return _segments[getFirstSelectedSegId()]; } // returns reference to first segment that is "selected"
|
||||
inline Segment& getMainSegment() { return _segments[getMainSegmentId()]; } // returns reference to main segment
|
||||
inline Segment* getSegments() { return &(_segments[0]); } // returns pointer to segment vector structure (warning: use carefully)
|
||||
@ -931,11 +935,6 @@ class WS2812FX { // 96 bytes
|
||||
bool cctFromRgb : 1;
|
||||
};
|
||||
|
||||
// using public variables to reduce code size increase due to inline function getSegment() (with bounds checking)
|
||||
// and color transitions
|
||||
uint32_t _colors_t[3]; // color used for effect (includes transition)
|
||||
uint16_t _virtualSegmentLength;
|
||||
|
||||
std::vector<segment> _segments;
|
||||
friend class Segment;
|
||||
|
||||
|
@ -148,57 +148,68 @@ void WS2812FX::setUpMatrix() {
|
||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||
uint16_t IRAM_ATTR_YN Segment::XY(int x, int y)
|
||||
{
|
||||
unsigned width = virtualWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
unsigned height = virtualHeight(); // segment height in logical pixels (is always >= 1)
|
||||
return isActive() ? (x%width) + (y%height) * width : 0;
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
return isActive() ? (x%vW) + (y%vH) * vW : 0;
|
||||
}
|
||||
|
||||
// raw setColor function without checks (checks are done in setPixelColorXY())
|
||||
void IRAM_ATTR_YN Segment::_setPixelColorXY_raw(int& x, int& y, uint32_t& col)
|
||||
{
|
||||
const int baseX = start + x;
|
||||
const int baseY = startY + y;
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
// if blending modes, blend with underlying pixel
|
||||
if (_modeBlend) col = color_blend16(strip.getPixelColorXY(baseX, baseY), col, 0xFFFFU - progress());
|
||||
#endif
|
||||
strip.setPixelColorXY(baseX, baseY, col);
|
||||
|
||||
// Apply mirroring
|
||||
if (mirror || mirror_y) {
|
||||
auto setMirroredPixel = [&](int mx, int my) {
|
||||
strip.setPixelColorXY(mx, my, col);
|
||||
};
|
||||
|
||||
const int mirrorX = start + width() - x - 1;
|
||||
const int mirrorY = startY + height() - y - 1;
|
||||
|
||||
if (mirror) setMirroredPixel(transpose ? baseX : mirrorX, transpose ? mirrorY : baseY);
|
||||
if (mirror_y) setMirroredPixel(transpose ? mirrorX : baseX, transpose ? baseY : mirrorY);
|
||||
if (mirror && mirror_y) setMirroredPixel(mirrorX, mirrorY);
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col)
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
|
||||
uint8_t _bri_t = currentBri();
|
||||
if (_bri_t < 255) {
|
||||
col = color_fade(col, _bri_t);
|
||||
}
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
// negative values of x & y cast into unsigend will become very large values and will therefore be greater than vW/vH
|
||||
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return; // if pixel would fall out of virtual segment just exit
|
||||
|
||||
if (reverse ) x = virtualWidth() - x - 1;
|
||||
if (reverse_y) y = virtualHeight() - y - 1;
|
||||
// if color is unscaled
|
||||
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||
|
||||
if (reverse ) x = vW - x - 1;
|
||||
if (reverse_y) y = vH - y - 1;
|
||||
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
||||
unsigned groupLen = groupLength();
|
||||
|
||||
x *= groupLength(); // expand to physical pixels
|
||||
y *= groupLength(); // expand to physical pixels
|
||||
|
||||
int W = width();
|
||||
int H = height();
|
||||
if (x >= W || y >= H) return; // if pixel would fall out of segment just exit
|
||||
|
||||
uint32_t tmpCol = col;
|
||||
for (int j = 0; j < grouping; j++) { // groupping vertically
|
||||
for (int g = 0; g < grouping; g++) { // groupping horizontally
|
||||
int xX = (x+g), yY = (y+j);
|
||||
if (xX >= W || yY >= H) continue; // we have reached one dimension's end
|
||||
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
// if blending modes, blend with underlying pixel
|
||||
if (_modeBlend) tmpCol = color_blend(strip.getPixelColorXY(start + xX, startY + yY), col, 0xFFFFU - progress(), true);
|
||||
#endif
|
||||
|
||||
strip.setPixelColorXY(start + xX, startY + yY, tmpCol);
|
||||
|
||||
if (mirror) { //set the corresponding horizontally mirrored pixel
|
||||
if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
||||
else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
||||
}
|
||||
if (mirror_y) { //set the corresponding vertically mirrored pixel
|
||||
if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, tmpCol);
|
||||
else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, tmpCol);
|
||||
}
|
||||
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
|
||||
strip.setPixelColorXY(start + width() - xX - 1, startY + height() - yY - 1, tmpCol);
|
||||
if (groupLen > 1) {
|
||||
int W = width();
|
||||
int H = height();
|
||||
x *= groupLen; // expand to physical pixels
|
||||
y *= groupLen; // expand to physical pixels
|
||||
const int maxY = std::min(y + grouping, H);
|
||||
const int maxX = std::min(x + grouping, W);
|
||||
for (int yY = y; yY < maxY; yY++) {
|
||||
for (int xX = x; xX < maxX; xX++) {
|
||||
_setPixelColorXY_raw(xX, yY, col);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_setPixelColorXY_raw(x, y, col);
|
||||
}
|
||||
}
|
||||
|
||||
@ -209,11 +220,8 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
||||
if (!isActive()) return; // not active
|
||||
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
|
||||
float fX = x * (cols-1);
|
||||
float fY = y * (rows-1);
|
||||
float fX = x * (vWidth()-1);
|
||||
float fY = y * (vHeight()-1);
|
||||
if (aa) {
|
||||
unsigned xL = roundf(fX-0.49f);
|
||||
unsigned xR = roundf(fX+0.49f);
|
||||
@ -251,9 +259,11 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa)
|
||||
// returns RGBW values of pixel
|
||||
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
||||
if (!isActive()) return 0; // not active
|
||||
if ((unsigned)x >= virtualWidth() || (unsigned)y >= virtualHeight() || x<0 || y<0) return 0; // if pixel would fall out of virtual segment just exit
|
||||
if (reverse ) x = virtualWidth() - x - 1;
|
||||
if (reverse_y) y = virtualHeight() - y - 1;
|
||||
const int vW = vWidth();
|
||||
const int vH = vHeight();
|
||||
if (unsigned(x) >= unsigned(vW) || unsigned(y) >= unsigned(vH)) return 0; // if pixel would fall out of virtual segment just exit
|
||||
if (reverse ) x = vW - x - 1;
|
||||
if (reverse_y) y = vH - y - 1;
|
||||
if (transpose) { std::swap(x,y); } // swap X & Y if segment transposed
|
||||
x *= groupLength(); // expand to physical pixels
|
||||
y *= groupLength(); // expand to physical pixels
|
||||
@ -261,128 +271,69 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
||||
return strip.getPixelColorXY(start + x, startY + y);
|
||||
}
|
||||
|
||||
// blurRow: perform a blur on a row of a rectangular matrix
|
||||
void Segment::blurRow(uint32_t row, fract8 blur_amount, bool smear){
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
|
||||
if (row >= rows) return;
|
||||
// blur one row
|
||||
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
uint32_t carryover = BLACK;
|
||||
// 2D blurring, can be asymmetrical
|
||||
void Segment::blur2D(uint8_t blur_x, uint8_t blur_y, bool smear) {
|
||||
if (!isActive()) return; // not active
|
||||
const unsigned cols = vWidth();
|
||||
const unsigned rows = vHeight();
|
||||
uint32_t lastnew;
|
||||
uint32_t last;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned x = 0; x < cols; x++) {
|
||||
uint32_t cur = getPixelColorXY(x, row);
|
||||
uint32_t part = color_fade(cur, seep);
|
||||
curnew = color_fade(cur, keep);
|
||||
if (x > 0) {
|
||||
if (carryover)
|
||||
curnew = color_add(curnew, carryover, true);
|
||||
uint32_t prev = color_add(lastnew, part, true);
|
||||
if (last != prev) // optimization: only set pixel if color has changed
|
||||
setPixelColorXY(x - 1, row, prev);
|
||||
} else // first pixel
|
||||
setPixelColorXY(x, row, curnew);
|
||||
lastnew = curnew;
|
||||
last = cur; // save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
}
|
||||
setPixelColorXY(cols-1, row, curnew); // set last pixel
|
||||
}
|
||||
|
||||
// blurCol: perform a blur on a column of a rectangular matrix
|
||||
void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) {
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
|
||||
if (col >= cols) return;
|
||||
// blur one column
|
||||
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t lastnew;
|
||||
uint32_t last;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned y = 0; y < rows; y++) {
|
||||
uint32_t cur = getPixelColorXY(col, y);
|
||||
uint32_t part = color_fade(cur, seep);
|
||||
curnew = color_fade(cur, keep);
|
||||
if (y > 0) {
|
||||
if (carryover)
|
||||
curnew = color_add(curnew, carryover, true);
|
||||
uint32_t prev = color_add(lastnew, part, true);
|
||||
if (last != prev) // optimization: only set pixel if color has changed
|
||||
setPixelColorXY(col, y - 1, prev);
|
||||
} else // first pixel
|
||||
setPixelColorXY(col, y, curnew);
|
||||
lastnew = curnew;
|
||||
last = cur; //save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
}
|
||||
setPixelColorXY(col, rows - 1, curnew);
|
||||
}
|
||||
|
||||
void Segment::blur2D(uint8_t blur_amount, bool smear) {
|
||||
if (!isActive() || blur_amount == 0) return; // not active
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
|
||||
const uint8_t keep = smear ? 255 : 255 - blur_amount;
|
||||
const uint8_t seep = blur_amount >> (1 + smear);
|
||||
uint32_t lastnew;
|
||||
uint32_t last;
|
||||
for (unsigned row = 0; row < rows; row++) {
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned x = 0; x < cols; x++) {
|
||||
uint32_t cur = getPixelColorXY(x, row);
|
||||
uint32_t part = color_fade(cur, seep);
|
||||
curnew = color_fade(cur, keep);
|
||||
if (x > 0) {
|
||||
if (carryover) curnew = color_add(curnew, carryover, true);
|
||||
uint32_t prev = color_add(lastnew, part, true);
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColorXY(x - 1, row, prev);
|
||||
} else setPixelColorXY(x, row, curnew); // first pixel
|
||||
lastnew = curnew;
|
||||
last = cur; // save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
if (blur_x) {
|
||||
const uint8_t keepx = smear ? 255 : 255 - blur_x;
|
||||
const uint8_t seepx = blur_x >> 1;
|
||||
for (unsigned row = 0; row < rows; row++) { // blur rows (x direction)
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned x = 0; x < cols; x++) {
|
||||
uint32_t cur = getPixelColorXY(x, row);
|
||||
uint32_t part = color_fade(cur, seepx);
|
||||
curnew = color_fade(cur, keepx);
|
||||
if (x > 0) {
|
||||
if (carryover) curnew = color_add(curnew, carryover);
|
||||
uint32_t prev = color_add(lastnew, part);
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColorXY(x - 1, row, prev);
|
||||
} else setPixelColorXY(x, row, curnew); // first pixel
|
||||
lastnew = curnew;
|
||||
last = cur; // save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
}
|
||||
setPixelColorXY(cols-1, row, curnew); // set last pixel
|
||||
}
|
||||
setPixelColorXY(cols-1, row, curnew); // set last pixel
|
||||
}
|
||||
for (unsigned col = 0; col < cols; col++) {
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned y = 0; y < rows; y++) {
|
||||
uint32_t cur = getPixelColorXY(col, y);
|
||||
uint32_t part = color_fade(cur, seep);
|
||||
curnew = color_fade(cur, keep);
|
||||
if (y > 0) {
|
||||
if (carryover) curnew = color_add(curnew, carryover, true);
|
||||
uint32_t prev = color_add(lastnew, part, true);
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColorXY(col, y - 1, prev);
|
||||
} else setPixelColorXY(col, y, curnew); // first pixel
|
||||
lastnew = curnew;
|
||||
last = cur; //save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
if (blur_y) {
|
||||
const uint8_t keepy = smear ? 255 : 255 - blur_y;
|
||||
const uint8_t seepy = blur_y >> 1;
|
||||
for (unsigned col = 0; col < cols; col++) {
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t curnew = BLACK;
|
||||
for (unsigned y = 0; y < rows; y++) {
|
||||
uint32_t cur = getPixelColorXY(col, y);
|
||||
uint32_t part = color_fade(cur, seepy);
|
||||
curnew = color_fade(cur, keepy);
|
||||
if (y > 0) {
|
||||
if (carryover) curnew = color_add(curnew, carryover);
|
||||
uint32_t prev = color_add(lastnew, part);
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColorXY(col, y - 1, prev);
|
||||
} else setPixelColorXY(col, y, curnew); // first pixel
|
||||
lastnew = curnew;
|
||||
last = cur; //save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
}
|
||||
setPixelColorXY(col, rows - 1, curnew);
|
||||
}
|
||||
setPixelColorXY(col, rows - 1, curnew);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// 2D Box blur
|
||||
void Segment::box_blur(unsigned radius, bool smear) {
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
if (radius > 3) radius = 3;
|
||||
const unsigned d = (1 + 2*radius) * (1 + 2*radius); // averaging divisor
|
||||
const unsigned cols = virtualWidth();
|
||||
const unsigned rows = virtualHeight();
|
||||
const unsigned cols = vWidth();
|
||||
const unsigned rows = vHeight();
|
||||
uint16_t *tmpRSum = new uint16_t[cols*rows];
|
||||
uint16_t *tmpGSum = new uint16_t[cols*rows];
|
||||
uint16_t *tmpBSum = new uint16_t[cols*rows];
|
||||
@ -448,40 +399,56 @@ void Segment::box_blur(unsigned radius, bool smear) {
|
||||
delete[] tmpBSum;
|
||||
delete[] tmpWSum;
|
||||
}
|
||||
|
||||
void Segment::moveX(int8_t delta, bool wrap) {
|
||||
if (!isActive()) return; // not active
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
if (!delta || abs(delta) >= cols) return;
|
||||
uint32_t newPxCol[cols];
|
||||
for (int y = 0; y < rows; y++) {
|
||||
if (delta > 0) {
|
||||
for (int x = 0; x < cols-delta; x++) newPxCol[x] = getPixelColorXY((x + delta), y);
|
||||
for (int x = cols-delta; x < cols; x++) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) - cols : x, y);
|
||||
} else {
|
||||
for (int x = cols-1; x >= -delta; x--) newPxCol[x] = getPixelColorXY((x + delta), y);
|
||||
for (int x = -delta-1; x >= 0; x--) newPxCol[x] = getPixelColorXY(wrap ? (x + delta) + cols : x, y);
|
||||
*/
|
||||
void Segment::moveX(int delta, bool wrap) {
|
||||
if (!isActive() || !delta) return; // not active
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
int absDelta = abs(delta);
|
||||
if (absDelta >= vW) return;
|
||||
uint32_t newPxCol[vW];
|
||||
int newDelta;
|
||||
int stop = vW;
|
||||
int start = 0;
|
||||
if (wrap) newDelta = (delta + vW) % vW; // +cols in case delta < 0
|
||||
else {
|
||||
if (delta < 0) start = absDelta;
|
||||
stop = vW - absDelta;
|
||||
newDelta = delta > 0 ? delta : 0;
|
||||
}
|
||||
for (int y = 0; y < vH; y++) {
|
||||
for (int x = 0; x < stop; x++) {
|
||||
int srcX = x + newDelta;
|
||||
if (wrap) srcX %= vW; // Wrap using modulo when `wrap` is true
|
||||
newPxCol[x] = getPixelColorXY(srcX, y);
|
||||
}
|
||||
for (int x = 0; x < cols; x++) setPixelColorXY(x, y, newPxCol[x]);
|
||||
for (int x = 0; x < stop; x++) setPixelColorXY(x + start, y, newPxCol[x]);
|
||||
}
|
||||
}
|
||||
|
||||
void Segment::moveY(int8_t delta, bool wrap) {
|
||||
if (!isActive()) return; // not active
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
if (!delta || abs(delta) >= rows) return;
|
||||
uint32_t newPxCol[rows];
|
||||
for (int x = 0; x < cols; x++) {
|
||||
if (delta > 0) {
|
||||
for (int y = 0; y < rows-delta; y++) newPxCol[y] = getPixelColorXY(x, (y + delta));
|
||||
for (int y = rows-delta; y < rows; y++) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) - rows : y);
|
||||
} else {
|
||||
for (int y = rows-1; y >= -delta; y--) newPxCol[y] = getPixelColorXY(x, (y + delta));
|
||||
for (int y = -delta-1; y >= 0; y--) newPxCol[y] = getPixelColorXY(x, wrap ? (y + delta) + rows : y);
|
||||
void Segment::moveY(int delta, bool wrap) {
|
||||
if (!isActive() || !delta) return; // not active
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
int absDelta = abs(delta);
|
||||
if (absDelta >= vH) return;
|
||||
uint32_t newPxCol[vH];
|
||||
int newDelta;
|
||||
int stop = vH;
|
||||
int start = 0;
|
||||
if (wrap) newDelta = (delta + vH) % vH; // +rows in case delta < 0
|
||||
else {
|
||||
if (delta < 0) start = absDelta;
|
||||
stop = vH - absDelta;
|
||||
newDelta = delta > 0 ? delta : 0;
|
||||
}
|
||||
for (int x = 0; x < vW; x++) {
|
||||
for (int y = 0; y < stop; y++) {
|
||||
int srcY = y + newDelta;
|
||||
if (wrap) srcY %= vH; // Wrap using modulo when `wrap` is true
|
||||
newPxCol[y] = getPixelColorXY(x, srcY);
|
||||
}
|
||||
for (int y = 0; y < rows; y++) setPixelColorXY(x, y, newPxCol[y]);
|
||||
for (int y = 0; y < stop; y++) setPixelColorXY(x, y + start, newPxCol[y]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,7 +456,7 @@ void Segment::moveY(int8_t delta, bool wrap) {
|
||||
// @param dir direction: 0=left, 1=left-up, 2=up, 3=right-up, 4=right, 5=right-down, 6=down, 7=left-down
|
||||
// @param delta number of pixels to move
|
||||
// @param wrap around
|
||||
void Segment::move(uint8_t dir, uint8_t delta, bool wrap) {
|
||||
void Segment::move(unsigned dir, unsigned delta, bool wrap) {
|
||||
if (delta==0) return;
|
||||
switch (dir) {
|
||||
case 0: moveX( delta, wrap); break;
|
||||
@ -507,46 +474,49 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
if (soft) {
|
||||
// Xiaolin Wu’s algorithm
|
||||
int rsq = radius*radius;
|
||||
const int rsq = radius*radius;
|
||||
int x = 0;
|
||||
int y = radius;
|
||||
unsigned oldFade = 0;
|
||||
while (x < y) {
|
||||
float yf = sqrtf(float(rsq - x*x)); // needs to be floating point
|
||||
unsigned fade = float(0xFFFF) * (ceilf(yf) - yf); // how much color to keep
|
||||
uint8_t fade = float(0xFF) * (ceilf(yf) - yf); // how much color to keep
|
||||
if (oldFade > fade) y--;
|
||||
oldFade = fade;
|
||||
setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade, true));
|
||||
setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade, true));
|
||||
setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade, true));
|
||||
setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade, true));
|
||||
setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade, true));
|
||||
setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade, true));
|
||||
setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade, true));
|
||||
setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade, true));
|
||||
setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade, true));
|
||||
setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade, true));
|
||||
setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade, true));
|
||||
setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade, true));
|
||||
setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade, true));
|
||||
setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade, true));
|
||||
setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade, true));
|
||||
setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade, true));
|
||||
int px, py;
|
||||
for (uint8_t i = 0; i < 16; i++) {
|
||||
int swaps = (i & 0x4 ? 1 : 0); // 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1
|
||||
int adj = (i < 8) ? 0 : 1; // 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
int dx = (i & 1) ? -1 : 1; // 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1
|
||||
int dy = (i & 2) ? -1 : 1; // 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, -1
|
||||
if (swaps) {
|
||||
px = cx + (y - adj) * dx;
|
||||
py = cy + x * dy;
|
||||
} else {
|
||||
px = cx + x * dx;
|
||||
py = cy + (y - adj) * dy;
|
||||
}
|
||||
uint32_t pixCol = getPixelColorXY(px, py);
|
||||
setPixelColorXY(px, py, adj ?
|
||||
color_blend(pixCol, col, fade) :
|
||||
color_blend(col, pixCol, fade));
|
||||
}
|
||||
x++;
|
||||
}
|
||||
} else {
|
||||
// pre-scale color for all pixels
|
||||
col = color_fade(col, _segBri);
|
||||
_colorScaled = true;
|
||||
// Bresenham’s Algorithm
|
||||
int d = 3 - (2*radius);
|
||||
int y = radius, x = 0;
|
||||
while (y >= x) {
|
||||
setPixelColorXY(cx+x, cy+y, col);
|
||||
setPixelColorXY(cx-x, cy+y, col);
|
||||
setPixelColorXY(cx+x, cy-y, col);
|
||||
setPixelColorXY(cx-x, cy-y, col);
|
||||
setPixelColorXY(cx+y, cy+x, col);
|
||||
setPixelColorXY(cx-y, cy+x, col);
|
||||
setPixelColorXY(cx+y, cy-x, col);
|
||||
setPixelColorXY(cx-y, cy-x, col);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int dx = (i & 1) ? -x : x;
|
||||
int dy = (i & 2) ? -y : y;
|
||||
setPixelColorXY(cx + dx, cy + dy, col);
|
||||
setPixelColorXY(cx + dy, cy + dx, col);
|
||||
}
|
||||
x++;
|
||||
if (d > 0) {
|
||||
y--;
|
||||
@ -555,33 +525,38 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
|
||||
d += 4 * x + 6;
|
||||
}
|
||||
}
|
||||
_colorScaled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs
|
||||
void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) {
|
||||
if (!isActive() || radius == 0) return; // not active
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
// draw soft bounding circle
|
||||
if (soft) drawCircle(cx, cy, radius, col, soft);
|
||||
// pre-scale color for all pixels
|
||||
col = color_fade(col, _segBri);
|
||||
_colorScaled = true;
|
||||
// fill it
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
if (x * x + y * y <= radius * radius &&
|
||||
int(cx)+x>=0 && int(cy)+y>=0 &&
|
||||
int(cx)+x<cols && int(cy)+y<rows)
|
||||
int(cx)+x >= 0 && int(cy)+y >= 0 &&
|
||||
int(cx)+x < vW && int(cy)+y < vH)
|
||||
setPixelColorXY(cx + x, cy + y, col);
|
||||
}
|
||||
}
|
||||
_colorScaled = false;
|
||||
}
|
||||
|
||||
//line function
|
||||
void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft) {
|
||||
if (!isActive()) return; // not active
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
if (x0 >= cols || x1 >= cols || y0 >= rows || y1 >= rows) return;
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
if (x0 >= vW || x1 >= vW || y0 >= vH || y1 >= vH) return;
|
||||
|
||||
const int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1; // x distance & step
|
||||
const int dy = abs(y1-y0), sy = y0<y1 ? 1 : -1; // y distance & step
|
||||
@ -608,17 +583,20 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0);
|
||||
float intersectY = y0;
|
||||
for (int x = x0; x <= x1; x++) {
|
||||
unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep
|
||||
unsigned seep = 0xFFFF - keep; // how much background to keep
|
||||
uint8_t keep = float(0xFF) * (intersectY-int(intersectY)); // how much color to keep
|
||||
uint8_t seep = 0xFF - keep; // how much background to keep
|
||||
int y = int(intersectY);
|
||||
if (steep) std::swap(x,y); // temporaryly swap if steep
|
||||
// pixel coverage is determined by fractional part of y co-ordinate
|
||||
setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true));
|
||||
setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true));
|
||||
setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep));
|
||||
setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep));
|
||||
intersectY += gradient;
|
||||
if (steep) std::swap(x,y); // restore if steep
|
||||
}
|
||||
} else {
|
||||
// pre-scale color for all pixels
|
||||
c = color_fade(c, _segBri);
|
||||
_colorScaled = true;
|
||||
// Bresenham's algorithm
|
||||
int err = (dx>dy ? dx : -dy)/2; // error direction
|
||||
for (;;) {
|
||||
@ -628,6 +606,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||
if (e2 < dy) { err += dx; y0 += sy; }
|
||||
}
|
||||
_colorScaled = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -639,16 +618,15 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
|
||||
// draws a raster font character on canvas
|
||||
// only supports: 4x6=24, 5x8=40, 5x12=60, 6x8=48 and 7x9=63 fonts ATM
|
||||
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, int8_t rotate) {
|
||||
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, int8_t rotate, bool usePalGrad) {
|
||||
if (!isActive()) return; // not active
|
||||
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
|
||||
chr -= 32; // align with font table entries
|
||||
const int cols = virtualWidth();
|
||||
const int rows = virtualHeight();
|
||||
const int font = w*h;
|
||||
|
||||
CRGB col = CRGB(color);
|
||||
CRGBPalette16 grad = CRGBPalette16(col, col2 ? CRGB(col2) : col);
|
||||
if(usePalGrad) grad = SEGPALETTE; // selected palette as gradient
|
||||
|
||||
//if (w<5 || w>6 || h!=8) return;
|
||||
for (int i = 0; i<h; i++) { // character height
|
||||
@ -661,7 +639,10 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font
|
||||
default: return;
|
||||
}
|
||||
col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
|
||||
uint32_t c = ColorFromPaletteWLED(grad, (i+1)*255/h, 255, NOBLEND);
|
||||
// pre-scale color for all pixels
|
||||
c = color_fade(c, _segBri);
|
||||
_colorScaled = true;
|
||||
for (int j = 0; j<w; j++) { // character width
|
||||
int x0, y0;
|
||||
switch (rotate) {
|
||||
@ -671,11 +652,12 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
case 1: x0 = x + i; y0 = y + j; break; // +90 deg
|
||||
default: x0 = x + (w-1) - j; y0 = y + i; break; // no rotation
|
||||
}
|
||||
if (x0 < 0 || x0 >= cols || y0 < 0 || y0 >= rows) continue; // drawing off-screen
|
||||
if (x0 < 0 || x0 >= (int)vWidth() || y0 < 0 || y0 >= (int)vHeight()) continue; // drawing off-screen
|
||||
if (((bits>>(j+(8-w))) & 0x01)) { // bit set
|
||||
setPixelColorXY(x0, y0, col);
|
||||
setPixelColorXY(x0, y0, c);
|
||||
}
|
||||
}
|
||||
_colorScaled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,10 +66,15 @@ static constexpr bool validatePinsAndTypes(const unsigned* types, unsigned numTy
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Segment class implementation
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
|
||||
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
|
||||
uint16_t Segment::maxHeight = 1;
|
||||
|
||||
unsigned Segment::_usedSegmentData = 0U; // amount of RAM all segments use for their data[]
|
||||
uint16_t Segment::maxWidth = DEFAULT_LED_COUNT;
|
||||
uint16_t Segment::maxHeight = 1;
|
||||
unsigned Segment::_vLength = 0;
|
||||
unsigned Segment::_vWidth = 0;
|
||||
unsigned Segment::_vHeight = 0;
|
||||
uint8_t Segment::_segBri = 0;
|
||||
uint32_t Segment::_currentColors[NUM_COLORS] = {0,0,0};
|
||||
bool Segment::_colorScaled = false;
|
||||
CRGBPalette16 Segment::_currentPalette = CRGBPalette16(CRGB::Black);
|
||||
CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
|
||||
CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR);
|
||||
@ -196,19 +201,7 @@ CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {
|
||||
if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0;
|
||||
if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // TODO remove strip dependency by moving customPalettes out of strip
|
||||
//default palette. Differs depending on effect
|
||||
if (pal == 0) switch (mode) {
|
||||
case FX_MODE_FIRE_2012 : pal = 35; break; // heat palette
|
||||
case FX_MODE_COLORWAVES : pal = 26; break; // landscape 33
|
||||
case FX_MODE_FILLNOISE8 : pal = 9; break; // ocean colors
|
||||
case FX_MODE_NOISE16_1 : pal = 20; break; // Drywet
|
||||
case FX_MODE_NOISE16_2 : pal = 43; break; // Blue cyan yellow
|
||||
case FX_MODE_NOISE16_3 : pal = 35; break; // heat palette
|
||||
case FX_MODE_NOISE16_4 : pal = 26; break; // landscape 33
|
||||
case FX_MODE_GLITTER : pal = 11; break; // rainbow colors
|
||||
case FX_MODE_SUNRISE : pal = 35; break; // heat palette
|
||||
case FX_MODE_RAILWAY : pal = 3; break; // prim + sec
|
||||
case FX_MODE_2DSOAP : pal = 11; break; // rainbow colors
|
||||
}
|
||||
if (pal == 0) pal = _default_palette; //load default palette set in FX _data, party colors as default
|
||||
switch (pal) {
|
||||
case 0: //default palette. Exceptions for specific effects above
|
||||
targetPalette = PartyColors_p; break;
|
||||
@ -385,7 +378,7 @@ void Segment::restoreSegenv(tmpsegd_t &tmpSeg) {
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t IRAM_ATTR Segment::currentBri(bool useCct) const {
|
||||
uint8_t Segment::currentBri(bool useCct) const {
|
||||
unsigned prog = progress();
|
||||
if (prog < 0xFFFFU) {
|
||||
unsigned curBri = (useCct ? cct : (on ? opacity : 0)) * prog;
|
||||
@ -403,16 +396,31 @@ uint8_t Segment::currentMode() const {
|
||||
return mode;
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR_YN Segment::currentColor(uint8_t slot) const {
|
||||
uint32_t Segment::currentColor(uint8_t slot) const {
|
||||
if (slot >= NUM_COLORS) slot = 0;
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
return isInTransition() ? color_blend(_t->_segT._colorT[slot], colors[slot], progress(), true) : colors[slot];
|
||||
return isInTransition() ? color_blend16(_t->_segT._colorT[slot], colors[slot], progress()) : colors[slot];
|
||||
#else
|
||||
return isInTransition() ? color_blend(_t->_colorT[slot], colors[slot], progress(), true) : colors[slot];
|
||||
return isInTransition() ? color_blend16(_t->_colorT[slot], colors[slot], progress()) : colors[slot];
|
||||
#endif
|
||||
}
|
||||
|
||||
void Segment::setCurrentPalette() {
|
||||
// pre-calculate drawing parameters for faster access (based on the idea from @softhack007 from MM fork)
|
||||
void Segment::beginDraw() {
|
||||
_vWidth = virtualWidth();
|
||||
_vHeight = virtualHeight();
|
||||
_vLength = virtualLength();
|
||||
_segBri = currentBri();
|
||||
// adjust gamma for effects
|
||||
for (unsigned i = 0; i < NUM_COLORS; i++) {
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
uint32_t col = isInTransition() ? color_blend16(_t->_segT._colorT[i], colors[i], progress()) : colors[i];
|
||||
#else
|
||||
uint32_t col = isInTransition() ? color_blend16(_t->_colorT[i], colors[i], progress()) : colors[i];
|
||||
#endif
|
||||
_currentColors[i] = gamma32(col);
|
||||
}
|
||||
// load palette into _currentPalette
|
||||
loadPalette(_currentPalette, palette);
|
||||
unsigned prog = progress();
|
||||
if (strip.paletteFade && prog < 0xFFFFU) {
|
||||
@ -444,8 +452,10 @@ void Segment::handleRandomPalette() {
|
||||
nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48);
|
||||
}
|
||||
|
||||
// segId is given when called from network callback, changes are queued if that segment is currently in its effect function
|
||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
||||
// sets Segment geometry (length or width/height and grouping, spacing and offset as well as 2D mapping)
|
||||
// strip must be suspended (strip.suspend()) before calling this function
|
||||
// this function may call fill() to clear pixels if spacing or mapping changed (which requires setting _vWidth, _vHeight, _vLength or beginDraw())
|
||||
void Segment::setGeometry(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y, uint8_t m12) {
|
||||
// return if neither bounds nor grouping have changed
|
||||
bool boundsUnchanged = (start == i1 && stop == i2);
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@ -453,11 +463,19 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
#endif
|
||||
if (boundsUnchanged
|
||||
&& (!grp || (grouping == grp && spacing == spc))
|
||||
&& (ofs == UINT16_MAX || ofs == offset)) return;
|
||||
&& (ofs == UINT16_MAX || ofs == offset)
|
||||
&& (m12 == map1D2D)
|
||||
) return;
|
||||
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
|
||||
if (stop) fill(BLACK); // turn old segment range off (clears pixels if changing spacing)
|
||||
if (stop || spc != spacing || m12 != map1D2D) {
|
||||
_vWidth = virtualWidth();
|
||||
_vHeight = virtualHeight();
|
||||
_vLength = virtualLength();
|
||||
_segBri = currentBri();
|
||||
fill(BLACK); // turn old segment range off or clears pixels if changing spacing (requires _vWidth/_vHeight/_vLength/_segBri)
|
||||
}
|
||||
if (grp) { // prevent assignment of 0
|
||||
grouping = grp;
|
||||
spacing = spc;
|
||||
@ -466,6 +484,7 @@ void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t
|
||||
spacing = 0;
|
||||
}
|
||||
if (ofs < UINT16_MAX) offset = ofs;
|
||||
map1D2D = constrain(m12, 0, 7);
|
||||
|
||||
DEBUG_PRINT(F("setUp segment: ")); DEBUG_PRINT(i1);
|
||||
DEBUG_PRINT(','); DEBUG_PRINT(i2);
|
||||
@ -554,9 +573,9 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
if (modeBlending) startTransition(strip.getTransition()); // set effect transitions
|
||||
#endif
|
||||
mode = fx;
|
||||
int sOpt;
|
||||
// load default values from effect string
|
||||
if (loadDefaults) {
|
||||
int sOpt;
|
||||
sOpt = extractModeDefaults(fx, "sx"); speed = (sOpt >= 0) ? sOpt : DEFAULT_SPEED;
|
||||
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
|
||||
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
|
||||
@ -573,6 +592,9 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) setPalette(sOpt); //else setPalette(0);
|
||||
}
|
||||
sOpt = extractModeDefaults(fx, "pal"); // always extract 'pal' to set _default_palette
|
||||
if(sOpt <= 0) sOpt = 6; // partycolors if zero or not set
|
||||
_default_palette = sOpt; // _deault_palette is loaded into pal0 in loadPalette() (if selected)
|
||||
markForReset();
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
@ -591,14 +613,14 @@ Segment &Segment::setPalette(uint8_t pal) {
|
||||
}
|
||||
|
||||
// 2D matrix
|
||||
unsigned IRAM_ATTR Segment::virtualWidth() const {
|
||||
unsigned Segment::virtualWidth() const {
|
||||
unsigned groupLen = groupLength();
|
||||
unsigned vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
|
||||
if (mirror) vWidth = (vWidth + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vWidth;
|
||||
}
|
||||
|
||||
unsigned IRAM_ATTR Segment::virtualHeight() const {
|
||||
unsigned Segment::virtualHeight() const {
|
||||
unsigned groupLen = groupLength();
|
||||
unsigned vHeight = ((transpose ? width() : height()) + groupLen - 1) / groupLen;
|
||||
if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
@ -642,7 +664,7 @@ static int getPinwheelLength(int vW, int vH) {
|
||||
#endif
|
||||
|
||||
// 1D strip
|
||||
uint16_t IRAM_ATTR Segment::virtualLength() const {
|
||||
uint16_t Segment::virtualLength() const {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (is2D()) {
|
||||
unsigned vW = virtualWidth();
|
||||
@ -676,18 +698,31 @@ uint16_t IRAM_ATTR Segment::virtualLength() const {
|
||||
|
||||
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
if (!isActive() || i < 0) return; // not active or invalid index
|
||||
#ifndef WLED_DISABLE_2D
|
||||
int vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows)
|
||||
int vStrip = 0;
|
||||
#endif
|
||||
i &= 0xFFFF;
|
||||
|
||||
if (i >= virtualLength() || i<0) return; // if pixel would fall out of segment just exit
|
||||
int vL = vLength();
|
||||
// if the 1D effect is using virtual strips "i" will have virtual strip id stored in upper 16 bits
|
||||
// in such case "i" will be > virtualLength()
|
||||
if (i >= vL) {
|
||||
// check if this is a virtual strip
|
||||
#ifndef WLED_DISABLE_2D
|
||||
vStrip = i>>16; // hack to allow running on virtual strips (2D segment columns/rows)
|
||||
i &= 0xFFFF; //truncate vstrip index
|
||||
if (i >= vL) return; // if pixel would still fall out of segment just exit
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (is2D()) {
|
||||
int vH = virtualHeight(); // segment height in logical pixels
|
||||
int vW = virtualWidth();
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
// pre-scale color for all pixels
|
||||
col = color_fade(col, _segBri);
|
||||
_colorScaled = true;
|
||||
switch (map1D2D) {
|
||||
case M12_Pixels:
|
||||
// use all available pixels as a long strip
|
||||
@ -695,12 +730,12 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||
break;
|
||||
case M12_pBar:
|
||||
// expand 1D effect vertically or have it play on virtual strips
|
||||
if (vStrip>0) setPixelColorXY(vStrip - 1, vH - i - 1, col);
|
||||
else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col);
|
||||
if (vStrip > 0) setPixelColorXY(vStrip - 1, vH - i - 1, col);
|
||||
else for (int x = 0; x < vW; x++) setPixelColorXY(x, vH - i - 1, col);
|
||||
break;
|
||||
case M12_pArc:
|
||||
// expand in circular fashion from center
|
||||
if (i==0)
|
||||
if (i == 0)
|
||||
setPixelColorXY(0, 0, col);
|
||||
else {
|
||||
float r = i;
|
||||
@ -779,13 +814,14 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||
break;
|
||||
}
|
||||
}
|
||||
_colorScaled = false;
|
||||
return;
|
||||
} else if (Segment::maxHeight!=1 && (width()==1 || height()==1)) {
|
||||
} else if (Segment::maxHeight != 1 && (width() == 1 || height() == 1)) {
|
||||
if (start < Segment::maxWidth*Segment::maxHeight) {
|
||||
// we have a vertical or horizontal 1D segment (WARNING: virtual...() may be transposed)
|
||||
int x = 0, y = 0;
|
||||
if (virtualHeight()>1) y = i;
|
||||
if (virtualWidth() >1) x = i;
|
||||
if (vHeight() > 1) y = i;
|
||||
if (vWidth() > 1) x = i;
|
||||
setPixelColorXY(x, y, col);
|
||||
return;
|
||||
}
|
||||
@ -793,10 +829,8 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||
#endif
|
||||
|
||||
unsigned len = length();
|
||||
uint8_t _bri_t = currentBri();
|
||||
if (_bri_t < 255) {
|
||||
col = color_fade(col, _bri_t);
|
||||
}
|
||||
// if color is unscaled
|
||||
if (!_colorScaled) col = color_fade(col, _segBri);
|
||||
|
||||
// expand pixel (taking into account start, grouping, spacing [and offset])
|
||||
i = i * groupLength();
|
||||
@ -819,14 +853,14 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col)
|
||||
indexMir += offset; // offset/phase
|
||||
if (indexMir >= stop) indexMir -= len; // wrap
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexMir), col, 0xFFFFU - progress(), true);
|
||||
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexMir), col, uint16_t(0xFFFFU - progress()));
|
||||
#endif
|
||||
strip.setPixelColor(indexMir, tmpCol);
|
||||
}
|
||||
indexSet += offset; // offset/phase
|
||||
if (indexSet >= stop) indexSet -= len; // wrap
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (_modeBlend) tmpCol = color_blend(strip.getPixelColor(indexSet), col, 0xFFFFU - progress(), true);
|
||||
if (_modeBlend) tmpCol = color_blend16(strip.getPixelColor(indexSet), col, uint16_t(0xFFFFU - progress()));
|
||||
#endif
|
||||
strip.setPixelColor(indexSet, tmpCol);
|
||||
}
|
||||
@ -871,23 +905,20 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
|
||||
uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
||||
{
|
||||
if (!isActive()) return 0; // not active
|
||||
#ifndef WLED_DISABLE_2D
|
||||
int vStrip = i>>16;
|
||||
#endif
|
||||
i &= 0xFFFF;
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (is2D()) {
|
||||
int vH = virtualHeight(); // segment height in logical pixels
|
||||
int vW = virtualWidth();
|
||||
const int vW = vWidth(); // segment width in logical pixels (can be 0 if segment is inactive)
|
||||
const int vH = vHeight(); // segment height in logical pixels (is always >= 1)
|
||||
switch (map1D2D) {
|
||||
case M12_Pixels:
|
||||
return getPixelColorXY(i % vW, i / vW);
|
||||
break;
|
||||
case M12_pBar:
|
||||
if (vStrip>0) return getPixelColorXY(vStrip - 1, vH - i -1);
|
||||
else return getPixelColorXY(0, vH - i -1);
|
||||
break;
|
||||
case M12_pBar: {
|
||||
int vStrip = i>>16; // virtual strips are only relevant in Bar expansion mode
|
||||
if (vStrip > 0) return getPixelColorXY(vStrip - 1, vH - (i & 0xFFFF) -1);
|
||||
else return getPixelColorXY(0, vH - i -1);
|
||||
break; }
|
||||
case M12_pArc:
|
||||
if (i >= vW && i >= vH) {
|
||||
unsigned vI = sqrt16(i*i/2);
|
||||
@ -931,7 +962,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
||||
}
|
||||
#endif
|
||||
|
||||
if (reverse) i = virtualLength() - i - 1;
|
||||
if (reverse) i = vLength() - i - 1;
|
||||
i *= groupLength();
|
||||
i += start;
|
||||
// offset/phase
|
||||
@ -940,7 +971,7 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColor(int i) const
|
||||
return strip.getPixelColor(i);
|
||||
}
|
||||
|
||||
uint8_t Segment::differs(Segment& b) const {
|
||||
uint8_t Segment::differs(const Segment& b) const {
|
||||
uint8_t d = 0;
|
||||
if (start != b.start) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS;
|
||||
@ -1020,12 +1051,16 @@ void Segment::refreshLightCapabilities() {
|
||||
*/
|
||||
void Segment::fill(uint32_t c) {
|
||||
if (!isActive()) return; // not active
|
||||
const int cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const int rows = virtualHeight(); // will be 1 for 1D
|
||||
const int cols = is2D() ? vWidth() : vLength();
|
||||
const int rows = vHeight(); // will be 1 for 1D
|
||||
// pre-scale color for all pixels
|
||||
c = color_fade(c, _segBri);
|
||||
_colorScaled = true;
|
||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
if (is2D()) setPixelColorXY(x, y, c);
|
||||
else setPixelColor(x, c);
|
||||
}
|
||||
_colorScaled = false;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1033,8 +1068,8 @@ void Segment::fill(uint32_t c) {
|
||||
*/
|
||||
void Segment::fade_out(uint8_t rate) {
|
||||
if (!isActive()) return; // not active
|
||||
const int cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const int rows = virtualHeight(); // will be 1 for 1D
|
||||
const int cols = is2D() ? vWidth() : vLength();
|
||||
const int rows = vHeight(); // will be 1 for 1D
|
||||
|
||||
rate = (255-rate) >> 1;
|
||||
float mappedRate = 1.0f / (float(rate) + 1.1f);
|
||||
@ -1072,8 +1107,8 @@ void Segment::fade_out(uint8_t rate) {
|
||||
// fades all pixels to black using nscale8()
|
||||
void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply
|
||||
const int cols = is2D() ? virtualWidth() : virtualLength();
|
||||
const int rows = virtualHeight(); // will be 1 for 1D
|
||||
const int cols = is2D() ? vWidth() : vLength();
|
||||
const int rows = vHeight(); // will be 1 for 1D
|
||||
|
||||
for (int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
if (is2D()) setPixelColorXY(x, y, color_fade(getPixelColorXY(x,y), 255-fadeBy));
|
||||
@ -1083,20 +1118,21 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
|
||||
/*
|
||||
* blurs segment content, source: FastLED colorutils.cpp
|
||||
* Note: for blur_amount > 215 this function does not work properly (creates alternating pattern)
|
||||
*/
|
||||
void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||
if (!isActive() || blur_amount == 0) return; // optimization: 0 means "don't blur"
|
||||
#ifndef WLED_DISABLE_2D
|
||||
if (is2D()) {
|
||||
// compatibility with 2D
|
||||
blur2D(blur_amount, smear);
|
||||
blur2D(blur_amount, blur_amount, smear); // symmetrical 2D blur
|
||||
//box_blur(map(blur_amount,1,255,1,3), smear);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
uint8_t keep = smear ? 255 : 255 - blur_amount;
|
||||
uint8_t seep = blur_amount >> (1 + smear);
|
||||
unsigned vlength = virtualLength();
|
||||
uint8_t seep = blur_amount >> 1;
|
||||
unsigned vlength = vLength();
|
||||
uint32_t carryover = BLACK;
|
||||
uint32_t lastnew;
|
||||
uint32_t last;
|
||||
@ -1106,12 +1142,11 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||
uint32_t part = color_fade(cur, seep);
|
||||
curnew = color_fade(cur, keep);
|
||||
if (i > 0) {
|
||||
if (carryover) curnew = color_add(curnew, carryover, true);
|
||||
uint32_t prev = color_add(lastnew, part, true);
|
||||
if (carryover) curnew = color_add(curnew, carryover);
|
||||
uint32_t prev = color_add(lastnew, part);
|
||||
// optimization: only set pixel if color has changed
|
||||
if (last != prev) setPixelColor(i - 1, prev);
|
||||
} else // first pixel
|
||||
setPixelColor(i, curnew);
|
||||
} else setPixelColor(i, curnew); // first pixel
|
||||
lastnew = curnew;
|
||||
last = cur; // save original value for comparison on next iteration
|
||||
carryover = part;
|
||||
@ -1126,11 +1161,11 @@ void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||
*/
|
||||
uint32_t Segment::color_wheel(uint8_t pos) const {
|
||||
if (palette) return color_from_palette(pos, false, true, 0); // perhaps "strip.paletteBlend < 2" should be better instead of "true"
|
||||
uint8_t w = W(currentColor(0));
|
||||
uint8_t w = W(getCurrentColor(0));
|
||||
pos = 255 - pos;
|
||||
if (pos < 85) {
|
||||
return RGBW32((255 - pos * 3), 0, (pos * 3), w);
|
||||
} else if(pos < 170) {
|
||||
} else if (pos < 170) {
|
||||
pos -= 85;
|
||||
return RGBW32(0, (pos * 3), (255 - pos * 3), w);
|
||||
} else {
|
||||
@ -1149,18 +1184,21 @@ uint32_t Segment::color_wheel(uint8_t pos) const {
|
||||
* @returns Single color from palette
|
||||
*/
|
||||
uint32_t Segment::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) const {
|
||||
uint32_t color = gamma32(currentColor(mcol));
|
||||
|
||||
uint32_t color = getCurrentColor(mcol < NUM_COLORS ? mcol : 0);
|
||||
// default palette or no RGB support on segment
|
||||
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) return (pbri == 255) ? color : color_fade(color, pbri, true);
|
||||
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) {
|
||||
return color_fade(color, pbri, true);
|
||||
}
|
||||
|
||||
const int vL = vLength();
|
||||
unsigned paletteIndex = i;
|
||||
if (mapping && virtualLength() > 1) paletteIndex = (i*255)/(virtualLength() -1);
|
||||
if (mapping && vL > 1) paletteIndex = (i*255)/(vL -1);
|
||||
// paletteBlend: 0 - wrap when moving, 1 - always wrap, 2 - never wrap, 3 - none (undefined)
|
||||
if (!wrap && strip.paletteBlend != 3) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end"
|
||||
CRGB fastled_col = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
||||
CRGBW palcol = ColorFromPalette(_currentPalette, paletteIndex, pbri, (strip.paletteBlend == 3)? NOBLEND:LINEARBLEND); // NOTE: paletteBlend should be global
|
||||
palcol.w = W(color);
|
||||
|
||||
return RGBW32(fastled_col.r, fastled_col.g, fastled_col.b, W(color));
|
||||
return palcol.color32;
|
||||
}
|
||||
|
||||
|
||||
@ -1324,11 +1362,6 @@ void WS2812FX::service() {
|
||||
|
||||
if (!seg.freeze) { //only run effect function if not frozen
|
||||
int oldCCT = BusManager::getSegmentCCT(); // store original CCT value (actually it is not Segment based)
|
||||
_virtualSegmentLength = seg.virtualLength(); //SEGLEN
|
||||
_colors_t[0] = gamma32(seg.currentColor(0));
|
||||
_colors_t[1] = gamma32(seg.currentColor(1));
|
||||
_colors_t[2] = gamma32(seg.currentColor(2));
|
||||
seg.setCurrentPalette(); // load actual palette
|
||||
// when correctWB is true we need to correct/adjust RGB value according to desired CCT value, but it will also affect actual WW/CW ratio
|
||||
// when cctFromRgb is true we implicitly calculate WW and CW from RGB values
|
||||
if (cctFromRgb) BusManager::setSegmentCCT(-1);
|
||||
@ -1340,13 +1373,14 @@ void WS2812FX::service() {
|
||||
// overwritten by later effect. To enable seamless blending for every effect, additional LED buffer
|
||||
// would need to be allocated for each effect and then blended together for each pixel.
|
||||
[[maybe_unused]] uint8_t tmpMode = seg.currentMode(); // this will return old mode while in transition
|
||||
frameDelay = (*_mode[seg.mode])(); // run new/current mode
|
||||
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||
frameDelay = (*_mode[seg.mode])(); // run new/current mode
|
||||
#ifndef WLED_DISABLE_MODE_BLEND
|
||||
if (modeBlending && seg.mode != tmpMode) {
|
||||
Segment::tmpsegd_t _tmpSegData;
|
||||
Segment::modeBlend(true); // set semaphore
|
||||
seg.swapSegenv(_tmpSegData); // temporarily store new mode state (and swap it with transitional state)
|
||||
_virtualSegmentLength = seg.virtualLength(); // update SEGLEN (mapping may have changed)
|
||||
seg.beginDraw(); // set up parameters for get/setPixelColor()
|
||||
unsigned d2 = (*_mode[tmpMode])(); // run old mode
|
||||
seg.restoreSegenv(_tmpSegData); // restore mode state (will also update transitional state)
|
||||
frameDelay = min(frameDelay,d2); // use shortest delay
|
||||
@ -1362,7 +1396,6 @@ void WS2812FX::service() {
|
||||
}
|
||||
_segment_index++;
|
||||
}
|
||||
_virtualSegmentLength = 0;
|
||||
_isServicing = false;
|
||||
_triggered = false;
|
||||
|
||||
@ -1412,50 +1445,12 @@ void WS2812FX::show() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a true value if any of the strips are still being updated.
|
||||
* On some hardware (ESP32), strip updates are done asynchronously.
|
||||
*/
|
||||
bool WS2812FX::isUpdating() const {
|
||||
return !BusManager::canAllShow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the refresh rate of the LED strip. Useful for finding out whether a given setup is fast enough.
|
||||
* Only updates on show() or is set to 0 fps if last show is more than 2 secs ago, so accuracy varies
|
||||
*/
|
||||
uint16_t WS2812FX::getFps() const {
|
||||
if (millis() - _lastShow > 2000) return 0;
|
||||
return (FPS_MULTIPLIER * _cumulativeFps) >> FPS_CALC_SHIFT; // _cumulativeFps is stored in fixed point
|
||||
}
|
||||
|
||||
void WS2812FX::setTargetFps(uint8_t fps) {
|
||||
void WS2812FX::setTargetFps(unsigned fps) {
|
||||
if (fps <= 250) _targetFps = fps;
|
||||
if (_targetFps > 0) _frametime = 1000 / _targetFps;
|
||||
else _frametime = MIN_FRAME_DELAY; // unlimited mode
|
||||
}
|
||||
|
||||
void WS2812FX::setMode(uint8_t segid, uint8_t m) {
|
||||
if (segid >= _segments.size()) return;
|
||||
|
||||
if (m >= getModeCount()) m = getModeCount() - 1;
|
||||
|
||||
if (_segments[segid].mode != m) {
|
||||
_segments[segid].setMode(m); // do not load defaults
|
||||
}
|
||||
}
|
||||
|
||||
//applies to all active and selected segments
|
||||
void WS2812FX::setColor(uint8_t slot, uint32_t c) {
|
||||
if (slot >= NUM_COLORS) return;
|
||||
|
||||
for (segment &seg : _segments) {
|
||||
if (seg.isActive() && seg.isSelected()) {
|
||||
seg.setColor(slot, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WS2812FX::setCCT(uint16_t k) {
|
||||
for (segment &seg : _segments) {
|
||||
if (seg.isActive() && seg.isSelected()) {
|
||||
@ -1502,7 +1497,7 @@ uint8_t WS2812FX::getFirstSelectedSegId() const {
|
||||
return getMainSegmentId();
|
||||
}
|
||||
|
||||
void WS2812FX::setMainSegmentId(uint8_t n) {
|
||||
void WS2812FX::setMainSegmentId(unsigned n) {
|
||||
_mainSegment = 0;
|
||||
if (n < _segments.size()) {
|
||||
_mainSegment = n;
|
||||
@ -1578,23 +1573,10 @@ void WS2812FX::purgeSegments() {
|
||||
}
|
||||
}
|
||||
|
||||
Segment& WS2812FX::getSegment(uint8_t id) {
|
||||
Segment& WS2812FX::getSegment(unsigned id) {
|
||||
return _segments[id >= _segments.size() ? getMainSegmentId() : id]; // vectors
|
||||
}
|
||||
|
||||
// sets new segment bounds, queues if that segment is currently running
|
||||
void WS2812FX::setSegment(uint8_t segId, uint16_t i1, uint16_t i2, uint8_t grouping, uint8_t spacing, uint16_t offset, uint16_t startY, uint16_t stopY) {
|
||||
if (segId >= getSegmentsNum()) {
|
||||
if (i2 <= i1) return; // do not append empty/inactive segments
|
||||
appendSegment(Segment(0, strip.getLengthTotal()));
|
||||
segId = getSegmentsNum()-1; // segments are added at the end of list
|
||||
}
|
||||
suspend();
|
||||
_segments[segId].setUp(i1, i2, grouping, spacing, offset, startY, stopY);
|
||||
resume();
|
||||
if (segId > 0 && segId == getSegmentsNum()-1 && i2 <= i1) _segments.pop_back(); // if last segment was deleted remove it from vector
|
||||
}
|
||||
|
||||
void WS2812FX::resetSegments() {
|
||||
_segments.clear(); // destructs all Segment as part of clearing
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@ -1793,7 +1775,7 @@ void WS2812FX::loadCustomPalettes() {
|
||||
}
|
||||
|
||||
//load custom mapping table from JSON file (called from finalizeInit() or deserializeState())
|
||||
bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
bool WS2812FX::deserializeMap(unsigned n) {
|
||||
// 2D support creates its own ledmap (on the fly) if a ledmap.json exists it will overwrite built one.
|
||||
|
||||
char fileName[32];
|
||||
@ -1845,14 +1827,6 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
return (customMappingSize > 0);
|
||||
}
|
||||
|
||||
uint16_t IRAM_ATTR WS2812FX::getMappedPixelIndex(uint16_t index) const {
|
||||
// convert logical address to physical
|
||||
if (index < customMappingSize
|
||||
&& (realtimeMode == REALTIME_MODE_INACTIVE || realtimeRespectLedMaps)) index = customMappingTable[index];
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
WS2812FX* WS2812FX::instance = nullptr;
|
||||
|
||||
@ -1865,5 +1839,5 @@ const char JSON_palette_names[] PROGMEM = R"=====([
|
||||
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
|
||||
"Aurora","Atlantica","C9 2","C9 New","Temperature","Aurora 2","Retro Clown","Candy","Toxy Reaf","Fairy Reaf",
|
||||
"Semi Blue","Pink Candy","Red Reaf","Aqua Flash","Yelblu Hot","Lite Light","Red Flash","Blink Red","Red Shift","Red Tide",
|
||||
"Candy2"
|
||||
"Candy2","Traffic Light"
|
||||
])=====";
|
||||
|
@ -126,10 +126,10 @@ void onAlexaChange(EspalexaDevice* dev)
|
||||
} else {
|
||||
colorKtoRGB(k, rgbw);
|
||||
}
|
||||
strip.setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
|
||||
strip.getMainSegment().setColor(0, RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]));
|
||||
} else {
|
||||
uint32_t color = dev->getRGB();
|
||||
strip.setColor(0, color);
|
||||
strip.getMainSegment().setColor(0, color);
|
||||
}
|
||||
stateUpdated(CALL_MODE_ALEXA);
|
||||
}
|
||||
|
@ -155,16 +155,6 @@ BusDigital::BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com)
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited strip %u (len %u) with type %u and pins %u,%u (itype %u). mA=%d/%d\n"), _valid?"S":"Uns", nr, bc.count, bc.type, _pins[0], is2Pin(bc.type)?_pins[1]:255, _iType, _milliAmpsPerLed, _milliAmpsMax);
|
||||
}
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
#ifndef MA_FOR_ESP
|
||||
#ifdef ESP8266
|
||||
#define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA)
|
||||
#else
|
||||
#define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//DISCLAIMER
|
||||
//The following function attemps to calculate the current LED power usage,
|
||||
//and will limit the brightness to stay below a set amperage threshold.
|
||||
@ -306,22 +296,22 @@ void BusDigital::setStatusPixel(uint32_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void IRAM_ATTR BusDigital::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (!_valid) return;
|
||||
uint8_t cctWW = 0, cctCW = 0;
|
||||
if (hasWhite()) c = autoWhiteCalc(c);
|
||||
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||
if (_data) {
|
||||
size_t offset = pix * getNumberOfChannels();
|
||||
uint8_t* dataptr = _data + offset;
|
||||
if (hasRGB()) {
|
||||
_data[offset++] = R(c);
|
||||
_data[offset++] = G(c);
|
||||
_data[offset++] = B(c);
|
||||
*dataptr++ = R(c);
|
||||
*dataptr++ = G(c);
|
||||
*dataptr++ = B(c);
|
||||
}
|
||||
if (hasWhite()) _data[offset++] = W(c);
|
||||
if (hasWhite()) *dataptr++ = W(c);
|
||||
// unfortunately as a segment may span multiple buses or a bus may contain multiple segments and each segment may have different CCT
|
||||
// we need to store CCT value for each pixel (if there is a color correction in play, convert K in CCT ratio)
|
||||
if (hasCCT()) _data[offset] = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it
|
||||
if (hasCCT()) *dataptr = Bus::_cct >= 1900 ? (Bus::_cct - 1900) >> 5 : (Bus::_cct < 0 ? 127 : Bus::_cct); // TODO: if _cct == -1 we simply ignore it
|
||||
} else {
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
@ -336,16 +326,22 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
case 2: c = RGBW32(R(cOld), G(cOld), W(c) , 0); break;
|
||||
}
|
||||
}
|
||||
if (hasCCT()) Bus::calculateCCT(c, cctWW, cctCW);
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, (cctCW<<8) | cctWW);
|
||||
uint16_t wwcw = 0;
|
||||
if (hasCCT()) {
|
||||
uint8_t cctWW = 0, cctCW = 0;
|
||||
Bus::calculateCCT(c, cctWW, cctCW);
|
||||
wwcw = (cctCW<<8) | cctWW;
|
||||
}
|
||||
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co, wwcw);
|
||||
}
|
||||
}
|
||||
|
||||
// returns original color if global buffering is enabled, else returns lossly restored color from bus
|
||||
uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const {
|
||||
uint32_t IRAM_ATTR BusDigital::getPixelColor(unsigned pix) const {
|
||||
if (!_valid) return 0;
|
||||
if (_data) {
|
||||
size_t offset = pix * getNumberOfChannels();
|
||||
const size_t offset = pix * getNumberOfChannels();
|
||||
uint32_t c;
|
||||
if (!hasRGB()) {
|
||||
c = RGBW32(_data[offset], _data[offset], _data[offset], _data[offset]);
|
||||
@ -356,7 +352,7 @@ uint32_t IRAM_ATTR BusDigital::getPixelColor(uint16_t pix) const {
|
||||
} else {
|
||||
if (_reversed) pix = _len - pix -1;
|
||||
pix += _skip;
|
||||
unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||
const unsigned co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||
uint32_t c = restoreColorLossy(PolyBus::getPixelColor(_busPtr, _iType, (_type==TYPE_WS2812_1CH_X3) ? IC_INDEX_WS2812_1CH_3X(pix) : pix, co),_bri);
|
||||
if (_type == TYPE_WS2812_1CH_X3) { // map to correct IC, each controls 3 LEDs
|
||||
unsigned r = R(c);
|
||||
@ -501,7 +497,7 @@ BusPwm::BusPwm(BusConfig &bc)
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited PWM strip with type %u, frequency %u, bit depth %u and pins %u,%u,%u,%u,%u\n"), _valid?"S":"Uns", bc.type, _frequency, _depth, _pins[0], _pins[1], _pins[2], _pins[3], _pins[4]);
|
||||
}
|
||||
|
||||
void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void BusPwm::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||
if (_type != TYPE_ANALOG_3CH) c = autoWhiteCalc(c);
|
||||
if (Bus::_cct >= 1900 && (_type == TYPE_ANALOG_3CH || _type == TYPE_ANALOG_4CH)) {
|
||||
@ -538,7 +534,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
}
|
||||
|
||||
//does no index check
|
||||
uint32_t BusPwm::getPixelColor(uint16_t pix) const {
|
||||
uint32_t BusPwm::getPixelColor(unsigned pix) const {
|
||||
if (!_valid) return 0;
|
||||
// TODO getting the reverse from CCT is involved (a quick approximation when CCT blending is ste to 0 implemented)
|
||||
switch (_type) {
|
||||
@ -567,19 +563,15 @@ void BusPwm::show() {
|
||||
const unsigned maxBri = (1<<_depth); // possible values: 16384 (14), 8192 (13), 4096 (12), 2048 (11), 1024 (10), 512 (9) and 256 (8)
|
||||
[[maybe_unused]] const unsigned bitShift = dithering * 4; // if dithering, _depth is 12 bit but LEDC channel is set to 8 bit (using 4 fractional bits)
|
||||
|
||||
// use CIE brightness formula (cubic) to fit (or approximate linearity of) human eye perceived brightness
|
||||
// the formula is based on 12 bit resolution as there is no need for greater precision
|
||||
// use CIE brightness formula (linear + cubic) to approximate human eye perceived brightness
|
||||
// see: https://en.wikipedia.org/wiki/Lightness
|
||||
unsigned pwmBri = (unsigned)_bri * 100; // enlarge to use integer math for linear response
|
||||
if (pwmBri < 2040) {
|
||||
// linear response for values [0-20]
|
||||
pwmBri = ((pwmBri << 12) + 115043) / 230087; //adding '0.5' before division for correct rounding
|
||||
} else {
|
||||
// cubic response for values [21-255]
|
||||
pwmBri += 4080;
|
||||
float temp = (float)pwmBri / 29580.0f;
|
||||
temp = temp * temp * temp * (float)maxBri;
|
||||
pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri]
|
||||
unsigned pwmBri = _bri;
|
||||
if (pwmBri < 21) { // linear response for values [0-20]
|
||||
pwmBri = (pwmBri * maxBri + 2300 / 2) / 2300 ; // adding '0.5' before division for correct rounding, 2300 gives a good match to CIE curve
|
||||
} else { // cubic response for values [21-255]
|
||||
float temp = float(pwmBri + 41) / float(255 + 41); // 41 is to match offset & slope to linear part
|
||||
temp = temp * temp * temp * (float)maxBri;
|
||||
pwmBri = (unsigned)temp; // pwmBri is in range [0-maxBri] C
|
||||
}
|
||||
|
||||
[[maybe_unused]] unsigned hPoint = 0; // phase shift (0 - maxBri)
|
||||
@ -674,7 +666,7 @@ BusOnOff::BusOnOff(BusConfig &bc)
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited On/Off strip with pin %u\n"), _valid?"S":"Uns", _pin);
|
||||
}
|
||||
|
||||
void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void BusOnOff::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (pix != 0 || !_valid) return; //only react to first pixel
|
||||
c = autoWhiteCalc(c);
|
||||
uint8_t r = R(c);
|
||||
@ -684,7 +676,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
_data[0] = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) const {
|
||||
uint32_t BusOnOff::getPixelColor(unsigned pix) const {
|
||||
if (!_valid) return 0;
|
||||
return RGBW32(_data[0], _data[0], _data[0], _data[0]);
|
||||
}
|
||||
@ -734,7 +726,7 @@ BusNetwork::BusNetwork(BusConfig &bc)
|
||||
DEBUG_PRINTF_P(PSTR("%successfully inited virtual strip with type %u and IP %u.%u.%u.%u\n"), _valid?"S":"Uns", bc.type, bc.pins[0], bc.pins[1], bc.pins[2], bc.pins[3]);
|
||||
}
|
||||
|
||||
void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void BusNetwork::setPixelColor(unsigned pix, uint32_t c) {
|
||||
if (!_valid || pix >= _len) return;
|
||||
if (_hasWhite) c = autoWhiteCalc(c);
|
||||
if (Bus::_cct >= 1900) c = colorBalanceFromKelvin(Bus::_cct, c); //color correction from CCT
|
||||
@ -745,7 +737,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (_hasWhite) _data[offset+3] = W(c);
|
||||
}
|
||||
|
||||
uint32_t BusNetwork::getPixelColor(uint16_t pix) const {
|
||||
uint32_t BusNetwork::getPixelColor(unsigned pix) const {
|
||||
if (!_valid || pix >= _len) return 0;
|
||||
unsigned offset = pix * _UDPchannels;
|
||||
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], (hasWhite() ? _data[offset+3] : 0));
|
||||
@ -943,7 +935,6 @@ void BusManager::show() {
|
||||
busses[i]->show();
|
||||
_milliAmpsUsed += busses[i]->getUsedCurrent();
|
||||
}
|
||||
if (_milliAmpsUsed) _milliAmpsUsed += MA_FOR_ESP;
|
||||
}
|
||||
|
||||
void BusManager::setStatusPixel(uint32_t c) {
|
||||
@ -952,7 +943,7 @@ void BusManager::setStatusPixel(uint32_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
void IRAM_ATTR BusManager::setPixelColor(unsigned pix, uint32_t c) {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
unsigned bstart = busses[i]->getStart();
|
||||
if (pix < bstart || pix >= bstart + busses[i]->getLength()) continue;
|
||||
@ -975,7 +966,7 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||
Bus::setCCT(cct);
|
||||
}
|
||||
|
||||
uint32_t BusManager::getPixelColor(uint16_t pix) {
|
||||
uint32_t BusManager::getPixelColor(unsigned pix) {
|
||||
for (unsigned i = 0; i < numBusses; i++) {
|
||||
unsigned bstart = busses[i]->getStart();
|
||||
if (!busses[i]->containsPixel(pix)) continue;
|
||||
|
@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "const.h"
|
||||
#include "pin_manager.h"
|
||||
#include <vector>
|
||||
|
||||
//colors.cpp
|
||||
@ -83,10 +84,10 @@ class Bus {
|
||||
virtual void show() = 0;
|
||||
virtual bool canShow() const { return true; }
|
||||
virtual void setStatusPixel(uint32_t c) {}
|
||||
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
|
||||
virtual void setPixelColor(unsigned pix, uint32_t c) = 0;
|
||||
virtual void setBrightness(uint8_t b) { _bri = b; };
|
||||
virtual void setColorOrder(uint8_t co) {}
|
||||
virtual uint32_t getPixelColor(uint16_t pix) const { return 0; }
|
||||
virtual uint32_t getPixelColor(unsigned pix) const { return 0; }
|
||||
virtual uint8_t getPins(uint8_t* pinArray = nullptr) const { return 0; }
|
||||
virtual uint16_t getLength() const { return isOk() ? _len : 0; }
|
||||
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
|
||||
@ -110,7 +111,7 @@ class Bus {
|
||||
inline void setStart(uint16_t start) { _start = start; }
|
||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
|
||||
inline uint8_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
|
||||
inline uint32_t getNumberOfChannels() const { return hasWhite() + 3*hasRGB() + hasCCT(); }
|
||||
inline uint16_t getStart() const { return _start; }
|
||||
inline uint8_t getType() const { return _type; }
|
||||
inline bool isOk() const { return _valid; }
|
||||
@ -119,8 +120,8 @@ class Bus {
|
||||
inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start + _len; }
|
||||
|
||||
static inline std::vector<LEDType> getLEDTypes() { return {{TYPE_NONE, "", PSTR("None")}}; } // not used. just for reference for derived classes
|
||||
static constexpr uint8_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
|
||||
static constexpr uint8_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
||||
static constexpr uint32_t getNumberOfPins(uint8_t type) { return isVirtual(type) ? 4 : isPWM(type) ? numPWMPins(type) : is2Pin(type) + 1; } // credit @PaoloTK
|
||||
static constexpr uint32_t getNumberOfChannels(uint8_t type) { return hasWhite(type) + 3*hasRGB(type) + hasCCT(type); }
|
||||
static constexpr bool hasRGB(uint8_t type) {
|
||||
return !((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_ANALOG_1CH || type == TYPE_ANALOG_2CH || type == TYPE_ONOFF);
|
||||
}
|
||||
@ -204,9 +205,9 @@ class BusDigital : public Bus {
|
||||
bool canShow() const override;
|
||||
void setBrightness(uint8_t b) override;
|
||||
void setStatusPixel(uint32_t c) override;
|
||||
[[gnu::hot]] void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
[[gnu::hot]] void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
void setColorOrder(uint8_t colorOrder) override;
|
||||
[[gnu::hot]] uint32_t getPixelColor(uint16_t pix) const override;
|
||||
[[gnu::hot]] uint32_t getPixelColor(unsigned pix) const override;
|
||||
uint8_t getColorOrder() const override { return _colorOrder; }
|
||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||
uint8_t skippedLeds() const override { return _skip; }
|
||||
@ -252,8 +253,8 @@ class BusPwm : public Bus {
|
||||
BusPwm(BusConfig &bc);
|
||||
~BusPwm() { cleanup(); }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(uint16_t pix) const override; //does no index check
|
||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(unsigned pix) const override; //does no index check
|
||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||
uint16_t getFrequency() const override { return _frequency; }
|
||||
void show() override;
|
||||
@ -279,8 +280,8 @@ class BusOnOff : public Bus {
|
||||
BusOnOff(BusConfig &bc);
|
||||
~BusOnOff() { cleanup(); }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(uint16_t pix) const override;
|
||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(unsigned pix) const override;
|
||||
uint8_t getPins(uint8_t* pinArray) const override;
|
||||
void show() override;
|
||||
void cleanup() { PinManager::deallocatePin(_pin, PinOwner::BusOnOff); }
|
||||
@ -299,8 +300,8 @@ class BusNetwork : public Bus {
|
||||
~BusNetwork() { cleanup(); }
|
||||
|
||||
bool canShow() const override { return !_broadcastLock; } // this should be a return value from UDP routine if it is still sending data out
|
||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(uint16_t pix) const override;
|
||||
void setPixelColor(unsigned pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(unsigned pix) const override;
|
||||
uint8_t getPins(uint8_t* pinArray = nullptr) const override;
|
||||
void show() override;
|
||||
void cleanup();
|
||||
@ -363,6 +364,16 @@ struct BusConfig {
|
||||
};
|
||||
|
||||
|
||||
//fine tune power estimation constants for your setup
|
||||
//you can set it to 0 if the ESP is powered by USB and the LEDs by external
|
||||
#ifndef MA_FOR_ESP
|
||||
#ifdef ESP8266
|
||||
#define MA_FOR_ESP 80 //how much mA does the ESP use (Wemos D1 about 80mA)
|
||||
#else
|
||||
#define MA_FOR_ESP 120 //how much mA does the ESP use (ESP32 about 120mA)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class BusManager {
|
||||
public:
|
||||
BusManager() {};
|
||||
@ -370,7 +381,7 @@ class BusManager {
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
static uint32_t memUsage(BusConfig &bc);
|
||||
static uint32_t memUsage(unsigned channels, unsigned count, unsigned buses = 1);
|
||||
static uint16_t currentMilliamps() { return _milliAmpsUsed; }
|
||||
static uint16_t currentMilliamps() { return _milliAmpsUsed + MA_FOR_ESP; }
|
||||
static uint16_t ablMilliampsMax() { return _milliAmpsMax; }
|
||||
|
||||
static int add(BusConfig &bc);
|
||||
@ -385,13 +396,13 @@ class BusManager {
|
||||
static void show();
|
||||
static bool canAllShow();
|
||||
static void setStatusPixel(uint32_t c);
|
||||
[[gnu::hot]] static void setPixelColor(uint16_t pix, uint32_t c);
|
||||
[[gnu::hot]] static void setPixelColor(unsigned pix, uint32_t c);
|
||||
static void setBrightness(uint8_t b);
|
||||
// for setSegmentCCT(), cct can only be in [-1,255] range; allowWBCorrection will convert it to K
|
||||
// WARNING: setSegmentCCT() is a misleading name!!! much better would be setGlobalCCT() or just setCCT()
|
||||
static void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||
static inline void setMilliampsMax(uint16_t max) { _milliAmpsMax = max;}
|
||||
static uint32_t getPixelColor(uint16_t pix);
|
||||
[[gnu::hot]] static uint32_t getPixelColor(unsigned pix);
|
||||
static inline int16_t getSegmentCCT() { return Bus::getCCT(); }
|
||||
|
||||
static Bus* getBus(uint8_t busNr);
|
||||
|
@ -436,13 +436,12 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
||||
else gammaCorrectBri = false;
|
||||
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
||||
else gammaCorrectCol = false;
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
||||
if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
} else {
|
||||
if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
gammaCorrectCol = false;
|
||||
}
|
||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||
|
||||
JsonObject light_tr = light["tr"];
|
||||
CJSON(fadeTransition, light_tr["mode"]);
|
||||
|
@ -5,61 +5,56 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* color blend function
|
||||
* color blend function, based on FastLED blend function
|
||||
* the calculation for each color is: result = (A*(amountOfA) + A + B*(amountOfB) + B) / 256 with amountOfA = 255 - amountOfB
|
||||
*/
|
||||
uint32_t color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) {
|
||||
if (blend == 0) return color1;
|
||||
unsigned blendmax = b16 ? 0xFFFF : 0xFF;
|
||||
if (blend == blendmax) return color2;
|
||||
unsigned shift = b16 ? 16 : 8;
|
||||
|
||||
uint32_t w1 = W(color1);
|
||||
uint32_t r1 = R(color1);
|
||||
uint32_t g1 = G(color1);
|
||||
uint32_t b1 = B(color1);
|
||||
|
||||
uint32_t w2 = W(color2);
|
||||
uint32_t r2 = R(color2);
|
||||
uint32_t g2 = G(color2);
|
||||
uint32_t b2 = B(color2);
|
||||
|
||||
uint32_t w3 = ((w2 * blend) + (w1 * (blendmax - blend))) >> shift;
|
||||
uint32_t r3 = ((r2 * blend) + (r1 * (blendmax - blend))) >> shift;
|
||||
uint32_t g3 = ((g2 * blend) + (g1 * (blendmax - blend))) >> shift;
|
||||
uint32_t b3 = ((b2 * blend) + (b1 * (blendmax - blend))) >> shift;
|
||||
|
||||
return RGBW32(r3, g3, b3, w3);
|
||||
uint32_t color_blend(uint32_t color1, uint32_t color2, uint8_t blend) {
|
||||
// min / max blend checking is omitted: calls with 0 or 255 are rare, checking lowers overall performance
|
||||
uint32_t rb1 = color1 & 0x00FF00FF;
|
||||
uint32_t wg1 = (color1>>8) & 0x00FF00FF;
|
||||
uint32_t rb2 = color2 & 0x00FF00FF;
|
||||
uint32_t wg2 = (color2>>8) & 0x00FF00FF;
|
||||
uint32_t rb3 = ((((rb1 << 8) | rb2) + (rb2 * blend) - (rb1 * blend)) >> 8) & 0x00FF00FF;
|
||||
uint32_t wg3 = ((((wg1 << 8) | wg2) + (wg2 * blend) - (wg1 * blend))) & 0xFF00FF00;
|
||||
return rb3 | wg3;
|
||||
}
|
||||
|
||||
/*
|
||||
* color add function that preserves ratio
|
||||
* idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
|
||||
* original idea: https://github.com/Aircoookie/WLED/pull/2465 by https://github.com/Proto-molecule
|
||||
* speed optimisations by @dedehai
|
||||
*/
|
||||
uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
|
||||
uint32_t color_add(uint32_t c1, uint32_t c2, bool preserveCR)
|
||||
{
|
||||
if (c1 == BLACK) return c2;
|
||||
if (c2 == BLACK) return c1;
|
||||
if (fast) {
|
||||
uint8_t r = R(c1);
|
||||
uint8_t g = G(c1);
|
||||
uint8_t b = B(c1);
|
||||
uint8_t w = W(c1);
|
||||
r = qadd8(r, R(c2));
|
||||
g = qadd8(g, G(c2));
|
||||
b = qadd8(b, B(c2));
|
||||
w = qadd8(w, W(c2));
|
||||
return RGBW32(r,g,b,w);
|
||||
uint32_t rb = (c1 & 0x00FF00FF) + (c2 & 0x00FF00FF); // mask and add two colors at once
|
||||
uint32_t wg = ((c1>>8) & 0x00FF00FF) + ((c2>>8) & 0x00FF00FF);
|
||||
uint32_t r = rb >> 16; // extract single color values
|
||||
uint32_t b = rb & 0xFFFF;
|
||||
uint32_t w = wg >> 16;
|
||||
uint32_t g = wg & 0xFFFF;
|
||||
|
||||
if (preserveCR) { // preserve color ratios
|
||||
uint32_t max = std::max(r,g); // check for overflow note
|
||||
max = std::max(max,b);
|
||||
max = std::max(max,w);
|
||||
//unsigned max = r; // check for overflow note
|
||||
//max = g > max ? g : max;
|
||||
//max = b > max ? b : max;
|
||||
//max = w > max ? w : max;
|
||||
if (max > 255) {
|
||||
uint32_t scale = (uint32_t(255)<<8) / max; // division of two 8bit (shifted) values does not work -> use bit shifts and multiplaction instead
|
||||
rb = ((rb * scale) >> 8) & 0x00FF00FF; //
|
||||
wg = (wg * scale) & 0xFF00FF00;
|
||||
} else wg = wg << 8; //shift white and green back to correct position
|
||||
return rb | wg;
|
||||
} else {
|
||||
uint32_t r = R(c1) + R(c2);
|
||||
uint32_t g = G(c1) + G(c2);
|
||||
uint32_t b = B(c1) + B(c2);
|
||||
uint32_t w = W(c1) + W(c2);
|
||||
unsigned max = r;
|
||||
if (g > max) max = g;
|
||||
if (b > max) max = b;
|
||||
if (w > max) max = w;
|
||||
if (max < 256) return RGBW32(r, g, b, w);
|
||||
else return RGBW32(r * 255 / max, g * 255 / max, b * 255 / max, w * 255 / max);
|
||||
r = r > 255 ? 255 : r;
|
||||
g = g > 255 ? 255 : g;
|
||||
b = b > 255 ? 255 : b;
|
||||
w = w > 255 ? 255 : w;
|
||||
return RGBW32(r,g,b,w);
|
||||
}
|
||||
}
|
||||
|
||||
@ -70,27 +65,53 @@ uint32_t color_add(uint32_t c1, uint32_t c2, bool fast)
|
||||
|
||||
uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
|
||||
{
|
||||
if (c1 == BLACK || amount + video == 0) return BLACK;
|
||||
if (amount == 255) return c1;
|
||||
if (c1 == BLACK || amount == 0) return BLACK;
|
||||
uint32_t scaledcolor; // color order is: W R G B from MSB to LSB
|
||||
uint32_t r = R(c1);
|
||||
uint32_t g = G(c1);
|
||||
uint32_t b = B(c1);
|
||||
uint32_t w = W(c1);
|
||||
uint32_t scale = amount; // 32bit for faster calculation
|
||||
if (video) {
|
||||
scaledcolor = (((r * scale) >> 8) + ((r && scale) ? 1 : 0)) << 16;
|
||||
scaledcolor |= (((g * scale) >> 8) + ((g && scale) ? 1 : 0)) << 8;
|
||||
scaledcolor |= ((b * scale) >> 8) + ((b && scale) ? 1 : 0);
|
||||
scaledcolor |= (((w * scale) >> 8) + ((w && scale) ? 1 : 0)) << 24;
|
||||
} else {
|
||||
scaledcolor = ((r * scale) >> 8) << 16;
|
||||
scaledcolor |= ((g * scale) >> 8) << 8;
|
||||
scaledcolor |= (b * scale) >> 8;
|
||||
scaledcolor |= ((w * scale) >> 8) << 24;
|
||||
uint32_t addRemains = 0;
|
||||
if (!video) scale++; // add one for correct scaling using bitshifts
|
||||
else { // video scaling: make sure colors do not dim to zero if they started non-zero
|
||||
addRemains = R(c1) ? 0x00010000 : 0;
|
||||
addRemains |= G(c1) ? 0x00000100 : 0;
|
||||
addRemains |= B(c1) ? 0x00000001 : 0;
|
||||
addRemains |= W(c1) ? 0x01000000 : 0;
|
||||
}
|
||||
uint32_t rb = (((c1 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue
|
||||
uint32_t wg = (((c1 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green
|
||||
scaledcolor = (rb | wg) + addRemains;
|
||||
return scaledcolor;
|
||||
}
|
||||
|
||||
// 1:1 replacement of fastled function optimized for ESP, slightly faster, more accurate and uses less flash (~ -200bytes)
|
||||
uint32_t ColorFromPaletteWLED(const CRGBPalette16& pal, unsigned index, uint8_t brightness, TBlendType blendType)
|
||||
{
|
||||
if (blendType == LINEARBLEND_NOWRAP) {
|
||||
index = (index*240) >> 8; // Blend range is affected by lo4 blend of values, remap to avoid wrapping
|
||||
}
|
||||
unsigned hi4 = byte(index) >> 4;
|
||||
const CRGB* entry = (CRGB*)((uint8_t*)(&(pal[0])) + (hi4 * sizeof(CRGB)));
|
||||
unsigned red1 = entry->r;
|
||||
unsigned green1 = entry->g;
|
||||
unsigned blue1 = entry->b;
|
||||
if (blendType != NOBLEND) {
|
||||
if (hi4 == 15) entry = &(pal[0]);
|
||||
else ++entry;
|
||||
unsigned f2 = ((index & 0x0F) << 4) + 1; // +1 so we scale by 256 as a max value, then result can just be shifted by 8
|
||||
unsigned f1 = (257 - f2); // f2 is 1 minimum, so this is 256 max
|
||||
red1 = (red1 * f1 + (unsigned)entry->r * f2) >> 8;
|
||||
green1 = (green1 * f1 + (unsigned)entry->g * f2) >> 8;
|
||||
blue1 = (blue1 * f1 + (unsigned)entry->b * f2) >> 8;
|
||||
}
|
||||
if (brightness < 255) { // note: zero checking could be done to return black but that is hardly ever used so it is omitted
|
||||
uint32_t scale = brightness + 1; // adjust for rounding (bitshift)
|
||||
red1 = (red1 * scale) >> 8;
|
||||
green1 = (green1 * scale) >> 8;
|
||||
blue1 = (blue1 * scale) >> 8;
|
||||
}
|
||||
return RGBW32(red1,green1,blue1,0);
|
||||
}
|
||||
|
||||
void setRandomColor(byte* rgb)
|
||||
{
|
||||
lastRandomIndex = get_random_wheel_index(lastRandomIndex);
|
||||
@ -103,91 +124,91 @@ void setRandomColor(byte* rgb)
|
||||
*/
|
||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
|
||||
{
|
||||
CHSV palettecolors[4]; //array of colors for the new palette
|
||||
uint8_t keepcolorposition = random8(4); //color position of current random palette to keep
|
||||
palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette
|
||||
palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color
|
||||
//generate 4 saturation and brightness value numbers
|
||||
//only one saturation is allowed to be below 200 creating mostly vibrant colors
|
||||
//only one brightness value number is allowed below 200, creating mostly bright palettes
|
||||
CHSV palettecolors[4]; // array of colors for the new palette
|
||||
uint8_t keepcolorposition = hw_random8(4); // color position of current random palette to keep
|
||||
palettecolors[keepcolorposition] = rgb2hsv(basepalette.entries[keepcolorposition*5]); // read one of the base colors of the current palette
|
||||
palettecolors[keepcolorposition].hue += hw_random8(10)-5; // +/- 5 randomness of base color
|
||||
// generate 4 saturation and brightness value numbers
|
||||
// only one saturation is allowed to be below 200 creating mostly vibrant colors
|
||||
// only one brightness value number is allowed below 200, creating mostly bright palettes
|
||||
|
||||
for (int i = 0; i < 3; i++) { //generate three high values
|
||||
palettecolors[i].saturation = random8(200,255);
|
||||
palettecolors[i].value = random8(220,255);
|
||||
for (int i = 0; i < 3; i++) { // generate three high values
|
||||
palettecolors[i].saturation = hw_random8(200,255);
|
||||
palettecolors[i].value = hw_random8(220,255);
|
||||
}
|
||||
//allow one to be lower
|
||||
palettecolors[3].saturation = random8(20,255);
|
||||
palettecolors[3].value = random8(80,255);
|
||||
// allow one to be lower
|
||||
palettecolors[3].saturation = hw_random8(20,255);
|
||||
palettecolors[3].value = hw_random8(80,255);
|
||||
|
||||
//shuffle the arrays
|
||||
// shuffle the arrays
|
||||
for (int i = 3; i > 0; i--) {
|
||||
std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation);
|
||||
std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value);
|
||||
std::swap(palettecolors[i].saturation, palettecolors[hw_random8(i + 1)].saturation);
|
||||
std::swap(palettecolors[i].value, palettecolors[hw_random8(i + 1)].value);
|
||||
}
|
||||
|
||||
//now generate three new hues based off of the hue of the chosen current color
|
||||
// now generate three new hues based off of the hue of the chosen current color
|
||||
uint8_t basehue = palettecolors[keepcolorposition].hue;
|
||||
uint8_t harmonics[3]; //hues that are harmonic but still a little random
|
||||
uint8_t type = random8(5); //choose a harmony type
|
||||
uint8_t harmonics[3]; // hues that are harmonic but still a little random
|
||||
uint8_t type = hw_random8(5); // choose a harmony type
|
||||
|
||||
switch (type) {
|
||||
case 0: // analogous
|
||||
harmonics[0] = basehue + random8(30, 50);
|
||||
harmonics[1] = basehue + random8(10, 30);
|
||||
harmonics[2] = basehue - random8(10, 30);
|
||||
harmonics[0] = basehue + hw_random8(30, 50);
|
||||
harmonics[1] = basehue + hw_random8(10, 30);
|
||||
harmonics[2] = basehue - hw_random8(10, 30);
|
||||
break;
|
||||
|
||||
case 1: // triadic
|
||||
harmonics[0] = basehue + 113 + random8(15);
|
||||
harmonics[1] = basehue + 233 + random8(15);
|
||||
harmonics[2] = basehue - 7 + random8(15);
|
||||
harmonics[0] = basehue + 113 + hw_random8(15);
|
||||
harmonics[1] = basehue + 233 + hw_random8(15);
|
||||
harmonics[2] = basehue - 7 + hw_random8(15);
|
||||
break;
|
||||
|
||||
case 2: // split-complementary
|
||||
harmonics[0] = basehue + 145 + random8(10);
|
||||
harmonics[1] = basehue + 205 + random8(10);
|
||||
harmonics[2] = basehue - 5 + random8(10);
|
||||
harmonics[0] = basehue + 145 + hw_random8(10);
|
||||
harmonics[1] = basehue + 205 + hw_random8(10);
|
||||
harmonics[2] = basehue - 5 + hw_random8(10);
|
||||
break;
|
||||
|
||||
|
||||
case 3: // square
|
||||
harmonics[0] = basehue + 85 + random8(10);
|
||||
harmonics[1] = basehue + 175 + random8(10);
|
||||
harmonics[2] = basehue + 265 + random8(10);
|
||||
harmonics[0] = basehue + 85 + hw_random8(10);
|
||||
harmonics[1] = basehue + 175 + hw_random8(10);
|
||||
harmonics[2] = basehue + 265 + hw_random8(10);
|
||||
break;
|
||||
|
||||
case 4: // tetradic
|
||||
harmonics[0] = basehue + 80 + random8(20);
|
||||
harmonics[1] = basehue + 170 + random8(20);
|
||||
harmonics[2] = basehue - 15 + random8(30);
|
||||
harmonics[0] = basehue + 80 + hw_random8(20);
|
||||
harmonics[1] = basehue + 170 + hw_random8(20);
|
||||
harmonics[2] = basehue - 15 + hw_random8(30);
|
||||
break;
|
||||
}
|
||||
|
||||
if (random8() < 128) {
|
||||
//50:50 chance of shuffling hues or keep the color order
|
||||
if (hw_random8() < 128) {
|
||||
// 50:50 chance of shuffling hues or keep the color order
|
||||
for (int i = 2; i > 0; i--) {
|
||||
std::swap(harmonics[i], harmonics[random8(i + 1)]);
|
||||
std::swap(harmonics[i], harmonics[hw_random8(i + 1)]);
|
||||
}
|
||||
}
|
||||
|
||||
//now set the hues
|
||||
// now set the hues
|
||||
int j = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (i==keepcolorposition) continue; //skip the base color
|
||||
if (i==keepcolorposition) continue; // skip the base color
|
||||
palettecolors[i].hue = harmonics[j];
|
||||
j++;
|
||||
}
|
||||
|
||||
bool makepastelpalette = false;
|
||||
if (random8() < 25) { //~10% chance of desaturated 'pastel' colors
|
||||
if (hw_random8() < 25) { // ~10% chance of desaturated 'pastel' colors
|
||||
makepastelpalette = true;
|
||||
}
|
||||
|
||||
//apply saturation & gamma correction
|
||||
// apply saturation & gamma correction
|
||||
CRGB RGBpalettecolors[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (makepastelpalette && palettecolors[i].saturation > 180) {
|
||||
if (makepastelpalette && palettecolors[i].saturation > 180) {
|
||||
palettecolors[i].saturation -= 160; //desaturate all four colors
|
||||
}
|
||||
}
|
||||
RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB
|
||||
RGBpalettecolors[i] = gamma32(((uint32_t)RGBpalettecolors[i]) & 0x00FFFFFFU); //strip alpha from CRGB
|
||||
}
|
||||
@ -198,34 +219,72 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette)
|
||||
RGBpalettecolors[3]);
|
||||
}
|
||||
|
||||
CRGBPalette16 generateRandomPalette() //generate fully random palette
|
||||
CRGBPalette16 generateRandomPalette() // generate fully random palette
|
||||
{
|
||||
return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||
CHSV(random8(), random8(160, 255), random8(128, 255)),
|
||||
CHSV(random8(), random8(160, 255), random8(128, 255)));
|
||||
return CRGBPalette16(CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
|
||||
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
|
||||
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)),
|
||||
CHSV(hw_random8(), hw_random8(160, 255), hw_random8(128, 255)));
|
||||
}
|
||||
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
||||
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb) // convert HSV (16bit hue) to RGB (32bit with white = 0)
|
||||
{
|
||||
float h = ((float)hue)/10922.5f; // hue*6/65535
|
||||
float s = ((float)sat)/255.0f;
|
||||
int i = int(h);
|
||||
float f = h - i;
|
||||
int p = int(255.0f * (1.0f-s));
|
||||
int q = int(255.0f * (1.0f-s*f));
|
||||
int t = int(255.0f * (1.0f-s*(1.0f-f)));
|
||||
p = constrain(p, 0, 255);
|
||||
q = constrain(q, 0, 255);
|
||||
t = constrain(t, 0, 255);
|
||||
switch (i%6) {
|
||||
case 0: rgb[0]=255,rgb[1]=t, rgb[2]=p; break;
|
||||
case 1: rgb[0]=q, rgb[1]=255,rgb[2]=p; break;
|
||||
case 2: rgb[0]=p, rgb[1]=255,rgb[2]=t; break;
|
||||
case 3: rgb[0]=p, rgb[1]=q, rgb[2]=255;break;
|
||||
case 4: rgb[0]=t, rgb[1]=p, rgb[2]=255;break;
|
||||
case 5: rgb[0]=255,rgb[1]=p, rgb[2]=q; break;
|
||||
unsigned int remainder, region, p, q, t;
|
||||
unsigned int h = hsv.h;
|
||||
unsigned int s = hsv.s;
|
||||
unsigned int v = hsv.v;
|
||||
if (s == 0) {
|
||||
rgb = v << 16 | v << 8 | v;
|
||||
return;
|
||||
}
|
||||
region = h / 10923; // 65536 / 6 = 10923
|
||||
remainder = (h - (region * 10923)) * 6;
|
||||
p = (v * (255 - s)) >> 8;
|
||||
q = (v * (255 - ((s * remainder) >> 16))) >> 8;
|
||||
t = (v * (255 - ((s * (65535 - remainder)) >> 16))) >> 8;
|
||||
switch (region) {
|
||||
case 0:
|
||||
rgb = v << 16 | t << 8 | p; break;
|
||||
case 1:
|
||||
rgb = q << 16 | v << 8 | p; break;
|
||||
case 2:
|
||||
rgb = p << 16 | v << 8 | t; break;
|
||||
case 3:
|
||||
rgb = p << 16 | q << 8 | v; break;
|
||||
case 4:
|
||||
rgb = t << 16 | p << 8 | v; break;
|
||||
default:
|
||||
rgb = v << 16 | p << 8 | q; break;
|
||||
}
|
||||
}
|
||||
|
||||
void rgb2hsv(const uint32_t rgb, CHSV32& hsv) // convert RGB to HSV (16bit hue), much more accurate and faster than fastled version
|
||||
{
|
||||
hsv.raw = 0;
|
||||
int32_t r = (rgb>>16)&0xFF;
|
||||
int32_t g = (rgb>>8)&0xFF;
|
||||
int32_t b = rgb&0xFF;
|
||||
int32_t minval, maxval, delta;
|
||||
minval = min(r, g);
|
||||
minval = min(minval, b);
|
||||
maxval = max(r, g);
|
||||
maxval = max(maxval, b);
|
||||
if (maxval == 0) return; // black
|
||||
hsv.v = maxval;
|
||||
delta = maxval - minval;
|
||||
hsv.s = (255 * delta) / maxval;
|
||||
if (hsv.s == 0) return; // gray value
|
||||
if (maxval == r) hsv.h = (10923 * (g - b)) / delta;
|
||||
else if (maxval == g) hsv.h = 21845 + (10923 * (b - r)) / delta;
|
||||
else hsv.h = 43690 + (10923 * (r - g)) / delta;
|
||||
}
|
||||
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) { //hue, sat to rgb
|
||||
uint32_t crgb;
|
||||
hsv2rgb(CHSV32(hue, sat, 255), crgb);
|
||||
rgb[0] = byte((crgb) >> 16);
|
||||
rgb[1] = byte((crgb) >> 8);
|
||||
rgb[2] = byte(crgb);
|
||||
}
|
||||
|
||||
//get RGB values from color temperature in K (https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html)
|
||||
@ -452,24 +511,8 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
||||
}
|
||||
}
|
||||
|
||||
//gamma 2.8 lookup table used for color correction
|
||||
uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
|
||||
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
|
||||
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
|
||||
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
|
||||
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
|
||||
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
|
||||
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
|
||||
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
|
||||
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
|
||||
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
|
||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||
// gamma lookup table used for color correction (filled on 1st use (cfg.cpp & set.cpp))
|
||||
uint8_t NeoGammaWLEDMethod::gammaT[256];
|
||||
|
||||
// re-calculates & fills gamma table
|
||||
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Readability defines and their associated numerical values + compile-time constants
|
||||
*/
|
||||
|
||||
#define GRADIENT_PALETTE_COUNT 58
|
||||
#define GRADIENT_PALETTE_COUNT 59
|
||||
|
||||
// You can define custom product info from build flags.
|
||||
// This is useful to allow API consumer to identify what type of WLED version
|
||||
|
@ -761,7 +761,7 @@ Swap: <select id="xw${s}" name="XW${s}">
|
||||
Enable automatic brightness limiter: <input type="checkbox" name="ABL" onchange="enABL()"><br>
|
||||
<div id="abl">
|
||||
<i>Automatically limits brightness to stay close to the limit.<br>
|
||||
Keep at <1A if poweing LEDs directly from the ESP 5V pin!<br>
|
||||
Keep at <1A if powering LEDs directly from the ESP 5V pin!<br>
|
||||
If using multiple outputs it is recommended to use per-output limiter.<br>
|
||||
Analog (PWM) and virtual LEDs cannot use automatic brightness limiter.<br></i>
|
||||
<div id="psuMA">Maximum PSU Current: <input name="MA" type="number" class="xl" min="250" max="65000" oninput="UI()" required> mA<br></div>
|
||||
|
@ -39,6 +39,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_DDP);
|
||||
|
||||
if (!realtimeOverride || (realtimeMode && useMainSegmentOnly)) {
|
||||
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||
for (unsigned i = start; i < stop; i++, c += ddpChannelsPerLed) {
|
||||
setRealtimePixel(i, data[c], data[c+1], data[c+2], ddpChannelsPerLed >3 ? data[c+3] : 0);
|
||||
}
|
||||
@ -147,6 +148,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||
|
||||
wChannel = (availDMXLen > 3) ? e131_data[dataOffset+3] : 0;
|
||||
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||
for (unsigned i = 0; i < totalLen; i++)
|
||||
setRealtimePixel(i, e131_data[dataOffset+0], e131_data[dataOffset+1], e131_data[dataOffset+2], wChannel);
|
||||
break;
|
||||
@ -164,6 +166,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
strip.setBrightness(bri, true);
|
||||
}
|
||||
|
||||
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||
for (unsigned i = 0; i < totalLen; i++)
|
||||
setRealtimePixel(i, e131_data[dataOffset+1], e131_data[dataOffset+2], e131_data[dataOffset+3], wChannel);
|
||||
break;
|
||||
@ -308,6 +311,7 @@ void handleE131Packet(e131_packet_t* p, IPAddress clientIP, byte protocol){
|
||||
}
|
||||
}
|
||||
|
||||
if (useMainSegmentOnly) strip.getMainSegment().beginDraw();
|
||||
if (!is4Chan) {
|
||||
for (unsigned i = previousLeds; i < ledsTotal; i++) {
|
||||
setRealtimePixel(i, e131_data[dmxOffset], e131_data[dmxOffset+1], e131_data[dmxOffset+2], 0);
|
||||
|
@ -66,6 +66,89 @@ typedef struct WiFiConfig {
|
||||
} wifi_config;
|
||||
|
||||
//colors.cpp
|
||||
#define ColorFromPalette ColorFromPaletteWLED // override fastled version
|
||||
|
||||
// CRGBW can be used to manipulate 32bit colors faster. However: if it is passed to functions, it adds overhead compared to a uint32_t color
|
||||
// use with caution and pay attention to flash size. Usually converting a uint32_t to CRGBW to extract r, g, b, w values is slower than using bitshifts
|
||||
// it can be useful to avoid back and forth conversions between uint32_t and fastled CRGB
|
||||
struct CRGBW {
|
||||
union {
|
||||
uint32_t color32; // Access as a 32-bit value (0xWWRRGGBB)
|
||||
struct {
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
uint8_t w;
|
||||
};
|
||||
uint8_t raw[4]; // Access as an array in the order B, G, R, W
|
||||
};
|
||||
|
||||
// Default constructor
|
||||
inline CRGBW() __attribute__((always_inline)) = default;
|
||||
|
||||
// Constructor from a 32-bit color (0xWWRRGGBB)
|
||||
constexpr CRGBW(uint32_t color) __attribute__((always_inline)) : color32(color) {}
|
||||
|
||||
// Constructor with r, g, b, w values
|
||||
constexpr CRGBW(uint8_t red, uint8_t green, uint8_t blue, uint8_t white = 0) __attribute__((always_inline)) : b(blue), g(green), r(red), w(white) {}
|
||||
|
||||
// Constructor from CRGB
|
||||
constexpr CRGBW(CRGB rgb) __attribute__((always_inline)) : b(rgb.b), g(rgb.g), r(rgb.r), w(0) {}
|
||||
|
||||
// Access as an array
|
||||
inline const uint8_t& operator[] (uint8_t x) const __attribute__((always_inline)) { return raw[x]; }
|
||||
|
||||
// Assignment from 32-bit color
|
||||
inline CRGBW& operator=(uint32_t color) __attribute__((always_inline)) { color32 = color; return *this; }
|
||||
|
||||
// Assignment from r, g, b, w
|
||||
inline CRGBW& operator=(const CRGB& rgb) __attribute__((always_inline)) { b = rgb.b; g = rgb.g; r = rgb.r; w = 0; return *this; }
|
||||
|
||||
// Conversion operator to uint32_t
|
||||
inline operator uint32_t() const __attribute__((always_inline)) {
|
||||
return color32;
|
||||
}
|
||||
/*
|
||||
// Conversion operator to CRGB
|
||||
inline operator CRGB() const __attribute__((always_inline)) {
|
||||
return CRGB(r, g, b);
|
||||
}
|
||||
|
||||
CRGBW& scale32 (uint8_t scaledown) // 32bit math
|
||||
{
|
||||
if (color32 == 0) return *this; // 2 extra instructions, worth it if called a lot on black (which probably is true) adding check if scaledown is zero adds much more overhead as its 8bit
|
||||
uint32_t scale = scaledown + 1;
|
||||
uint32_t rb = (((color32 & 0x00FF00FF) * scale) >> 8) & 0x00FF00FF; // scale red and blue
|
||||
uint32_t wg = (((color32 & 0xFF00FF00) >> 8) * scale) & 0xFF00FF00; // scale white and green
|
||||
color32 = rb | wg;
|
||||
return *this;
|
||||
}*/
|
||||
|
||||
};
|
||||
|
||||
struct CHSV32 { // 32bit HSV color with 16bit hue for more accurate conversions
|
||||
union {
|
||||
struct {
|
||||
uint16_t h; // hue
|
||||
uint8_t s; // saturation
|
||||
uint8_t v; // value
|
||||
};
|
||||
uint32_t raw; // 32bit access
|
||||
};
|
||||
inline CHSV32() __attribute__((always_inline)) = default; // default constructor
|
||||
|
||||
/// Allow construction from hue, saturation, and value
|
||||
/// @param ih input hue
|
||||
/// @param is input saturation
|
||||
/// @param iv input value
|
||||
inline CHSV32(uint16_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 16bit h, s, v
|
||||
: h(ih), s(is), v(iv) {}
|
||||
inline CHSV32(uint8_t ih, uint8_t is, uint8_t iv) __attribute__((always_inline)) // constructor from 8bit h, s, v
|
||||
: h((uint16_t)ih << 8), s(is), v(iv) {}
|
||||
inline CHSV32(const CHSV& chsv) __attribute__((always_inline)) // constructor from CHSV
|
||||
: h((uint16_t)chsv.h << 8), s(chsv.s), v(chsv.v) {}
|
||||
inline operator CHSV() const { return CHSV((uint8_t)(h >> 8), s, v); } // typecast to CHSV
|
||||
};
|
||||
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
|
||||
class NeoGammaWLEDMethod {
|
||||
public:
|
||||
@ -78,13 +161,18 @@ class NeoGammaWLEDMethod {
|
||||
};
|
||||
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||
[[gnu::hot]] uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||
[[gnu::hot]] uint32_t color_add(uint32_t,uint32_t, bool fast=false);
|
||||
[[gnu::hot]] uint32_t color_blend(uint32_t c1, uint32_t c2 , uint8_t blend);
|
||||
inline uint32_t color_blend16(uint32_t c1, uint32_t c2, uint16_t b) { return color_blend(c1, c2, b >> 8); };
|
||||
[[gnu::hot]] uint32_t color_add(uint32_t, uint32_t, bool preserveCR = false);
|
||||
[[gnu::hot]] uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false);
|
||||
[[gnu::hot]] uint32_t ColorFromPaletteWLED(const CRGBPalette16 &pal, unsigned index, uint8_t brightness = (uint8_t)255U, TBlendType blendType = LINEARBLEND);
|
||||
CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette);
|
||||
CRGBPalette16 generateRandomPalette();
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void hsv2rgb(const CHSV32& hsv, uint32_t& rgb);
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb);
|
||||
void rgb2hsv(const uint32_t rgb, CHSV32& hsv);
|
||||
inline CHSV rgb2hsv(const CRGB c) { CHSV32 hsv; rgb2hsv((uint32_t((byte(c.r) << 16) | (byte(c.g) << 8) | (byte(c.b)))), hsv); return CHSV(hsv); } // CRGB to hsv
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
||||
void colorXYtoRGB(float x, float y, byte* rgb); // only defined if huesync disabled TODO
|
||||
@ -370,6 +458,12 @@ void userConnected();
|
||||
void userLoop();
|
||||
|
||||
//util.cpp
|
||||
#ifdef ESP8266
|
||||
#define HW_RND_REGISTER RANDOM_REG32
|
||||
#else // ESP32 family
|
||||
#include "soc/wdev_reg.h"
|
||||
#define HW_RND_REGISTER REG_READ(WDEV_RND_REG)
|
||||
#endif
|
||||
int getNumVal(const String* req, uint16_t pos);
|
||||
void parseNumber(const char* str, byte* val, byte minv=0, byte maxv=255);
|
||||
bool getVal(JsonVariant elem, byte* val, byte minv=0, byte maxv=255); // getVal supports inc/decrementing and random ("X~Y(r|~[w][-][Z])" form)
|
||||
@ -397,6 +491,23 @@ void enumerateLedmaps();
|
||||
uint8_t get_random_wheel_index(uint8_t pos);
|
||||
float mapf(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
|
||||
// fast (true) random numbers using hardware RNG, all functions return values in the range lowerlimit to upperlimit-1
|
||||
// note: for true random numbers with high entropy, do not call faster than every 200ns (5MHz)
|
||||
// tests show it is still highly random reading it quickly in a loop (better than fastled PRNG)
|
||||
// for 8bit and 16bit random functions: no limit check is done for best speed
|
||||
// 32bit inputs are used for speed and code size, limits don't work if inverted or out of range
|
||||
// inlining does save code size except for random(a,b) and 32bit random with limits
|
||||
#define random hw_random // replace arduino random()
|
||||
inline uint32_t hw_random() { return HW_RND_REGISTER; };
|
||||
uint32_t hw_random(uint32_t upperlimit); // not inlined for code size
|
||||
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit);
|
||||
inline uint16_t hw_random16() { return HW_RND_REGISTER; };
|
||||
inline uint16_t hw_random16(uint32_t upperlimit) { return (hw_random16() * upperlimit) >> 16; }; // input range 0-65535 (uint16_t)
|
||||
inline int16_t hw_random16(int32_t lowerlimit, int32_t upperlimit) { int32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random16(range); }; // signed limits, use int16_t ranges
|
||||
inline uint8_t hw_random8() { return HW_RND_REGISTER; };
|
||||
inline uint8_t hw_random8(uint32_t upperlimit) { return (hw_random8() * upperlimit) >> 8; }; // input range 0-255
|
||||
inline uint8_t hw_random8(uint32_t lowerlimit, uint32_t upperlimit) { uint32_t range = upperlimit - lowerlimit; return lowerlimit + hw_random8(range); }; // input range 0-255
|
||||
|
||||
// RAII guard class for the JSON Buffer lock
|
||||
// Modeled after std::lock_guard
|
||||
class JSONBufferGuard {
|
||||
|
@ -129,7 +129,7 @@ static void changeEffectSpeed(int8_t amount)
|
||||
} else { // if Effect == "solid Color", change the hue of the primary color
|
||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col = CRGB(sseg.colors[0]);
|
||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
CHSV prim_hsv = rgb2hsv(fastled_col);
|
||||
int16_t new_val = (int16_t)prim_hsv.h + amount;
|
||||
if (new_val > 255) new_val -= 255; // roll-over if bigger than 255
|
||||
if (new_val < 0) new_val += 255; // roll-over if smaller than 0
|
||||
@ -173,7 +173,7 @@ static void changeEffectIntensity(int8_t amount)
|
||||
} else { // if Effect == "solid Color", change the saturation of the primary color
|
||||
Segment& sseg = irApplyToAllSelected ? strip.getFirstSelectedSeg() : strip.getMainSegment();
|
||||
CRGB fastled_col = CRGB(sseg.colors[0]);
|
||||
CHSV prim_hsv = rgb2hsv_approximate(fastled_col);
|
||||
CHSV prim_hsv = rgb2hsv(fastled_col);
|
||||
int16_t new_val = (int16_t) prim_hsv.s + amount;
|
||||
prim_hsv.s = (byte)constrain(new_val,0,255); // constrain to 0-255
|
||||
hsv2rgb_rainbow(prim_hsv, fastled_col);
|
||||
@ -435,7 +435,7 @@ static void decodeIR44(uint32_t code)
|
||||
case IR44_DIY2 : presetFallback(2, FX_MODE_BREATH, 0); break;
|
||||
case IR44_DIY3 : presetFallback(3, FX_MODE_FIRE_FLICKER, 0); break;
|
||||
case IR44_DIY4 : presetFallback(4, FX_MODE_RAINBOW, 0); break;
|
||||
case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR_SMOOTH, 0); break;
|
||||
case IR44_DIY5 : presetFallback(5, FX_MODE_METEOR, 0); break;
|
||||
case IR44_DIY6 : presetFallback(6, FX_MODE_RAIN, 0); break;
|
||||
case IR44_AUTO : changeEffect(FX_MODE_STATIC); break;
|
||||
case IR44_FLASH : changeEffect(FX_MODE_PALETTE); break;
|
||||
@ -593,7 +593,7 @@ static void decodeIRJson(uint32_t code)
|
||||
decBrightness();
|
||||
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
|
||||
uint8_t p1 = fdo["PL"] | 1;
|
||||
uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1);
|
||||
uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1);
|
||||
uint8_t p3 = fdo["FP"] | 0;
|
||||
presetFallback(p1, p2, p3);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
//DEBUG_PRINTLN(F("-- JSON deserialize segment."));
|
||||
Segment& seg = strip.getSegment(id);
|
||||
//DEBUG_PRINTF_P(PSTR("-- Original segment: %p (%p)\n"), &seg, seg.data);
|
||||
Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor)
|
||||
const Segment prev = seg; //make a backup so we can tell if something changed (calling copy constructor)
|
||||
//DEBUG_PRINTF_P(PSTR("-- Duplicate segment: %p (%p)\n"), &prev, prev.data);
|
||||
|
||||
int start = elem["start"] | seg.start;
|
||||
@ -96,17 +96,11 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
uint16_t of = seg.offset;
|
||||
uint8_t soundSim = elem["si"] | seg.soundSim;
|
||||
uint8_t map1D2D = elem["m12"] | seg.map1D2D;
|
||||
|
||||
if ((spc>0 && spc!=seg.spacing) || seg.map1D2D!=map1D2D) seg.fill(BLACK); // clear spacing gaps
|
||||
|
||||
seg.map1D2D = constrain(map1D2D, 0, 7);
|
||||
uint8_t set = elem[F("set")] | seg.set;
|
||||
seg.set = constrain(set, 0, 3);
|
||||
seg.soundSim = constrain(soundSim, 0, 3);
|
||||
|
||||
uint8_t set = elem[F("set")] | seg.set;
|
||||
seg.set = constrain(set, 0, 3);
|
||||
|
||||
int len = 1;
|
||||
if (stop > start) len = stop - start;
|
||||
int len = (stop > start) ? stop - start : 1;
|
||||
int offset = elem[F("of")] | INT32_MAX;
|
||||
if (offset != INT32_MAX) {
|
||||
int offsetAbs = abs(offset);
|
||||
@ -117,7 +111,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
if (stop > start && of > len -1) of = len -1;
|
||||
|
||||
// update segment (delete if necessary)
|
||||
seg.setUp(start, stop, grp, spc, of, startY, stopY); // strip needs to be suspended for this to work without issues
|
||||
seg.setGeometry(start, stop, grp, spc, of, startY, stopY, map1D2D); // strip needs to be suspended for this to work without issues
|
||||
|
||||
if (newSeg) seg.refreshLightCapabilities(); // fix for #3403
|
||||
|
||||
|
@ -75,6 +75,7 @@ byte scaledBri(byte in)
|
||||
void applyBri() {
|
||||
if (!realtimeMode || !arlsForceMaxBri)
|
||||
{
|
||||
//DEBUG_PRINTF_P(PSTR("Applying strip brightness: %d (%d,%d)\n"), (int)briT, (int)bri, (int)briOld);
|
||||
strip.setBrightness(scaledBri(briT));
|
||||
}
|
||||
}
|
||||
@ -139,7 +140,6 @@ void stateUpdated(byte callMode) {
|
||||
|
||||
if (transitionActive) {
|
||||
briOld = briT;
|
||||
tperLast = 0;
|
||||
} else
|
||||
strip.setTransitionMode(true); // force all segments to transition mode
|
||||
transitionActive = true;
|
||||
@ -179,22 +179,21 @@ void handleTransitions()
|
||||
updateInterfaces(interfaceUpdateCallMode);
|
||||
|
||||
if (transitionActive && strip.getTransition() > 0) {
|
||||
float tper = (millis() - transitionStartTime)/(float)strip.getTransition();
|
||||
if (tper >= 1.0f) {
|
||||
int ti = millis() - transitionStartTime;
|
||||
int tr = strip.getTransition();
|
||||
if (ti/tr) {
|
||||
strip.setTransitionMode(false); // stop all transitions
|
||||
// restore (global) transition time if not called from UDP notifier or single/temporary transition from JSON (also playlist)
|
||||
if (jsonTransitionOnce) strip.setTransition(transitionDelay);
|
||||
transitionActive = false;
|
||||
jsonTransitionOnce = false;
|
||||
tperLast = 0;
|
||||
applyFinalBri();
|
||||
return;
|
||||
}
|
||||
if (tper - tperLast < 0.004f) return; // less than 1 bit change (1/255)
|
||||
tperLast = tper;
|
||||
briT = briOld + ((bri - briOld) * tper);
|
||||
|
||||
applyBri();
|
||||
byte briTO = briT;
|
||||
int deltaBri = (int)bri - (int)briOld;
|
||||
briT = briOld + (deltaBri * ti / tr);
|
||||
if (briTO != briT) applyBri();
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,8 +228,8 @@ void handleNightlight()
|
||||
colNlT[1] = effectSpeed;
|
||||
colNlT[2] = effectPalette;
|
||||
|
||||
strip.setMode(strip.getFirstSelectedSegId(), FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode
|
||||
effectCurrent = FX_MODE_SUNRISE;
|
||||
strip.getFirstSelectedSeg().setMode(FX_MODE_STATIC); // make sure seg runtime is reset if it was in sunrise mode
|
||||
effectCurrent = FX_MODE_SUNRISE; // colorUpdated() will take care of assigning that to all selected segments
|
||||
effectSpeed = nightlightDelayMins;
|
||||
effectPalette = 0;
|
||||
if (effectSpeed > 60) effectSpeed = 60; //currently limited to 60 minutes
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Color palettes for FastLED effects (65-73).
|
||||
* 4 bytes per color: index, red, green, blue
|
||||
*/
|
||||
|
||||
// From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
||||
@ -844,6 +845,12 @@ const byte candy2_gp[] PROGMEM = {
|
||||
211, 39, 33, 34,
|
||||
255, 1, 1, 1};
|
||||
|
||||
const byte trafficlight_gp[] PROGMEM = {
|
||||
0, 0, 0, 0, //black
|
||||
85, 0, 255, 0, //green
|
||||
170, 255, 255, 0, //yellow
|
||||
255, 255, 0, 0}; //red
|
||||
|
||||
// array of fastled palettes (palette 6 - 12)
|
||||
const TProgmemRGBPalette16 *const fastledPalettes[] PROGMEM = {
|
||||
&PartyColors_p, //06-00 Party
|
||||
@ -917,7 +924,8 @@ const byte* const gGradientPalettes[] PROGMEM = {
|
||||
blink_red_gp, //67-54 Blink Red
|
||||
red_shift_gp, //68-55 Red Shift
|
||||
red_tide_gp, //69-56 Red Tide
|
||||
candy2_gp //70-57 Candy2
|
||||
candy2_gp, //70-57 Candy2
|
||||
trafficlight_gp //71-58 Traffic Light
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -146,7 +146,7 @@ static bool remoteJson(int button)
|
||||
parsed = true;
|
||||
} else if (cmdStr.startsWith(F("!presetF"))) { //!presetFallback
|
||||
uint8_t p1 = fdo["PL"] | 1;
|
||||
uint8_t p2 = fdo["FX"] | random8(strip.getModeCount() -1);
|
||||
uint8_t p2 = fdo["FX"] | hw_random8(strip.getModeCount() -1);
|
||||
uint8_t p3 = fdo["FP"] | 0;
|
||||
presetWithFallback(p1, p2, p3);
|
||||
parsed = true;
|
||||
|
@ -319,13 +319,12 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
||||
gammaCorrectBri = request->hasArg(F("GB"));
|
||||
gammaCorrectCol = request->hasArg(F("GC"));
|
||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||
else {
|
||||
if (gammaCorrectVal <= 1.0f || gammaCorrectVal > 3) {
|
||||
gammaCorrectVal = 1.0f; // no gamma correction
|
||||
gammaCorrectBri = false;
|
||||
gammaCorrectCol = false;
|
||||
}
|
||||
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal); // fill look-up table
|
||||
|
||||
fadeTransition = request->hasArg(F("TF"));
|
||||
modeBlending = request->hasArg(F("EB"));
|
||||
@ -839,8 +838,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
|
||||
// temporary values, write directly to segments, globals are updated by setValuesFromFirstSelectedSeg()
|
||||
uint32_t col0 = selseg.colors[0];
|
||||
uint32_t col1 = selseg.colors[1];
|
||||
uint32_t col0 = selseg.colors[0];
|
||||
uint32_t col1 = selseg.colors[1];
|
||||
uint32_t col2 = selseg.colors[2];
|
||||
byte colIn[4] = {R(col0), G(col0), B(col0), W(col0)};
|
||||
byte colInSec[4] = {R(col1), G(col1), B(col1), W(col1)};
|
||||
byte effectIn = selseg.mode;
|
||||
@ -875,7 +875,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
spcI = std::max(0,getNumVal(&req, pos));
|
||||
}
|
||||
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY);
|
||||
strip.suspend(); // must suspend strip operations before changing geometry
|
||||
selseg.setGeometry(startI, stopI, grpI, spcI, UINT16_MAX, startY, stopY, selseg.map1D2D);
|
||||
strip.resume();
|
||||
|
||||
pos = req.indexOf(F("RV=")); //Segment reverse
|
||||
if (pos > 0) selseg.reverse = req.charAt(pos+3) != '0';
|
||||
@ -921,7 +923,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
//set brightness
|
||||
updateVal(req.c_str(), "&A=", &bri);
|
||||
|
||||
bool col0Changed = false, col1Changed = false;
|
||||
bool col0Changed = false, col1Changed = false, col2Changed = false;
|
||||
//set colors
|
||||
col0Changed |= updateVal(req.c_str(), "&R=", &colIn[0]);
|
||||
col0Changed |= updateVal(req.c_str(), "&G=", &colIn[1]);
|
||||
@ -978,7 +980,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
|
||||
//set color from HEX or 32bit DEC
|
||||
byte tmpCol[4];
|
||||
pos = req.indexOf(F("CL="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(colIn, (char*)req.substring(pos + 3).c_str());
|
||||
@ -991,10 +992,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
}
|
||||
pos = req.indexOf(F("C3="));
|
||||
if (pos > 0) {
|
||||
byte tmpCol[4];
|
||||
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
||||
uint32_t col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||
col2 = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||
selseg.setColor(2, col2); // defined above (SS= or main)
|
||||
if (!singleSegment) strip.setColor(2, col2); // will set color to all active & selected segments
|
||||
col2Changed = true;
|
||||
}
|
||||
|
||||
//set to random hue SR=0->1st SR=1->2nd
|
||||
@ -1005,29 +1007,22 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
col0Changed |= (!sec); col1Changed |= sec;
|
||||
}
|
||||
|
||||
//swap 2nd & 1st
|
||||
pos = req.indexOf(F("SC"));
|
||||
if (pos > 0) {
|
||||
byte temp;
|
||||
for (unsigned i=0; i<4; i++) {
|
||||
temp = colIn[i];
|
||||
colIn[i] = colInSec[i];
|
||||
colInSec[i] = temp;
|
||||
}
|
||||
col0Changed = col1Changed = true;
|
||||
}
|
||||
|
||||
// apply colors to selected segment, and all selected segments if applicable
|
||||
if (col0Changed) {
|
||||
uint32_t colIn0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]);
|
||||
selseg.setColor(0, colIn0);
|
||||
if (!singleSegment) strip.setColor(0, colIn0); // will set color to all active & selected segments
|
||||
col0 = RGBW32(colIn[0], colIn[1], colIn[2], colIn[3]);
|
||||
selseg.setColor(0, col0);
|
||||
}
|
||||
|
||||
if (col1Changed) {
|
||||
uint32_t colIn1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]);
|
||||
selseg.setColor(1, colIn1);
|
||||
if (!singleSegment) strip.setColor(1, colIn1); // will set color to all active & selected segments
|
||||
col1 = RGBW32(colInSec[0], colInSec[1], colInSec[2], colInSec[3]);
|
||||
selseg.setColor(1, col1);
|
||||
}
|
||||
|
||||
//swap 2nd & 1st
|
||||
pos = req.indexOf(F("SC"));
|
||||
if (pos > 0) {
|
||||
std::swap(col0,col1);
|
||||
col0Changed = col1Changed = true;
|
||||
}
|
||||
|
||||
bool fxModeChanged = false, speedChanged = false, intensityChanged = false, paletteChanged = false;
|
||||
@ -1057,6 +1052,9 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (speedChanged) seg.speed = speedIn;
|
||||
if (intensityChanged) seg.intensity = intensityIn;
|
||||
if (paletteChanged) seg.setPalette(paletteIn);
|
||||
if (col0Changed) seg.setColor(0, col0);
|
||||
if (col1Changed) seg.setColor(1, col1);
|
||||
if (col2Changed) seg.setColor(2, col2);
|
||||
if (custom1Changed) seg.custom1 = custom1In;
|
||||
if (custom2Changed) seg.custom2 = custom2In;
|
||||
if (custom3Changed) seg.custom3 = custom3In;
|
||||
|
@ -234,12 +234,12 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
//apply colors from notification to main segment, only if not syncing full segments
|
||||
if ((receiveNotificationColor || !someSel) && (version < 11 || !receiveSegmentOptions)) {
|
||||
// primary color, only apply white if intented (version > 0)
|
||||
strip.setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0));
|
||||
strip.getMainSegment().setColor(0, RGBW32(udpIn[3], udpIn[4], udpIn[5], (version > 0) ? udpIn[10] : 0));
|
||||
if (version > 1) {
|
||||
strip.setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color
|
||||
strip.getMainSegment().setColor(1, RGBW32(udpIn[12], udpIn[13], udpIn[14], udpIn[15])); // secondary color
|
||||
}
|
||||
if (version > 6) {
|
||||
strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color
|
||||
strip.getMainSegment().setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); // tertiary color
|
||||
if (version > 9 && udpIn[37] < 255) { // valid CCT/Kelvin value
|
||||
unsigned cct = udpIn[38];
|
||||
if (udpIn[37] > 0) { //Kelvin
|
||||
@ -260,11 +260,12 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
// are we syncing bounds and slave has more active segments than master?
|
||||
if (receiveSegmentBounds && numSrcSegs < strip.getActiveSegmentsNum()) {
|
||||
DEBUG_PRINTLN(F("Removing excessive segments."));
|
||||
for (size_t i=strip.getSegmentsNum(); i>numSrcSegs; i--) {
|
||||
if (strip.getSegment(i).isActive()) {
|
||||
strip.setSegment(i-1,0,0); // delete segment
|
||||
}
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
for (size_t i=strip.getSegmentsNum(); i>numSrcSegs && i>0; i--) {
|
||||
Segment &seg = strip.getSegment(i-1);
|
||||
if (seg.isActive()) seg.deactivate(); // delete segment
|
||||
}
|
||||
strip.resume();
|
||||
}
|
||||
size_t inactiveSegs = 0;
|
||||
for (size_t i = 0; i < numSrcSegs && i < strip.getMaxSegments(); i++) {
|
||||
@ -300,7 +301,7 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
if (!receiveSegmentOptions) {
|
||||
DEBUG_PRINTF_P(PSTR("Set segment w/o options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY);
|
||||
selseg.setGeometry(start, stop, selseg.grouping, selseg.spacing, offset, startY, stopY, selseg.map1D2D);
|
||||
strip.resume();
|
||||
continue; // we do receive bounds, but not options
|
||||
}
|
||||
@ -342,12 +343,12 @@ void parseNotifyPacket(uint8_t *udpIn) {
|
||||
if (receiveSegmentBounds) {
|
||||
DEBUG_PRINTF_P(PSTR("Set segment w/ options: %d [%d,%d;%d,%d]\n"), id, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY);
|
||||
selseg.setGeometry(start, stop, udpIn[5+ofs], udpIn[6+ofs], offset, startY, stopY, selseg.map1D2D);
|
||||
strip.resume();
|
||||
} else {
|
||||
DEBUG_PRINTF_P(PSTR("Set segment grouping: %d [%d,%d]\n"), id, (int)udpIn[5+ofs], (int)udpIn[6+ofs]);
|
||||
strip.suspend(); //should not be needed as UDP handling is not done in ISR callbacks but still added "just in case"
|
||||
selseg.setUp(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY);
|
||||
selseg.setGeometry(selseg.start, selseg.stop, udpIn[5+ofs], udpIn[6+ofs], selseg.offset, selseg.startY, selseg.stopY, selseg.map1D2D);
|
||||
strip.resume();
|
||||
}
|
||||
}
|
||||
@ -416,18 +417,18 @@ void realtimeLock(uint32_t timeoutMs, byte md)
|
||||
start = mainseg.start;
|
||||
stop = mainseg.stop;
|
||||
mainseg.freeze = true;
|
||||
// if WLED was off and using main segment only, freeze non-main segments so they stay off
|
||||
if (bri == 0) {
|
||||
for (size_t s = 0; s < strip.getSegmentsNum(); s++) {
|
||||
strip.getSegment(s).freeze = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
start = 0;
|
||||
stop = strip.getLengthTotal();
|
||||
}
|
||||
// clear strip/segment
|
||||
for (size_t i = start; i < stop; i++) strip.setPixelColor(i,BLACK);
|
||||
// if WLED was off and using main segment only, freeze non-main segments so they stay off
|
||||
if (useMainSegmentOnly && bri == 0) {
|
||||
for (size_t s=0; s < strip.getSegmentsNum(); s++) {
|
||||
strip.getSegment(s).freeze = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if strip is off (bri==0) and not already in RTM
|
||||
if (briT == 0 && !realtimeMode && !realtimeOverride) {
|
||||
@ -510,12 +511,10 @@ void handleNotifications()
|
||||
rgbUdp.read(lbuf, packetSize);
|
||||
realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION);
|
||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||
unsigned id = 0;
|
||||
unsigned totalLen = strip.getLengthTotal();
|
||||
for (size_t i = 0; i < packetSize -2; i += 3)
|
||||
{
|
||||
if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
|
||||
for (size_t i = 0, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++) {
|
||||
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
||||
id++; if (id >= totalLen) break;
|
||||
}
|
||||
if (!(realtimeMode && useMainSegmentOnly)) strip.show();
|
||||
return;
|
||||
@ -595,17 +594,11 @@ void handleNotifications()
|
||||
|
||||
unsigned id = (tpmPayloadFrameSize/3)*(packetNum-1); //start LED
|
||||
unsigned totalLen = strip.getLengthTotal();
|
||||
for (size_t i = 6; i < tpmPayloadFrameSize + 4U; i += 3)
|
||||
{
|
||||
if (id < totalLen)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
id++;
|
||||
}
|
||||
else break;
|
||||
if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
|
||||
for (size_t i = 6; i < tpmPayloadFrameSize + 4U && id < totalLen; i += 3, id++) {
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
}
|
||||
if (tpmPacketCount == numPackets) //reset packet count and show if all packets were received
|
||||
{
|
||||
if (tpmPacketCount == numPackets) { //reset packet count and show if all packets were received
|
||||
tpmPacketCount = 0;
|
||||
strip.show();
|
||||
}
|
||||
@ -629,6 +622,7 @@ void handleNotifications()
|
||||
if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return;
|
||||
|
||||
unsigned totalLen = strip.getLengthTotal();
|
||||
if (useMainSegmentOnly) strip.getMainSegment().beginDraw(); // set up parameters for get/setPixelColor()
|
||||
if (udpIn[0] == 1 && packetSize > 5) //warls
|
||||
{
|
||||
for (size_t i = 2; i < packetSize -3; i += 4)
|
||||
@ -637,39 +631,29 @@ void handleNotifications()
|
||||
}
|
||||
} else if (udpIn[0] == 2 && packetSize > 4) //drgb
|
||||
{
|
||||
unsigned id = 0;
|
||||
for (size_t i = 2; i < packetSize -2; i += 3)
|
||||
for (size_t i = 2, id = 0; i < packetSize -2 && id < totalLen; i += 3, id++)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
|
||||
id++; if (id >= totalLen) break;
|
||||
}
|
||||
} else if (udpIn[0] == 3 && packetSize > 6) //drgbw
|
||||
{
|
||||
unsigned id = 0;
|
||||
for (size_t i = 2; i < packetSize -3; i += 4)
|
||||
for (size_t i = 2, id = 0; i < packetSize -3 && id < totalLen; i += 4, id++)
|
||||
{
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
|
||||
id++; if (id >= totalLen) break;
|
||||
}
|
||||
} else if (udpIn[0] == 4 && packetSize > 7) //dnrgb
|
||||
{
|
||||
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (size_t i = 4; i < packetSize -2; i += 3)
|
||||
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 3, id++)
|
||||
{
|
||||
if (id >= totalLen) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
|
||||
id++;
|
||||
}
|
||||
} else if (udpIn[0] == 5 && packetSize > 8) //dnrgbw
|
||||
{
|
||||
unsigned id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
|
||||
for (size_t i = 4; i < packetSize -2; i += 4)
|
||||
for (size_t i = 4; i < packetSize -2 && id < totalLen; i += 4, id++)
|
||||
{
|
||||
if (id >= totalLen) break;
|
||||
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
|
||||
id++;
|
||||
}
|
||||
}
|
||||
strip.show();
|
||||
@ -704,11 +688,11 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
|
||||
b = gamma8(b);
|
||||
w = gamma8(w);
|
||||
}
|
||||
uint32_t col = RGBW32(r,g,b,w);
|
||||
if (useMainSegmentOnly) {
|
||||
Segment &seg = strip.getMainSegment();
|
||||
if (pix<seg.length()) seg.setPixelColor(pix, r, g, b, w);
|
||||
strip.getMainSegment().setPixelColor(pix, col); // this expects that strip.getMainSegment().beginDraw() has been called in handleNotification()
|
||||
} else {
|
||||
strip.setPixelColor(pix, r, g, b, w);
|
||||
strip.setPixelColor(pix, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@
|
||||
#endif
|
||||
|
||||
#ifdef USERMOD_BH1750
|
||||
#include "../usermods/BH1750_v2/usermod_BH1750.h"
|
||||
#include "../usermods/BH1750_v2/usermod_bh1750.h"
|
||||
#endif
|
||||
|
||||
// BME280 v2 usermod. Define "USERMOD_BME280" in my_config.h
|
||||
|
@ -14,7 +14,7 @@ int getNumVal(const String* req, uint16_t pos)
|
||||
void parseNumber(const char* str, byte* val, byte minv, byte maxv)
|
||||
{
|
||||
if (str == nullptr || str[0] == '\0') return;
|
||||
if (str[0] == 'r') {*val = random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
|
||||
if (str[0] == 'r') {*val = hw_random8(minv,maxv?maxv:255); return;} // maxv for random cannot be 0
|
||||
bool wrap = false;
|
||||
if (str[0] == 'w' && strlen(str) > 1) {str++; wrap = true;}
|
||||
if (str[0] == '~') {
|
||||
@ -474,9 +474,9 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
break;
|
||||
case UMS_WeWillRockYou:
|
||||
if (ms%2000 < 200) {
|
||||
volumeSmth = random8(255);
|
||||
volumeSmth = hw_random8();
|
||||
for (int i = 0; i<5; i++)
|
||||
fftResult[i] = random8(255);
|
||||
fftResult[i] = hw_random8();
|
||||
}
|
||||
else if (ms%2000 < 400) {
|
||||
volumeSmth = 0;
|
||||
@ -484,9 +484,9 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
fftResult[i] = 0;
|
||||
}
|
||||
else if (ms%2000 < 600) {
|
||||
volumeSmth = random8(255);
|
||||
volumeSmth = hw_random8();
|
||||
for (int i = 5; i<11; i++)
|
||||
fftResult[i] = random8(255);
|
||||
fftResult[i] = hw_random8();
|
||||
}
|
||||
else if (ms%2000 < 800) {
|
||||
volumeSmth = 0;
|
||||
@ -494,9 +494,9 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
fftResult[i] = 0;
|
||||
}
|
||||
else if (ms%2000 < 1000) {
|
||||
volumeSmth = random8(255);
|
||||
volumeSmth = hw_random8();
|
||||
for (int i = 11; i<16; i++)
|
||||
fftResult[i] = random8(255);
|
||||
fftResult[i] = hw_random8();
|
||||
}
|
||||
else {
|
||||
volumeSmth = 0;
|
||||
@ -516,7 +516,7 @@ um_data_t* simulateSound(uint8_t simulationId)
|
||||
break;
|
||||
}
|
||||
|
||||
samplePeak = random8() > 250;
|
||||
samplePeak = hw_random8() > 250;
|
||||
FFT_MajorPeak = 21 + (volumeSmth*volumeSmth) / 8.0f; // walk thru full range of 21hz...8200hz
|
||||
maxVol = 31; // this gets feedback fro UI
|
||||
binNum = 8; // this gets feedback fro UI
|
||||
@ -582,7 +582,7 @@ void enumerateLedmaps() {
|
||||
uint8_t get_random_wheel_index(uint8_t pos) {
|
||||
uint8_t r = 0, x = 0, y = 0, d = 0;
|
||||
while (d < 42) {
|
||||
r = random8();
|
||||
r = hw_random8();
|
||||
x = abs(pos - r);
|
||||
y = 255 - x;
|
||||
d = MIN(x, y);
|
||||
@ -594,3 +594,18 @@ uint8_t get_random_wheel_index(uint8_t pos) {
|
||||
float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
// 32 bit random number generator, inlining uses more code, use hw_random16() if speed is critical (see fcn_declare.h)
|
||||
uint32_t hw_random(uint32_t upperlimit) {
|
||||
uint32_t rnd = hw_random();
|
||||
uint64_t scaled = uint64_t(rnd) * uint64_t(upperlimit);
|
||||
return scaled >> 32;
|
||||
}
|
||||
|
||||
int32_t hw_random(int32_t lowerlimit, int32_t upperlimit) {
|
||||
if(lowerlimit >= upperlimit) {
|
||||
return lowerlimit;
|
||||
}
|
||||
uint32_t diff = upperlimit - lowerlimit;
|
||||
return hw_random(diff) + lowerlimit;
|
||||
}
|
@ -222,6 +222,7 @@ void WLED::loop()
|
||||
BusManager::setBrightness(bri); // fix re-initialised bus' brightness #4005
|
||||
if (aligned) strip.makeAutoSegments();
|
||||
else strip.fixInvalidSegments();
|
||||
BusManager::setBrightness(bri); // fix re-initialised bus' brightness
|
||||
doSerializeConfig = true;
|
||||
}
|
||||
if (loadLedmap >= 0) {
|
||||
@ -543,14 +544,8 @@ void WLED::setup()
|
||||
#endif
|
||||
|
||||
// Seed FastLED random functions with an esp random value, which already works properly at this point.
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
const uint32_t seed32 = esp_random();
|
||||
#elif defined(ARDUINO_ARCH_ESP8266)
|
||||
const uint32_t seed32 = RANDOM_REG32;
|
||||
#else
|
||||
const uint32_t seed32 = random(std::numeric_limits<long>::max());
|
||||
#endif
|
||||
random16_set_seed((uint16_t)((seed32 & 0xFFFF) ^ (seed32 >> 16)));
|
||||
const uint32_t seed32 = hw_random();
|
||||
random16_set_seed((uint16_t)seed32);
|
||||
|
||||
#if WLED_WATCHDOG_TIMEOUT > 0
|
||||
enableWatchdog();
|
||||
@ -575,10 +570,11 @@ void WLED::beginStrip()
|
||||
} else {
|
||||
// fix for #3196
|
||||
if (bootPreset > 0) {
|
||||
bool oldTransition = fadeTransition; // workaround if transitions are enabled
|
||||
fadeTransition = false; // ignore transitions temporarily
|
||||
strip.setColor(0, BLACK); // set all segments black
|
||||
fadeTransition = oldTransition; // restore transitions
|
||||
// set all segments black (no transition)
|
||||
for (unsigned i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment &seg = strip.getSegment(i);
|
||||
if (seg.isActive()) seg.colors[0] = BLACK;
|
||||
}
|
||||
col[0] = col[1] = col[2] = col[3] = 0; // needed for colorUpdated()
|
||||
}
|
||||
briLast = briS; bri = 0;
|
||||
|
@ -3,7 +3,6 @@
|
||||
/*
|
||||
Main sketch, global variable declarations
|
||||
@title WLED project sketch
|
||||
@version 0.15.0-dev
|
||||
@author Christian Schwinne
|
||||
*/
|
||||
|
||||
@ -583,7 +582,6 @@ WLED_GLOBAL bool transitionActive _INIT(false);
|
||||
WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration
|
||||
WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json)
|
||||
WLED_GLOBAL unsigned long transitionStartTime;
|
||||
WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f
|
||||
WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt")
|
||||
WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s)
|
||||
WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random
|
||||
|
Loading…
x
Reference in New Issue
Block a user