Merge remote-tracking branch 'upstream/mdev' into mdev
This commit is contained in:
368
wled00/FX.cpp
368
wled00/FX.cpp
@@ -37,6 +37,9 @@
|
||||
|
||||
#define indexToVStrip(index, stripNr) ((index) | (int((stripNr)+1)<<16))
|
||||
|
||||
// WLEDMM replace abs8 by abs, as abs8 does not work for numbers >127
|
||||
#define abs8(x) abs(x)
|
||||
|
||||
// effect utility functions
|
||||
static uint8_t sin_gap(uint16_t in) {
|
||||
if (in & 0x100) return 0;
|
||||
@@ -98,6 +101,14 @@ static long map2(long x, long in_min, long in_max, long out_min, long out_max)
|
||||
}
|
||||
|
||||
|
||||
static um_data_t* getAudioData() {
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
return um_data;
|
||||
}
|
||||
// effect functions
|
||||
|
||||
/*
|
||||
@@ -1994,11 +2005,7 @@ uint16_t mode_partyjerk() {
|
||||
* step: pos
|
||||
*/
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
|
||||
SEGENV.aux0++;
|
||||
@@ -2148,7 +2155,7 @@ uint16_t mode_fire_2012() {
|
||||
|
||||
// Step 4. Map from heat cells to LED colors
|
||||
for (int j = 0; j < SEGLEN; j++) {
|
||||
SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, min(heat[j],byte(240)), 255, NOBLEND));
|
||||
SEGMENT.setPixelColor(indexToVStrip(j, stripNr), ColorFromPalette(SEGPALETTE, min(heat[j], byte(240)), 255, NOBLEND));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -2156,14 +2163,19 @@ uint16_t mode_fire_2012() {
|
||||
for (int stripNr=0; stripNr<strips; stripNr++)
|
||||
virtualStrip::runStrip(stripNr, &heat[stripNr * SEGLEN], it);
|
||||
|
||||
if (SEGMENT.is2D()) SEGMENT.blur(32);
|
||||
if (SEGMENT.is2D()) {
|
||||
uint8_t blurAmount = SEGMENT.custom2 >> 2;
|
||||
if (blurAmount > 48) blurAmount += blurAmount-48; // extra blur when slider > 192 (bush burn)
|
||||
if (blurAmount < 16) SEGMENT.blurCols(SEGMENT.custom2 >> 1); // no side-burn when slider < 64 (faster)
|
||||
else SEGMENT.blur(blurAmount);
|
||||
}
|
||||
|
||||
if (it != SEGENV.step)
|
||||
SEGENV.step = it;
|
||||
|
||||
return FRAMETIME;
|
||||
}
|
||||
static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,,Boost;;!;1.5d;sx=64,ix=160,m12=1"; // bars WLEDMM 1.5d,
|
||||
static const char _data_FX_MODE_FIRE_2012[] PROGMEM = "Fire 2012@Cooling,Spark rate,,2D Blur,Boost;;!;1.5d;sx=64,ix=160,c2=128,m12=1"; // bars WLEDMM 1.5d,
|
||||
|
||||
|
||||
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
||||
@@ -4922,17 +4934,18 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma
|
||||
}
|
||||
|
||||
SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails
|
||||
unsigned long t = strip.now/128; // timebase
|
||||
const unsigned long ratio = 128; // rotation speed
|
||||
unsigned long t = strip.now; // timebase
|
||||
// outer stars
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + t * i);
|
||||
y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + t * i);
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio);
|
||||
y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio);
|
||||
SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255));
|
||||
}
|
||||
// inner stars
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + t * i);
|
||||
y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + t * i);
|
||||
x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio);
|
||||
y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio);
|
||||
SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255));
|
||||
}
|
||||
// central white dot
|
||||
@@ -4969,8 +4982,8 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so
|
||||
SEGMENT.fadeToBlackBy(40);
|
||||
for (size_t i = 0; i < numLines; i++) {
|
||||
byte x1 = beatsin8(2 + SEGMENT.speed/16, 0, (cols - 1));
|
||||
byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (cols - 1));
|
||||
byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 24);
|
||||
byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (rows - 1));
|
||||
byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24);
|
||||
byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64);
|
||||
CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND);
|
||||
|
||||
@@ -5054,10 +5067,12 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma
|
||||
if ((i + ms / 8) & 3) {
|
||||
// draw a gradient line between x and x1
|
||||
x = x / 2; x1 = x1 / 2;
|
||||
uint8_t steps = abs8(x - x1) + 1;
|
||||
unsigned steps = abs8(x - x1) + 1;
|
||||
bool positive = (x1 >= x); // direction of drawing
|
||||
for (size_t k = 1; k <= steps; k++) {
|
||||
uint8_t rate = k * 255 / steps;
|
||||
uint8_t dx = lerp8by8(x, x1, rate);
|
||||
unsigned rate = k * 255 / steps;
|
||||
//unsigned dx = lerp8by8(x, x1, rate);
|
||||
unsigned dx = positive? (x + k-1) : (x - k+1); // behaves the same as "lerp8by8" but does not create holes
|
||||
//SEGMENT.setPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND).nscale8_video(rate));
|
||||
SEGMENT.addPixelColorXY(dx, i, ColorFromPalette(SEGPALETTE, hue, 255, LINEARBLEND)); // use setPixelColorXY for different look
|
||||
SEGMENT.fadePixelColorXY(dx, i, rate);
|
||||
@@ -5364,7 +5379,7 @@ uint16_t mode_2Dgameoflife(void) { // Written by Ewoud Wijma, inspired by https:
|
||||
SEGENV.step = strip.now;
|
||||
return FRAMETIME;
|
||||
} // mode_2Dgameoflife()
|
||||
static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!,Color Mutation ☾,Blur ☾,,,All Colors ☾,Overlay BG ☾,Wrap ☾,;!,!;!;2;sx=56,ix=2,c1=128,o1=0,o2=0,o3=1";
|
||||
static const char _data_FX_MODE_2DGAMEOFLIFE[] PROGMEM = "Game Of Life@!,Color Mutation ☾,Blur ☾,,,All Colors ☾,Overlay BG ☾,Wrap ☾;!,!;!;2;sx=56,ix=2,c1=128,o1=0,o2=0,o3=1";
|
||||
|
||||
/////////////////////////
|
||||
// 2D SnowFall //
|
||||
@@ -5637,7 +5652,10 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline
|
||||
float ylocn = float(cos8(phase/2 + i*2)) / 255.0f;
|
||||
//SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing
|
||||
unsigned palIndex = (256*ylocn) + phase/2 + (i* SEGMENT.speed)/64;
|
||||
SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(palIndex, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing - color follows rotation
|
||||
//SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(palIndex, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing - color follows rotation
|
||||
// WLEDMM wu_pixel is 50% faster, and still lokks better
|
||||
SEGMENT.wu_pixel(uint32_t(xlocn * (cols <<8)), uint32_t(ylocn * (rows <<8)),
|
||||
CRGB(SEGMENT.color_from_palette(palIndex, false, PALETTE_SOLID_WRAP, 0)));
|
||||
}
|
||||
} else
|
||||
for (int i=0; i < 256; i ++) {
|
||||
@@ -6381,6 +6399,10 @@ uint16_t mode_2Dfloatingblobs(void) {
|
||||
}
|
||||
|
||||
SEGMENT.fadeToBlackBy(20);
|
||||
bool drawAA = (SEGMENT.custom1 > 0) && (SEGMENT.custom1 < 6); //WLEDMM
|
||||
const uint16_t minDim = min(cols, rows); // WLEDMM use smaller dimension to find good blob size
|
||||
float max_grow = min(minDim/4.f,2.f);
|
||||
if (minDim>=24) max_grow =(minDim/8.0f); // WLEDMM allow bigger blobs
|
||||
|
||||
// Bounce balls around
|
||||
for (size_t i = 0; i < Amount; i++) {
|
||||
@@ -6389,18 +6411,18 @@ uint16_t mode_2Dfloatingblobs(void) {
|
||||
if (blob->grow[i]) {
|
||||
// enlarge radius until it is >= 4
|
||||
blob->r[i] += (fabsf(blob->sX[i]) > fabsf(blob->sY[i]) ? fabsf(blob->sX[i]) : fabsf(blob->sY[i])) * 0.05f;
|
||||
if (blob->r[i] >= min(cols/4.f,2.f)) {
|
||||
if (blob->r[i] >= max_grow) {
|
||||
blob->grow[i] = false;
|
||||
}
|
||||
} else {
|
||||
// reduce radius until it is < 1
|
||||
blob->r[i] -= (fabsf(blob->sX[i]) > fabsf(blob->sY[i]) ? fabsf(blob->sX[i]) : fabsf(blob->sY[i])) * 0.05f;
|
||||
if (blob->r[i] < 1.f) {
|
||||
if (blob->r[i] < 0.8f) {
|
||||
blob->grow[i] = true;
|
||||
}
|
||||
}
|
||||
uint32_t c = SEGMENT.color_from_palette(blob->color[i], false, false, 0);
|
||||
if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c);
|
||||
if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c, drawAA);
|
||||
else SEGMENT.setPixelColorXY((int)roundf(blob->x[i]), (int)roundf(blob->y[i]), c);
|
||||
// move x
|
||||
if (blob->x[i] + blob->r[i] >= cols - 1) blob->x[i] += (blob->sX[i] * ((cols - 1 - blob->x[i]) / blob->r[i] + 0.005f));
|
||||
@@ -6468,7 +6490,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
||||
if (SEGMENT.name) for (size_t i=0,j=0; i<maxLen; i++) if (SEGMENT.name[i]>31 && SEGMENT.name[i]<128) text[j++] = SEGMENT.name[i];
|
||||
const bool zero = strchr(text, '0') != nullptr;
|
||||
|
||||
if (!strlen(text) || !strncmp_P(text,PSTR("#F"),2) || !strncmp_P(text,PSTR("#P"),2) || !strncmp_P(text,PSTR("#DATE"),5) || !strncmp_P(text,PSTR("#DDMM"),5) || !strncmp_P(text,PSTR("#MMDD"),5) || !strncmp_P(text,PSTR("#TIME"),5) || !strncmp_P(text,PSTR("#HH"),3) || !strncmp_P(text,PSTR("#MM"),3)) { // fallback if empty segment name: display date and time
|
||||
if (!strlen(text) || !strncmp_P(text,PSTR("#F"),2) || !strncmp_P(text,PSTR("#P"),2) || !strncmp_P(text,PSTR("#A"),2) || !strncmp_P(text,PSTR("#DATE"),5) || !strncmp_P(text,PSTR("#DDMM"),5) || !strncmp_P(text,PSTR("#MMDD"),5) || !strncmp_P(text,PSTR("#TIME"),5) || !strncmp_P(text,PSTR("#HH"),3) || !strncmp_P(text,PSTR("#MM"),3)) { // fallback if empty segment name: display date and time
|
||||
char sec[5]= {'\0'};
|
||||
byte AmPmHour = hour(localTime);
|
||||
boolean isitAM = true;
|
||||
@@ -6501,6 +6523,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
||||
SEGMENT.blendPixelColorXY(x, y, SEGCOLOR(1), 255 - (SEGMENT.custom1>>1));
|
||||
}
|
||||
}
|
||||
bool drawShadow = (SEGMENT.check2) && (SEGMENT.custom1 == 0);
|
||||
for (int i = 0; i < numberOfLetters; i++) {
|
||||
if (int(cols) - int(SEGENV.aux0) + letterWidth*(i+1) < 0) continue; // don't draw characters off-screen
|
||||
uint32_t col1 = SEGMENT.color_from_palette(SEGENV.aux1, false, PALETTE_SOLID_WRAP, 0);
|
||||
@@ -6509,7 +6532,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
||||
col1 = SEGCOLOR(0);
|
||||
col2 = SEGCOLOR(2);
|
||||
}
|
||||
SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, col1, col2);
|
||||
SEGMENT.drawCharacter(text[i], int(cols) - int(SEGENV.aux0) + letterWidth*i, yoffset, letterWidth, letterHeight, col1, col2, drawShadow);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
@@ -6620,11 +6643,7 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
Ripple* ripples = reinterpret_cast<Ripple*>(SEGENV.data);
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
|
||||
#ifdef ESP32
|
||||
float FFT_MajorPeak = *(float*) um_data->u_data[4];
|
||||
@@ -6720,11 +6739,7 @@ uint16_t mode_2DSwirl(void) {
|
||||
uint8_t nj = (cols - 1) - j;
|
||||
uint16_t ms = strip.now;
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0]; //ewowi: use instead of sampleAvg???
|
||||
int16_t volumeRaw = *(int16_t*) um_data->u_data[1];
|
||||
|
||||
@@ -6757,11 +6772,7 @@ uint16_t mode_2DWaverly(void) {
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
float soundPressure = *(float*) um_data->u_data[9];
|
||||
float agcSensitivity= *(float*) um_data->u_data[10];
|
||||
@@ -6773,20 +6784,26 @@ uint16_t mode_2DWaverly(void) {
|
||||
|
||||
long t = strip.now / 2;
|
||||
for (int i = 0; i < cols; i++) {
|
||||
uint16_t thisVal = volumeSmth*SEGMENT.intensity/64 * inoise8(i * 45 , t , t)/64; // WLEDMM back to SR code
|
||||
uint16_t thisMax = map(thisVal, 0, 512, 0, rows);
|
||||
//uint16_t thisVal = volumeSmth*SEGMENT.intensity/64 * inoise8(i * 45 , t , t)/64; // WLEDMM back to SR code
|
||||
unsigned thisVal = unsigned(volumeSmth*SEGMENT.intensity) * inoise8(i * 45 , t , t) / (64*64); // WLEDMM same result but more accurate
|
||||
|
||||
for (int j = 0; j < thisMax; j++) {
|
||||
//int thisMax = map(thisVal, 0, 512, 0, rows);
|
||||
int thisMax = (thisVal * rows) / 512; // WLEDMM same result, just faster
|
||||
int thisMax2 = min(int(rows), thisMax); // WLEDMM limit height to visible are
|
||||
|
||||
for (int j = 0; j < thisMax2; j++) {
|
||||
//int jmap = map(j, 0, thisMax, 250, 0);
|
||||
int jmap = 250 - ((j * 250) / thisMax); // WLEDMM same result, just faster
|
||||
if (!SEGENV.check1)
|
||||
SEGMENT.addPixelColorXY(i, j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND));
|
||||
SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, map(j, 0, thisMax, 250, 0), 255, LINEARBLEND));
|
||||
SEGMENT.addPixelColorXY(i, j, ColorFromPalette(SEGPALETTE, jmap, 255, LINEARBLEND));
|
||||
SEGMENT.addPixelColorXY((cols - 1) - i, (rows - 1) - j, ColorFromPalette(SEGPALETTE, jmap, 255, LINEARBLEND));
|
||||
}
|
||||
}
|
||||
SEGMENT.blur(16);
|
||||
|
||||
return FRAMETIME;
|
||||
} // mode_2DWaverly()
|
||||
static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly ☾@Amplification,Sensitivity,,,,No Clouds,Sound Pressure,AGC debug;;!;2v;ix=64,si=0"; // Beatsin
|
||||
static const char _data_FX_MODE_2DWAVERLY[] PROGMEM = "Waverly ☾@Fade Rate,Amplification,,,,No Clouds,Sound Pressure,AGC debug;;!;2v;ix=64,si=0"; // Beatsin
|
||||
|
||||
#endif // WLED_DISABLE_2D
|
||||
|
||||
@@ -6809,11 +6826,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline.
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
|
||||
//SEGMENT.fade_out(240);
|
||||
@@ -6861,11 +6874,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
|
||||
// printUmData();
|
||||
@@ -6912,11 +6921,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline.
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
Gravity* gravcen = reinterpret_cast<Gravity*>(SEGENV.data);
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
// int16_t volumeRaw = *(int16_t*)um_data->u_data[1]; //WLEDMM: this variable not used here
|
||||
float soundPressure = *(float*) um_data->u_data[9];
|
||||
@@ -6989,11 +6994,7 @@ static const char _data_FX_MODE_GRAVIMETER[] PROGMEM = "Gravimeter ☾@Rate of f
|
||||
// * JUGGLES //
|
||||
//////////////////////
|
||||
uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline.
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
if (SEGENV.call == 0) {SEGENV.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM use lossless getPixelColor()
|
||||
|
||||
@@ -7016,11 +7017,7 @@ static const char _data_FX_MODE_JUGGLES[] PROGMEM = "Juggles@!,# of balls;!,!;!;
|
||||
uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline. With some enhancements by @softhack007
|
||||
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
int16_t volumeRaw = *(int16_t*)um_data->u_data[1];
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
float soundPressure = *(float*) um_data->u_data[9];
|
||||
@@ -7072,11 +7069,7 @@ static const char _data_FX_MODE_MATRIPIX[] PROGMEM = "Matripix ☾@!,Brightness,
|
||||
uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline.
|
||||
// Changing xdist to SEGENV.aux0 and ydist to SEGENV.aux1.
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
@@ -7115,11 +7108,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline.
|
||||
CRGB::DarkOrange, CRGB::DarkOrange, CRGB::Orange, CRGB::Orange,
|
||||
CRGB::Yellow, CRGB::Orange, CRGB::Yellow, CRGB::Yellow);
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
|
||||
if (SEGENV.call == 0) SEGMENT.fill(BLACK);
|
||||
@@ -7143,11 +7132,7 @@ static const char _data_FX_MODE_NOISEFIRE[] PROGMEM = "Noisefire@!,!;;;01v;m12=2
|
||||
///////////////////////
|
||||
uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline.
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
int16_t volumeRaw = *(int16_t*)um_data->u_data[1];
|
||||
if (SEGENV.call == 0) {SEGENV.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM use lossless getPixelColor()
|
||||
@@ -7185,11 +7170,7 @@ uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline.
|
||||
SEGMENT.fill(BLACK);
|
||||
}
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
int16_t volumeRaw = *(int16_t*)um_data->u_data[1];
|
||||
|
||||
uint8_t secondHand = micros()/(256-SEGMENT.speed)/500+1 % 16;
|
||||
@@ -7223,11 +7204,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline.
|
||||
if (!SEGENV.allocateData(sizeof(plasphase))) return mode_static(); //allocation failed
|
||||
Plasphase* plasmoip = reinterpret_cast<Plasphase*>(SEGENV.data);
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
@@ -7266,11 +7243,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline.
|
||||
uint8_t fadeVal = map2(SEGMENT.speed,0,255, 224, 254);
|
||||
uint16_t pos = random16(SEGLEN); // Set a random starting position.
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
|
||||
uint8_t *maxVol = (uint8_t*)um_data->u_data[6];
|
||||
uint8_t *binNum = (uint8_t*)um_data->u_data[7];
|
||||
@@ -7318,11 +7291,7 @@ uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline.
|
||||
}
|
||||
SEGMENT.fade_out(fadeVal);
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
int16_t volumeRaw = *(int16_t*)um_data->u_data[1];
|
||||
|
||||
if (volumeRaw > 1) {
|
||||
@@ -7347,10 +7316,7 @@ uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
|
||||
if (!SEGENV.allocateData(32*sizeof(uint8_t))) return mode_static(); //allocation failed
|
||||
uint8_t *myVals = reinterpret_cast<uint8_t*>(SEGENV.data); // Used to store a pile of samples because WLED frame rate and WLED sample rate are not synchronized. Frame rate is too low.
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float volumeSmth = *(float*) um_data->u_data[0];
|
||||
if (SEGENV.call == 0) {SEGENV.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM use lossless getPixelColor()
|
||||
|
||||
@@ -7380,11 +7346,7 @@ static const char _data_FX_MODE_PIXELS[] PROGMEM = "Pixels@Fade rate,# of pixels
|
||||
uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
|
||||
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
@@ -7414,11 +7376,7 @@ static const char _data_FX_MODE_BLURZ[] PROGMEM = "Blurz@Fade rate,Blur;!,Color
|
||||
uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
|
||||
// Hint: Looks best with segment brightness set to max (use global brightness to reduce brightness)
|
||||
// even with 1D effect we have to take logic for 2D segments for allocation as fill_solid() fills whole segment
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
float volumeSmth = *(float*)um_data->u_data[0];
|
||||
|
||||
@@ -7466,11 +7424,7 @@ uint16_t mode_DJLight(void) { // Written by Stefan Petrick, Ad
|
||||
// No need to prevent from executing on single led strips, only mid will be set (mid = 0)
|
||||
const int mid = SEGLEN / 2;
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
float volumeSmth = *(float*)um_data->u_data[0];
|
||||
|
||||
@@ -7536,11 +7490,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN.
|
||||
// Start frequency = 60 Hz and log10(60) = 1.78
|
||||
// End frequency = MAX_FREQUENCY in Hz and lo10(MAX_FREQUENCY) = MAX_FREQ_LOG10
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float FFT_MajorPeak = *(float*)um_data->u_data[SEGENV.check1 ? 8:4]; // WLEDMM may use FFT_MajorPeakSmth
|
||||
float my_magnitude = *(float*)um_data->u_data[5] / 4.0f;
|
||||
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
|
||||
@@ -7581,11 +7531,7 @@ static const char _data_FX_MODE_FREQMAP[] PROGMEM = "Freqmap@Fade rate,Starting
|
||||
///////////////////////
|
||||
uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Pleschung.
|
||||
// No need to prevent from executing on single led strips, we simply change pixel 0 each time and avoid the shift
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float FFT_MajorPeak = *(float*)um_data->u_data[4];
|
||||
float volumeSmth = *(float*)um_data->u_data[0];
|
||||
|
||||
@@ -7622,9 +7568,9 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
|
||||
}
|
||||
|
||||
// shift the pixels one pixel up
|
||||
SEGMENT.setPixelColor(0, color);
|
||||
// if SEGLEN equals 1 this loop won't execute
|
||||
for (int i = SEGLEN - 1; i > 0; i--) SEGMENT.setPixelColor(i, SEGMENT.getPixelColor(i-1)); //move to the left
|
||||
SEGMENT.setPixelColor(0, color);
|
||||
}
|
||||
|
||||
return FRAMETIME;
|
||||
@@ -7640,11 +7586,7 @@ static const char _data_FX_MODE_FREQMATRIX[] PROGMEM = "Freqmatrix@Speed,Sound e
|
||||
// SEGMENT.speed select faderate
|
||||
// SEGMENT.intensity select colour index
|
||||
uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float FFT_MajorPeak = *(float*)um_data->u_data[4];
|
||||
float my_magnitude = *(float*)um_data->u_data[5] / 16.0f;
|
||||
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
|
||||
@@ -7687,11 +7629,7 @@ static const char _data_FX_MODE_FREQPIXELS[] PROGMEM = "Freqpixels@Fade rate,Sta
|
||||
// Depending on the music stream you have you might find it useful to change the frequency mapping.
|
||||
uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschung. With some enhancements by @softhack007
|
||||
// As before, this effect can also work on single pixels, we just lose the shifting effect
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float FFT_MajorPeak = *(float*)um_data->u_data[4];
|
||||
float volumeSmth = *(float*)um_data->u_data[0];
|
||||
|
||||
@@ -7761,11 +7699,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline.
|
||||
if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed
|
||||
Gravity* gravcen = reinterpret_cast<Gravity*>(SEGENV.data);
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float FFT_MajorPeak = *(float*)um_data->u_data[4];
|
||||
float volumeSmth = *(float*)um_data->u_data[0];
|
||||
if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; // log10(0) is "forbidden" (throws exception)
|
||||
@@ -7814,11 +7748,7 @@ static const char _data_FX_MODE_GRAVFREQ[] PROGMEM = "Gravfreq ☾@Rate of fall,
|
||||
// ** Noisemove //
|
||||
//////////////////////
|
||||
uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuline
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
|
||||
@@ -7847,11 +7777,7 @@ static const char _data_FX_MODE_NOISEMOVE[] PROGMEM = "Noisemove@Speed of perlin
|
||||
// ** Rocktaves //
|
||||
//////////////////////
|
||||
uint16_t mode_rocktaves(void) { // Rocktaves. Same note from each octave is same colour. By: Andrew Tuline
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
float FFT_MajorPeak = *(float*) um_data->u_data[8]; // WLEDMM use FFT_MajorPeakSmth
|
||||
float my_magnitude = *(float*) um_data->u_data[5] / 16.0f;
|
||||
|
||||
@@ -7895,11 +7821,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
|
||||
// effect can work on single pixels, we just lose the shifting effect
|
||||
|
||||
if (SEGENV.call == 0) SEGMENT.fill(BLACK);
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t samplePeak = *(uint8_t*)um_data->u_data[3];
|
||||
float FFT_MajorPeak = *(float*) um_data->u_data[4];
|
||||
uint8_t *maxVol = (uint8_t*)um_data->u_data[6];
|
||||
@@ -7960,11 +7882,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma.
|
||||
if (!SEGENV.allocateData(cols*sizeof(uint16_t))) return mode_static(); //allocation failed
|
||||
uint16_t *previousBarHeight = reinterpret_cast<uint16_t*>(SEGENV.data); //array of previous bar heights per frequency band
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
|
||||
@@ -8071,11 +7989,7 @@ uint16_t mode_2DFunkyPlank(void) { // Written by ??? Adapted by Wil
|
||||
bandInc = (NUMB_BANDS / cols);
|
||||
}
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
|
||||
@@ -8156,7 +8070,7 @@ uint16_t mode_2DAkemi(void) {
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (SEGENV.call == 0) {SEGMENT.setUpLeds(); SEGMENT.fill(BLACK);}
|
||||
if (SEGENV.call == 0) {SEGMENT.fill(BLACK);}
|
||||
|
||||
uint16_t counter = (strip.now * ((SEGMENT.speed >> 2) +2)) & 0xFFFF;
|
||||
counter = counter >> 8;
|
||||
@@ -8164,10 +8078,7 @@ uint16_t mode_2DAkemi(void) {
|
||||
const float lightFactor = 0.15f;
|
||||
const float normalFactor = 0.4f;
|
||||
|
||||
um_data_t *um_data = nullptr;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t fftResult[NUM_GEQ_CHANNELS] = {0};
|
||||
if (um_data->u_data != nullptr) memcpy(fftResult, um_data->u_data[2], sizeof(fftResult)); // WLEDMM buffer curent values
|
||||
float base = fftResult[0]/255.0f;
|
||||
@@ -8200,11 +8111,12 @@ uint16_t mode_2DAkemi(void) {
|
||||
|
||||
//add geq left and right
|
||||
if (um_data) {
|
||||
for (int x=0; x < cols/8; x++) {
|
||||
uint16_t band = x * cols/8;
|
||||
int xMax = cols/8;
|
||||
for (int x=0; x < xMax; x++) {
|
||||
size_t band = map2(x, 0, max(xMax,4), 0, 15); // map 0..cols/8 to 16 GEQ bands
|
||||
CRGB color = SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0);
|
||||
band = constrain(band, 0, 15);
|
||||
uint16_t barHeight = map(fftResult[band], 0, 255, 0, 17*rows/32);
|
||||
CRGB color = SEGMENT.color_from_palette((band * 35), false, PALETTE_SOLID_WRAP, 0);
|
||||
|
||||
for (int y=0; y < barHeight; y++) {
|
||||
SEGMENT.setPixelColorXY(x, rows/2-y, color);
|
||||
@@ -8553,11 +8465,7 @@ uint16_t mode_GEQLASER(void) {
|
||||
uint16_t horizon = map2(SEGMENT.custom1,0,255,rows-1,0);
|
||||
uint8_t depth = SEGMENT.custom2; // depth of perspective. 255 = infinite ("laser")
|
||||
|
||||
um_data_t *um_data;
|
||||
if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) {
|
||||
// add support for no audio
|
||||
um_data = simulateSound(SEGMENT.soundSim);
|
||||
}
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
|
||||
uint8_t heights[NUM_GEQ_CHANNELS] = { 0 };
|
||||
@@ -8661,6 +8569,84 @@ static const char _data_FX_MODE_GEQLASER[] PROGMEM = "GEQ 3D ☾@Speed,Front Fil
|
||||
|
||||
#endif // WLED_DISABLE_2D
|
||||
|
||||
/*
|
||||
@title MoonModules WLED - Painbrush Effect
|
||||
@file included in FX.cpp
|
||||
@repo https://github.com/MoonModules/WLED, submit changes to this file as PRs to MoonModules/WLED
|
||||
@Authors https://github.com/MoonModules/WLED/commits/mdev/
|
||||
@Copyright © 2024 Github MoonModules Commit Authors (contact moonmodules@icloud.com for details)
|
||||
@license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
|
||||
|
||||
This function is part of the MoonModules WLED fork also known as "WLED-MM".
|
||||
WLED-MM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
WLED-MM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with WLED-MM. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
///////////////////////
|
||||
// 2D Paintbrush //
|
||||
///////////////////////
|
||||
uint16_t mode_2DPaintbrush() {
|
||||
|
||||
// Author: @TroyHacks
|
||||
// @license GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
|
||||
|
||||
if (!strip.isMatrix) return mode_static(); // not a 2D set-up
|
||||
|
||||
const uint16_t cols = SEGMENT.virtualWidth();
|
||||
const uint16_t rows = SEGMENT.virtualHeight();
|
||||
|
||||
if (!SEGENV.allocateData(4)) return mode_static(); //allocation failed
|
||||
|
||||
if (SEGENV.call == 0) {
|
||||
SEGMENT.setUpLeds();
|
||||
SEGMENT.fill(BLACK);
|
||||
SEGENV.aux0 = 0;
|
||||
}
|
||||
|
||||
bool phase_chaos = SEGMENT.check3;
|
||||
bool soft = SEGMENT.check2;
|
||||
bool color_chaos = SEGMENT.check1;
|
||||
CRGB color;
|
||||
|
||||
byte numLines = map8(SEGMENT.intensity,1,16);
|
||||
|
||||
SEGENV.aux0++; // hue
|
||||
SEGMENT.fadeToBlackBy(map8(SEGENV.custom1,10,128));
|
||||
|
||||
um_data_t *um_data = getAudioData();
|
||||
uint8_t *fftResult = (uint8_t*)um_data->u_data[2];
|
||||
|
||||
SEGENV.aux1 = phase_chaos?random8():0;
|
||||
|
||||
for (size_t i = 0; i < numLines; i++) {
|
||||
byte bin = map(i,0,numLines,0,15);
|
||||
|
||||
byte x1 = beatsin8(max(16,int(SEGMENT.speed))/16*1 + fftResult[0]/16, 0, (cols-1), fftResult[bin], SEGENV.aux1);
|
||||
byte x2 = beatsin8(max(16,int(SEGMENT.speed))/16*2 + fftResult[0]/16, 0, (cols-1), fftResult[bin], SEGENV.aux1);
|
||||
byte y1 = beatsin8(max(16,int(SEGMENT.speed))/16*3 + fftResult[0]/16, 0, (rows-1), fftResult[bin], SEGENV.aux1);
|
||||
byte y2 = beatsin8(max(16,int(SEGMENT.speed))/16*4 + fftResult[0]/16, 0, (rows-1), fftResult[bin], SEGENV.aux1);
|
||||
|
||||
int length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
|
||||
length = map8(fftResult[bin],0,length);
|
||||
|
||||
if (length > max(1,int(SEGMENT.custom3))) {
|
||||
if (color_chaos) {
|
||||
color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND);
|
||||
} else {
|
||||
uint16_t colorIndex = map(i,0,numLines,0,255);
|
||||
color = SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0);
|
||||
}
|
||||
SEGMENT.drawLine(x1,y1,x2,y2,color,soft,length);
|
||||
}
|
||||
}
|
||||
return FRAMETIME;
|
||||
} // mode_2DPaintbrush()
|
||||
static const char _data_FX_MODE_2DPAINTBRUSH[] PROGMEM = "Paintbrush ☾@Oscillator Offset,# of lines,Fade Rate,,Min Length,Color Chaos,Anti-aliasing,Phase Chaos;!,,Peaks;!;2f;sx=160,ix=255,c1=80,c2=255,c3=0,pal=72,o1=0,o2=1,o3=0";
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// mode data
|
||||
@@ -8908,6 +8894,8 @@ void WS2812FX::setupEffectData() {
|
||||
|
||||
addEffect(FX_MODE_GEQLASER, &mode_GEQLASER, _data_FX_MODE_GEQLASER); // audio
|
||||
|
||||
addEffect(FX_MODE_2DPAINTBRUSH, &mode_2DPaintbrush, _data_FX_MODE_2DPAINTBRUSH); // audio
|
||||
|
||||
#endif // WLED_DISABLE_2D
|
||||
|
||||
}
|
||||
|
||||
168
wled00/FX.h
168
wled00/FX.h
@@ -33,7 +33,7 @@
|
||||
|
||||
bool canUseSerial(void); // WLEDMM implemented in wled_serial.cpp
|
||||
void strip_wait_until_idle(String whoCalledMe); // WLEDMM implemented in FX_fcn.cpp
|
||||
bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn.cpp
|
||||
bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented in FX_fcn.cpp
|
||||
|
||||
#define FASTLED_INTERNAL //remove annoying pragma messages
|
||||
#define USE_GET_MILLISECOND_TIMER
|
||||
@@ -87,11 +87,13 @@ bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn.
|
||||
#ifndef MAX_NUM_SEGMENTS
|
||||
#define MAX_NUM_SEGMENTS 32
|
||||
#endif
|
||||
#ifndef MAX_SEGMENT_DATA
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#define MAX_SEGMENT_DATA 24576
|
||||
#else
|
||||
#define MAX_SEGMENT_DATA 32767
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* How much data bytes each segment should max allocate to leave enough space for other segments,
|
||||
@@ -348,10 +350,10 @@ bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn.
|
||||
#define FX_MODE_STARBURST_AR 192 // WLED-SR audioreactive fireworks starburst
|
||||
// #define FX_MODE_PALETTE_AR 193 // WLED-SR audioreactive palette
|
||||
#define FX_MODE_FIREWORKS_AR 194 // WLED-SR audioreactive fireworks
|
||||
#define FX_MODE_GEQLASER 195 // WLED-MM GEQ Laser
|
||||
#define FX_MODE_2DSNOWFALL 196 // WLED-MM Snowfall
|
||||
|
||||
#define MODE_COUNT 197
|
||||
#define FX_MODE_GEQLASER 195 // WLED-MM GEQ Laser
|
||||
#define FX_MODE_2DPAINTBRUSH 196 // WLED-MM Paintbrush
|
||||
#define FX_MODE_2DSNOWFALL 197 // WLED-MM Snowfall
|
||||
#define MODE_COUNT 198
|
||||
|
||||
typedef enum mapping1D2D {
|
||||
M12_Pixels = 0,
|
||||
@@ -435,6 +437,21 @@ typedef struct Segment {
|
||||
static size_t _usedSegmentData; // WLEDMM uint16_t is too small
|
||||
void setPixelColorXY_fast(int x, int y,uint32_t c, uint32_t scaled_col, int cols, int rows); // set relative pixel within segment with color - faster, but no error checking!!!
|
||||
|
||||
bool _isSimpleSegment = false; // simple = no grouping or spacing - mirror, transpose or reverse allowed
|
||||
bool _isSuperSimpleSegment = false; // superSimple = no grouping or spacing, no mirror - only transpose or reverse allowed
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
// WLEDMM cache some values that won't change while drawing a frame
|
||||
bool _isValid2D = false;
|
||||
uint8_t _brightness = 255; // final pixel brightness - including transitions and segment opacity
|
||||
bool _firstFill = true; // dirty HACK support
|
||||
uint16_t _2dWidth = 0; // virtualWidth
|
||||
uint16_t _2dHeight = 0; // virtualHeight
|
||||
|
||||
void setPixelColorXY_slow(int x, int y, uint32_t c); // set relative pixel within segment with color - full slow version
|
||||
#else
|
||||
void setPixelColorXY_slow(int x, int y, uint32_t c) { setPixelColorXY(x,y,c); } // not FASTPATH - slow is the normal
|
||||
#endif
|
||||
|
||||
// perhaps this should be per segment, not static
|
||||
static CRGBPalette16 _currentPalette; // palette used for current effect (includes transition, used in color_from_palette())
|
||||
|
||||
@@ -578,7 +595,7 @@ typedef struct Segment {
|
||||
void setCCT(uint16_t k);
|
||||
void setOpacity(uint8_t o);
|
||||
void setOption(uint8_t n, bool val);
|
||||
void setMode(uint8_t fx, bool loadDefaults = false);
|
||||
void setMode(uint8_t fx, bool loadDefaults = false, bool sliderDefaultsOnly = false);
|
||||
void setPalette(uint8_t pal);
|
||||
uint8_t differs(Segment& b) const;
|
||||
void refreshLightCapabilities(void);
|
||||
@@ -588,6 +605,7 @@ typedef struct Segment {
|
||||
bool allocateData(size_t len);
|
||||
void deallocateData(void);
|
||||
void resetIfRequired(void);
|
||||
void startFrame(void); // cache a few values that don't change while an effect is drawing
|
||||
/**
|
||||
* Flags that before the next effect is calculated,
|
||||
* the internal segment state should be reset.
|
||||
@@ -626,7 +644,7 @@ typedef struct Segment {
|
||||
void setPixelColor(float i, uint32_t c, bool aa = true);
|
||||
inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); }
|
||||
inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
uint32_t __attribute__((pure)) getPixelColor(int i); // WLEDMM attribute added
|
||||
uint32_t __attribute__((pure)) getPixelColor(int i) const; // WLEDMM attribute added
|
||||
// 1D support functions (some implement 2D as well)
|
||||
void blur(uint8_t, bool smear = false);
|
||||
void fill(uint32_t c);
|
||||
@@ -638,11 +656,22 @@ typedef struct Segment {
|
||||
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); } // automatically inline
|
||||
inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline
|
||||
void fadePixelColor(uint16_t n, uint8_t fade);
|
||||
uint8_t get_random_wheel_index(uint8_t pos);
|
||||
uint8_t get_random_wheel_index(uint8_t pos) const;
|
||||
uint32_t __attribute__((pure)) color_from_palette(uint_fast16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255);
|
||||
uint32_t __attribute__((pure)) color_wheel(uint8_t pos);
|
||||
|
||||
// 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
// 2D matrix
|
||||
#ifndef WLEDMM_FASTPATH
|
||||
inline uint16_t virtualWidth() const { // WLEDMM use fast types, and make function inline
|
||||
uint_fast16_t groupLen = groupLength();
|
||||
uint_fast16_t vWidth = ((transpose ? height() : width()) + groupLen - 1) / groupLen;
|
||||
@@ -655,22 +684,53 @@ typedef struct Segment {
|
||||
if (mirror_y) vHeight = (vHeight + 1) /2; // divide by 2 if mirror, leave at least a single LED
|
||||
return vHeight;
|
||||
}
|
||||
#else
|
||||
inline uint16_t virtualWidth() const { return(_2dWidth);} // WLEDMM get pre-calculated virtualWidth
|
||||
inline uint16_t virtualHeight() const { return(_2dHeight);} // WLEDMM get pre-calculated virtualHeight
|
||||
|
||||
uint16_t calc_virtualWidth() const {
|
||||
uint_fast16_t groupLen = groupLength();
|
||||
uint_fast16_t 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;
|
||||
}
|
||||
uint16_t calc_virtualHeight() const {
|
||||
uint_fast16_t groupLen = groupLength();
|
||||
uint_fast16_t 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
|
||||
return vHeight;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t nrOfVStrips(void) const;
|
||||
void createjMap(); //WLEDMM jMap
|
||||
void deletejMap(); //WLEDMM jMap
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
inline uint16_t XY(uint_fast16_t x, uint_fast16_t y) { // support function to get relative index within segment (for leds[]) // WLEDMM inline for speed
|
||||
uint_fast16_t width = virtualWidth(); // segment width in logical pixels
|
||||
uint_fast16_t height = virtualHeight(); // segment height in logical pixels
|
||||
if (width == 0) return 0; // softhack007 avoid div/0
|
||||
if (height == 0) return (x%width); // softhack007 avoid div/0
|
||||
inline uint16_t XY(uint_fast16_t x, uint_fast16_t y) const { // support function to get relative index within segment (for leds[]) // WLEDMM inline for speed
|
||||
uint_fast16_t width = max(uint16_t(1), virtualWidth()); // segment width in logical pixels -- softhack007 avoid div/0
|
||||
uint_fast16_t height = max(uint16_t(1), virtualHeight()); // segment height in logical pixels -- softhack007 avoid div/0
|
||||
return (x%width) + (y%height) * width;
|
||||
}
|
||||
|
||||
//void setPixelColorXY_fast(int x, int y,uint32_t c); // set relative pixel within segment with color - wrapper for _fast
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
// WLEDMM this is a "gateway" function - we either call _fast or fall back to "slow"
|
||||
inline void setPixelColorXY(int x, int y, uint32_t col) {
|
||||
if (!_isSimpleSegment) { // slow path
|
||||
setPixelColorXY_slow(x, y, col);
|
||||
} else { // fast path
|
||||
// some sanity checks
|
||||
if (!_isValid2D) return; // not active
|
||||
if ((unsigned(x) >= _2dWidth) || (unsigned(y) >= _2dHeight)) return; // check if (x,y) are out-of-range - due to 2's complement, this also catches negative values
|
||||
if (!_brightness && !transitional) return; // black-out
|
||||
|
||||
uint32_t scaled_col = (_brightness == 255) ? col : color_fade(col, _brightness); // calculate final color
|
||||
setPixelColorXY_fast(x, y, col, scaled_col, int(_2dWidth), int(_2dHeight)); // call "fast" function
|
||||
}
|
||||
}
|
||||
#else
|
||||
void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color
|
||||
#endif
|
||||
inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); }
|
||||
inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); }
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
@@ -680,7 +740,7 @@ typedef struct Segment {
|
||||
inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); }
|
||||
inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); }
|
||||
//#endif
|
||||
uint32_t __attribute__((pure)) getPixelColorXY(int x, int y);
|
||||
uint32_t __attribute__((pure)) getPixelColorXY(int x, int y) const;
|
||||
// 2D support functions
|
||||
void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t 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); }
|
||||
@@ -696,13 +756,13 @@ typedef struct Segment {
|
||||
void move(uint8_t dir, uint8_t 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 fillCircle(unsigned cx, unsigned cy, int radius, uint32_t col, bool soft);
|
||||
inline void fillCircle(unsigned cx, unsigned cy, int 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, uint8_t depth = UINT8_MAX);
|
||||
inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false, uint8_t depth = UINT8_MAX) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft, depth); } // automatic inline
|
||||
void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor = 0);
|
||||
inline void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // 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);
|
||||
void drawArc(unsigned x0, unsigned y0, int radius, uint32_t color, uint32_t fillColor = 0);
|
||||
inline void drawArc(unsigned x0, unsigned y0, int radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // 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, bool drawShadow = false);
|
||||
inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline
|
||||
void wu_pixel(uint32_t x, uint32_t y, CRGB c);
|
||||
//void blur1d(fract8 blur_amount); // blur all rows in 1 dimension
|
||||
@@ -746,7 +806,7 @@ typedef struct Segment {
|
||||
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 wu_pixel(uint32_t x, uint32_t y, CRGB c) {}
|
||||
#endif
|
||||
uint8_t * getAudioPalette(int pal); //WLEDMM netmindz ar palette
|
||||
uint8_t * getAudioPalette(int pal) const; //WLEDMM netmindz ar palette
|
||||
} segment;
|
||||
//static int segSize = sizeof(Segment);
|
||||
|
||||
@@ -869,64 +929,66 @@ class WS2812FX { // 96 bytes
|
||||
|
||||
bool
|
||||
checkSegmentAlignment(void),
|
||||
hasRGBWBus(void),
|
||||
hasCCTBus(void),
|
||||
hasRGBWBus(void) const,
|
||||
hasCCTBus(void) const,
|
||||
// return true if the strip is being sent pixel updates
|
||||
isUpdating(void),
|
||||
isUpdating(void) const,
|
||||
deserializeMap(uint8_t n=0),
|
||||
useLedsArray = false;
|
||||
|
||||
inline bool isServicing(void) { return _isServicing; }
|
||||
inline bool hasWhiteChannel(void) {return _hasWhiteChannel;}
|
||||
inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;}
|
||||
inline bool isServicing(void) const { return _isServicing; }
|
||||
inline bool hasWhiteChannel(void) const {return _hasWhiteChannel;}
|
||||
inline bool isOffRefreshRequired(void) const {return _isOffRefreshRequired;}
|
||||
|
||||
uint8_t
|
||||
paletteFade,
|
||||
paletteBlend,
|
||||
milliampsPerLed,
|
||||
cctBlending,
|
||||
getActiveSegmentsNum(void),
|
||||
getFirstSelectedSegId(void),
|
||||
getLastActiveSegmentId(void),
|
||||
getActiveSegsLightCapabilities(bool selectedOnly = false),
|
||||
getActiveSegmentsNum(void) const,
|
||||
getFirstSelectedSegId(void) __attribute__((pure)),
|
||||
getLastActiveSegmentId(void) const,
|
||||
getActiveSegsLightCapabilities(bool selectedOnly = false) __attribute__((pure)),
|
||||
setPixelSegment(uint8_t n);
|
||||
|
||||
inline uint8_t getBrightness(void) { return _brightness; }
|
||||
inline uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline uint8_t getSegmentsNum(void) { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId(void) { return _segment_index; }
|
||||
inline uint8_t getMainSegmentId(void) { return _mainSegment; }
|
||||
inline uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; } // will only return built-in palette count
|
||||
inline uint8_t getTargetFps() { return _targetFps; }
|
||||
inline uint8_t getModeCount() { return _modeCount; }
|
||||
inline uint8_t getBrightness(void) const { return _brightness; }
|
||||
inline uint8_t getSegmentsNum(void) const { return _segments.size(); } // returns currently present segments
|
||||
inline uint8_t getCurrSegmentId(void) const { return _segment_index; }
|
||||
inline uint8_t getMainSegmentId(void) const { return _mainSegment; }
|
||||
inline uint8_t getTargetFps() const { return _targetFps; }
|
||||
inline uint8_t getModeCount() const { return _modeCount; }
|
||||
inline static constexpr uint8_t getMaxSegments(void) { return MAX_NUM_SEGMENTS; } // returns maximum number of supported segments (fixed value)
|
||||
inline static constexpr uint8_t getPaletteCount() { return 13 + GRADIENT_PALETTE_COUNT; } // will only return built-in palette count
|
||||
|
||||
uint16_t
|
||||
ablMilliampsMax,
|
||||
currentMilliamps,
|
||||
getLengthPhysical(void),
|
||||
__attribute__((pure)) getLengthTotal(void), // will include virtual/nonexistent pixels in matrix //WLEDMM attribute added
|
||||
getFps();
|
||||
getLengthPhysical(void) const,
|
||||
getLengthPhysical2(void) const, // WLEDMM total length including HUB75, network busses excluded
|
||||
__attribute__((pure)) getLengthTotal(void) const, // will include virtual/nonexistent pixels in matrix //WLEDMM attribute added
|
||||
getFps() const;
|
||||
|
||||
inline uint16_t getFrameTime(void) { return _frametime; }
|
||||
inline uint16_t getMinShowDelay(void) { return MIN_SHOW_DELAY; }
|
||||
inline uint16_t getLength(void) { return _length; } // 2D matrix may have less pixels than W*H
|
||||
inline uint16_t getTransition(void) { return _transitionDur; }
|
||||
inline uint16_t getFrameTime(void) const { return _frametime; }
|
||||
inline uint16_t getMinShowDelay(void) const { return MIN_SHOW_DELAY; }
|
||||
inline uint16_t getLength(void) const { return _length; } // 2D matrix may have less pixels than W*H
|
||||
inline uint16_t getTransition(void) const { return _transitionDur; }
|
||||
|
||||
uint32_t
|
||||
now,
|
||||
timebase;
|
||||
uint32_t __attribute__((pure)) getPixelColor(uint_fast16_t); // WLEDMM attribute pure = does not have side-effects
|
||||
uint32_t __attribute__((pure)) getPixelColor(uint_fast16_t) const; // WLEDMM attribute pure = does not have side-effects
|
||||
uint32_t __attribute__((pure)) getPixelColorRestored(uint_fast16_t i) const;// WLEDMM gets the original color from the driver (without downscaling by _bri)
|
||||
|
||||
inline uint32_t getLastShow(void) { return _lastShow; }
|
||||
inline uint32_t segColor(uint8_t i) { return _colors_t[i]; }
|
||||
inline uint32_t getLastShow(void) const { return _lastShow; }
|
||||
inline uint32_t segColor(uint8_t i) const { return _colors_t[i]; }
|
||||
|
||||
const char *
|
||||
getModeData(uint8_t id = 0) { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||
getModeData(uint8_t id = 0) const { return (id && id<_modeCount) ? _modeData[id] : PSTR("Solid"); }
|
||||
|
||||
const char **
|
||||
getModeDataSrc(void) { return &(_modeData[0]); } // vectors use arrays for underlying data
|
||||
|
||||
Segment& getSegment(uint8_t id);
|
||||
Segment& getSegment(uint8_t id) __attribute__((pure));
|
||||
inline Segment& getFirstSelectedSeg(void) { return _segments[getFirstSelectedSegId()]; }
|
||||
inline Segment& getMainSegment(void) { return _segments[getMainSegmentId()]; }
|
||||
inline Segment* getSegments(void) { return &(_segments[0]); }
|
||||
@@ -993,7 +1055,7 @@ class WS2812FX { // 96 bytes
|
||||
inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); }
|
||||
|
||||
uint32_t
|
||||
getPixelColorXY(uint16_t, uint16_t);
|
||||
getPixelColorXY(uint16_t, uint16_t) const;
|
||||
|
||||
// end 2D support
|
||||
|
||||
@@ -1008,6 +1070,8 @@ class WS2812FX { // 96 bytes
|
||||
std::vector<segment> _segments;
|
||||
friend class Segment;
|
||||
|
||||
uint32_t getPixelColorXYRestored(uint16_t x, uint16_t y) const; // WLEDMM gets the original color from the driver (without downscaling by _bri)
|
||||
|
||||
private:
|
||||
uint16_t _length;
|
||||
uint8_t _brightness;
|
||||
|
||||
@@ -66,9 +66,26 @@ void WS2812FX::setUpMatrix() {
|
||||
|
||||
USER_PRINTF("setUpMatrix %d x %d\n", Segment::maxWidth, Segment::maxHeight);
|
||||
|
||||
// WLEDMM check if mapping table is necessary (avoiding heap fragmentation)
|
||||
#if defined(WLED_ENABLE_HUB75MATRIX)
|
||||
bool needLedMap = (loadedLedmap >0); // ledmap loaded
|
||||
needLedMap |= WLED_FS.exists(F("/2d-gaps.json")); // gapFile found
|
||||
needLedMap |= panel.size() > 1; // 2D config: more than one panel
|
||||
if (panel.size() == 1) {
|
||||
Panel &p = panel[0];
|
||||
needLedMap |= p.serpentine; // panel serpentine
|
||||
needLedMap |= p.vertical; // panel not horizotal
|
||||
needLedMap |= p.bottomStart | p.rightStart; // panel not top left, or not left->light
|
||||
needLedMap |= (p.xOffset > 0) || (p.yOffset > 0); // panel does not start at (0,0)
|
||||
}
|
||||
#else
|
||||
bool needLedMap = true; // always use ledMaps on non-HUB75 builds
|
||||
#endif
|
||||
|
||||
//WLEDMM recreate customMappingTable if more space needed
|
||||
if (Segment::maxWidth * Segment::maxHeight > customMappingTableSize) {
|
||||
size_t size = max(ledmapMaxSize, size_t(Segment::maxWidth * Segment::maxHeight)); // TroyHacks
|
||||
if (!needLedMap) size = 0; // softhack007
|
||||
USER_PRINTF("setupmatrix customMappingTable alloc %d from %d\n", size, customMappingTableSize);
|
||||
//if (customMappingTable != nullptr) delete[] customMappingTable;
|
||||
//customMappingTable = new uint16_t[size];
|
||||
@@ -88,8 +105,9 @@ void WS2812FX::setUpMatrix() {
|
||||
if (customMappingTable != nullptr) customMappingTableSize = size;
|
||||
}
|
||||
|
||||
if (customMappingTable != nullptr) {
|
||||
if ((customMappingTable != nullptr) || (!needLedMap)) { // softhack007
|
||||
customMappingSize = Segment::maxWidth * Segment::maxHeight;
|
||||
if (!needLedMap) customMappingSize = 0; // softhack007
|
||||
|
||||
// fill with empty in case we don't fill the entire matrix
|
||||
for (size_t i = 0; i< customMappingTableSize; i++) { //WLEDMM use customMappingTableSize
|
||||
@@ -130,6 +148,7 @@ void WS2812FX::setUpMatrix() {
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
|
||||
if (needLedMap && customMappingTable != nullptr) { // softhack007
|
||||
uint16_t x, y, pix=0; //pixel
|
||||
for (size_t pan = 0; pan < panel.size(); pan++) {
|
||||
Panel &p = panel[pan];
|
||||
@@ -146,6 +165,7 @@ void WS2812FX::setUpMatrix() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete gap array as we no longer need it
|
||||
if (gapTable) {delete[] gapTable; gapTable=nullptr;} // softhack prevent dangling pointer
|
||||
@@ -171,13 +191,31 @@ void WS2812FX::setUpMatrix() {
|
||||
//WLEDMM: no resetSegments here, only do it in set.cpp/handleSettingsSet - as we want t0 maintain the segment settings after setup has changed
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WLED_ENABLE_HUB75MATRIX
|
||||
// softhack007 hack: delete mapping table in case it only contains "identity"
|
||||
if (customMappingTable != nullptr && customMappingTableSize > 0) {
|
||||
bool isIdentity = true;
|
||||
for (size_t i = 0; (i< customMappingSize) && isIdentity; i++) { //WLEDMM use customMappingTableSize
|
||||
if (customMappingTable[i] != (uint16_t)i ) isIdentity = false;
|
||||
}
|
||||
if (isIdentity) {
|
||||
free(customMappingTable); customMappingTable = nullptr;
|
||||
USER_PRINTF("!setupmatrix: customMappingTable is not needed. Dropping %d bytes.\n", customMappingTableSize * sizeof(uint16_t));
|
||||
customMappingTableSize = 0;
|
||||
customMappingSize = 0;
|
||||
loadedLedmap = 0; //WLEDMM
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
isMatrix = false; // no matter what config says
|
||||
#endif
|
||||
}
|
||||
|
||||
// absolute matrix version of setPixelColor(), without error checking
|
||||
void IRAM_ATTR WS2812FX::setPixelColorXY_fast(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally
|
||||
void IRAM_ATTR __attribute__((hot)) WS2812FX::setPixelColorXY_fast(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally
|
||||
{
|
||||
uint_fast16_t index = y * Segment::maxWidth + x;
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
@@ -200,7 +238,7 @@ void IRAM_ATTR_YN WS2812FX::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM
|
||||
}
|
||||
|
||||
// returns RGBW values of pixel
|
||||
uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
uint32_t __attribute__((hot)) WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) const {
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint_fast16_t index = (y * Segment::maxWidth + x); //WLEDMM: use fast types
|
||||
#else
|
||||
@@ -211,19 +249,48 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) {
|
||||
return busses.getPixelColor(index);
|
||||
}
|
||||
|
||||
uint32_t __attribute__((hot)) WS2812FX::getPixelColorXYRestored(uint16_t x, uint16_t y) const { // WLEDMM gets the original color from the driver (without downscaling by _bri)
|
||||
#ifndef WLED_DISABLE_2D
|
||||
uint_fast16_t index = (y * Segment::maxWidth + x); //WLEDMM: use fast types
|
||||
#else
|
||||
uint16_t index = x;
|
||||
#endif
|
||||
if (index < customMappingSize) index = customMappingTable[index];
|
||||
if (index >= _length) return 0;
|
||||
return busses.getPixelColorRestored(index);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// Segment:: routines
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef WLED_DISABLE_2D
|
||||
|
||||
// WLEDMM cache some values so we don't need to re-calc then for each pixel
|
||||
void Segment::startFrame(void) {
|
||||
_isSimpleSegment = (grouping == 1) && (spacing == 0); // we can handle pixels faster when no grouping or spacing is involved
|
||||
_isSuperSimpleSegment = !mirror && !mirror_y && (grouping == 1) && (spacing == 0); // fastest - we only draw one pixel per call
|
||||
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
_isValid2D = isActive() && is2D();
|
||||
_brightness = currentBri(on ? opacity : 0);
|
||||
// if (reverse_y) _isSimpleSegment = false; // for A/B testing
|
||||
_2dWidth = is2D() ? calc_virtualWidth() : virtualLength();
|
||||
_2dHeight = calc_virtualHeight();
|
||||
#if 0 && defined(WLED_ENABLE_HUB75MATRIX)
|
||||
_firstFill = true; // dirty HACK
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
// WLEDMM end
|
||||
|
||||
// XY(x,y) - gets pixel index within current segment (often used to reference leds[] array element)
|
||||
// WLEDMM Segment::XY()is declared inline, see FX.h
|
||||
|
||||
|
||||
// Simplified version of Segment::setPixelColorXY - without error checking. Does not support grouping or spacing
|
||||
// * expects scaled color (final brightness) as additional input parameter, plus segment virtualWidth() and virtualHeight()
|
||||
void IRAM_ATTR Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_t scaled_col, int cols, int rows) //WLEDMM
|
||||
void IRAM_ATTR __attribute__((hot)) Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_t scaled_col, int cols, int rows) //WLEDMM
|
||||
{
|
||||
unsigned i = UINT_MAX;
|
||||
bool sameColor = false;
|
||||
@@ -245,7 +312,11 @@ void IRAM_ATTR Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_
|
||||
|
||||
// set the requested pixel
|
||||
strip.setPixelColorXY_fast(start + x, startY + y, scaled_col);
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
bool simpleSegment = _isSuperSimpleSegment;
|
||||
#else
|
||||
bool simpleSegment = !mirror && !mirror_y;
|
||||
#endif
|
||||
if (simpleSegment) return; // WLEDMM shortcut when no mirroring needed
|
||||
|
||||
// handle mirroring
|
||||
@@ -260,15 +331,19 @@ void IRAM_ATTR Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_
|
||||
else strip.setPixelColorXY_fast(start + x, startY + hei_ - y - 1, scaled_col);
|
||||
}
|
||||
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
|
||||
strip.setPixelColorXY_fast(wid_ - x - 1, hei_ - y - 1, scaled_col);
|
||||
strip.setPixelColorXY_fast(start + wid_ - x - 1, startY + hei_ - y - 1, scaled_col);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// normal Segment::setPixelColorXY with error checking, and support for grouping / spacing
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
void IRAM_ATTR_YN Segment::setPixelColorXY_slow(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally, renamed to "_slow"
|
||||
#else
|
||||
void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally
|
||||
#endif
|
||||
{
|
||||
if (Segment::maxHeight==1) return; // not a matrix set-up
|
||||
if ((Segment::maxHeight==1) || !isActive()) return; // not a matrix set-up
|
||||
const int_fast16_t cols = virtualWidth(); // WLEDMM optimization
|
||||
const int_fast16_t rows = virtualHeight();
|
||||
|
||||
@@ -297,15 +372,19 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM:
|
||||
if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
|
||||
|
||||
// WLEDMM shortcut when no grouping/spacing used
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
bool simpleSegment = _isSuperSimpleSegment;
|
||||
#else
|
||||
bool simpleSegment = !mirror && !mirror_y && (grouping == 1) && (spacing == 0);
|
||||
#endif
|
||||
if (simpleSegment) {
|
||||
strip.setPixelColorXY(start + x, startY + y, col);
|
||||
return;
|
||||
}
|
||||
|
||||
const int_fast16_t glen_ = groupLength(); // WLEDMM optimization
|
||||
const int_fast16_t wid_ = width();
|
||||
const int_fast16_t hei_ = height();
|
||||
const uint_fast16_t glen_ = groupLength(); // WLEDMM optimization
|
||||
const uint_fast16_t wid_ = width();
|
||||
const uint_fast16_t hei_ = height();
|
||||
|
||||
x *= glen_; // expand to physical pixels
|
||||
y *= glen_; // expand to physical pixels
|
||||
@@ -328,18 +407,20 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM:
|
||||
else strip.setPixelColorXY(start + xX, startY + hei_ - yY - 1, col);
|
||||
}
|
||||
if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel
|
||||
strip.setPixelColorXY(wid_ - xX - 1, hei_ - yY - 1, col);
|
||||
strip.setPixelColorXY(start + wid_ - xX - 1, startY + hei_ - yY - 1, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WLEDMM setPixelColorXY(float x, float y, uint32_t col, ..) is depricated. use wu_pixel(x,y,col) instead.
|
||||
// anti-aliased version of setPixelColorXY()
|
||||
void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa, bool fast) // WLEDMM some speedups due to fast int and faster sqrt16
|
||||
{
|
||||
if (Segment::maxHeight==1) return; // not a matrix set-up
|
||||
if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized
|
||||
|
||||
#if 0 // depricated
|
||||
const uint_fast16_t cols = virtualWidth();
|
||||
const uint_fast16_t rows = virtualHeight();
|
||||
|
||||
@@ -383,10 +464,16 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa, bool fast
|
||||
} else {
|
||||
setPixelColorXY(uint16_t(roundf(fX)), uint16_t(roundf(fY)), col);
|
||||
}
|
||||
|
||||
#else // replacement using wu_pixel
|
||||
unsigned px = x * (virtualWidth() <<8);
|
||||
unsigned py = y * (virtualHeight() <<8);
|
||||
wu_pixel(px, py, CRGB(col));
|
||||
#endif
|
||||
}
|
||||
|
||||
// returns RGBW values of pixel
|
||||
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) {
|
||||
uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const {
|
||||
if (x<0 || y<0 || !isActive()) return 0; // not active or out-of range
|
||||
if (ledsrgb) {
|
||||
int i = XY(x,y);
|
||||
@@ -395,10 +482,11 @@ uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) {
|
||||
if (reverse ) x = virtualWidth() - x - 1;
|
||||
if (reverse_y) y = virtualHeight() - y - 1;
|
||||
if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed
|
||||
x *= groupLength(); // expand to physical pixels
|
||||
y *= groupLength(); // expand to physical pixels
|
||||
const uint_fast16_t groupLength_ = groupLength(); // WLEDMM small optimization
|
||||
x *= groupLength_; // expand to physical pixels
|
||||
y *= groupLength_; // expand to physical pixels
|
||||
if (x >= width() || y >= height()) return 0;
|
||||
return strip.getPixelColorXY(start + x, startY + y);
|
||||
return strip.getPixelColorXYRestored(start + x, startY + y);
|
||||
}
|
||||
|
||||
// Blends the specified color with the existing pixel color.
|
||||
@@ -409,17 +497,19 @@ void Segment::blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t
|
||||
|
||||
// Adds the specified color with the existing pixel color perserving color balance.
|
||||
void IRAM_ATTR_YN Segment::addPixelColorXY(int x, int y, uint32_t color, bool fast) {
|
||||
if (!isActive()) return; // not active
|
||||
if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit
|
||||
uint32_t col = getPixelColorXY(x,y);
|
||||
col = color_add(col, color, fast);
|
||||
setPixelColorXY(x, y, col);
|
||||
// if (!isActive()) return; // not active //WLEDMM sanity check is repeated in getPixelColorXY / setPixelColorXY
|
||||
// if (x >= virtualWidth() || y >= virtualHeight() || x<0 || y<0) return; // if pixel would fall out of virtual segment just exit //WLEDMM
|
||||
uint32_t oldCol = getPixelColorXY(x,y);
|
||||
uint32_t col = color_add(oldCol, color, fast);
|
||||
if (col != oldCol) setPixelColorXY(x, y, col);
|
||||
}
|
||||
|
||||
void Segment::fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade) {
|
||||
if (!isActive()) return; // not active
|
||||
CRGB pix = CRGB(getPixelColorXY(x,y)).nscale8_video(fade);
|
||||
setPixelColorXY(x, y, pix);
|
||||
// if (!isActive()) return; // not active //WLEDMM sanity check is repeated in getPixelColorXY / setPixelColorXY
|
||||
CRGB pix = CRGB(getPixelColorXY(x,y));
|
||||
CRGB oldPix = pix;
|
||||
pix = pix.nscale8_video(fade);
|
||||
if (pix != oldPix) setPixelColorXY(int(x), int(y), pix);
|
||||
}
|
||||
|
||||
// blurRow: perform a blur on a row of a rectangular matrix
|
||||
@@ -521,7 +611,7 @@ void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) {
|
||||
for (int j = 0; j < dim1; j++) {
|
||||
int x = vertical ? i : j;
|
||||
int y = vertical ? j : i;
|
||||
setPixelColorXY(x, y, out[j]);
|
||||
if (in[j] != out[j]) setPixelColorXY(x, y, out[j]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -635,19 +725,26 @@ void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col,
|
||||
}
|
||||
|
||||
// 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
|
||||
void Segment::fillCircle(unsigned cx, unsigned cy, int radius, uint32_t col, bool soft) {
|
||||
if (!isActive() || radius <= 0) return; // not active
|
||||
// draw soft bounding circle
|
||||
if (soft) drawCircle(cx, cy, radius, col, soft);
|
||||
// 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 &&
|
||||
int16_t(cx)+x>=0 && int16_t(cy)+y>=0 &&
|
||||
int16_t(cx)+x<cols && int16_t(cy)+y<rows)
|
||||
|
||||
const int_fast32_t maxRadius2 = radius * radius - (((radius > 3) && !soft) ? 1:0); // WLEDMM pre-compute r^2; '-1' removes spikes from bigger blobs
|
||||
// WLEDMM pre-compute boundaries
|
||||
const int startx = max(-radius, -int(cx));
|
||||
const int endx = min(radius, cols-1-int(cx));
|
||||
const int starty = max(-radius, -int(cy));
|
||||
const int endy = min(radius, rows-1-int(cy));
|
||||
|
||||
// fill it - WLEDMM optimized
|
||||
for (int y = starty; y <= endy; y++) {
|
||||
for (int x = startx; x <= endx; x++) {
|
||||
if ((x * x + y * y) <= maxRadius2) {
|
||||
setPixelColorXY(cx + x, cy + y, col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -674,7 +771,11 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
uint32_t scaled_col = c;
|
||||
if (simpleSegment) {
|
||||
// segment brightness must be pre-calculated for the "fast" setPixelColorXY variant!
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
uint8_t _bri_t = _brightness;
|
||||
#else
|
||||
uint8_t _bri_t = currentBri(on ? opacity : 0);
|
||||
#endif
|
||||
if (!_bri_t && !transitional) return;
|
||||
if (_bri_t < 255) scaled_col = color_fade(c, _bri_t);
|
||||
}
|
||||
@@ -699,7 +800,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
// single pixel (line length == 0)
|
||||
if (dx+dy == 0) {
|
||||
if (simpleSegment) setPixelColorXY_fast(x0, y0, c, scaled_col, cols, rows);
|
||||
else setPixelColorXY(x0, y0, c);
|
||||
else setPixelColorXY_slow(x0, y0, c);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -735,7 +836,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
for (;;) {
|
||||
// if (x0 >= cols || y0 >= rows) break; // WLEDMM we hit the edge - should never happen
|
||||
if (simpleSegment) setPixelColorXY_fast(x0, y0, c, scaled_col, cols, rows);
|
||||
else setPixelColorXY(x0, y0, c);
|
||||
else setPixelColorXY_slow(x0, y0, c);
|
||||
if (x0==x1 && y0==y1) break;
|
||||
int e2 = err;
|
||||
if (e2 >-dx) { err -= dy; x0 += sx; }
|
||||
@@ -744,27 +845,34 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3
|
||||
}
|
||||
}
|
||||
|
||||
void Segment::drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor) {
|
||||
if (!isActive()) return; // not active
|
||||
// float step = degrees / (2.85f*MAX(radius,1));
|
||||
// for (float rad = 0.0f; rad <= degrees+step/2; rad += step) {
|
||||
// // may want to try float version as well (with or without antialiasing)
|
||||
// int x = roundf(sin_t(rad) * radius);
|
||||
// int y = roundf(cos_t(rad) * radius);
|
||||
// setPixelColorXY(x+x0, y+y0, c);
|
||||
// }
|
||||
float minradius = radius - .5;
|
||||
float maxradius = radius + .5;
|
||||
for (int x=0; x<virtualWidth(); x++) for (int y=0; y<virtualHeight(); y++) {
|
||||
void Segment::drawArc(unsigned x0, unsigned y0, int radius, uint32_t color, uint32_t fillColor) {
|
||||
if (!isActive() || (radius <=0)) return; // not active
|
||||
float minradius = float(radius) - .5;
|
||||
float maxradius = float(radius) + .5;
|
||||
// WLEDMM pre-calculate values to speed up the loop
|
||||
const int minradius2 = roundf(minradius * minradius);
|
||||
const int maxradius2 = roundf(maxradius * maxradius);
|
||||
|
||||
int newX = x - x0;
|
||||
int newY = y - y0;
|
||||
// WLEDMM only loop over surrounding square (50% faster)
|
||||
const int width = virtualWidth();
|
||||
const int height = virtualHeight();
|
||||
const int startx = max(0, int(x0)-radius-1);
|
||||
const int endx = min(width, int(x0)+radius+1);
|
||||
const int starty = max(0, int(y0)-radius-1);
|
||||
const int endy = min(height, int(y0)+radius+1);
|
||||
|
||||
if (newX*newX + newY*newY >= minradius * minradius && newX*newX + newY*newY <= maxradius * maxradius)
|
||||
for (int x=startx; x<endx; x++) for (int y=starty; y<endy; y++) {
|
||||
int newX2 = x - int(x0); newX2 *= newX2; // (distance from centerX) ^2
|
||||
int newY2 = y - int(y0); newY2 *= newY2; // (distance from centerY) ^2
|
||||
int distance2 = newX2 + newY2;
|
||||
|
||||
if ((distance2 >= minradius2) && (distance2 <= maxradius2)) {
|
||||
setPixelColorXY(x, y, color);
|
||||
} else {
|
||||
if (fillColor != 0)
|
||||
if (newX*newX + newY*newY < minradius * minradius)
|
||||
if (distance2 < minradius2)
|
||||
setPixelColorXY(x, y, fillColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,7 +922,7 @@ bool Segment::jsonToPixels(char * name, uint8_t fileNr) {
|
||||
|
||||
// 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) {
|
||||
void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2, bool drawShadow) {
|
||||
if (!isActive()) return; // not active
|
||||
if (chr < 32 || chr > 126) return; // only ASCII 32-126 supported
|
||||
chr -= 32; // align with font table entries
|
||||
@@ -824,6 +932,7 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
|
||||
CRGB col = CRGB(color);
|
||||
CRGBPalette16 grad = CRGBPalette16(col, col2 ? CRGB(col2) : col);
|
||||
uint32_t bgCol = SEGCOLOR(1);
|
||||
|
||||
//if (w<5 || w>6 || h!=8) return;
|
||||
for (int i = 0; i<h; i++) { // character height
|
||||
@@ -831,19 +940,39 @@ void Segment::drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w,
|
||||
if (y0 < 0) continue; // drawing off-screen
|
||||
if (y0 >= rows) break; // drawing off-screen
|
||||
uint8_t bits = 0;
|
||||
uint8_t bits_up = 0; // WLEDMM this is the previous line: font[(chr * h) + i -1]
|
||||
switch (font) {
|
||||
case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]); break; // 5x8 font
|
||||
case 40: bits = pgm_read_byte_near(&console_font_5x8[(chr * h) + i]); break; // 5x8 font
|
||||
case 48: bits = pgm_read_byte_near(&console_font_6x8[(chr * h) + i]); break; // 6x8 font
|
||||
case 63: bits = pgm_read_byte_near(&console_font_7x9[(chr * h) + i]); break; // 7x9 font
|
||||
case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]); break; // 5x12 font
|
||||
case 24: bits = pgm_read_byte_near(&console_font_4x6[(chr * h) + i]);
|
||||
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_4x6[(chr * h) + i -1]);
|
||||
break; // 5x8 font
|
||||
case 40: bits = pgm_read_byte_near(&console_font_5x8[(chr * h) + i]);
|
||||
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_5x8[(chr * h) + i -1]);
|
||||
break; // 5x8 font
|
||||
case 48: bits = pgm_read_byte_near(&console_font_6x8[(chr * h) + i]);
|
||||
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_6x8[(chr * h) + i -1]);
|
||||
break; // 6x8 font
|
||||
case 63: bits = pgm_read_byte_near(&console_font_7x9[(chr * h) + i]);
|
||||
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_7x9[(chr * h) + i -1]);
|
||||
break; // 7x9 font
|
||||
case 60: bits = pgm_read_byte_near(&console_font_5x12[(chr * h) + i]);
|
||||
if ((i>0) && drawShadow) bits_up = pgm_read_byte_near(&console_font_5x12[(chr * h) + i -1]);
|
||||
break; // 5x12 font
|
||||
default: return;
|
||||
}
|
||||
col = ColorFromPalette(grad, (i+1)*255/h, 255, NOBLEND);
|
||||
for (int j = 0; j<w; j++) { // character width
|
||||
int16_t x0 = x + (w-1) - j;
|
||||
if ((x0 >= 0 || x0 < cols) && ((bits>>(j+(8-w))) & 0x01)) { // bit set & drawing on-screen
|
||||
if ((x0 >= 0) || (x0 < cols)) {
|
||||
if ((bits>>(j+(8-w))) & 0x01) { // bit set & drawing on-screen
|
||||
setPixelColorXY(x0, y0, col);
|
||||
} else {
|
||||
if (drawShadow) {
|
||||
// WLEDMM
|
||||
if ((j < (w-1)) && (bits>>(j+(8-w) +1)) & 0x01) setPixelColorXY(x0, y0, bgCol); // blank when pixel to the right is set
|
||||
else if ((j > 0) && (bits>>(j+(8-w) -1)) & 0x01) setPixelColorXY(x0, y0, bgCol);// blank when pixel to the left is set
|
||||
else if ((bits_up>>(j+(8-w))) & 0x01) setPixelColorXY(x0, y0, bgCol); // blank when pixel above is set
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -859,11 +988,14 @@ void Segment::wu_pixel(uint32_t x, uint32_t y, CRGB c) { //awesome wu_pixel
|
||||
WU_WEIGHT(ix, yy), WU_WEIGHT(xx, yy)};
|
||||
// multiply the intensities by the colour, and saturating-add them to the pixels
|
||||
for (int i = 0; i < 4; i++) {
|
||||
CRGB led = getPixelColorXY((x >> 8) + (i & 1), (y >> 8) + ((i >> 1) & 1));
|
||||
int wu_x = (x >> 8) + (i & 1); // WLEDMM precalculate x
|
||||
int wu_y = (y >> 8) + ((i >> 1) & 1); // WLEDMM precalculate y
|
||||
CRGB led = getPixelColorXY(wu_x, wu_y);
|
||||
CRGB oldLed = led;
|
||||
led.r = qadd8(led.r, c.r * wu[i] >> 8);
|
||||
led.g = qadd8(led.g, c.g * wu[i] >> 8);
|
||||
led.b = qadd8(led.b, c.b * wu[i] >> 8);
|
||||
setPixelColorXY(int((x >> 8) + (i & 1)), int((y >> 8) + ((i >> 1) & 1)), led);
|
||||
if (led != oldLed) setPixelColorXY(wu_x, wu_y, led); // WLEDMM don't repaint same color
|
||||
}
|
||||
}
|
||||
#undef WU_WEIGHT
|
||||
|
||||
@@ -102,6 +102,11 @@ Segment::Segment(const Segment &orig) {
|
||||
DEBUG_PRINTLN(F("-- Copy segment constructor --"));
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment)); //WLEDMM copy to this
|
||||
transitional = false; // copied segment cannot be in transition
|
||||
// WLEDMM temporarily prevent any fast draw calls to the new segment
|
||||
// _isValid2D = false;
|
||||
_isSimpleSegment = false;
|
||||
_isSuperSimpleSegment = false;
|
||||
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
_dataLen = 0;
|
||||
@@ -132,7 +137,7 @@ void Segment::allocLeds() {
|
||||
ledsrgbSize = ledsrgb?size:0;
|
||||
if (ledsrgb == nullptr) {
|
||||
USER_PRINTLN("allocLeds failed!!");
|
||||
errorFlag = ERR_LOW_MEM; // WLEDMM raise errorflag
|
||||
errorFlag = ERR_LOW_BUF; // WLEDMM raise errorflag
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -143,8 +148,17 @@ void Segment::allocLeds() {
|
||||
// move constructor --> moves everything (including buffer) from orig to this
|
||||
Segment::Segment(Segment &&orig) noexcept {
|
||||
DEBUG_PRINTLN(F("-- Move segment constructor --"));
|
||||
|
||||
// WLEDMM temporarily prevent any fast draw calls to old and new segment
|
||||
orig._isSimpleSegment = false;
|
||||
orig._isSuperSimpleSegment = false;
|
||||
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
orig.transitional = false; // old segment cannot be in transition any more
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
// WLEDMM prevent any draw calls to old segment
|
||||
orig._isValid2D = false;
|
||||
#endif
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
@@ -169,6 +183,12 @@ Segment& Segment::operator= (const Segment &orig) {
|
||||
// copy source
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
transitional = false;
|
||||
|
||||
// WLEDMM prevent any fast draw calls to this segment until the next frame starts
|
||||
//_isValid2D = false;
|
||||
_isSimpleSegment = false;
|
||||
_isSuperSimpleSegment = false;
|
||||
|
||||
// erase pointers to allocated data
|
||||
name = nullptr;
|
||||
data = nullptr;
|
||||
@@ -196,7 +216,16 @@ Segment& Segment::operator= (Segment &&orig) noexcept {
|
||||
deallocateData(); // free old runtime data
|
||||
if (_t) { delete _t; _t = nullptr; }
|
||||
if (ledsrgb && !Segment::_globalLeds) free(ledsrgb); //WLEDMM: not needed anymore as we will use leds from copy. no need to nullify ledsrgb as it gets new value in memcpy
|
||||
|
||||
// WLEDMM temporarily prevent any fast draw calls to old and new segment
|
||||
orig._isSimpleSegment = false;
|
||||
orig._isSuperSimpleSegment = false;
|
||||
|
||||
memcpy((void*)this, (void*)&orig, sizeof(Segment));
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
// WLEDMM temporarily prevent any draw calls to old segment
|
||||
orig._isValid2D = false;
|
||||
#endif
|
||||
orig.name = nullptr;
|
||||
orig.data = nullptr;
|
||||
orig._dataLen = 0;
|
||||
@@ -266,6 +295,7 @@ void Segment::resetIfRequired() {
|
||||
deallocateData();
|
||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||
reset = false; // setOption(SEG_OPTION_RESET, false);
|
||||
startFrame(); // WLEDMM update cached propoerties
|
||||
}
|
||||
}
|
||||
|
||||
@@ -564,15 +594,11 @@ void Segment::setOption(uint8_t n, bool val) {
|
||||
if (!(n == SEG_OPTION_SELECTED || n == SEG_OPTION_RESET || n == SEG_OPTION_TRANSITIONAL)) stateChanged = true; // send UDP/WS broadcast
|
||||
}
|
||||
|
||||
void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
void Segment::setMode(uint8_t fx, bool loadDefaults, bool sliderDefaultsOnly) {
|
||||
//WLEDMM: return to old setting if not explicitly set
|
||||
static int16_t oldMap = -1;
|
||||
static int16_t oldSim = -1;
|
||||
static int16_t oldPalette = -1;
|
||||
static byte oldReverse = -1;
|
||||
static byte oldMirror = -1;
|
||||
static byte oldReverse_y = -1;
|
||||
static byte oldMirror_y = -1;
|
||||
// if we have a valid mode & is not reserved
|
||||
if (fx < strip.getModeCount() && strncmp_P("RSVD", strip.getModeData(fx), 4)) {
|
||||
if (fx != mode) {
|
||||
@@ -591,14 +617,16 @@ void Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
//WLEDMM: return to old setting if not explicitly set
|
||||
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) {if (oldMap==-1) oldMap = map1D2D; map1D2D = constrain(sOpt, 0, 7);} else {if (oldMap!=-1) map1D2D = oldMap; oldMap = -1;}
|
||||
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) {if (oldSim==-1) oldSim = soundSim; soundSim = constrain(sOpt, 0, 1);} else {if (oldSim!=-1) soundSim = oldSim; oldSim = -1;}
|
||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) {if (oldReverse==-1) oldReverse = reverse; reverse = (bool)sOpt;} else {if (oldReverse!=-1) reverse = oldReverse==1; oldReverse = -1;}
|
||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) {if (oldMirror==-1) oldMirror = mirror; mirror = (bool)sOpt;} else {if (oldMirror!=-1) mirror = oldMirror==1; oldMirror = -1;} // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) {if (oldReverse_y==-1) oldReverse_y = reverse_y; reverse_y = (bool)sOpt;} else {if (oldReverse_y!=-1) reverse_y = oldReverse_y==1; oldReverse_y = -1;}
|
||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) {if (oldMirror_y==-1) oldMirror_y = mirror_y; mirror_y = (bool)sOpt;} else {if (oldMirror_y!=-1) mirror_y = oldMirror_y==1; oldMirror_y = -1;} // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) {if (oldPalette==-1) oldPalette = palette; setPalette(sOpt);} else {if (oldPalette!=-1) setPalette(oldPalette); oldPalette = -1;}
|
||||
if (!sliderDefaultsOnly) {
|
||||
//WLEDMM: return to old setting if not explicitly set
|
||||
sOpt = extractModeDefaults(fx, "m12"); if (sOpt >= 0) {if (oldMap==-1) oldMap = map1D2D; map1D2D = constrain(sOpt, 0, 7);} else {if (oldMap!=-1) map1D2D = oldMap; oldMap = -1;}
|
||||
sOpt = extractModeDefaults(fx, "si"); if (sOpt >= 0) {if (oldSim==-1) oldSim = soundSim; soundSim = constrain(sOpt, 0, 1);} else {if (oldSim!=-1) soundSim = oldSim; oldSim = -1;}
|
||||
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) reverse = (bool)sOpt;
|
||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
||||
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) {if (oldPalette==-1) oldPalette = palette; setPalette(sOpt);} else {if (oldPalette!=-1) setPalette(oldPalette); oldPalette = -1;}
|
||||
}
|
||||
}
|
||||
if (!fadeTransition) markForReset(); // WLEDMM quickfix for effect "double startup" bug. -> only works when "Crossfade" is disabled (led settings)
|
||||
stateChanged = true; // send UDP/WS broadcast
|
||||
@@ -673,7 +701,11 @@ class JMapC {
|
||||
if (size > 0)
|
||||
return size;
|
||||
else
|
||||
#ifndef WLEDMM_FASTPATH
|
||||
return SEGMENT.virtualWidth() * SEGMENT.virtualHeight(); //pixels
|
||||
#else
|
||||
return SEGMENT.calc_virtualWidth() * SEGMENT.calc_virtualHeight(); // calc pixel sizes
|
||||
#endif
|
||||
}
|
||||
void setPixelColor(uint16_t i, uint32_t col) {
|
||||
updatejMapDoc();
|
||||
@@ -765,7 +797,11 @@ class JMapC {
|
||||
jMapFile.close();
|
||||
|
||||
maxWidth++; maxHeight++;
|
||||
#ifndef WLEDMM_FASTPATH
|
||||
scale = min(SEGMENT.virtualWidth() / maxWidth, SEGMENT.virtualHeight() / maxHeight); // WLEDMM use native min/max
|
||||
#else
|
||||
scale = min(SEGMENT.calc_virtualWidth() / maxWidth, SEGMENT.calc_virtualHeight() / maxHeight); // WLEDMM re-calc width/heiht from active settings
|
||||
#endif
|
||||
dataSize += sizeof(jVectorMap);
|
||||
USER_PRINT("dataSize ");
|
||||
USER_PRINT(dataSize);
|
||||
@@ -803,10 +839,13 @@ constexpr int Pinwheel_Size_Medium = 32; // larger than this -> use "Big"
|
||||
constexpr int Pinwheel_Steps_Big = 304; // no holes up to 50x50
|
||||
constexpr int Pinwheel_Size_Big = 50; // larger than this -> use "XL"
|
||||
constexpr int Pinwheel_Steps_XL = 368;
|
||||
constexpr int Pinwheel_Size_XL = 58; // larger than this -> use "XXL"
|
||||
constexpr int Pinwheel_Steps_XXL = 456;
|
||||
constexpr float Int_to_Rad_Small = (DEG_TO_RAD * 360) / Pinwheel_Steps_Small; // conversion: from 0...72 to Radians
|
||||
constexpr float Int_to_Rad_Med = (DEG_TO_RAD * 360) / Pinwheel_Steps_Medium; // conversion: from 0...192 to Radians
|
||||
constexpr float Int_to_Rad_Big = (DEG_TO_RAD * 360) / Pinwheel_Steps_Big; // conversion: from 0...304 to Radians
|
||||
constexpr float Int_to_Rad_XL = (DEG_TO_RAD * 360) / Pinwheel_Steps_XL; // conversion: from 0...368 to Radians
|
||||
constexpr float Int_to_Rad_XXL = (DEG_TO_RAD * 360) / Pinwheel_Steps_XXL; // conversion: from 0...456 to Radians
|
||||
|
||||
constexpr int Fixed_Scale = 512; // fixpoint scaling factor (9bit for fraction)
|
||||
|
||||
@@ -816,8 +855,9 @@ static float getPinwheelAngle(int i, int vW, int vH) {
|
||||
if (maxXY <= Pinwheel_Size_Small) return float(i) * Int_to_Rad_Small;
|
||||
if (maxXY <= Pinwheel_Size_Medium) return float(i) * Int_to_Rad_Med;
|
||||
if (maxXY <= Pinwheel_Size_Big) return float(i) * Int_to_Rad_Big;
|
||||
if (maxXY <= Pinwheel_Size_XL) return float(i) * Int_to_Rad_XL;
|
||||
// else
|
||||
return float(i) * Int_to_Rad_XL;
|
||||
return float(i) * Int_to_Rad_XXL;
|
||||
}
|
||||
// Pinwheel helper function: matrix dimensions to number of rays
|
||||
static int getPinwheelLength(int vW, int vH) {
|
||||
@@ -825,8 +865,9 @@ static int getPinwheelLength(int vW, int vH) {
|
||||
if (maxXY <= Pinwheel_Size_Small) return Pinwheel_Steps_Small;
|
||||
if (maxXY <= Pinwheel_Size_Medium) return Pinwheel_Steps_Medium;
|
||||
if (maxXY <= Pinwheel_Size_Big) return Pinwheel_Steps_Big;
|
||||
if (maxXY <= Pinwheel_Size_XL) return Pinwheel_Steps_XL;
|
||||
// else
|
||||
return Pinwheel_Steps_XL;
|
||||
return Pinwheel_Steps_XXL;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -873,7 +914,7 @@ uint16_t Segment::virtualLength() const {
|
||||
}
|
||||
|
||||
//WLEDMM used for M12_sBlock
|
||||
void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH, uint16_t vStrip) {
|
||||
static void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH, uint16_t vStrip) {
|
||||
float i2;
|
||||
if (i<=SEGLEN*0.25) { //top, left to right
|
||||
i2 = i/(SEGLEN*0.25);
|
||||
@@ -898,7 +939,7 @@ void xyFromBlock(uint16_t &x,uint16_t &y, uint16_t i, uint16_t vW, uint16_t vH,
|
||||
|
||||
}
|
||||
|
||||
void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATTR conditionally
|
||||
void IRAM_ATTR_YN __attribute__((hot)) Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATTR conditionally
|
||||
{
|
||||
if (!isActive()) return; // not active
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@@ -927,42 +968,51 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
|
||||
if (i==0)
|
||||
setPixelColorXY(0, 0, col);
|
||||
else {
|
||||
//WLEDMM: drawArc(0, 0, i, col); could work as alternative
|
||||
if (!_isSuperSimpleSegment) {
|
||||
// WLEDMM: drawArc() is faster if it's NOT "super simple" as the regular M12_pArc
|
||||
// can do "useSymmetry" to speed things along, but a more complicated segment likey
|
||||
// uses mirroring which generates a symmetry speed-up, or other things which mean
|
||||
// less pixels are calculated.
|
||||
drawArc(0, 0, i, col);
|
||||
} else {
|
||||
//WLEDMM: some optimizations for the drawing loop
|
||||
// pre-calculate loop limits, exploit symmetry at 45deg
|
||||
float radius = float(i);
|
||||
|
||||
// float step = HALF_PI / (2.85f * radius); // upstream uses this
|
||||
float step = HALF_PI / (M_PI * radius); // WLEDMM we use the correct circumference
|
||||
bool useSymmetry = (max(vH, vW) > 20); // for segments wider than 20 pixels, we exploit symmetry
|
||||
unsigned numSteps;
|
||||
if (useSymmetry) numSteps = 1 + ((HALF_PI/2.0f + step/2.0f) / step); // with symmetry
|
||||
else numSteps = 1 + ((HALF_PI + step/2.0f) / step); // without symmetry
|
||||
|
||||
//WLEDMM: some optimizations for the drawing loop
|
||||
// pre-calculate loop limits, exploit symmetry at 45deg
|
||||
float radius = float(i);
|
||||
// float step = HALF_PI / (2.85f * radius); // upstream uses this
|
||||
float step = HALF_PI / (M_PI * radius); // WLEDMM we use the correct circumference
|
||||
bool useSymmetry = (max(vH, vW) > 20); // for segments wider than 20 pixels, we exploit symmetry
|
||||
unsigned numSteps;
|
||||
if (useSymmetry) numSteps = 1 + ((HALF_PI/2.0f + step/2.0f) / step); // with symmetry
|
||||
else numSteps = 1 + ((HALF_PI + step/2.0f) / step); // without symmetry
|
||||
float rad = 0.0f;
|
||||
for (unsigned count = 0; count < numSteps; count++) {
|
||||
// may want to try float version as well (with or without antialiasing)
|
||||
// int x = max(0, min(vW-1, (int)roundf(sinf(rad) * radius)));
|
||||
// int y = max(0, min(vH-1, (int)roundf(cosf(rad) * radius)));
|
||||
int x = roundf(sinf(rad) * radius);
|
||||
int y = roundf(cosf(rad) * radius);
|
||||
setPixelColorXY(x, y, col);
|
||||
if(useSymmetry) setPixelColorXY(y, x, col);// WLEDMM
|
||||
rad += step;
|
||||
}
|
||||
|
||||
float rad = 0.0f;
|
||||
for (unsigned count = 0; count < numSteps; count++) {
|
||||
// may want to try float version as well (with or without antialiasing)
|
||||
int x = roundf(sinf(rad) * radius);
|
||||
int y = roundf(cosf(rad) * radius);
|
||||
setPixelColorXY(x, y, col);
|
||||
if(useSymmetry) setPixelColorXY(y, x, col);// WLEDMM
|
||||
rad += step;
|
||||
// // Bresenham’s Algorithm (may not fill every pixel)
|
||||
// int d = 3 - (2*i);
|
||||
// int y = i, x = 0;
|
||||
// while (y >= x) {
|
||||
// setPixelColorXY(x, y, col);
|
||||
// setPixelColorXY(y, x, col);
|
||||
// x++;
|
||||
// if (d > 0) {
|
||||
// y--;
|
||||
// d += 4 * (x - y) + 10;
|
||||
// } else {
|
||||
// d += 4 * x + 6;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
// Bresenham’s Algorithm (may not fill every pixel)
|
||||
//int d = 3 - (2*i);
|
||||
//int y = i, x = 0;
|
||||
//while (y >= x) {
|
||||
// setPixelColorXY(x, y, col);
|
||||
// setPixelColorXY(y, x, col);
|
||||
// x++;
|
||||
// if (d > 0) {
|
||||
// y--;
|
||||
// d += 4 * (x - y) + 10;
|
||||
// } else {
|
||||
// d += 4 * x + 6;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
break;
|
||||
case M12_pCorner: {
|
||||
@@ -1057,7 +1107,7 @@ void IRAM_ATTR_YN Segment::setPixelColor(int i, uint32_t col) //WLEDMM: IRAM_ATT
|
||||
// set pixel
|
||||
if (x != lastX || y != lastY) { // only paint if pixel position is different
|
||||
if (simpleSegment) setPixelColorXY_fast(x, y, col, scaled_col, vW, vH);
|
||||
else setPixelColorXY(x, y, col);
|
||||
else setPixelColorXY_slow(x, y, col);
|
||||
}
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
@@ -1162,7 +1212,7 @@ void Segment::setPixelColor(float i, uint32_t col, bool aa)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Segment::getPixelColor(int i)
|
||||
uint32_t __attribute__((hot)) Segment::getPixelColor(int i) const
|
||||
{
|
||||
if (!isActive()) return 0; // not active
|
||||
#ifndef WLED_DISABLE_2D
|
||||
@@ -1254,7 +1304,7 @@ uint32_t Segment::getPixelColor(int i)
|
||||
if (offset < INT16_MAX) i += offset; // WLEDMM
|
||||
if ((i >= stop) && (stop>0)) i -= length(); // WLEDMM avoid negative index (stop = 0 is a possible value)
|
||||
if (i<0) i=0; // WLEDMM just to be 100% sure
|
||||
return strip.getPixelColor(i);
|
||||
return strip.getPixelColorRestored(i);
|
||||
}
|
||||
|
||||
uint8_t Segment::differs(Segment& b) const {
|
||||
@@ -1336,8 +1386,20 @@ void Segment::refreshLightCapabilities() {
|
||||
/*
|
||||
* Fills segment with color - WLEDMM using faster sPC if possible
|
||||
*/
|
||||
void Segment::fill(uint32_t c) {
|
||||
void __attribute__((hot)) Segment::fill(uint32_t c) {
|
||||
if (!isActive()) return; // not active
|
||||
|
||||
#if 0 && defined(WLED_ENABLE_HUB75MATRIX) && defined(WLEDMM_FASTPATH)
|
||||
// DIRTY HACK - this ignores the first fill(black) in each frame, knowing that HUB75 has already blanked out the display.
|
||||
if (_firstFill) {
|
||||
_firstFill = false;
|
||||
if (c == BLACK) {
|
||||
if (ledsrgb && ledsrgbSize > 0) memset(ledsrgb, 0, ledsrgbSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types
|
||||
const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
|
||||
@@ -1351,12 +1413,12 @@ void Segment::fill(uint32_t c) {
|
||||
if (_bri_t < 255) scaled_col = color_fade(c, _bri_t);
|
||||
}
|
||||
// fill 2D segment
|
||||
for(int y = 0; y < rows; y++) for (int x = 0; x < cols; x++) {
|
||||
for(unsigned y = 0; y < rows; y++) for (unsigned x = 0; x < cols; x++) {
|
||||
if (simpleSegment) setPixelColorXY_fast(x, y, c, scaled_col, cols, rows);
|
||||
else setPixelColorXY(x, y, c);
|
||||
else setPixelColorXY_slow(x, y, c);
|
||||
}
|
||||
} else { // fill 1D strip
|
||||
for (int x = 0; x < cols; x++) setPixelColor(x, c);
|
||||
for (unsigned x = 0; x < cols; x++) setPixelColor(int(x), c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1395,7 +1457,7 @@ void Segment::fadePixelColor(uint16_t n, uint8_t fade) {
|
||||
/*
|
||||
* fade out function, higher rate = quicker fade
|
||||
*/
|
||||
void Segment::fade_out(uint8_t rate) {
|
||||
void __attribute__((hot)) Segment::fade_out(uint8_t rate) {
|
||||
if (!isActive()) return; // not active
|
||||
const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types
|
||||
const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
@@ -1409,8 +1471,8 @@ void Segment::fade_out(uint8_t rate) {
|
||||
int g2 = G(color2);
|
||||
int b2 = B(color2);
|
||||
|
||||
for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) {
|
||||
uint32_t color = is2D() ? getPixelColorXY(x, y) : getPixelColor(x);
|
||||
for (unsigned y = 0; y < rows; y++) for (unsigned x = 0; x < cols; x++) {
|
||||
uint32_t color = is2D() ? getPixelColorXY(int(x), int(y)) : getPixelColor(int(x));
|
||||
if (color == color2) continue; // WLEDMM speedup - pixel color = target color, so nothing to do
|
||||
int w1 = W(color);
|
||||
int r1 = R(color);
|
||||
@@ -1427,15 +1489,17 @@ void Segment::fade_out(uint8_t rate) {
|
||||
rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1;
|
||||
gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1;
|
||||
bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1;
|
||||
uint32_t colorNew = RGBW32(r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); // WLEDMM
|
||||
|
||||
//if ((wdelta == 0) && (rdelta == 0) && (gdelta == 0) && (bdelta == 0)) continue; // WLEDMM delta = zero => no change // causes problem with text overlay
|
||||
if (is2D()) setPixelColorXY((uint16_t)x, (uint16_t)y, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
|
||||
else setPixelColor((uint16_t)x, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta);
|
||||
if (colorNew != color) { // WLEDMM speedup - do not repaint the same color
|
||||
if (is2D()) setPixelColorXY(int(x), int(y), colorNew);
|
||||
else setPixelColor(int(x), colorNew);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fades all pixels to black using nscale8()
|
||||
void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
void __attribute__((hot)) Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
if (!isActive() || fadeBy == 0) return; // optimization - no scaling to apply
|
||||
const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types
|
||||
const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D
|
||||
@@ -1443,8 +1507,13 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
|
||||
// WLEDMM minor optimization
|
||||
if(is2D()) {
|
||||
for (uint_fast16_t y = 0; y < rows; y++) for (uint_fast16_t x = 0; x < cols; x++) {
|
||||
setPixelColorXY((uint16_t)x, (uint16_t)y, CRGB(getPixelColorXY(x,y)).nscale8(scaledown));
|
||||
for (unsigned y = 0; y < rows; y++) for (unsigned x = 0; x < cols; x++) {
|
||||
uint32_t cc = getPixelColorXY(int(x),int(y)); // WLEDMM avoid RGBW32 -> CRGB -> RGBW32 conversion
|
||||
uint32_t cc2 = color_fade(cc, scaledown); // fade
|
||||
#ifdef WLEDMM_FASTPATH
|
||||
if (cc2 != cc) // WLEDMM only re-paint if faded color is different - normally disabled - causes problem with text overlay
|
||||
#endif
|
||||
setPixelColorXY(int(x), int(y), cc2);
|
||||
}
|
||||
} else {
|
||||
for (uint_fast16_t x = 0; x < cols; x++) {
|
||||
@@ -1456,7 +1525,7 @@ void Segment::fadeToBlackBy(uint8_t fadeBy) {
|
||||
/*
|
||||
* blurs segment content, source: FastLED colorutils.cpp
|
||||
*/
|
||||
void Segment::blur(uint8_t blur_amount, bool smear) {
|
||||
void __attribute__((hot)) 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()) {
|
||||
@@ -1517,7 +1586,7 @@ uint32_t Segment::color_wheel(uint8_t pos) {
|
||||
/*
|
||||
* Returns a new, random wheel index with a minimum distance of 42 from pos.
|
||||
*/
|
||||
uint8_t Segment::get_random_wheel_index(uint8_t pos) { // WLEDMM use fast int types, use native min/max
|
||||
uint8_t Segment::get_random_wheel_index(uint8_t pos) const { // WLEDMM use fast int types, use native min/max
|
||||
uint_fast8_t r = 0, x = 0, y = 0, d = 0;
|
||||
|
||||
while(d < 42) {
|
||||
@@ -1538,7 +1607,7 @@ uint8_t Segment::get_random_wheel_index(uint8_t pos) { // WLEDMM use fast int ty
|
||||
* @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling)
|
||||
* @returns Single color from palette
|
||||
*/
|
||||
uint32_t Segment::color_from_palette(uint_fast16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) // WLEDMM use fast int types
|
||||
uint32_t __attribute__((hot)) Segment::color_from_palette(uint_fast16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) // WLEDMM use fast int types
|
||||
{
|
||||
// default palette or no RGB support on segment
|
||||
if ((palette == 0 && mcol < NUM_COLORS) || !_isRGB) {
|
||||
@@ -1558,7 +1627,7 @@ uint32_t Segment::color_from_palette(uint_fast16_t i, bool mapping, bool wrap, u
|
||||
}
|
||||
|
||||
//WLEDMM netmindz ar palette
|
||||
uint8_t * Segment::getAudioPalette(int pal) {
|
||||
uint8_t * Segment::getAudioPalette(int pal) const {
|
||||
// https://forum.makerforums.info/t/hi-is-it-possible-to-define-a-gradient-palette-at-runtime-the-define-gradient-palette-uses-the/63339
|
||||
|
||||
um_data_t *um_data;
|
||||
@@ -1835,6 +1904,7 @@ void WS2812FX::service() {
|
||||
if (!cctFromRgb || correctWB) busses.setSegmentCCT(seg.currentBri(seg.cct, true), correctWB);
|
||||
for (uint8_t c = 0; c < NUM_COLORS; c++) _colors_t[c] = gamma32(_colors_t[c]);
|
||||
|
||||
seg.startFrame(); // WLEDMM
|
||||
// effect blending (execute previous effect)
|
||||
// actual code may be a bit more involved as effects have runtime data including allocated memory
|
||||
//if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress());
|
||||
@@ -1866,13 +1936,19 @@ void IRAM_ATTR WS2812FX::setPixelColor(int i, uint32_t col)
|
||||
busses.setPixelColor(i, col);
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getPixelColor(uint_fast16_t i) // WLEDMM fast int types
|
||||
uint32_t WS2812FX::getPixelColor(uint_fast16_t i) const // WLEDMM fast int types
|
||||
{
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
if (i >= _length) return 0;
|
||||
return busses.getPixelColor(i);
|
||||
}
|
||||
|
||||
uint32_t WS2812FX::getPixelColorRestored(uint_fast16_t i) const // WLEDMM gets the original color from the driver (without downscaling by _bri)
|
||||
{
|
||||
if (i < customMappingSize) i = customMappingTable[i];
|
||||
if (i >= _length) return 0;
|
||||
return busses.getPixelColorRestored(i);
|
||||
}
|
||||
|
||||
//DISCLAIMER
|
||||
//The following function attemps to calculate the current LED power usage,
|
||||
@@ -1917,7 +1993,8 @@ void WS2812FX::estimateCurrentAndLimitBri() {
|
||||
|
||||
for (uint_fast8_t bNum = 0; bNum < busses.getNumBusses(); bNum++) {
|
||||
Bus *bus = busses.getBus(bNum);
|
||||
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
|
||||
auto btype = bus->getType();
|
||||
if (EXCLUDE_FROM_ABL(btype)) continue; // WLEDMM exclude non-ABL and network busses
|
||||
uint16_t len = bus->getLength();
|
||||
uint32_t busPowerSum = 0;
|
||||
for (uint_fast16_t i = 0; i < len; i++) { //sum up the usage of each LED
|
||||
@@ -2004,7 +2081,7 @@ void WS2812FX::show(void) {
|
||||
* 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() {
|
||||
bool WS2812FX::isUpdating() const {
|
||||
return !busses.canAllShow();
|
||||
}
|
||||
|
||||
@@ -2012,7 +2089,7 @@ bool WS2812FX::isUpdating() {
|
||||
* 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() {
|
||||
uint16_t WS2812FX::getFps() const {
|
||||
if (millis() - _lastShow > 2000) return 0;
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
return ((_cumulativeFps500 + 250) / 500); // +250 for proper rounding
|
||||
@@ -2103,14 +2180,14 @@ void WS2812FX::setMainSegmentId(uint8_t n) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getLastActiveSegmentId(void) {
|
||||
uint8_t WS2812FX::getLastActiveSegmentId(void) const {
|
||||
for (size_t i = _segments.size() -1; i > 0; i--) {
|
||||
if (_segments[i].isActive()) return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t WS2812FX::getActiveSegmentsNum(void) {
|
||||
uint8_t WS2812FX::getActiveSegmentsNum(void) const {
|
||||
uint8_t c = 0;
|
||||
for (size_t i = 0; i < _segments.size(); i++) {
|
||||
if (_segments[i].isActive()) c++;
|
||||
@@ -2118,17 +2195,30 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) {
|
||||
return c;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthTotal(void) { // WLEDMM fast int types
|
||||
uint16_t WS2812FX::getLengthTotal(void) const { // WLEDMM fast int types
|
||||
uint_fast16_t len = Segment::maxWidth * Segment::maxHeight; // will be _length for 1D (see finalizeInit()) but should cover whole matrix for 2D
|
||||
if (isMatrix && _length > len) len = _length; // for 2D with trailing strip
|
||||
return len;
|
||||
}
|
||||
|
||||
uint16_t WS2812FX::getLengthPhysical(void) { // WLEDMM fast int types
|
||||
uint16_t WS2812FX::getLengthPhysical(void) const { // WLEDMM fast int types
|
||||
uint_fast16_t len = 0;
|
||||
for (unsigned b = 0; b < busses.getNumBusses(); b++) { // WLEDMM use native (fast) types
|
||||
Bus *bus = busses.getBus(b);
|
||||
if (bus->getType() >= TYPE_NET_DDP_RGB) continue; //exclude non-physical network busses
|
||||
auto btype = bus->getType();
|
||||
if (EXCLUDE_FROM_ABL(btype)) continue; //exclude HUB75, and non-physical network busses
|
||||
len += bus->getLength();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
//WLEDMM - getLengthPhysical plus plysical busses not supporting ABL (i.e. HUB75)
|
||||
uint16_t WS2812FX::getLengthPhysical2(void) const {
|
||||
uint_fast16_t len = 0;
|
||||
for (unsigned b = 0; b < busses.getNumBusses(); b++) {
|
||||
Bus *bus = busses.getBus(b);
|
||||
auto btype = bus->getType();
|
||||
if (IS_VIRTUAL(btype)) continue;
|
||||
len += bus->getLength();
|
||||
}
|
||||
return len;
|
||||
@@ -2137,7 +2227,7 @@ uint16_t WS2812FX::getLengthPhysical(void) { // WLEDMM fast int types
|
||||
//used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw.
|
||||
//returns if there is an RGBW bus (supports RGB and White, not only white)
|
||||
//not influenced by auto-white mode, also true if white slider does not affect output white channel
|
||||
bool WS2812FX::hasRGBWBus(void) {
|
||||
bool WS2812FX::hasRGBWBus(void) const {
|
||||
for (unsigned b = 0; b < busses.getNumBusses(); b++) { // WLEDMM use native (fast) types
|
||||
Bus *bus = busses.getBus(b);
|
||||
if (bus == nullptr || bus->getLength()==0) break;
|
||||
@@ -2146,7 +2236,7 @@ bool WS2812FX::hasRGBWBus(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WS2812FX::hasCCTBus(void) {
|
||||
bool WS2812FX::hasCCTBus(void) const {
|
||||
if (cctFromRgb && !correctWB) return false;
|
||||
for (unsigned b = 0; b < busses.getNumBusses(); b++) { // WLEDMM use native (fast) types
|
||||
Bus *bus = busses.getBus(b);
|
||||
@@ -2490,6 +2580,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
uint16_t maxHeight = atoi(cleanUpName(fileName));
|
||||
//DEBUG_PRINTF(" (\"height\": %s) \n", fileName)
|
||||
|
||||
#ifndef WLEDMM_NO_MAP_RESET
|
||||
//WLEDMM: support ledmap file properties width and height: if found change segment
|
||||
if (maxWidth * maxHeight > 0) {
|
||||
Segment::maxWidth = maxWidth;
|
||||
@@ -2498,6 +2589,7 @@ bool WS2812FX::deserializeMap(uint8_t n) {
|
||||
}
|
||||
else
|
||||
setUpMatrix(); //reset segment sizes to panels
|
||||
#endif
|
||||
}
|
||||
|
||||
USER_PRINTF("deserializeMap %d x %d\n", Segment::maxWidth, Segment::maxHeight);
|
||||
|
||||
@@ -9,6 +9,36 @@
|
||||
#include "bus_wrapper.h"
|
||||
#include "bus_manager.h"
|
||||
|
||||
// WLEDMM functions to get/set bits in an array - based on functions created by Brandon for GOL
|
||||
// toDo : make this a class that's completely defined in a header file
|
||||
bool getBitFromArray(const uint8_t* byteArray, size_t position) { // get bit value
|
||||
size_t byteIndex = position / 8;
|
||||
unsigned bitIndex = position % 8;
|
||||
uint8_t byteValue = byteArray[byteIndex];
|
||||
return (byteValue >> bitIndex) & 1;
|
||||
}
|
||||
|
||||
void setBitInArray(uint8_t* byteArray, size_t position, bool value) { // set bit - with error handling for nullptr
|
||||
//if (byteArray == nullptr) return;
|
||||
size_t byteIndex = position / 8;
|
||||
unsigned bitIndex = position % 8;
|
||||
if (value)
|
||||
byteArray[byteIndex] |= (1 << bitIndex);
|
||||
else
|
||||
byteArray[byteIndex] &= ~(1 << bitIndex);
|
||||
}
|
||||
|
||||
size_t getBitArrayBytes(size_t num_bits) { // number of bytes needed for an array with num_bits bits
|
||||
return (num_bits + 7) / 8;
|
||||
}
|
||||
|
||||
void setBitArray(uint8_t* byteArray, size_t numBits, bool value) { // set all bits to same value
|
||||
if (byteArray == nullptr) return;
|
||||
size_t len = getBitArrayBytes(numBits);
|
||||
if (value) memset(byteArray, 0xFF, len);
|
||||
else memset(byteArray, 0x00, len);
|
||||
}
|
||||
|
||||
//WLEDMM: #define DEBUGOUT(x) netDebugEnabled?NetDebug.print(x):Serial.print(x) not supported in this file as netDebugEnabled not in scope
|
||||
#if 0
|
||||
//colors.cpp
|
||||
@@ -49,13 +79,6 @@ uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte
|
||||
#include "wled.h"
|
||||
#endif
|
||||
|
||||
//color mangling macros
|
||||
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
||||
#define R(c) (byte((c) >> 16))
|
||||
#define G(c) (byte((c) >> 8))
|
||||
#define B(c) (byte(c))
|
||||
#define W(c) (byte((c) >> 24))
|
||||
|
||||
|
||||
void ColorOrderMap::add(uint16_t start, uint16_t len, uint8_t colorOrder) {
|
||||
if (_count >= WLED_MAX_COLOR_ORDER_MAPPINGS) {
|
||||
@@ -86,7 +109,7 @@ uint8_t IRAM_ATTR ColorOrderMap::getPixelColorOrder(uint16_t pix, uint8_t defaul
|
||||
}
|
||||
|
||||
|
||||
uint32_t Bus::autoWhiteCalc(uint32_t c) {
|
||||
uint32_t Bus::autoWhiteCalc(uint32_t c) const {
|
||||
uint8_t aWM = _autoWhiteMode;
|
||||
if (_gAWM != AW_GLOBAL_DISABLED) aWM = _gAWM;
|
||||
if (aWM == RGBW_MODE_MANUAL_ONLY) return c;
|
||||
@@ -182,7 +205,7 @@ void IRAM_ATTR BusDigital::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
PolyBus::setPixelColor(_busPtr, _iType, pix, c, co);
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR_YN BusDigital::getPixelColor(uint16_t pix) {
|
||||
uint32_t IRAM_ATTR_YN BusDigital::getPixelColor(uint16_t pix) const {
|
||||
if (reversed) pix = _len - pix -1;
|
||||
else pix += _skip;
|
||||
uint8_t co = _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder);
|
||||
@@ -200,7 +223,7 @@ uint32_t IRAM_ATTR_YN BusDigital::getPixelColor(uint16_t pix) {
|
||||
return PolyBus::getPixelColor(_busPtr, _iType, pix, co);
|
||||
}
|
||||
|
||||
uint8_t BusDigital::getPins(uint8_t* pinArray) {
|
||||
uint8_t BusDigital::getPins(uint8_t* pinArray) const {
|
||||
uint8_t numPins = IS_2PIN(_type) ? 2 : 1;
|
||||
for (uint8_t i = 0; i < numPins; i++) pinArray[i] = _pins[i];
|
||||
return numPins;
|
||||
@@ -317,7 +340,7 @@ void BusPwm::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
}
|
||||
|
||||
//does no index check
|
||||
uint32_t BusPwm::getPixelColor(uint16_t pix) {
|
||||
uint32_t BusPwm::getPixelColor(uint16_t pix) const {
|
||||
if (!_valid) return 0;
|
||||
#if 1
|
||||
// WLEDMM stick with the old code - we don't have cctICused
|
||||
@@ -356,7 +379,7 @@ void BusPwm::show() {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t BusPwm::getPins(uint8_t* pinArray) {
|
||||
uint8_t BusPwm::getPins(uint8_t* pinArray) const {
|
||||
if (!_valid) return 0;
|
||||
uint8_t numPins = NUM_PWM_PINS(_type);
|
||||
for (uint8_t i = 0; i < numPins; i++) {
|
||||
@@ -408,7 +431,7 @@ void BusOnOff::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
_data = bool(r|g|b|w) && bool(_bri) ? 0xFF : 0;
|
||||
}
|
||||
|
||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) {
|
||||
uint32_t BusOnOff::getPixelColor(uint16_t pix) const {
|
||||
if (!_valid) return 0;
|
||||
return RGBW32(_data, _data, _data, _data);
|
||||
}
|
||||
@@ -418,7 +441,7 @@ void BusOnOff::show() {
|
||||
digitalWrite(_pin, reversed ? !(bool)_data : (bool)_data);
|
||||
}
|
||||
|
||||
uint8_t BusOnOff::getPins(uint8_t* pinArray) {
|
||||
uint8_t BusOnOff::getPins(uint8_t* pinArray) const {
|
||||
if (!_valid) return 0;
|
||||
pinArray[0] = _pin;
|
||||
return 1;
|
||||
@@ -467,7 +490,7 @@ void BusNetwork::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (_rgbw) _data[offset+3] = W(c);
|
||||
}
|
||||
|
||||
uint32_t BusNetwork::getPixelColor(uint16_t pix) {
|
||||
uint32_t BusNetwork::getPixelColor(uint16_t pix) const {
|
||||
if (!_valid || pix >= _len) return 0;
|
||||
uint16_t offset = pix * _UDPchannels;
|
||||
return RGBW32(_data[offset], _data[offset+1], _data[offset+2], _rgbw ? (_data[offset+3] << 24) : 0);
|
||||
@@ -480,7 +503,7 @@ void BusNetwork::show() {
|
||||
_broadcastLock = false;
|
||||
}
|
||||
|
||||
uint8_t BusNetwork::getPins(uint8_t* pinArray) {
|
||||
uint8_t BusNetwork::getPins(uint8_t* pinArray) const {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
pinArray[i] = _client[i];
|
||||
}
|
||||
@@ -500,12 +523,35 @@ void BusNetwork::cleanup() {
|
||||
#warning "HUB75 driver enabled (experimental)"
|
||||
|
||||
BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWhite) {
|
||||
size_t lastHeap = ESP.getFreeHeap();
|
||||
|
||||
mxconfig.double_buff = false; // default to off, known to cause issue with some effects but needs more memory
|
||||
|
||||
|
||||
_valid = false;
|
||||
fourScanPanel = nullptr;
|
||||
|
||||
mxconfig.double_buff = false; // Use our own memory-optimised buffer rather than the driver's own double-buffer
|
||||
|
||||
// mxconfig.driver = HUB75_I2S_CFG::ICN2038S; // experimental - use specific shift register driver
|
||||
// mxconfig.latch_blanking = 3;
|
||||
// mxconfig.i2sspeed = HUB75_I2S_CFG::HZ_10M; // experimental - 5MHZ should be enugh, but colours looks slightly better at 10MHz
|
||||
// mxconfig.min_refresh_rate = 90;
|
||||
mxconfig.clkphase = false; // can help in case that the leftmost column is invisible, or pixels on the right side "bleeds out" to the left.
|
||||
|
||||
// How many panels we have connected, cap at sane value
|
||||
mxconfig.chain_length = max((uint8_t) 1, min(bc.pins[0], (uint8_t) 4)); // prevent bad data preventing boot due to low memory
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(BOARD_HAS_PSRAM)
|
||||
if(bc.pins[0] > 4) {
|
||||
USER_PRINTLN("WARNING, chain limited to 4");
|
||||
}
|
||||
# else
|
||||
// Disable this check if you are want to try bigger setups and accept you
|
||||
// might need to do full erase to recover from memory relayed boot-loop if you push too far
|
||||
if(mxconfig.mx_height >= 64 && (bc.pins[0] > 1)) {
|
||||
USER_PRINTLN("WARNING, only single panel can be used of 64 pixel boards due to memory");
|
||||
//mxconfig.chain_length = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(bc.type) {
|
||||
case 101:
|
||||
mxconfig.mx_width = 32;
|
||||
@@ -533,12 +579,13 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
|
||||
break;
|
||||
}
|
||||
|
||||
if(mxconfig.mx_height >= 64 && (bc.pins[0] > 1)) {
|
||||
USER_PRINT("WARNING, only single panel can be used of 64 pixel boards due to memory")
|
||||
mxconfig.chain_length = 1;
|
||||
}
|
||||
|
||||
// mxconfig.driver = HUB75_I2S_CFG::SHIFTREG;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S2)// classic esp32, or esp32-s2: reduce bitdepth for large panels
|
||||
if (mxconfig.mx_height >= 64) {
|
||||
if (mxconfig.chain_length * mxconfig.mx_width > 192) mxconfig.setPixelColorDepthBits(3);
|
||||
else if (mxconfig.chain_length * mxconfig.mx_width > 64) mxconfig.setPixelColorDepthBits(4);
|
||||
else mxconfig.setPixelColorDepthBits(8);
|
||||
} else mxconfig.setPixelColorDepthBits(8);
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ADAFRUIT_MATRIXPORTAL_ESP32S3) // MatrixPortal ESP32-S3
|
||||
|
||||
@@ -546,8 +593,6 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
|
||||
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA - Matrix Portal S3 config");
|
||||
|
||||
mxconfig.double_buff = true; // <------------- Turn on double buffer
|
||||
|
||||
mxconfig.gpio.r1 = 42;
|
||||
mxconfig.gpio.g1 = 41;
|
||||
mxconfig.gpio.b1 = 40;
|
||||
@@ -565,6 +610,76 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
|
||||
mxconfig.gpio.d = 35;
|
||||
mxconfig.gpio.e = 21;
|
||||
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3) && defined(BOARD_HAS_PSRAM)// ESP32-S3
|
||||
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA - S3 with PSRAM");
|
||||
|
||||
mxconfig.gpio.r1 = 1;
|
||||
mxconfig.gpio.g1 = 2;
|
||||
mxconfig.gpio.b1 = 42;
|
||||
// 4th pin is GND
|
||||
mxconfig.gpio.r2 = 41;
|
||||
mxconfig.gpio.g2 = 40;
|
||||
mxconfig.gpio.b2 = 39;
|
||||
mxconfig.gpio.e = 38;
|
||||
mxconfig.gpio.a = 45;
|
||||
mxconfig.gpio.b = 48;
|
||||
mxconfig.gpio.c = 47;
|
||||
mxconfig.gpio.d = 21;
|
||||
mxconfig.gpio.clk = 18;
|
||||
mxconfig.gpio.lat = 8;
|
||||
mxconfig.gpio.oe = 3;
|
||||
// 16th pin is GND
|
||||
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3) // ESP32-S3
|
||||
|
||||
// Huidu HD-WF2 ESP32-S3
|
||||
// https://www.aliexpress.com/item/1005002258734810.html
|
||||
// https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/issues/433
|
||||
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA - HD-WF2 S3 config");
|
||||
|
||||
mxconfig.gpio.r1 = 2;
|
||||
mxconfig.gpio.g1 = 6;
|
||||
mxconfig.gpio.b1 = 10;
|
||||
mxconfig.gpio.r2 = 3;
|
||||
mxconfig.gpio.g2 = 7;
|
||||
mxconfig.gpio.b2 = 11;
|
||||
|
||||
mxconfig.gpio.lat = 33;
|
||||
mxconfig.gpio.oe = 35;
|
||||
mxconfig.gpio.clk = 34;
|
||||
|
||||
mxconfig.gpio.a = 39;
|
||||
mxconfig.gpio.b = 38;
|
||||
mxconfig.gpio.c = 37;
|
||||
mxconfig.gpio.d = 36;
|
||||
mxconfig.gpio.e = 21;
|
||||
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2) // ESP32-S2
|
||||
|
||||
// Huidu HD-WF1 ESP32-S2
|
||||
// https://github.com/mrcodetastic/ESP32-HUB75-MatrixPanel-DMA/issues/433
|
||||
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA - HD-WF1 S2 config");
|
||||
|
||||
mxconfig.gpio.r1 = 2;
|
||||
mxconfig.gpio.g1 = 6;
|
||||
mxconfig.gpio.b1 = 3;
|
||||
mxconfig.gpio.r2 = 4;
|
||||
mxconfig.gpio.g2 = 8;
|
||||
mxconfig.gpio.b2 = 5;
|
||||
|
||||
mxconfig.gpio.lat = 33;
|
||||
mxconfig.gpio.oe = 35;
|
||||
mxconfig.gpio.clk = 34;
|
||||
|
||||
mxconfig.gpio.a = 39;
|
||||
mxconfig.gpio.b = 38;
|
||||
mxconfig.gpio.c = 37;
|
||||
mxconfig.gpio.d = 36;
|
||||
mxconfig.gpio.e = 12;
|
||||
|
||||
#elif defined(ESP32_FORUM_PINOUT) // Common format for boards designed for SmartMatrix
|
||||
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA - ESP32_FORUM_PINOUT");
|
||||
@@ -624,9 +739,8 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
|
||||
|
||||
#endif
|
||||
|
||||
mxconfig.chain_length = max((u_int8_t) 1, min(bc.pins[0], (u_int8_t) 4)); // prevent bad data preventing boot due to low memory
|
||||
|
||||
USER_PRINTF("MatrixPanel_I2S_DMA config - %ux%u length: %u\n", mxconfig.mx_width, mxconfig.mx_height, mxconfig.chain_length);
|
||||
USER_PRINTF("MatrixPanel_I2S_DMA config - %ux%u (type %u) length: %u, %u bits/pixel.\n", mxconfig.mx_width, mxconfig.mx_height, bc.type, mxconfig.chain_length, mxconfig.getPixelColorDepthBits() * 3);
|
||||
DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap()); lastHeap = ESP.getFreeHeap();
|
||||
|
||||
// OK, now we can create our matrix object
|
||||
display = new MatrixPanel_I2S_DMA(mxconfig);
|
||||
@@ -655,14 +769,50 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA created");
|
||||
// let's adjust default brightness
|
||||
display->setBrightness8(25); // range is 0-255, 0 - 0%, 255 - 100%
|
||||
_bri = 25;
|
||||
|
||||
delay(24); // experimental
|
||||
DEBUG_PRINT(F("heap usage: ")); DEBUG_PRINTLN(lastHeap - ESP.getFreeHeap());
|
||||
// Allocate memory and start DMA display
|
||||
if( not display->begin() ) {
|
||||
USER_PRINTLN("****** MatrixPanel_I2S_DMA !KABOOM! I2S memory allocation failed ***********");
|
||||
USER_PRINT(F("heap usage: ")); USER_PRINTLN(lastHeap - ESP.getFreeHeap());
|
||||
return;
|
||||
}
|
||||
else {
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA begin ok");
|
||||
USER_PRINT(F("heap usage: ")); USER_PRINTLN(lastHeap - ESP.getFreeHeap());
|
||||
delay(18); // experiment - give the driver a moment (~ one full frame @ 60hz) to settle
|
||||
_valid = true;
|
||||
display->clearScreen(); // initially clear the screen buffer
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA clear ok");
|
||||
|
||||
if (_ledBuffer) free(_ledBuffer); // should not happen
|
||||
if (_ledsDirty) free(_ledsDirty); // should not happen
|
||||
|
||||
_ledsDirty = (byte*) malloc(getBitArrayBytes(_len)); // create LEDs dirty bits
|
||||
|
||||
if (_ledsDirty == nullptr) {
|
||||
display->stopDMAoutput();
|
||||
delete display; display = nullptr;
|
||||
_valid = false;
|
||||
USER_PRINTLN(F("MatrixPanel_I2S_DMA not started - not enough memory for dirty bits!"));
|
||||
USER_PRINT(F("heap usage: ")); USER_PRINTLN(lastHeap - ESP.getFreeHeap());
|
||||
return; // fail is we cannot get memory for the buffer
|
||||
}
|
||||
setBitArray(_ledsDirty, _len, false); // reset dirty bits
|
||||
|
||||
if (mxconfig.double_buff == false) {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3) && CONFIG_SPIRAM_MODE_OCT && defined(BOARD_HAS_PSRAM) && (defined(WLED_USE_PSRAM) || defined(WLED_USE_PSRAM_JSON))
|
||||
if (psramFound()) {
|
||||
_ledBuffer = (CRGB*) ps_calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
|
||||
} else {
|
||||
_ledBuffer = (CRGB*) calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
|
||||
}
|
||||
#else
|
||||
_ledBuffer = (CRGB*) calloc(_len, sizeof(CRGB)); // create LEDs buffer (initialized to BLACK)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
switch(bc.type) {
|
||||
@@ -686,28 +836,134 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh
|
||||
break;
|
||||
}
|
||||
|
||||
if (_valid) {
|
||||
_panelWidth = fourScanPanel ? fourScanPanel->width() : display->width(); // cache width - it will never change
|
||||
}
|
||||
|
||||
USER_PRINTLN("MatrixPanel_I2S_DMA started");
|
||||
USER_PRINT(F("MatrixPanel_I2S_DMA "));
|
||||
USER_PRINTF("%sstarted, width=%u, %u pixels.\n", _valid? "":"not ", _panelWidth, _len);
|
||||
|
||||
if (mxconfig.double_buff == true) USER_PRINTLN(F("MatrixPanel_I2S_DMA driver native double-buffering enabled."));
|
||||
if (_ledBuffer != nullptr) USER_PRINTLN(F("MatrixPanel_I2S_DMA LEDS buffer enabled."));
|
||||
if (_ledsDirty != nullptr) USER_PRINTLN(F("MatrixPanel_I2S_DMA LEDS dirty bit optimization enabled."));
|
||||
if ((_ledBuffer != nullptr) || (_ledsDirty != nullptr)) {
|
||||
USER_PRINT(F("MatrixPanel_I2S_DMA LEDS buffer uses "));
|
||||
USER_PRINT((_ledBuffer? _len*sizeof(CRGB) :0) + (_ledsDirty? getBitArrayBytes(_len) :0));
|
||||
USER_PRINTLN(F(" bytes."));
|
||||
}
|
||||
USER_PRINT(F("heap usage: ")); USER_PRINTLN(lastHeap - ESP.getFreeHeap());
|
||||
}
|
||||
|
||||
void BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
r = R(c);
|
||||
g = G(c);
|
||||
b = B(c);
|
||||
if(fourScanPanel != nullptr) {
|
||||
x = pix % fourScanPanel->width();
|
||||
y = floor(pix / fourScanPanel->width());
|
||||
fourScanPanel->drawPixelRGB888(x, y, r, g, b);
|
||||
void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) {
|
||||
if (!_valid || pix >= _len) return;
|
||||
// if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT
|
||||
|
||||
if (_ledBuffer) {
|
||||
CRGB fastled_col = CRGB(c);
|
||||
if (_ledBuffer[pix] != fastled_col) {
|
||||
_ledBuffer[pix] = fastled_col;
|
||||
setBitInArray(_ledsDirty, pix, true); // flag pixel as "dirty"
|
||||
}
|
||||
}
|
||||
else {
|
||||
x = pix % display->width();
|
||||
y = floor(pix / display->width());
|
||||
display->drawPixelRGB888(x, y, r, g, b);
|
||||
if ((c == BLACK) && (getBitFromArray(_ledsDirty, pix) == false)) return; // ignore black if pixel is already black
|
||||
setBitInArray(_ledsDirty, pix, c != BLACK); // dirty = true means "color is not BLACK"
|
||||
|
||||
#ifndef NO_CIE1931
|
||||
c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction
|
||||
#endif
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
|
||||
if(fourScanPanel != nullptr) {
|
||||
int width = _panelWidth;
|
||||
int x = pix % width;
|
||||
int y = pix / width;
|
||||
fourScanPanel->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b);
|
||||
} else {
|
||||
int width = _panelWidth;
|
||||
int x = pix % width;
|
||||
int y = pix / width;
|
||||
display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t BusHub75Matrix::getPixelColor(uint16_t pix) const {
|
||||
if (!_valid || pix >= _len) return BLACK;
|
||||
if (_ledBuffer)
|
||||
return uint32_t(_ledBuffer[pix].scale8(_bri)) & 0x00FFFFFF; // scale8() is needed to mimic NeoPixelBus, which returns scaled-down colours
|
||||
else
|
||||
return getBitFromArray(_ledsDirty, pix) ? DARKGREY: BLACK; // just a hack - we only know if the pixel is black or not
|
||||
}
|
||||
|
||||
uint32_t __attribute__((hot)) BusHub75Matrix::getPixelColorRestored(uint16_t pix) const {
|
||||
if (!_valid || pix >= _len) return BLACK;
|
||||
if (_ledBuffer)
|
||||
return uint32_t(_ledBuffer[pix]) & 0x00FFFFFF;
|
||||
else
|
||||
return getBitFromArray(_ledsDirty, pix) ? DARKGREY: BLACK; // just a hack - we only know if the pixel is black or not
|
||||
}
|
||||
|
||||
void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) {
|
||||
this->display->setBrightness(b);
|
||||
_bri = b;
|
||||
// if (_bri > 238) _bri=238; // not strictly needed. Enable this line if you see glitches at highest brightness.
|
||||
display->setBrightness(_bri);
|
||||
}
|
||||
|
||||
void __attribute__((hot)) BusHub75Matrix::show(void) {
|
||||
if (!_valid) return;
|
||||
display->setBrightness(_bri);
|
||||
|
||||
if (_ledBuffer) {
|
||||
// write out buffered LEDs
|
||||
bool isFourScan = (fourScanPanel != nullptr);
|
||||
//if (isFourScan) fourScanPanel->setRotation(0);
|
||||
unsigned height = isFourScan ? fourScanPanel->height() : display->height();
|
||||
unsigned width = _panelWidth;
|
||||
|
||||
//while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker.
|
||||
|
||||
size_t pix = 0; // running pixel index
|
||||
for (int y=0; y<height; y++) for (int x=0; x<width; x++) {
|
||||
if (getBitFromArray(_ledsDirty, pix) == true) { // only repaint the "dirty" pixels
|
||||
uint32_t c = uint32_t(_ledBuffer[pix]) & 0x00FFFFFF; // get RGB color, removing FastLED "alpha" component
|
||||
#ifndef NO_CIE1931
|
||||
c = unGamma24(c); // to use the driver linear brightness feature, we first need to undo WLED gamma correction
|
||||
#endif
|
||||
uint8_t r = R(c);
|
||||
uint8_t g = G(c);
|
||||
uint8_t b = B(c);
|
||||
if (isFourScan) fourScanPanel->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b);
|
||||
else display->drawPixelRGB888(int16_t(x), int16_t(y), r, g, b);
|
||||
}
|
||||
pix ++;
|
||||
}
|
||||
setBitArray(_ledsDirty, _len, false); // buffer shown - reset all dirty bits
|
||||
}
|
||||
|
||||
if(mxconfig.double_buff) {
|
||||
display->flipDMABuffer(); // Show the back buffer, set current output buffer to the back (i.e. no longer being sent to LED panels)
|
||||
// while(!previousBufferFree) delay(1); // experimental - Wait before we allow any writing to the buffer. Stop flicker.
|
||||
display->clearScreen(); // Now clear the back-buffer
|
||||
setBitArray(_ledsDirty, _len, false); // dislay buffer is blank - reset all dirty bits
|
||||
}
|
||||
}
|
||||
|
||||
void BusHub75Matrix::cleanup() {
|
||||
if (display && _valid) display->stopDMAoutput(); // terminate DMA driver (display goes black)
|
||||
_valid = false;
|
||||
_panelWidth = 0;
|
||||
deallocatePins();
|
||||
USER_PRINTLN("HUB75 output ended.");
|
||||
|
||||
//if (fourScanPanel != nullptr) delete fourScanPanel; // warning: deleting object of polymorphic class type 'VirtualMatrixPanel' which has non-virtual destructor might cause undefined behavior
|
||||
delete display;
|
||||
display = nullptr;
|
||||
fourScanPanel = nullptr;
|
||||
if (_ledBuffer != nullptr) free(_ledBuffer); _ledBuffer = nullptr;
|
||||
if (_ledsDirty != nullptr) free(_ledsDirty); _ledsDirty = nullptr;
|
||||
}
|
||||
|
||||
void BusHub75Matrix::deallocatePins() {
|
||||
@@ -766,7 +1022,7 @@ int BusManager::add(BusConfig &bc) {
|
||||
busses[numBusses] = new BusHub75Matrix(bc);
|
||||
USER_PRINTLN("[BusHub75Matrix] ");
|
||||
#else
|
||||
USER_PRINTLN("[unsupported! BusHub75Matrix] ");
|
||||
USER_PRINTLN("[unsupported! BusHub75Matrix - add flag -D WLED_ENABLE_HUB75MATRIX] ");
|
||||
return -1;
|
||||
#endif
|
||||
} else if (IS_DIGITAL(bc.type)) {
|
||||
@@ -808,7 +1064,7 @@ void BusManager::setStatusPixel(uint32_t c) {
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) {
|
||||
void IRAM_ATTR __attribute__((hot)) BusManager::setPixelColor(uint16_t pix, uint32_t c, int16_t cct) {
|
||||
if ((pix >= laststart) && (pix < lastend ) && (lastBus != nullptr)) {
|
||||
// WLEDMM same bus as last time - no need to search again
|
||||
lastBus->setPixelColor(pix - laststart, c);
|
||||
@@ -836,7 +1092,7 @@ void BusManager::setBrightness(uint8_t b, bool immediate) {
|
||||
}
|
||||
}
|
||||
|
||||
void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||
void __attribute__((cold)) BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||
if (cct > 255) cct = 255;
|
||||
if (cct >= 0) {
|
||||
//if white balance correction allowed, save as kelvin value instead of 0-255
|
||||
@@ -845,7 +1101,7 @@ void BusManager::setSegmentCCT(int16_t cct, bool allowWBCorrection) {
|
||||
Bus::setCCT(cct);
|
||||
}
|
||||
|
||||
uint32_t IRAM_ATTR BusManager::getPixelColor(uint_fast16_t pix) { // WLEDMM use fast native types, IRAM_ATTR
|
||||
uint32_t IRAM_ATTR __attribute__((hot)) BusManager::getPixelColor(uint_fast16_t pix) { // WLEDMM use fast native types, IRAM_ATTR
|
||||
if ((pix >= laststart) && (pix < lastend ) && (lastBus != nullptr)) {
|
||||
// WLEDMM same bus as last time - no need to search again
|
||||
return lastBus->getPixelColor(pix - laststart);
|
||||
@@ -866,20 +1122,41 @@ uint32_t IRAM_ATTR BusManager::getPixelColor(uint_fast16_t pix) { // WLEDMM
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool BusManager::canAllShow() {
|
||||
uint32_t IRAM_ATTR __attribute__((hot)) BusManager::getPixelColorRestored(uint_fast16_t pix) { // WLEDMM uses bus::getPixelColorRestored()
|
||||
if ((pix >= laststart) && (pix < lastend ) && (lastBus != nullptr)) {
|
||||
// WLEDMM same bus as last time - no need to search again
|
||||
return lastBus->getPixelColorRestored(pix - laststart);
|
||||
}
|
||||
|
||||
for (uint_fast8_t i = 0; i < numBusses; i++) {
|
||||
Bus* b = busses[i];
|
||||
uint_fast16_t bstart = b->getStart();
|
||||
if (pix < bstart || pix >= bstart + b->getLength()) continue;
|
||||
else {
|
||||
// WLEDMM remember last Bus we took
|
||||
lastBus = b;
|
||||
laststart = bstart;
|
||||
lastend = bstart + b->getLength();
|
||||
return b->getPixelColorRestored(pix - bstart);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool BusManager::canAllShow() const {
|
||||
for (uint8_t i = 0; i < numBusses; i++) {
|
||||
if (!busses[i]->canShow()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Bus* BusManager::getBus(uint8_t busNr) {
|
||||
Bus* BusManager::getBus(uint8_t busNr) const {
|
||||
if (busNr >= numBusses) return nullptr;
|
||||
return busses[busNr];
|
||||
}
|
||||
|
||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||
uint16_t BusManager::getTotalLength() {
|
||||
uint16_t BusManager::getTotalLength() const {
|
||||
uint_fast16_t len = 0;
|
||||
for (uint_fast8_t i=0; i<numBusses; i++) len += busses[i]->getLength(); // WLEDMM use fast native types
|
||||
return len;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#ifdef WLED_ENABLE_HUB75MATRIX
|
||||
#include <ESP32-HUB75-MatrixPanel-I2S-DMA.h>
|
||||
#include <ESP32-VirtualMatrixPanel-I2S-DMA.h>
|
||||
//extern volatile bool previousBufferFree; // experimental
|
||||
#endif
|
||||
/*
|
||||
* Class for addressing various light types
|
||||
@@ -11,6 +12,27 @@
|
||||
|
||||
#include "const.h"
|
||||
|
||||
#if !defined(FASTLED_VERSION) // only pull in FastLED if we don't have it yet
|
||||
#define FASTLED_INTERNAL
|
||||
#include <FastLED.h>
|
||||
#endif
|
||||
|
||||
//color mangling macros
|
||||
#if !defined(RGBW32)
|
||||
#define RGBW32(r,g,b,w) (uint32_t((byte(w) << 24) | (byte(r) << 16) | (byte(g) << 8) | (byte(b))))
|
||||
#define R(c) (byte((c) >> 16))
|
||||
#define G(c) (byte((c) >> 8))
|
||||
#define B(c) (byte(c))
|
||||
#define W(c) (byte((c) >> 24))
|
||||
#endif
|
||||
|
||||
// WLEDMM bitarray utilities
|
||||
void setBitInArray(uint8_t* byteArray, size_t position, bool value); // set bit
|
||||
bool getBitFromArray(const uint8_t* byteArray, size_t position) __attribute__((pure)); // get bit value
|
||||
size_t getBitArrayBytes(size_t num_bits) __attribute__((const)); // number of bytes needed for an array with num_bits bits
|
||||
void setBitArray(uint8_t* byteArray, size_t numBits, bool value); // set all bits to same value
|
||||
|
||||
|
||||
#define GET_BIT(var,bit) (((var)>>(bit))&0x01)
|
||||
#define SET_BIT(var,bit) ((var)|=(uint16_t)(0x0001<<(bit)))
|
||||
#define UNSET_BIT(var,bit) ((var)&=(~(uint16_t)(0x0001<<(bit))))
|
||||
@@ -32,18 +54,18 @@ struct BusConfig {
|
||||
uint8_t skipAmount;
|
||||
bool refreshReq;
|
||||
uint8_t autoWhite;
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255};
|
||||
uint8_t pins[5] = {LEDPIN, 255, 255, 255, 255}; // WLEDMM warning: this means that BusConfig cannot handle nore than 5 pins per bus!
|
||||
uint16_t frequency;
|
||||
BusConfig(uint8_t busType, uint8_t* ppins, uint16_t pstart, uint16_t len = 1, uint8_t pcolorOrder = COL_ORDER_GRB, bool rev = false, uint8_t skip = 0, byte aw=RGBW_MODE_MANUAL_ONLY, uint16_t clock_kHz=0U) {
|
||||
refreshReq = (bool) GET_BIT(busType,7);
|
||||
type = busType & 0x7F; // bit 7 may be/is hacked to include refresh info (1=refresh in off state, 0=no refresh)
|
||||
count = len; start = pstart; colorOrder = pcolorOrder; reversed = rev; skipAmount = skip; autoWhite = aw; frequency = clock_kHz;
|
||||
uint8_t nPins = 1;
|
||||
if (type >= TYPE_NET_DDP_RGB && type < 96) nPins = 4; //virtual network bus. 4 "pins" store IP address
|
||||
else if (type > 47) nPins = 2;
|
||||
else if (type > 40 && type < 46) nPins = NUM_PWM_PINS(type);
|
||||
else if (type >= TYPE_HUB75MATRIX && type <= (TYPE_HUB75MATRIX + 10)) nPins = 0;
|
||||
for (uint8_t i = 0; i < nPins; i++) pins[i] = ppins[i];
|
||||
uint8_t nPins = 1; // default = only one pin (clockless LEDs like WS281x)
|
||||
if ((type >= TYPE_NET_DDP_RGB) && (type < (TYPE_NET_DDP_RGB + 16))) nPins = 4; // virtual network bus. 4 "pins" store IP address
|
||||
else if ((type > 47) && (type < 63)) nPins = 2; // (data + clock / SPI) busses - two pins
|
||||
else if (IS_PWM(type)) nPins = NUM_PWM_PINS(type); // PWM needs 1..5 pins
|
||||
else if (type >= TYPE_HUB75MATRIX && type <= (TYPE_HUB75MATRIX + 10)) nPins = 1; // HUB75 does not use LED pins, but we need to preserve the "chain length" parameter
|
||||
for (uint8_t i = 0; i < min(unsigned(nPins), sizeof(pins)/sizeof(pins[0])); i++) pins[i] = ppins[i]; //softhack007 fix for potential array out-of-bounds access
|
||||
}
|
||||
|
||||
//validates start and length and extends total if needed
|
||||
@@ -112,35 +134,36 @@ class Bus {
|
||||
virtual bool canShow() { return true; }
|
||||
virtual void setStatusPixel(uint32_t c) {}
|
||||
virtual void setPixelColor(uint16_t pix, uint32_t c) = 0;
|
||||
virtual uint32_t getPixelColor(uint16_t pix) { return 0; }
|
||||
virtual void setBrightness(uint8_t b, bool immediate=false) { _bri = b; };
|
||||
virtual uint32_t getPixelColor(uint16_t pix) const { return 0; }
|
||||
virtual uint32_t getPixelColorRestored(uint16_t pix) const { return restore_Color_Lossy(getPixelColor(pix), _bri); } // override in case your bus has a lossless buffer (HUB75, FastLED, Art-Net)
|
||||
virtual void setBrightness(uint8_t b, bool immediate=false) { _bri = b; }
|
||||
virtual void cleanup() = 0;
|
||||
virtual uint8_t getPins(uint8_t* pinArray) { return 0; }
|
||||
virtual uint16_t getLength() { return _len; }
|
||||
virtual uint8_t getPins(uint8_t* pinArray) const { return 0; }
|
||||
virtual inline uint16_t getLength() const { return _len; }
|
||||
virtual void setColorOrder() {}
|
||||
virtual uint8_t getColorOrder() { return COL_ORDER_RGB; }
|
||||
virtual uint8_t skippedLeds() { return 0; }
|
||||
virtual uint16_t getFrequency() { return 0U; }
|
||||
inline uint16_t getStart() { return _start; }
|
||||
virtual uint8_t getColorOrder() const { return COL_ORDER_RGB; }
|
||||
virtual uint8_t skippedLeds() const { return 0; }
|
||||
virtual uint16_t getFrequency() const { return 0U; }
|
||||
inline uint16_t getStart() const { return _start; }
|
||||
inline void setStart(uint16_t start) { _start = start; }
|
||||
inline uint8_t getType() { return _type; }
|
||||
inline bool isOk() { return _valid; }
|
||||
inline bool isOffRefreshRequired() { return _needsRefresh; }
|
||||
bool containsPixel(uint16_t pix) { return pix >= _start && pix < _start+_len; }
|
||||
virtual uint16_t getMaxPixels() { return MAX_LEDS_PER_BUS; };
|
||||
inline uint8_t getType() const { return _type; }
|
||||
inline bool isOk() const { return _valid; }
|
||||
inline bool isOffRefreshRequired() const { return _needsRefresh; }
|
||||
//inline bool containsPixel(uint16_t pix) const { return pix >= _start && pix < _start+_len; } // WLEDMM not used, plus wrong - it does not consider skipped pixels
|
||||
virtual uint16_t getMaxPixels() const { return MAX_LEDS_PER_BUS; }
|
||||
|
||||
virtual bool hasRGB() {
|
||||
virtual bool hasRGB() const {
|
||||
if ((_type >= TYPE_WS2812_1CH && _type <= TYPE_WS2812_WWA) || _type == TYPE_ANALOG_1CH || _type == TYPE_ANALOG_2CH || _type == TYPE_ONOFF) return false;
|
||||
return true;
|
||||
}
|
||||
virtual bool hasWhite() { return Bus::hasWhite(_type); }
|
||||
virtual bool hasWhite() const { return Bus::hasWhite(_type); }
|
||||
static bool hasWhite(uint8_t type) {
|
||||
if ((type >= TYPE_WS2812_1CH && type <= TYPE_WS2812_WWA) || type == TYPE_SK6812_RGBW || type == TYPE_TM1814 || type == TYPE_UCS8904) return true; // digital types with white channel
|
||||
if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; // analog types with white channel
|
||||
if (type == TYPE_NET_DDP_RGBW) return true; // network types with white channel
|
||||
return false;
|
||||
}
|
||||
virtual bool hasCCT() {
|
||||
virtual bool hasCCT() const {
|
||||
if (_type == TYPE_WS2812_2CH_X3 || _type == TYPE_WS2812_WWA ||
|
||||
_type == TYPE_ANALOG_2CH || _type == TYPE_ANALOG_5CH) return true;
|
||||
return false;
|
||||
@@ -157,10 +180,21 @@ class Bus {
|
||||
#endif
|
||||
}
|
||||
inline void setAutoWhiteMode(uint8_t m) { if (m < 5) _autoWhiteMode = m; }
|
||||
inline uint8_t getAutoWhiteMode() { return _autoWhiteMode; }
|
||||
inline uint8_t getAutoWhiteMode() const { return _autoWhiteMode; }
|
||||
inline static void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; }
|
||||
inline static uint8_t getGlobalAWMode() { return _gAWM; }
|
||||
|
||||
inline uint32_t restore_Color_Lossy(uint32_t c, uint8_t restoreBri) const { // shamelessly grabbed from upstream, who grabbed from NPB, who ..
|
||||
if (restoreBri < 255) {
|
||||
uint8_t* chan = (uint8_t*) &c;
|
||||
for (uint_fast8_t i=0; i<4; i++) {
|
||||
uint_fast16_t val = chan[i];
|
||||
chan[i] = ((val << 8) + restoreBri) / (restoreBri + 1); //adding _bri slightly improves recovery / stops degradation on re-scale
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
bool reversed = false;
|
||||
|
||||
protected:
|
||||
@@ -175,7 +209,7 @@ class Bus {
|
||||
static int16_t _cct;
|
||||
static uint8_t _cctBlend;
|
||||
|
||||
uint32_t autoWhiteCalc(uint32_t c);
|
||||
uint32_t autoWhiteCalc(uint32_t c) const;
|
||||
};
|
||||
|
||||
|
||||
@@ -185,7 +219,7 @@ class BusDigital : public Bus {
|
||||
|
||||
inline void show();
|
||||
|
||||
bool canShow();
|
||||
bool canShow() override;
|
||||
|
||||
void setBrightness(uint8_t b, bool immediate);
|
||||
|
||||
@@ -193,25 +227,25 @@ class BusDigital : public Bus {
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
uint32_t getPixelColor(uint16_t pix) const override;
|
||||
|
||||
uint8_t getColorOrder() {
|
||||
uint8_t getColorOrder() const {
|
||||
return _colorOrder;
|
||||
}
|
||||
|
||||
uint16_t getLength() {
|
||||
uint16_t getLength() const override {
|
||||
return _len - _skip;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
uint8_t getPins(uint8_t* pinArray) const;
|
||||
|
||||
void setColorOrder(uint8_t colorOrder);
|
||||
|
||||
uint8_t skippedLeds() {
|
||||
uint8_t skippedLeds() const override {
|
||||
return _skip;
|
||||
}
|
||||
|
||||
uint16_t getFrequency() { return _frequencykHz; }
|
||||
uint16_t getFrequency() const override { return _frequencykHz; }
|
||||
|
||||
void reinit();
|
||||
|
||||
@@ -239,13 +273,13 @@ class BusPwm : public Bus {
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
//does no index check
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
uint32_t getPixelColor(uint16_t pix) const;
|
||||
|
||||
void show();
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
uint8_t getPins(uint8_t* pinArray) const;
|
||||
|
||||
uint16_t getFrequency() { return _frequency; }
|
||||
uint16_t getFrequency() const override { return _frequency; }
|
||||
|
||||
void cleanup() {
|
||||
deallocatePins();
|
||||
@@ -273,11 +307,12 @@ class BusOnOff : public Bus {
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
uint32_t getPixelColor(uint16_t pix);
|
||||
uint32_t getPixelColor(uint16_t pix) const;
|
||||
uint32_t getPixelColorRestored(uint16_t pix) const override { return getPixelColor(pix);} // WLEDMM BusOnOff ignores brightness
|
||||
|
||||
void show();
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
uint8_t getPins(uint8_t* pinArray) const;
|
||||
|
||||
void cleanup() {
|
||||
pinManager.deallocatePin(_pin, PinOwner::BusOnOff);
|
||||
@@ -297,24 +332,25 @@ class BusNetwork : public Bus {
|
||||
public:
|
||||
BusNetwork(BusConfig &bc);
|
||||
|
||||
uint16_t getMaxPixels() override { return 4096; };
|
||||
bool hasRGB() { return true; }
|
||||
bool hasWhite() { return _rgbw; }
|
||||
uint16_t getMaxPixels() const override { return 4096; };
|
||||
bool hasRGB() const { return true; }
|
||||
bool hasWhite() const { return _rgbw; }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
|
||||
uint32_t __attribute__((pure)) getPixelColor(uint16_t pix); // WLEDMM attribute added
|
||||
uint32_t __attribute__((pure)) getPixelColor(uint16_t pix) const; // WLEDMM attribute added
|
||||
uint32_t __attribute__((pure)) getPixelColorRestored(uint16_t pix) const override { return getPixelColor(pix);} // WLEDMM BusNetwork ignores brightness
|
||||
|
||||
void show();
|
||||
|
||||
bool canShow() {
|
||||
bool canShow() override {
|
||||
// this should be a return value from UDP routine if it is still sending data out
|
||||
return !_broadcastLock;
|
||||
}
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray);
|
||||
uint8_t getPins(uint8_t* pinArray) const;
|
||||
|
||||
uint16_t getLength() {
|
||||
uint16_t getLength() const override {
|
||||
return _len;
|
||||
}
|
||||
|
||||
@@ -338,36 +374,27 @@ class BusHub75Matrix : public Bus {
|
||||
public:
|
||||
BusHub75Matrix(BusConfig &bc);
|
||||
|
||||
uint16_t getMaxPixels() override { return 4096; };
|
||||
uint16_t getMaxPixels() const override { return MAX_LEDS; };
|
||||
|
||||
bool hasRGB() { return true; }
|
||||
bool hasWhite() { return false; }
|
||||
bool hasRGB() const override { return true; }
|
||||
bool hasWhite() const override { return false; }
|
||||
|
||||
void setPixelColor(uint16_t pix, uint32_t c);
|
||||
void setPixelColor(uint16_t pix, uint32_t c) override;
|
||||
uint32_t getPixelColor(uint16_t pix) const override;
|
||||
uint32_t getPixelColorRestored(uint16_t pix) const override; // lossless getPixelColor supported
|
||||
|
||||
void show() {
|
||||
if(mxconfig.double_buff) {
|
||||
display->flipDMABuffer(); // Show the back buffer, set currently output buffer to the back (i.e. no longer being sent to LED panels)
|
||||
display->clearScreen(); // Now clear the back-buffer
|
||||
}
|
||||
}
|
||||
void show(void) override;
|
||||
|
||||
void setBrightness(uint8_t b, bool immediate);
|
||||
void setBrightness(uint8_t b, bool immediate) override;
|
||||
|
||||
uint8_t getPins(uint8_t* pinArray) {
|
||||
uint8_t getPins(uint8_t* pinArray) const override {
|
||||
pinArray[0] = mxconfig.chain_length;
|
||||
return 1;
|
||||
} // Fake value due to keep finaliseInit happy
|
||||
|
||||
void deallocatePins();
|
||||
|
||||
void cleanup() {
|
||||
deallocatePins();
|
||||
fourScanPanel = nullptr;
|
||||
// delete fourScanPanel;
|
||||
delete display;
|
||||
_valid = false;
|
||||
}
|
||||
void cleanup(void) override;
|
||||
|
||||
~BusHub75Matrix() {
|
||||
cleanup();
|
||||
@@ -377,8 +404,9 @@ class BusHub75Matrix : public Bus {
|
||||
MatrixPanel_I2S_DMA *display = nullptr;
|
||||
VirtualMatrixPanel *fourScanPanel = nullptr;
|
||||
HUB75_I2S_CFG mxconfig;
|
||||
uint8_t r, g, b, x, y;
|
||||
|
||||
unsigned _panelWidth = 0;
|
||||
CRGB *_ledBuffer = nullptr;
|
||||
byte *_ledsDirty = nullptr;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -387,7 +415,7 @@ class BusManager {
|
||||
BusManager() {};
|
||||
|
||||
//utility to get the approx. memory usage of a given BusConfig
|
||||
static uint32_t memUsage(BusConfig &bc);
|
||||
static uint32_t memUsage(BusConfig &bc) __attribute__((pure));
|
||||
|
||||
int add(BusConfig &bc);
|
||||
|
||||
@@ -405,13 +433,14 @@ class BusManager {
|
||||
void setSegmentCCT(int16_t cct, bool allowWBCorrection = false);
|
||||
|
||||
uint32_t __attribute__((pure)) getPixelColor(uint_fast16_t pix); // WLEDMM attribute added
|
||||
uint32_t __attribute__((pure)) getPixelColorRestored(uint_fast16_t pix); // WLEDMM
|
||||
|
||||
bool canAllShow();
|
||||
bool canAllShow() const;
|
||||
|
||||
Bus* getBus(uint8_t busNr);
|
||||
Bus* getBus(uint8_t busNr) const;
|
||||
|
||||
//semi-duplicate of strip.getLengthTotal() (though that just returns strip._length, calculated in finalizeInit())
|
||||
uint16_t getTotalLength();
|
||||
uint16_t getTotalLength() const;
|
||||
|
||||
inline void updateColorOrderMap(const ColorOrderMap &com) {
|
||||
memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap));
|
||||
@@ -421,7 +450,7 @@ class BusManager {
|
||||
return colorOrderMap;
|
||||
}
|
||||
|
||||
inline uint8_t getNumBusses() {
|
||||
inline uint8_t getNumBusses() const {
|
||||
return numBusses;
|
||||
}
|
||||
|
||||
@@ -434,7 +463,7 @@ class BusManager {
|
||||
unsigned laststart = 0;
|
||||
unsigned lastend = 0;
|
||||
|
||||
inline uint8_t getNumVirtualBusses() {
|
||||
inline uint8_t getNumVirtualBusses() const {
|
||||
int j = 0;
|
||||
for (int i=0; i<numBusses; i++) if (busses[i]->getType() >= TYPE_NET_DDP_RGB && busses[i]->getType() < 96) j++;
|
||||
return j;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
/*
|
||||
* color blend function
|
||||
*/
|
||||
IRAM_ATTR_YN uint32_t color_blend(uint32_t color1, uint32_t color2, uint_fast16_t blend, bool b16) {
|
||||
IRAM_ATTR_YN __attribute__((hot)) uint32_t color_blend(uint32_t color1, uint32_t color2, uint_fast16_t blend, bool b16) {
|
||||
if(blend == 0) return color1;
|
||||
if (color1 == color2) return color1; // WLEDMM shortcut
|
||||
const uint_fast16_t blendmax = b16 ? 0xFFFF : 0xFF;
|
||||
@@ -71,7 +71,7 @@ IRAM_ATTR_YN uint32_t color_add(uint32_t c1, uint32_t c2, bool fast) // WLEDMM
|
||||
* if using "video" method the resulting color will never become black unless it is already black
|
||||
*/
|
||||
|
||||
IRAM_ATTR_YN uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
|
||||
IRAM_ATTR_YN __attribute__((hot)) uint32_t color_fade(uint32_t c1, uint8_t amount, bool video)
|
||||
{
|
||||
if (amount == 0) return 0; // WLEDMM shortcut
|
||||
|
||||
@@ -297,7 +297,7 @@ static float maxf (float v, float w) // WLEDMM better use standard library fmax
|
||||
|
||||
// adjust RGB values based on color temperature in K (range [2800-10200]) (https://en.wikipedia.org/wiki/Color_balance)
|
||||
// called from bus manager when color correction is enabled!
|
||||
uint32_t IRAM_ATTR_YN colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) // WLEDMM: IRAM_ATTR_YN
|
||||
uint32_t __attribute__((hot)) IRAM_ATTR_YN colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) // WLEDMM: IRAM_ATTR_YN
|
||||
{
|
||||
//remember so that slow colorKtoRGB() doesn't have to run for every setPixelColor()
|
||||
static byte correctionRGB[4] = {0,0,0,0};
|
||||
@@ -406,13 +406,19 @@ static void calcInvGammaTable(float gamma)
|
||||
gammaTinv[i] = (int)(powf((float)i / 255.0f, gammaInv) * 255.0f + 0.5f);
|
||||
}
|
||||
}
|
||||
uint8_t unGamma8(uint8_t value) {
|
||||
uint8_t __attribute__((hot)) unGamma8(uint8_t value) {
|
||||
//if (!gammaCorrectCol || (value == 0) || (value == 255)) return value;
|
||||
if ((value == 0) || (value == 255)) return value;
|
||||
if ((gammaCorrectVal < 0.999f) || (gammaCorrectVal > 3.0f)) return value;
|
||||
if (gammaTinv[255] == 0) calcInvGammaTable(gammaCorrectVal);
|
||||
return gammaTinv[value];
|
||||
}
|
||||
|
||||
uint32_t __attribute__((hot)) unGamma24(uint32_t c) {
|
||||
if ((gammaCorrectVal < 0.999f) || (gammaCorrectVal > 3.0f)) return c;
|
||||
if (gammaTinv[255] == 0) calcInvGammaTable(gammaCorrectVal);
|
||||
return RGBW32(gammaTinv[R(c)], gammaTinv[G(c)], gammaTinv[B(c)], W(c));
|
||||
}
|
||||
// wleDMM end
|
||||
|
||||
uint8_t gamma8_cal(uint8_t b, float gamma)
|
||||
@@ -432,13 +438,13 @@ void calcGammaTable(float gamma)
|
||||
}
|
||||
|
||||
// used for individual channel or brightness gamma correction
|
||||
IRAM_ATTR_YN uint8_t gamma8(uint8_t b) // WLEDMM added IRAM_ATTR_YN
|
||||
IRAM_ATTR_YN __attribute__((hot)) uint8_t gamma8(uint8_t b) // WLEDMM added IRAM_ATTR_YN
|
||||
{
|
||||
return gammaT[b];
|
||||
}
|
||||
|
||||
// used for color gamma correction
|
||||
uint32_t gamma32(uint32_t color)
|
||||
uint32_t __attribute__((hot)) gamma32(uint32_t color)
|
||||
{
|
||||
if (!gammaCorrectCol) return color;
|
||||
uint8_t w = W(color);
|
||||
|
||||
@@ -245,7 +245,9 @@
|
||||
#define TYPE_P9813 53
|
||||
#define TYPE_LPD6803 54
|
||||
|
||||
// WLEDMM additional types
|
||||
#define TYPE_HUB75MATRIX 100 // 100 - 110
|
||||
// WLEDMM caution - do not use bus types > 127
|
||||
|
||||
//Network types (master broadcast) (80-95)
|
||||
#define TYPE_NET_DDP_RGB 80 //network DDP RGB bus (master broadcast bus)
|
||||
@@ -257,6 +259,8 @@
|
||||
#define IS_PWM(t) ((t) > 40 && (t) < 46)
|
||||
#define NUM_PWM_PINS(t) ((t) - 40) //for analog PWM 41-45 only
|
||||
#define IS_2PIN(t) ((t) > 47)
|
||||
#define IS_VIRTUAL(t) ( ((t) <= TYPE_RESERVED) || (((t) >= TYPE_NET_DDP_RGB) && ((t) < (TYPE_NET_DDP_RGB + 16))) ) // WLEDMM 80..95 are network "virtual" busses
|
||||
#define EXCLUDE_FROM_ABL(t) ( IS_VIRTUAL(t) || ( (t) >= (TYPE_HUB75MATRIX) && (t) < (TYPE_HUB75MATRIX + 10))) // WLEDMM do not apply auto-brightness-limiter on these bus types
|
||||
|
||||
//Color orders
|
||||
#define COL_ORDER_GRB 0 //GRB(w),defaut
|
||||
@@ -352,6 +356,7 @@
|
||||
#define ERR_LOW_SEG_MEM 34 // WLEDMM: low memory (segment data RAM)
|
||||
#define ERR_LOW_WS_MEM 35 // WLEDMM: low memory (ws)
|
||||
#define ERR_LOW_AJAX_MEM 36 // WLEDMM: low memory (oappend)
|
||||
#define ERR_LOW_BUF 37 // WLEDMM: low memory (LED buffer from allocLEDs)
|
||||
|
||||
// Timer mode types
|
||||
#define NL_MODE_SET 0 //After nightlight time elapsed, set to target brightness
|
||||
@@ -425,13 +430,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
#define E131_MAX_UNIVERSE_COUNT 20
|
||||
#else
|
||||
#ifdef ESP8266
|
||||
#define E131_MAX_UNIVERSE_COUNT 9
|
||||
#ifndef E131_MAX_UNIVERSE_COUNT
|
||||
#ifdef WLED_USE_ETHERNET
|
||||
#define E131_MAX_UNIVERSE_COUNT 20
|
||||
#else
|
||||
#define E131_MAX_UNIVERSE_COUNT 12
|
||||
#ifdef ESP8266
|
||||
#define E131_MAX_UNIVERSE_COUNT 9
|
||||
#else
|
||||
#define E131_MAX_UNIVERSE_COUNT 12
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -478,7 +485,9 @@
|
||||
#endif
|
||||
|
||||
//#define MIN_HEAP_SIZE (8k for AsyncWebServer)
|
||||
#if !defined(MIN_HEAP_SIZE)
|
||||
#define MIN_HEAP_SIZE 8192
|
||||
#endif
|
||||
|
||||
// Maximum size of node map (list of other WLED instances)
|
||||
#ifdef ESP8266
|
||||
|
||||
@@ -27,7 +27,7 @@ var cfg = {
|
||||
theme:{base:"dark", bg:{url:""}, alpha:{bg:0.6,tab:0.8}, color:{bg:""}},
|
||||
comp :{colors:{picker: true, rgb: false, quick: true, hex: false},
|
||||
labels:true, pcmbot:false, pid:true, seglen:false, segpwr:false, segexp:true,
|
||||
css:true, hdays:false, fxdef:true} //WLEDMM segexp true as default
|
||||
css:true, hdays:false, fxdef:true, fxdef2:false} //WLEDMM segexp true as default, fxdef2 added
|
||||
};
|
||||
var hol = [
|
||||
[0,11,24,4,"https://aircoookie.github.io/xmas.png"], // christmas
|
||||
@@ -696,7 +696,7 @@ function populateInfo(i)
|
||||
if (i.ver.includes("0.14.0-b15.22")) vcn = "Lupo";
|
||||
if (i.ver.includes("0.14.1-b3")) vcn = "Fried Chicken"; // final line of "One Vision" by Queen
|
||||
if (i.ver.includes("0.14.3-b")) vcn = "Fried Chicken";
|
||||
cn += `v${i.ver} <i>"${vcn}"</i><p>(WLEDMM_${i.ver} ${i.rel}.bin)</p><p><em>build ${i.vid}</em></p><table>
|
||||
cn += `v${i.ver} <i>"${vcn}"</i><p>(WLEDMM ${i.rel}.bin)</p><p><em>build ${i.vid}</em></p><table>
|
||||
${urows}
|
||||
${urows===""?'':'<tr><td colspan=2><hr style="height:1px;border-width:0;color:SeaGreen;background-color:Seagreen"></td></tr>'}
|
||||
${i.opt&0x100?inforow("Net Print ☾","<button class=\"btn btn-xs\" onclick=\"requestJson({'netDebug':"+(i.opt&0x0080?"false":"true")+"});\"><i class=\"icons "+(i.opt&0x0080?"on":"off")+"\"></i></button>"):''}
|
||||
@@ -2008,6 +2008,9 @@ function readState(s,command=false)
|
||||
case 36:
|
||||
errstr = "Low Memory (oappend buffer).";
|
||||
break;
|
||||
case 37:
|
||||
errstr = "no memory for LEDs buffer.";
|
||||
break;
|
||||
}
|
||||
showToast('Error ' + s.error + ": " + errstr, true);
|
||||
}
|
||||
@@ -2853,7 +2856,7 @@ function setFX(ind = null)
|
||||
} else {
|
||||
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
||||
}
|
||||
var obj = {"seg": {"fx": parseInt(ind), "fxdef": cfg.comp.fxdef}}; // fxdef sets effect parameters to default values
|
||||
var obj = {"seg": {"fx": parseInt(ind), "fxdef": cfg.comp.fxdef, "fxdef2": cfg.comp.fxdef2}}; // fxdef sets effect parameters to default values; WLEDMM fxdef2 only set slider defaults
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
if (s+c > sLC) sLC = s+c; //update total count
|
||||
if(c>maxLC)maxLC=c; //max per output
|
||||
var t = parseInt(d.getElementsByName("LT"+n)[0].value); // LED type SELECT
|
||||
if (t<80) sPC+=c; //virtual out busses do not count towards physical LEDs
|
||||
if ((t<128) && ((t<80) || ((t>99)))) sPC+=c; //virtual out busses do not count towards physical LEDs //WLEDMM include HUB75 (>=100)
|
||||
} // increase led count
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
"segexp" : "Always expand first segment",
|
||||
"css": "Enable custom CSS",
|
||||
"hdays": "Enable custom Holidays list",
|
||||
"fxdef": "Use effect default parameters"
|
||||
"fxdef": "Use effect default parameters",
|
||||
"fxdef2": "Don't use effect palette and segment parameters"
|
||||
},
|
||||
"theme":{
|
||||
"alpha": {
|
||||
|
||||
@@ -1135,7 +1135,7 @@ function setSegBri(s)
|
||||
function setEffect(ind = 0)
|
||||
{
|
||||
tglFxDropdown();
|
||||
var obj = {"seg": {"fx": parseInt(ind), "fxdef":true}}; // fxdef sets effect parameters to default values, TODO add client setting
|
||||
var obj = {"seg": {"fx": parseInt(ind), "fxdef":true, "fxdef2":false}}; // fxdef sets effect parameters to default values, TODO add client setting
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +187,9 @@ void DMXInput::updateInternal()
|
||||
unsigned long now = millis();
|
||||
if (dmx_receive(inputPortNum, &packet, DMX_TIMEOUT_TICK)) {
|
||||
if (!packet.err) {
|
||||
if(!connected) {
|
||||
USER_PRINTLN("DMX Input - connected");
|
||||
}
|
||||
connected = true;
|
||||
identify = isIdentifyOn();
|
||||
if (!packet.is_rdm) {
|
||||
@@ -199,6 +202,9 @@ void DMXInput::updateInternal()
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(connected) {
|
||||
USER_PRINTLN("DMX Input - disconnected");
|
||||
}
|
||||
connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ void calcGammaTable(float gamma);
|
||||
uint8_t __attribute__((pure)) gamma8(uint8_t b); // WLEDMM: added attribute pure
|
||||
uint32_t __attribute__((pure)) gamma32(uint32_t); // WLEDMM: added attribute pure
|
||||
uint8_t unGamma8(uint8_t value); // WLEDMM revert gamma correction
|
||||
uint32_t unGamma24(uint32_t c); // WLEDMM for 24bit color (white left as-is)
|
||||
|
||||
//dmx_output.cpp
|
||||
void initDMXOutput();
|
||||
@@ -249,7 +250,7 @@ void refreshNodeList();
|
||||
void sendSysInfoUDP();
|
||||
|
||||
//network.cpp
|
||||
int getSignalQuality(int rssi);
|
||||
int getSignalQuality(int rssi) __attribute__((const));
|
||||
void WiFiEvent(WiFiEvent_t event);
|
||||
|
||||
//um_manager.cpp
|
||||
@@ -298,6 +299,7 @@ class Usermod {
|
||||
virtual ~Usermod() { if (um_data) delete um_data; }
|
||||
virtual void setup() = 0; // pure virtual, has to be overriden
|
||||
virtual void loop() = 0; // pure virtual, has to be overriden
|
||||
virtual void loop2() {} // WLEDMM called just before effects will be processed
|
||||
virtual void handleOverlayDraw() {} // called after all effects have been processed, just before strip.show()
|
||||
virtual bool handleButton(uint8_t b) { return false; } // button overrides are possible here
|
||||
virtual bool getUMData(um_data_t **data) { if (data) *data = nullptr; return false; }; // usermod data exchange [see examples for audio effects]
|
||||
@@ -324,10 +326,11 @@ class Usermod {
|
||||
class UsermodManager {
|
||||
private:
|
||||
Usermod* ums[WLED_MAX_USERMODS];
|
||||
byte numMods = 0;
|
||||
unsigned numMods = 0;
|
||||
|
||||
public:
|
||||
void loop();
|
||||
void loop2(); // WLEDMM loop just before drawing effects (presets and everything already handled)
|
||||
void handleOverlayDraw();
|
||||
bool handleButton(uint8_t b);
|
||||
bool getUMData(um_data_t **um_data, uint8_t mod_id = USERMOD_ID_RESERVED); // USERMOD_ID_RESERVED will poll all usermods
|
||||
@@ -368,7 +371,7 @@ bool oappendi(int i); // append new number to temp buffer efficiently
|
||||
void sappend(char stype, const char* key, int val);
|
||||
void sappends(char stype, const char* key, char* val);
|
||||
void prepareHostname(char* hostname);
|
||||
bool isAsterisksOnly(const char* str, byte maxLen);
|
||||
bool isAsterisksOnly(const char* str, byte maxLen) __attribute__((pure));
|
||||
bool requestJSONBufferLock(uint8_t module=255);
|
||||
void releaseJSONBufferLock();
|
||||
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
||||
@@ -409,13 +412,14 @@ void clearEEPROM();
|
||||
//wled_math.cpp
|
||||
#ifndef WLED_USE_REAL_MATH
|
||||
template <typename T> T atan_t(T x);
|
||||
float cos_t(float phi);
|
||||
float sin_t(float x);
|
||||
float tan_t(float x);
|
||||
float cos_t(float phi) __attribute__((const));
|
||||
float sin_t(float x) __attribute__((const));
|
||||
float tan_t(float x) __attribute__((const));
|
||||
float acos_t(float x);
|
||||
float asin_t(float x);
|
||||
float floor_t(float x);
|
||||
float fmod_t(float num, float denom);
|
||||
float atan_t(float x) __attribute__((const));
|
||||
float floor_t(float x) __attribute__((const));
|
||||
float fmod_t(float num, float denom) __attribute__((const));
|
||||
#else
|
||||
#include <math.h> // WLEDMM use "float" variants
|
||||
#define sin_t sinf
|
||||
|
||||
@@ -211,7 +211,7 @@ void sendImprovInfoResponse() {
|
||||
//Use serverDescription if it has been changed from the default "WLED", else mDNS name
|
||||
bool useMdnsName = (strcmp(serverDescription, "WLED") == 0 && strlen(cmDNS) > 0);
|
||||
char vString[32];
|
||||
snprintf_P(vString, sizeof(vString)-1, PSTR("0.14.1-b32.40/%i"),VERSION);
|
||||
snprintf_P(vString, sizeof(vString)-1, PSTR("0.14.1-b32.41/%i"),VERSION);
|
||||
const char *str[4] = {"WLED", vString, bString, useMdnsName ? cmDNS : serverDescription};
|
||||
|
||||
sendImprovRPCResult(ImprovRPCType::Request_Info, 4, str);
|
||||
|
||||
@@ -302,7 +302,7 @@ bool deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
// end fix
|
||||
if (getVal(elem["fx"], &fx, 0, last)) { //load effect ('r' random, '~' inc/dec, 0-255 exact value, 5~10r pick random between 5 & 10)
|
||||
if (!presetId && currentPlaylist>=0) unloadPlaylist();
|
||||
if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")]);
|
||||
if (fx != seg.mode) seg.setMode(fx, elem[F("fxdef")], elem[F("fxdef2")]); // WLEDMM fxdef2 added
|
||||
}
|
||||
|
||||
//getVal also supports inc/decrementing and random
|
||||
@@ -904,8 +904,8 @@ void serializeInfo(JsonObject root)
|
||||
|
||||
JsonObject leds = root.createNestedObject("leds");
|
||||
leds[F("count")] = strip.getLengthTotal();
|
||||
leds[F("countP")] = strip.getLengthPhysical(); //WLEDMM
|
||||
leds[F("pwr")] = strip.currentMilliamps;
|
||||
leds[F("countP")] = strip.getLengthPhysical2(); //WLEDMM - getLengthPhysical plus plysical busses not supporting ABL (i.e. HUB75)
|
||||
leds[F("pwr")] = strip.currentMilliamps > 100 ? strip.currentMilliamps : 0; // WLEDMM show "not calculated" for HUB75, or when all LEDs are out
|
||||
leds["fps"] = strip.getFps();
|
||||
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
||||
leds[F("maxseg")] = strip.getMaxSegments();
|
||||
|
||||
@@ -68,7 +68,7 @@ void toggleOnOff()
|
||||
|
||||
|
||||
//scales the brightness with the briMultiplier factor
|
||||
IRAM_ATTR_YN byte scaledBri(byte in) // WLEDMM added IRAM_ATTR_YN
|
||||
IRAM_ATTR_YN __attribute__((hot)) byte scaledBri(byte in) // WLEDMM added IRAM_ATTR_YN
|
||||
{
|
||||
if (briMultiplier == 100) return(in); // WLEDMM shortcut
|
||||
uint_fast16_t val = ((uint_fast16_t)in*(uint_fast16_t)briMultiplier)/100; // WLEDMM
|
||||
|
||||
@@ -89,7 +89,7 @@ const ethernet_settings ethernetBoards[] = {
|
||||
|
||||
// ESP32-ETHERNET-KIT-VE
|
||||
{
|
||||
0, // eth_address,
|
||||
1, // eth_address, WLED-MM: Changed from 0 to 1 based on not working with 0 on same devkit.
|
||||
5, // eth_power,
|
||||
23, // eth_mdc,
|
||||
18, // eth_mdio,
|
||||
|
||||
@@ -113,13 +113,18 @@ String PinManagerClass::getPinSpecialText(int gpio) { // special purpose PIN in
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// ESP32-S3
|
||||
if (gpio > 18 && gpio < 21) return (F("USB (CDC) / JTAG"));
|
||||
#if !defined(BOARD_HAS_PSRAM)
|
||||
if (gpio > 32 && gpio < 38) return (F("(optional) Octal Flash or PSRAM"));
|
||||
#else
|
||||
if (gpio > 18 && gpio < 21) return (F("USB (CDC) or JTAG"));
|
||||
#if CONFIG_SPIRAM_MODE_OCT && defined(BOARD_HAS_PSRAM)
|
||||
if (gpio > 32 && gpio < 38) return (F("(reserved) Octal PSRAM or Octal Flash"));
|
||||
#endif
|
||||
//if (gpio == 0 || gpio == 3 || gpio == 45 || gpio == 46) return (F("(strapping pin)"));
|
||||
#ifdef ARDUINO_TTGO_T7_S3
|
||||
// experimental: a few special pins of the T7-S3 board
|
||||
if (gpio == 2) return (F("(reserved) _VBAT voltage monitoring"));
|
||||
if (gpio == 17) return (F("onboard LED"));
|
||||
//if (gpio == 3) return (F("(cross-connected to pin 3-1)")); // WLEDMM experimental
|
||||
//if (gpio == 12) return (F("(cross-connected to pin 12-1)")); // WLEDMM experimental
|
||||
#endif
|
||||
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// ESP32-S2
|
||||
@@ -129,7 +134,7 @@ String PinManagerClass::getPinSpecialText(int gpio) { // special purpose PIN in
|
||||
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// ESP32-C3
|
||||
if (gpio > 17 && gpio < 20) return (F("USB (CDC) / JTAG"));
|
||||
if (gpio > 17 && gpio < 20) return (F("USB (CDC) or JTAG"));
|
||||
//if (gpio == 2 || gpio == 8 || gpio == 9) return (F("(strapping pin)"));
|
||||
|
||||
#else
|
||||
@@ -723,19 +728,25 @@ bool PinManagerClass::joinWire(int8_t pinSDA, int8_t pinSCL) {
|
||||
*/
|
||||
|
||||
// Check if supplied GPIO is ok to use
|
||||
bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
bool PinManagerClass::isPinOk(byte gpio, bool output) const
|
||||
{
|
||||
#ifdef ESP32
|
||||
if (digitalPinIsValid(gpio)) {
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
// strapping pins: 2, 8, & 9
|
||||
if (gpio > 11 && gpio < 18) return false; // 11-17 SPI FLASH
|
||||
#if ARDUINO_USB_CDC_ON_BOOT == 1 || ARDUINO_USB_DFU_ON_BOOT == 1
|
||||
if (gpio > 17 && gpio < 20) return false; // 18-19 USB-JTAG
|
||||
#endif
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// 00 to 18 are for general use. Be careful about straping pins GPIO0 and GPIO3 - these may be pulled-up or pulled-down on your board.
|
||||
#if ARDUINO_USB_CDC_ON_BOOT == 1 || ARDUINO_USB_DFU_ON_BOOT == 1
|
||||
if (gpio > 18 && gpio < 21) return false; // 19 + 20 = USB-JTAG. Not recommended for other uses.
|
||||
#endif
|
||||
if (gpio > 21 && gpio < 33) return false; // 22 to 32: not connected + SPI FLASH
|
||||
//if (gpio > 32 && gpio < 38) return false; // 33 to 37: not available if using _octal_ SPI Flash or _octal_ PSRAM
|
||||
// #if CONFIG_SPIRAM_MODE_OCT && defined(BOARD_HAS_PSRAM)
|
||||
// if (gpio > 32 && gpio < 38) return !psramFound(); // 33 to 37: not available if using _octal_ SPI Flash or _octal_ PSRAM
|
||||
// #endif
|
||||
// 38 to 48 are for general use. Be careful about straping pins GPIO45 and GPIO46 - these may be pull-up or pulled-down on your board.
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// strapping pins: 0, 45 & 46
|
||||
@@ -757,7 +768,7 @@ bool PinManagerClass::isPinOk(byte gpio, bool output)
|
||||
return false;
|
||||
}
|
||||
|
||||
PinOwner PinManagerClass::getPinOwner(byte gpio) {
|
||||
PinOwner PinManagerClass::getPinOwner(byte gpio) const {
|
||||
if (gpio >= WLED_NUM_PINS) return PinOwner::None; // catch error case, to avoid array out-of-bounds access
|
||||
if (!isPinOk(gpio, false)) return PinOwner::None;
|
||||
return ownerTag[gpio];
|
||||
|
||||
@@ -125,9 +125,9 @@ class PinManagerClass {
|
||||
// will return true for reserved pins
|
||||
bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None);
|
||||
// will return false for reserved pins
|
||||
bool isPinOk(byte gpio, bool output = true);
|
||||
bool isPinOk(byte gpio, bool output = true) const;
|
||||
|
||||
PinOwner getPinOwner(byte gpio);
|
||||
PinOwner getPinOwner(byte gpio) const;
|
||||
|
||||
// WLEDMM begin
|
||||
String getOwnerText(PinOwner tag); // WLEDMM - return PIN owner tag as text
|
||||
|
||||
@@ -1062,7 +1062,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
for (uint8_t i = 0; i < strip.getSegmentsNum(); i++) {
|
||||
Segment& seg = strip.getSegment(i);
|
||||
if (i != selectedSeg && (singleSegment || !seg.isActive() || !seg.isSelected())) continue; // skip non main segments if not applying to all
|
||||
if (fxModeChanged) seg.setMode(effectIn, req.indexOf(F("FXD="))>0); // apply defaults if FXD= is specified
|
||||
if (fxModeChanged) seg.setMode(effectIn, req.indexOf(F("FXD="))>0, req.indexOf(F("FXD2="))>0); // apply defaults if FXD= is specified
|
||||
if (speedChanged) seg.speed = speedIn;
|
||||
if (intensityChanged) seg.intensity = intensityIn;
|
||||
if (paletteChanged) seg.setPalette(paletteIn);
|
||||
|
||||
@@ -116,7 +116,7 @@ char* dayShortStr(uint8_t day);
|
||||
|
||||
/* low level functions to convert to and from system time */
|
||||
void breakTime(time_t time, tmElements_t &tm); // break time_t into elements
|
||||
time_t makeTime(tmElements_t &tm); // convert time elements into time_t
|
||||
time_t makeTime(tmElements_t &tm) __attribute__((pure)); // convert time elements into time_t
|
||||
|
||||
} // extern "C++"
|
||||
#endif // __cplusplus
|
||||
|
||||
@@ -4,49 +4,50 @@
|
||||
*/
|
||||
|
||||
//Usermod Manager internals
|
||||
void UsermodManager::setup() { for (byte i = 0; i < numMods; i++) ums[i]->setup(); }
|
||||
void UsermodManager::connected() { for (byte i = 0; i < numMods; i++) ums[i]->connected(); }
|
||||
void UsermodManager::loop() { for (byte i = 0; i < numMods; i++) ums[i]->loop(); }
|
||||
void UsermodManager::handleOverlayDraw() { for (byte i = 0; i < numMods; i++) ums[i]->handleOverlayDraw(); }
|
||||
// void UsermodManager::appendConfigData() { for (byte i = 0; i < numMods; i++) ums[i]->appendConfigData(); } //WLEDMM not used
|
||||
void UsermodManager::setup() { for (unsigned i = 0; i < numMods; i++) ums[i]->setup(); }
|
||||
void UsermodManager::connected() { for (unsigned i = 0; i < numMods; i++) ums[i]->connected(); }
|
||||
void UsermodManager::loop() { for (unsigned i = 0; i < numMods; i++) ums[i]->loop(); }
|
||||
void UsermodManager::loop2() { for (unsigned i = 0; i < numMods; i++) ums[i]->loop2(); }
|
||||
void UsermodManager::handleOverlayDraw() { for (unsigned i = 0; i < numMods; i++) ums[i]->handleOverlayDraw(); }
|
||||
// void UsermodManager::appendConfigData() { for (unsigned i = 0; i < numMods; i++) ums[i]->appendConfigData(); } //WLEDMM not used
|
||||
bool UsermodManager::handleButton(uint8_t b) {
|
||||
bool overrideIO = false;
|
||||
for (byte i = 0; i < numMods; i++) {
|
||||
for (unsigned i = 0; i < numMods; i++) {
|
||||
if (ums[i]->handleButton(b)) overrideIO = true;
|
||||
}
|
||||
return overrideIO;
|
||||
}
|
||||
bool UsermodManager::getUMData(um_data_t **data, uint8_t mod_id) {
|
||||
for (byte i = 0; i < numMods; i++) {
|
||||
for (unsigned i = 0; i < numMods; i++) {
|
||||
if (mod_id > 0 && ums[i]->getId() != mod_id) continue; // only get data form requested usermod if provided
|
||||
if (ums[i]->getUMData(data)) return true; // if usermod does provide data return immediately (only one usermod can provide data at one time)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void UsermodManager::addToJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); }
|
||||
void UsermodManager::addToJsonInfo(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); }
|
||||
void UsermodManager::readFromJsonState(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); }
|
||||
void UsermodManager::addToConfig(JsonObject& obj) { for (byte i = 0; i < numMods; i++) ums[i]->addToConfig(obj); }
|
||||
void UsermodManager::addToJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonState(obj); }
|
||||
void UsermodManager::addToJsonInfo(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToJsonInfo(obj); }
|
||||
void UsermodManager::readFromJsonState(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->readFromJsonState(obj); }
|
||||
void UsermodManager::addToConfig(JsonObject& obj) { for (unsigned i = 0; i < numMods; i++) ums[i]->addToConfig(obj); }
|
||||
bool UsermodManager::readFromConfig(JsonObject& obj) {
|
||||
bool allComplete = true;
|
||||
for (byte i = 0; i < numMods; i++) {
|
||||
for (unsigned i = 0; i < numMods; i++) {
|
||||
if (!ums[i]->readFromConfig(obj)) allComplete = false;
|
||||
}
|
||||
return allComplete;
|
||||
}
|
||||
void UsermodManager::onMqttConnect(bool sessionPresent) { for (byte i = 0; i < numMods; i++) ums[i]->onMqttConnect(sessionPresent); }
|
||||
void UsermodManager::onMqttConnect(bool sessionPresent) { for (unsigned i = 0; i < numMods; i++) ums[i]->onMqttConnect(sessionPresent); }
|
||||
bool UsermodManager::onMqttMessage(char* topic, char* payload) {
|
||||
for (byte i = 0; i < numMods; i++) if (ums[i]->onMqttMessage(topic, payload)) return true;
|
||||
for (unsigned i = 0; i < numMods; i++) if (ums[i]->onMqttMessage(topic, payload)) return true;
|
||||
return false;
|
||||
}
|
||||
void UsermodManager::onUpdateBegin(bool init) { for (byte i = 0; i < numMods; i++) ums[i]->onUpdateBegin(init); } // notify usermods that update is to begin
|
||||
void UsermodManager::onStateChange(uint8_t mode) { for (byte i = 0; i < numMods; i++) ums[i]->onStateChange(mode); } // notify usermods that WLED state changed
|
||||
void UsermodManager::onUpdateBegin(bool init) { for (unsigned i = 0; i < numMods; i++) ums[i]->onUpdateBegin(init); } // notify usermods that update is to begin
|
||||
void UsermodManager::onStateChange(uint8_t mode) { for (unsigned i = 0; i < numMods; i++) ums[i]->onStateChange(mode); } // notify usermods that WLED state changed
|
||||
|
||||
/*
|
||||
* Enables usermods to lookup another Usermod.
|
||||
*/
|
||||
Usermod* UsermodManager::lookup(uint16_t mod_id) {
|
||||
for (byte i = 0; i < numMods; i++) {
|
||||
for (unsigned i = 0; i < numMods; i++) {
|
||||
if (ums[i]->getId() == mod_id) {
|
||||
return ums[i];
|
||||
}
|
||||
@@ -57,7 +58,7 @@ Usermod* UsermodManager::lookup(uint16_t mod_id) {
|
||||
//WLEDMM: used by Usermods in xml.cpp
|
||||
Usermod* UsermodManager::lookupName(const char *mod_name) {
|
||||
//WLEDMM: hack to get the usermod object with the mod_name (better would be to store the usermod name in the class but that requires change to all usermods)
|
||||
for (byte i = 0; i < numMods; i++) {
|
||||
for (unsigned i = 0; i < numMods; i++) {
|
||||
// StaticJsonDocument <1024> docx;
|
||||
JsonObject um = doc.createNestedObject("um"); //WLEDMM reuse the global doc variable here
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include "wled.h"
|
||||
#include "wled_ethernet.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp_ota_ops.h"
|
||||
#endif
|
||||
#warning WLED-MM GPL-v3. By installing WLED MM you implicitly accept the terms!
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET)
|
||||
@@ -211,6 +213,19 @@ void WLED::loop()
|
||||
handlePresets();
|
||||
yield();
|
||||
|
||||
#if defined(_MoonModules_WLED_) && defined(WLEDMM_FASTPATH)
|
||||
#ifdef WLED_DEBUG
|
||||
unsigned long usermod2Millis = millis();
|
||||
#endif
|
||||
usermods.loop2();
|
||||
#ifdef WLED_DEBUG
|
||||
usermod2Millis = millis() - usermod2Millis;
|
||||
avgUsermodMillis += usermod2Millis;
|
||||
if (usermod2Millis > maxUsermodMillis) maxUsermodMillis = usermod2Millis;
|
||||
#endif
|
||||
yield();
|
||||
#endif
|
||||
|
||||
#ifdef WLED_DEBUG
|
||||
unsigned long stripMillis = millis();
|
||||
#endif
|
||||
@@ -293,6 +308,7 @@ void WLED::loop()
|
||||
delete busConfigs[i]; busConfigs[i] = nullptr;
|
||||
}
|
||||
strip.finalizeInit();
|
||||
busses.setBrightness(bri); // fix re-initialised bus' brightness #4005
|
||||
loadLedmap = true;
|
||||
if (aligned) strip.makeAutoSegments();
|
||||
else strip.fixInvalidSegments();
|
||||
@@ -448,6 +464,9 @@ void WLED::setup()
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
pinMode(hardwareRX, INPUT_PULLDOWN); delay(1); // suppress noise in case RX pin is floating (at low noise energy) - see issue #3128
|
||||
#endif
|
||||
#ifdef WLED_BOOTUPDELAY
|
||||
delay(WLED_BOOTUPDELAY); // delay to let voltage stabilize, helps with boot issues on some setups
|
||||
#endif
|
||||
Serial.begin(115200);
|
||||
if (!Serial) delay(1000); // WLEDMM make sure that Serial has initalized
|
||||
|
||||
@@ -498,7 +517,10 @@ void WLED::setup()
|
||||
#ifdef WLED_RELEASE_NAME
|
||||
USER_PRINTF(" WLEDMM_%s %s, build %s.\n", versionString, releaseString, TOSTRING(VERSION)); // WLEDMM specific
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
const esp_partition_t *running_partition = esp_ota_get_running_partition();
|
||||
USER_PRINTF("Running from: %s which is %u bytes and type %u subtype %u at address %x\n",running_partition->label,running_partition->size,running_partition->type,running_partition->subtype,running_partition->address);
|
||||
#endif
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
DEBUG_PRINT(F("esp32 "));
|
||||
DEBUG_PRINTLN(ESP.getSdkVersion());
|
||||
@@ -586,9 +608,11 @@ void WLED::setup()
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM)
|
||||
//psramInit(); //WLEDMM?? softhack007: not sure if explicit init is really needed ... lets disable it here and see if that works
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
// S3: reserve GPIO 33-37 for "octal" PSRAM
|
||||
managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#if CONFIG_SPIRAM_MODE_OCT && defined(BOARD_HAS_PSRAM)
|
||||
// S3: reserve GPIO 33-37 for "octal" PSRAM
|
||||
managed_pin_type pins[] = { {33, true}, {34, true}, {35, true}, {36, true}, {37, true} };
|
||||
pinManager.allocateMultiplePins(pins, sizeof(pins)/sizeof(managed_pin_type), PinOwner::SPI_RAM);
|
||||
#endif
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
// S2: reserve GPIO 26-32 for PSRAM (may fail due to isPinOk() but that will also prevent other allocation)
|
||||
//managed_pin_type pins[] = { {26, true}, {27, true}, {28, true}, {29, true}, {30, true}, {31, true}, {32, true} };
|
||||
@@ -807,7 +831,11 @@ void WLED::setup()
|
||||
USER_PRINTLN(F("\nGPIO\t| Assigned to\t\t| Info"));
|
||||
USER_PRINTLN(F("--------|-----------------------|------------"));
|
||||
for(int pinNr = 0; pinNr < WLED_NUM_PINS; pinNr++) { // 49 = highest PIN on ESP32-S3
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
if((pinManager.isPinOk(pinNr, false)) || (pinNr > 18 && pinNr < 21)) { // softhack007: list USB pins
|
||||
#else
|
||||
if(pinManager.isPinOk(pinNr, false)) {
|
||||
#endif
|
||||
//if ((!pinManager.isPinAllocated(pinNr)) && (pinManager.getPinSpecialText(pinNr).length() == 0)) continue; // un-comment to hide no-name,unused GPIO pins
|
||||
bool is_inOut = pinManager.isPinOk(pinNr, true);
|
||||
#if 0 // for testing
|
||||
@@ -849,6 +877,7 @@ void WLED::setup()
|
||||
USER_PRINTLN(F("\n"));
|
||||
#endif
|
||||
|
||||
USER_PRINT(F("Free heap ")); USER_PRINTLN(ESP.getFreeHeap());USER_PRINTLN();
|
||||
USER_PRINTLN(F("WLED initialization done.\n"));
|
||||
delay(50);
|
||||
// repeat Ada prompt
|
||||
@@ -1217,7 +1246,7 @@ void WLED::handleConnection()
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
// reconnect WiFi to clear stale allocations if heap gets too low
|
||||
if ((!strip.isUpdating()) && (now - heapTime > 5000)) { // WLEDMM: updated with better logic for small heap available by block, not total. // WLEDMM trying to use a moment when the strip is idle
|
||||
#if defined(ARDUINO_ARCH_ESP32S2)
|
||||
#if defined(ARDUINO_ARCH_ESP32S2) || defined(WLED_ENABLE_HUB75MATRIX)
|
||||
uint32_t heap = ESP.getFreeHeap(); // WLEDMM works better on -S2
|
||||
#else
|
||||
uint32_t heap = heap_caps_get_largest_free_block(0x1800); // WLEDMM: This is a better metric for free heap.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2407171
|
||||
#define VERSION 2409280
|
||||
|
||||
// WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED.
|
||||
#define _MoonModules_WLED_
|
||||
@@ -928,9 +928,9 @@ public:
|
||||
}
|
||||
|
||||
// boot starts here
|
||||
void setup();
|
||||
void setup() __attribute__((used));
|
||||
|
||||
void loop();
|
||||
void loop() __attribute__((used));
|
||||
void reset();
|
||||
|
||||
void beginStrip();
|
||||
|
||||
@@ -61,6 +61,7 @@ void esp_heap_trace_free_hook(void* ptr)
|
||||
unsigned long lastMillis = 0; //WLEDMM
|
||||
unsigned long loopCounter = 0; //WLEDMM
|
||||
|
||||
void setup() __attribute__((used)); // needed for -flto
|
||||
void setup() {
|
||||
#ifdef WLED_DEBUG_HEAP
|
||||
esp_err_t error = heap_caps_register_failed_alloc_callback(heap_caps_alloc_failed_hook);
|
||||
@@ -68,6 +69,7 @@ void setup() {
|
||||
WLED::instance().setup();
|
||||
}
|
||||
|
||||
void loop() __attribute__((used)); // needed for -flto
|
||||
void loop() {
|
||||
//WLEDMM show loops per second
|
||||
loopCounter++;
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#include "wled.h"
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
#include "esp_ota_ops.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Adalight and TPM2 handler
|
||||
@@ -119,6 +122,34 @@ void handleSerial()
|
||||
} else if (next == 'v') {
|
||||
Serial.print("WLED"); Serial.write(' '); Serial.println(VERSION);
|
||||
|
||||
} else if (next == '^') {
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
esp_err_t err;
|
||||
const esp_partition_t *boot_partition = esp_ota_get_boot_partition();
|
||||
const esp_partition_t *running_partition = esp_ota_get_running_partition();
|
||||
USER_PRINTF("Running on %s and we should have booted from %s. This %s\n",running_partition->label,boot_partition->label,(String(running_partition->label) == String(boot_partition->label))?"is what we expect.":"means OTA messed up!");
|
||||
if (String(running_partition->label) == String(boot_partition->label)) {
|
||||
esp_partition_iterator_t new_boot_partition_iterator = NULL;
|
||||
if (boot_partition->subtype == ESP_PARTITION_SUBTYPE_APP_OTA_0) {
|
||||
new_boot_partition_iterator = esp_partition_find(ESP_PARTITION_TYPE_APP,ESP_PARTITION_SUBTYPE_APP_OTA_1,"app1");
|
||||
} else {
|
||||
new_boot_partition_iterator = esp_partition_find(ESP_PARTITION_TYPE_APP,ESP_PARTITION_SUBTYPE_APP_OTA_0,"app0");
|
||||
}
|
||||
const esp_partition_t* new_boot_partition = esp_partition_get(new_boot_partition_iterator);
|
||||
err = esp_ota_set_boot_partition(new_boot_partition);
|
||||
if (err == ESP_OK) {
|
||||
USER_PRINTF("Switching boot partitions from %s to %s in 3 seconds!\n",boot_partition->label,new_boot_partition->label);
|
||||
delay(3000);
|
||||
esp_restart();
|
||||
} else {
|
||||
USER_PRINTF("Looks like the other app partition (%s) is invalid. Ignoring.\n",new_boot_partition->label);
|
||||
}
|
||||
} else {
|
||||
USER_PRINTF("Looks like the other partion is invalid as we exepected %s but we booted failsafe to %s. Ignoring boot change.\n",boot_partition->label,running_partition->label);
|
||||
}
|
||||
#else
|
||||
USER_PRINTLN("Boot partition switching is only available for ESP32 and newer boards.");
|
||||
#endif
|
||||
} else if (next == 'X') {
|
||||
forceReconnect = true; // WLEDMM - force reconnect via Serial
|
||||
} else if (next == 0xB0) {updateBaudRate( 115200);
|
||||
|
||||
@@ -10,9 +10,11 @@ static volatile unsigned long wsLastLiveTime = 0; // WLEDMM
|
||||
//uint8_t* wsFrameBuffer = nullptr;
|
||||
|
||||
#if !defined(ARDUINO_ARCH_ESP32) || defined(WLEDMM_FASTPATH) // WLEDMM
|
||||
#define WS_LIVE_INTERVAL 120
|
||||
#define WS_LIVE_INTERVAL_MAX 120
|
||||
#define WS_LIVE_INTERVAL_MIN 25
|
||||
#else
|
||||
#define WS_LIVE_INTERVAL 80
|
||||
#define WS_LIVE_INTERVAL_MAX 80
|
||||
#define WS_LIVE_INTERVAL_MIN 40
|
||||
#endif
|
||||
|
||||
void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len)
|
||||
@@ -215,7 +217,11 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static"
|
||||
if ((bufSize < 1) || (used < 1)) return(false); // WLEDMM should not happen
|
||||
AsyncWebSocketBuffer wsBuf(bufSize);
|
||||
if (!wsBuf) {
|
||||
USER_PRINTLN(F("WS buffer allocation failed."));
|
||||
static unsigned long last_err_time = 0;
|
||||
if (millis() - last_err_time > 300) { // WLEDMM limit to 3 messages per second
|
||||
USER_PRINTF("WS buffer allocation failed (!wsBuf %u bytes).\n", bufSize);
|
||||
last_err_time = millis();
|
||||
}
|
||||
errorFlag = ERR_LOW_WS_MEM;
|
||||
return false; //out of memory
|
||||
}
|
||||
@@ -247,6 +253,7 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static"
|
||||
}
|
||||
#endif
|
||||
uint32_t c = restoreColorLossy(strip.getPixelColor(i), stripBrightness); // WLEDMM full bright preview - does _not_ recover ABL reductions
|
||||
//uint32_t c = strip.getPixelColorRestored(i);
|
||||
// WLEDMM begin: preview with color gamma correction
|
||||
if (gammaCorrectPreview) {
|
||||
uint8_t w = W(c); // not sure why, but it looks better if using "white" without corrections
|
||||
@@ -269,7 +276,7 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static"
|
||||
|
||||
void handleWs()
|
||||
{
|
||||
if ((millis() - wsLastLiveTime) > (unsigned long)(max((strip.getLengthTotal()/20), WS_LIVE_INTERVAL))) //WLEDMM dynamic nr of peek frames per second
|
||||
if ((millis() - wsLastLiveTime) > (unsigned long)(max(WS_LIVE_INTERVAL_MIN, min((strip.getLengthTotal()/80), WS_LIVE_INTERVAL_MAX)))) //WLEDMM dynamic nr of peek frames per second
|
||||
{
|
||||
#ifdef ESP8266
|
||||
ws.cleanupClients(3);
|
||||
|
||||
Reference in New Issue
Block a user