#include <Arduino.h>
#include <math.h>
#define SBK_BARDRIVE_WITH_ANIM
// Wokwi setup: MAX7219 via hardware SPI.
#define CS_PIN 10
#include <SBK_MAX72xxHard.h>
SBK_MAX72xxHard driver(CS_PIN, 2);
// 16 logical bar segments mapped as a linear strip across the visually first row
// on 2 chained Wokwi MAX7219 modules (row/col are transposed visually).
// Segment 0..7: device 0, row 0..7, col 0
// Segment 8..15: device 1, row 0..7, col 0
const uint8_t BARGRAPH_16SEG_MAP[16][3] = {
{0, 0, 0},
{0, 1, 0},
{0, 2, 0},
{0, 3, 0},
{0, 4, 0},
{0, 5, 0},
{0, 6, 0},
{0, 7, 0},
{1, 0, 0},
{1, 1, 0},
{1, 2, 0},
{1, 3, 0},
{1, 4, 0},
{1, 5, 0},
{1, 6, 0},
{1, 7, 0}
};
#include <SBK_BarDrive.h>
SBK_BarDrive<SBK_MAX72xxHard> bar(&driver, 0, BARGRAPH_16SEG_MAP);
uint8_t demoMode = 0;
unsigned long lastSwitch = 0;
uint16_t fakeSignal1 = 0;
uint16_t generateFakeSignal(uint32_t tMillis);
void setup() {
Serial.begin(115200);
randomSeed(analogRead(A0));
Serial.print(F("Animation showcase setup..."));
driver.begin();
driver.setBrightness(0, 10);
driver.setBrightness(1, 10);
bar.setDirection(BarDirection::FORWARD);
demoMode = 11; // Start by rolling into mode 0 on first pass
Serial.println(F("done. Showcase begin."));
}
void loop() {
bar.animations().update();
bar.show();
if (!bar.animations().isRunning()) {
lastSwitch = millis();
bar.animations().stop().resetLogic();
Serial.println();
demoMode = (demoMode + 1) % 12;
}
switch (demoMode) {
case 0:
if (!bar.animations().isRunning()) {
bar.animations().animInit().fillUpIntv(30).loop();
Serial.println(F("Demo 0: fillUp loop."));
}
break;
case 1:
if (!bar.animations().isRunning()) {
bar.animations().animInit().bounceFillUpIntv(30, 30, 20, 80).loop();
Serial.println(F("Demo 1: bounce fill loop."));
}
break;
case 2:
if (!bar.animations().isRunning()) {
bar.animations().animInit().collidingBlocks(50, 4, 4, 6).loop();
Serial.println(F("Demo 2: colliding blocks."));
}
break;
case 3:
if (!bar.animations().isRunning()) {
bar.animations().animInit().explodingBlocks(50, 8, 10);
Serial.println(F("Demo 3: exploding blocks."));
}
break;
case 4:
if (!bar.animations().isRunning()) {
bar.animations().animInit().scrollingUpBlocks(50, 5, 3, 8).loop();
Serial.println(F("Demo 4: scrolling up blocks."));
}
break;
case 5:
if (!bar.animations().isRunning()) {
bar.animations().animInit().scrollingDownBlocks(50, 2, 4);
Serial.println(F("Demo 5: scrolling down blocks."));
}
break;
case 6:
if (!bar.animations().isRunning()) {
bar.animations().animInit().followSignalSmooth(&fakeSignal1, 100, 0, 1023, 70, 5);
Serial.println(F("Demo 6: followSignalSmooth."));
}
break;
case 7:
if (!bar.animations().isRunning()) {
bar.animations().animInit().followDualSignalFromCenter(&fakeSignal1, 100);
Serial.println(F("Demo 7: dual signal from center."));
}
break;
case 8:
if (!bar.animations().isRunning()) {
bar.animations().animInit().followSignalFloatingPeak(&fakeSignal1,50);
Serial.println(F("Demo 8: floating peak."));
}
break;
case 9:
if (!bar.animations().isRunning()) {
bar.animations().animInit().downStackingBlocks(50, 1, 0).loop();
Serial.println(F("Demo 9: down stacking blocks."));
}
break;
case 10:
if (!bar.animations().isRunning()) {
bar.animations().setAllOff().animInit().randomFill(100);
Serial.println(F("Demo 10: random fill."));
}
break;
case 11:
if (!bar.animations().isRunning()) {
bar.animations().animInit().randomEmpty(100);
Serial.println(F("Demo 11: random empty."));
}
break;
}
// Toggle animation logic midway for logic-invertible animations.
if (!bar.animations().isNonInvertingLogicAnim() && !bar.animations().isLogicInverted() && millis() - lastSwitch >= 5000) {
if ((demoMode == 3 || demoMode == 5 || demoMode == 7) || bar.animations().animPendingLoop()) {
bar.animations().invertLogic();
Serial.println(F(" Animation logic inverted."));
}
}
// End the current demo mode window.
if (millis() - lastSwitch > 10000) {
if (bar.animations().isLoopEnabled()) {
bar.animations().noLoop();
Serial.println(F(" Loop stopped."));
}
if (demoMode == 6 || demoMode == 7 || demoMode == 8) {
bar.animations().stop();
}
if ((demoMode == 3 || demoMode == 5) && bar.animations().isBlockEmissionEnabled()) {
bar.animations().stopBlockEmission();
Serial.println(F(" Block emission stopped."));
}
}
fakeSignal1 = generateFakeSignal(millis());
}
uint16_t generateFakeSignal(uint32_t tMillis) {
float baseFreq = 0.0015;
float noiseFreq = 0.006;
float noiseAmp = 300;
float base = sin(tMillis * baseFreq) * 400 + 500;
float noise = sin(tMillis * noiseFreq + random(0, 1000)) * noiseAmp;
return constrain(base + noise, 0, 1023);
}