Skip to content

Commit

Permalink
FastLed dynamic ! multi pin allocation
Browse files Browse the repository at this point in the history
AppEffects:
- move call++ and gHue ++ from AppModLeds to effect loop
- all effects loops call superclass loop
- Ripples3DEffect: use interval parameter
- add credentials
- BouncingBalls1D (WIP)

AppLedsV:
- remove NUM_LEDS_FastLed (now dynamic 🎉)
- rename LedsV::ledsP to LedsV::ledsPhysical (to distinguish between global ledsP (which is a pointer to LedsV::ledsPhysical)

AppModLedFixGen
- add pinList variable (csv of pins)
- generateChFun: pinList csv to array of pins
- generateChFun: use pinList to generate pin numbers in ledfix.json

AppModLeds:
- remove DATA_PIN (now dynamic 🎉)
- remove dataPin variable
- add BouncingBalls effect
- move FastLed.addLeds from setup to loop.doMap
- doMap: for all Leds pins, decode startLed and nrOfLeds and call FastLED.addLeds for each pin (dynamic pin allocation!).
  • Loading branch information
ewowi committed Aug 11, 2023
1 parent 9653e83 commit 58394fe
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 52 deletions.
116 changes: 113 additions & 3 deletions src/App/AppEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ static unsigned long call = 0;
class Effect {
public:
virtual const char * name() { return nullptr;}

virtual void setup() {}
virtual void loop() {}

virtual void loop() {
call++;

// do some periodic updates
EVERY_N_MILLISECONDS( 20 ) { gHue++; } // slowly cycle the "base color" through the rainbow
}

virtual bool controls(JsonObject parentVar) {return false;}
};

Expand All @@ -27,6 +35,7 @@ class RainbowEffect: public Effect {
}
void setup() {}
void loop() {
Effect::loop();
// FastLED's built-in rainbow generator
fill_rainbow( ledsP, LedsV::nrOfLedsP, gHue, 7);
}
Expand All @@ -39,6 +48,7 @@ class RainbowWithGlitterEffect:public RainbowEffect {
}
void setup() {}
void loop() {
Effect::loop();
// built-in FastLED rainbow, plus some random sparkly glitter
RainbowEffect::loop();
addGlitter(80);
Expand All @@ -58,6 +68,7 @@ class SinelonEffect: public Effect {
}
void setup() {}
void loop() {
Effect::loop();
// a colored dot sweeping back and forth, with fading trails
fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 20);
int pos = beatsin16( 13, 0, LedsV::nrOfLedsV-1 );
Expand All @@ -74,6 +85,7 @@ class RunningEffect: public Effect {
}
void setup() {}
void loop() {
Effect::loop();
// a colored dot sweeping back and forth, with fading trails
fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 70); //physical leds
// int pos0 = (call-1)%ledsV.nrOfLeds;
Expand All @@ -90,6 +102,7 @@ class ConfettiEffect: public Effect {
}
void setup() {}
void loop() {
Effect::loop();
// random colored speckles that blink in and fade smoothly
fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 10);
int pos = random16(LedsV::nrOfLedsP);
Expand All @@ -104,6 +117,7 @@ class BPMEffect: public Effect {
}
void setup() {}
void loop() {
Effect::loop();
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
uint8_t BeatsPerMinute = 62;
CRGBPalette16 palette = PartyColors_p;
Expand All @@ -124,6 +138,7 @@ class JuggleEffect: public Effect {
}
void setup() {}
void loop() {
Effect::loop();
// eight colored dots, weaving in and out of sync with each other
fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 20);
uint8_t dothue = 0;
Expand All @@ -141,7 +156,10 @@ class Ripples3DEffect: public Effect {
}
void setup() {}
void loop() {
float ripple_interval = 1.3;// * (SEGMENT.intensity/128.0);
Effect::loop();
uint8_t interval = mdl->getValue("interval");

float ripple_interval = 1.3 * (interval/128.0);

fill_solid(ledsP, LedsV::nrOfLedsP, CRGB::Black);
// fill(CRGB::Black);
Expand All @@ -159,6 +177,10 @@ class Ripples3DEffect: public Effect {
}
}
}
bool controls(JsonObject parentVar) {
ui->initSlider(parentVar, "interval", 128, false);
return true;
}
};

class SphereMove3DEffect: public Effect {
Expand All @@ -168,6 +190,7 @@ class SphereMove3DEffect: public Effect {
}
void setup() {}
void loop() {
Effect::loop();
uint16_t origin_x, origin_y, origin_z, d;
float diameter;

Expand Down Expand Up @@ -206,6 +229,7 @@ uint16_t XY( uint8_t x, uint8_t y) {
return x + y * LedsV::widthV;
}

//Frizzles2D inspired by WLED, Stepko, Andrew Tuline, https://editor.soulmatelights.com/gallery/640-color-frizzles
class Frizzles2D: public Effect {
public:
const char * name() {
Expand All @@ -217,6 +241,7 @@ class Frizzles2D: public Effect {
}

void loop() {
Effect::loop();
fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 16);
CRGBPalette16 palette = PartyColors_p;

Expand Down Expand Up @@ -245,6 +270,7 @@ class Lines2D: public Effect {
void setup() {}

void loop() {
Effect::loop();
fadeToBlackBy( ledsP, LedsV::nrOfLedsP, 100);
CRGBPalette16 palette = PartyColors_p;

Expand All @@ -271,6 +297,7 @@ uint8_t gamma8(uint8_t b) { //we do nothing with gamma for now
return b;
}

//DistortionWaves2D inspired by WLED, ldirko, https://editor.soulmatelights.com/gallery/1089-distorsion-waves
class DistortionWaves2D: public Effect {
public:
const char * name() {
Expand All @@ -282,6 +309,7 @@ class DistortionWaves2D: public Effect {
}

void loop() {
Effect::loop();

const uint16_t cols = LedsV::widthV;
const uint16_t rows = LedsV::widthV;
Expand Down Expand Up @@ -331,7 +359,89 @@ class DistortionWaves2D: public Effect {
ui->initSlider(parentVar, "scale", 128, false);
return true;
}
}; // Frizzles2D
}; // DistortionWaves2D


//BouncingBalls1D inspired by WLED
//each needs 12 bytes
typedef struct Ball {
unsigned long lastBounceTime;
float impactVelocity;
float height;
} ball;

#define maxNumBalls 16

class BouncingBalls1D: public Effect {
public:
Ball balls[maxNumBalls];

const char * name() {
return "Bouncing Balls 1D";
}

void setup() {
for (size_t i = 0; i < maxNumBalls; i++) balls[i].lastBounceTime = millis();
}

void loop() {
Effect::loop();

uint8_t grav = mdl->getValue("gravity");
uint8_t nrOfBalls = mdl->getValue("nrOfBalls");

// number of balls based on intensity setting to max of 7 (cycles colors)
// non-chosen color is a random color
uint16_t numBalls = (grav * (maxNumBalls - 1)) / 255 + 1; // minimum 1 ball
const float gravity = -9.81f; // standard value of gravity
// const bool hasCol2 = SEGCOLOR(2);
const unsigned long time = millis();

for (size_t i = 0; i < numBalls; i++) {
float timeSinceLastBounce = (time - balls[i].lastBounceTime)/((255-grav)/64 +1);
float timeSec = timeSinceLastBounce/1000.0f;
balls[i].height = (0.5f * gravity * timeSec + balls[i].impactVelocity) * timeSec; // avoid use pow(x, 2) - its extremely slow !

if (balls[i].height <= 0.0f) {
balls[i].height = 0.0f;
//damping for better effect using multiple balls
float dampening = 0.9f - float(i)/float(numBalls * numBalls); // avoid use pow(x, 2) - its extremely slow !
balls[i].impactVelocity = dampening * balls[i].impactVelocity;
balls[i].lastBounceTime = time;

if (balls[i].impactVelocity < 0.015f) {
float impactVelocityStart = sqrtf(-2.0f * gravity) * random8(5,11)/10.0f; // randomize impact velocity
balls[i].impactVelocity = impactVelocityStart;
}
} else if (balls[i].height > 1.0f) {
continue; // do not draw OOB ball
}

// uint32_t color = SEGCOLOR(0);
// if (SEGMENT.palette) {
// color = SEGMENT.color_wheel(i*(256/MAX(numBalls, 8)));
// }
// else if (hasCol2) {
// color = SEGCOLOR(i % NUM_COLORS);
// }

int pos = roundf(balls[i].height * (LedsV::nrOfLedsV - 1));

CRGBPalette16 palette = PartyColors_p;

CRGB color = ColorFromPalette(palette, i*(256/max(numBalls, (uint16_t)8)), 255);

ledsV[pos] = color;
// if (SEGLEN<32) SEGMENT.setPixelColor(indexToVStrip(pos, stripNr), color); // encode virtual strip into index
// else SEGMENT.setPixelColor(balls[i].height + (stripNr+1)*10.0f, color);
} //nrOfBalls
}

bool controls(JsonObject parentVar) {
ui->initSlider(parentVar, "gravity", 128, false);
ui->initSlider(parentVar, "nrOfBalls", 128, false);
return true;
}
}; // DistortionWaves2D

static std::vector<Effect *> effects;
11 changes: 5 additions & 6 deletions src/App/AppLedsV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,11 @@ void LedsV::ledFixProjectAndMap() {
} //if 1D-3D
else {
char details[32] = "";
print->fFormat(details, sizeof(details), "%d-%d", prevLeds, mappingTableLedCounter - 1);
print->fFormat(details, sizeof(details), "%d-%d", prevLeds, mappingTableLedCounter - 1); //careful: AppModLeds:loop uses this to assign to FastLed
print->print("pins %d: %s (%d)\n", currPin, details);
pins->allocatePin(currPin, "Leds", details);

prevLeds = mappingTableLedCounter;

}
}); //create the right type, otherwise crash

Expand Down Expand Up @@ -215,22 +214,22 @@ void LedsV::setPixelColor(int indexV, CRGB color) {
if (indexV >= mappingTable.size()) return;
for (uint16_t indexP:mappingTable[indexV]) {
if (indexP < NUM_LEDS_Preview)
ledsP[indexP] = color;
ledsPhysical[indexP] = color;
}
}
else //no projection
ledsP[projectionNr==p_Random?random(nrOfLedsP):indexV] = color;
ledsPhysical[projectionNr==p_Random?random(nrOfLedsP):indexV] = color;
}

CRGB LedsV::getPixelColor(int indexV) {
if (mappingTable.size()) {
if (indexV >= mappingTable.size()) return CRGB::Black;
if (!mappingTable[indexV].size() || mappingTable[indexV][0] > NUM_LEDS_Preview) return CRGB::Black;

return ledsP[mappingTable[indexV][0]]; //any would do as they are all the same
return ledsPhysical[mappingTable[indexV][0]]; //any would do as they are all the same
}
else //no projection
return ledsP[indexV];
return ledsPhysical[indexV];
}

// LedsV& operator+=(const CRGB color) {
Expand Down
8 changes: 4 additions & 4 deletions src/App/AppLedsV.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <vector>
#include "ArduinoJson.h"

#define NUM_LEDS_FastLed 1024
#define NUM_LEDS_Preview 4096

//keep them global for the time being as FastLed effects refer to them and want to keep that code as unchanged as possible
Expand All @@ -34,7 +33,7 @@ class LedsV {

public:
// CRGB *leds = nullptr;
CRGB ledsP[NUM_LEDS_Preview];
CRGB ledsPhysical[NUM_LEDS_Preview];
// if (!leds)
// leds = (CRGB*)calloc(nrOfLeds, sizeof(CRGB));
// else
Expand All @@ -60,7 +59,7 @@ class LedsV {

void ledFixProjectAndMap();

uint16_t indexVLocal = 0;
uint16_t indexVLocal = 0; //set in operator[], used by operator=

// ledsV[indexV] stores indexV locally
LedsV& operator[](uint16_t indexV);
Expand Down Expand Up @@ -100,6 +99,7 @@ class LedsV {
static uint16_t mappingTableLedCounter;
};

//Global vars!
//after header split they all needs to be static otherwise multiple definition link error
static LedsV ledsV = LedsV(); //virtual leds
static CRGB *ledsP = ledsV.ledsP; //physical leds, used by FastLed in particular
static CRGB *ledsP = ledsV.ledsPhysical; //physical leds, used by FastLed in particular
Loading

0 comments on commit 58394fe

Please sign in to comment.