13#if defined(__AVR__) || defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RP2350) || defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_TEENSYLC)
25#include "fl/screenmap.h"
26#include "fl/math_macros.h"
31#include "screenmap.json.h"
46constexpr int lengths[] = {
61CRGB leds0[lengths[BlackStrip]] = {};
62CRGB leds1[lengths[GreenStrip]] = {};
63CRGB leds2[lengths[RedStrip]] = {};
64CRGB leds3[lengths[BlueStrip]] = {};
65CRGB *leds[] = {leds0, leds1, leds2, leds3};
68byte ledColors[40][14][3];
73Slider sliderDecay(
"decay", .97f, .8, 1.0, .01);
77#define numberOfRipples 30
78Ripple ripples[numberOfRipples] = {
89float highestIrReading;
92#define heartbeatLockout \
94#define heartbeatDelta 300
97#define lowTemperature 33.0
98#define highTemperature 37.0
99float lastKnownTemperature =
100 (lowTemperature + highTemperature) /
108#define gyroThreshold \
110float gyroX, gyroY, gyroZ;
114#define randomPulsesEnabled true
115#define cubePulsesEnabled true
116Checkbox starburstPulsesEnabled(
"Starburst Pulses",
true);
117Checkbox simulatedBiometricsEnabled(
"Simulated Biometrics",
true);
119#define autoPulseTimeout \
122#define randomPulseTime 2000
123unsigned long lastRandomPulse;
124byte lastAutoPulseNode = 255;
126byte numberOfAutoPulseTypes =
127 randomPulsesEnabled + cubePulsesEnabled + int(starburstPulsesEnabled);
128byte currentAutoPulseType = 255;
129#define autoPulseChangeTime 30000
130unsigned long lastAutoPulseChange;
132#define simulatedHeartbeatBaseTime \
134#define simulatedHeartbeatVariance \
136#define simulatedEdaBaseTime 1000
137#define simulatedEdaVariance 10000
138unsigned long nextSimulatedHeartbeat;
139unsigned long nextSimulatedEda;
142bool isNodeOnBorder(
byte node) {
143 for (
int i = 0; i < numberOfBorderNodes; i++) {
144 if (node == borderNodes[i]) {
151Checkbox allWhite(
"All White",
false);
153Button simulatedHeartbeat(
"Simulated Heartbeat");
154Button triggerStarburst(
"Trigger Starburst");
155Button triggerRainbowCube(
"Rainbow Cube");
156Button triggerBorderWave(
"Border Wave");
157Button triggerSpiral(
"Spiral Wave");
158bool wasHeartbeatClicked =
false;
159bool wasStarburstClicked =
false;
160bool wasRainbowCubeClicked =
false;
161bool wasBorderWaveClicked =
false;
162bool wasSpiralClicked =
false;
165 Serial.begin(115200);
167 Serial.println(
"*** LET'S GOOOOO ***");
169 Serial.println(
"JSON SCREENMAP");
170 Serial.println(JSON_SCREEN_MAP);
173 ScreenMap::ParseJson(JSON_SCREEN_MAP, &segmentMaps);
175 printf(
"Parsed %d segment maps\n",
int(segmentMaps.size()));
176 for (
auto kv : segmentMaps) {
177 Serial.print(kv.first.c_str());
179 Serial.println(kv.second.getLength());
186 ok = segmentMaps.get(
"red_segment", &red) && ok;
187 ok = segmentMaps.get(
"back_segment", &black) && ok;
188 ok = segmentMaps.get(
"green_segment", &green) && ok;
189 ok = segmentMaps.get(
"blue_segment", &blue) && ok;
191 Serial.println(
"Failed to get all segment maps");
196 CRGB* red_leds = leds[RedStrip];
197 CRGB* black_leds = leds[BlackStrip];
198 CRGB* green_leds = leds[GreenStrip];
199 CRGB* blue_leds = leds[BlueStrip];
212 unsigned long benchmark = millis();
218 for (
int strip = 0; strip < 40; strip++) {
219 for (
int led = 0; led < 14; led++) {
220 for (
int i = 0; i < 3; i++) {
221 ledColors[strip][led][i] *= sliderDecay.value();
226 for (
int i = 0; i < numberOfRipples; i++) {
227 ripples[i].advance(ledColors);
230 for (
int segment = 0; segment < 40; segment++) {
231 for (
int fromBottom = 0; fromBottom < 14; fromBottom++) {
232 int strip = ledAssignments[segment][0];
233 int led = round(fmap(fromBottom, 0, 13, ledAssignments[segment][2],
234 ledAssignments[segment][1]));
235 leds[strip][led] =
CRGB(ledColors[segment][fromBottom][0],
236 ledColors[segment][fromBottom][1],
237 ledColors[segment][fromBottom][2]);
243 for (
int i = 0; i < 4; i++) {
244 for (
int j = 0; j < lengths[i]; j++) {
254 wasHeartbeatClicked = bool(simulatedHeartbeat);
255 wasStarburstClicked = bool(triggerStarburst);
256 wasRainbowCubeClicked = bool(triggerRainbowCube);
257 wasBorderWaveClicked = bool(triggerBorderWave);
258 wasSpiralClicked = bool(triggerSpiral);
260 if (wasSpiralClicked) {
262 unsigned int baseColor = random(0xFFFF);
263 byte centerNode = 15;
266 for (
int i = 0; i < 6; i++) {
267 if (nodeConnections[centerNode][i] >= 0) {
268 for (
int j = 0; j < numberOfRipples; j++) {
269 if (ripples[j].state == dead) {
272 Adafruit_DotStar_ColorHSV(
273 baseColor + (0xFFFF / 6) * i, 255, 255),
276 i % 2 ? alwaysTurnsLeft : alwaysTurnsRight);
282 lastHeartbeat = millis();
285 if (wasBorderWaveClicked) {
287 unsigned int baseColor = random(0xFFFF);
290 for (
int i = 0; i < numberOfBorderNodes; i++) {
291 byte node = borderNodes[i];
293 for (
int dir = 0; dir < 6; dir++) {
294 if (nodeConnections[node][dir] >= 0 &&
295 !isNodeOnBorder(nodeConnections[node][dir])) {
296 for (
int j = 0; j < numberOfRipples; j++) {
297 if (ripples[j].state == dead) {
300 Adafruit_DotStar_ColorHSV(
301 baseColor + (0xFFFF / numberOfBorderNodes) * i,
311 lastHeartbeat = millis();
314 if (wasRainbowCubeClicked) {
316 int node = cubeNodes[random(numberOfCubeNodes)];
317 unsigned int baseColor = random(0xFFFF);
318 byte behavior = random(2) ? alwaysTurnsLeft : alwaysTurnsRight;
320 for (
int i = 0; i < 6; i++) {
321 if (nodeConnections[node][i] >= 0) {
322 for (
int j = 0; j < numberOfRipples; j++) {
323 if (ripples[j].state == dead) {
326 Adafruit_DotStar_ColorHSV(
327 baseColor + (0xFFFF / 6) * i, 255, 255),
334 lastHeartbeat = millis();
337 if (wasStarburstClicked) {
339 unsigned int baseColor = random(0xFFFF);
340 byte behavior = random(2) ? alwaysTurnsLeft : alwaysTurnsRight;
342 for (
int i = 0; i < 6; i++) {
343 for (
int j = 0; j < numberOfRipples; j++) {
344 if (ripples[j].state == dead) {
347 Adafruit_DotStar_ColorHSV(
348 baseColor + (0xFFFF / 6) * i, 255, 255),
349 .65, 1500, behavior);
354 lastHeartbeat = millis();
357 if (wasHeartbeatClicked) {
359 for (
int i = 0; i < 6; i++) {
360 for (
int j = 0; j < numberOfRipples; j++) {
361 if (ripples[j].state == dead) {
362 ripples[j].start(15, i, 0xEE1111,
363 float(random(100)) / 100.0 * .1 + .4, 1000, 0);
368 lastHeartbeat = millis();
371 if (millis() - lastHeartbeat >= autoPulseTimeout) {
373 if (numberOfAutoPulseTypes &&
374 millis() - lastRandomPulse >= randomPulseTime) {
375 unsigned int baseColor = random(0xFFFF);
377 if (currentAutoPulseType == 255 ||
378 (numberOfAutoPulseTypes > 1 &&
379 millis() - lastAutoPulseChange >= autoPulseChangeTime)) {
380 byte possiblePulse = 255;
382 possiblePulse = random(3);
384 if (possiblePulse == currentAutoPulseType)
387 switch (possiblePulse) {
389 if (!randomPulsesEnabled)
394 if (!cubePulsesEnabled)
399 if (!starburstPulsesEnabled)
407 currentAutoPulseType = possiblePulse;
408 lastAutoPulseChange = millis();
413 switch (currentAutoPulseType) {
416 bool foundStartingNode =
false;
417 while (!foundStartingNode) {
419 foundStartingNode =
true;
420 for (
int i = 0; i < numberOfBorderNodes; i++) {
423 if (node == borderNodes[i])
424 foundStartingNode =
false;
427 if (node == lastAutoPulseNode)
428 foundStartingNode =
false;
431 lastAutoPulseNode = node;
433 for (
int i = 0; i < 6; i++) {
434 if (nodeConnections[node][i] >= 0) {
435 for (
int j = 0; j < numberOfRipples; j++) {
436 if (ripples[j].state == dead) {
442 Adafruit_DotStar_ColorHSV(baseColor, 255,
444 float(random(100)) / 100.0 * .2 + .5, 3000,
456 int node = cubeNodes[random(numberOfCubeNodes)];
458 while (node == lastAutoPulseNode)
459 node = cubeNodes[random(numberOfCubeNodes)];
461 lastAutoPulseNode = node;
463 byte behavior = random(2) ? alwaysTurnsLeft : alwaysTurnsRight;
465 for (
int i = 0; i < 6; i++) {
466 if (nodeConnections[node][i] >= 0) {
467 for (
int j = 0; j < numberOfRipples; j++) {
468 if (ripples[j].state == dead) {
474 Adafruit_DotStar_ColorHSV(baseColor, 255,
487 byte behavior = random(2) ? alwaysTurnsLeft : alwaysTurnsRight;
489 lastAutoPulseNode = starburstNode;
491 for (
int i = 0; i < 6; i++) {
492 for (
int j = 0; j < numberOfRipples; j++) {
493 if (ripples[j].state == dead) {
496 Adafruit_DotStar_ColorHSV(
497 baseColor + (0xFFFF / 6) * i, 255, 255),
498 .65, 1500, behavior);
510 lastRandomPulse = millis();
513 if (simulatedBiometricsEnabled) {
515 if (millis() >= nextSimulatedHeartbeat) {
516 for (
int i = 0; i < 6; i++) {
517 for (
int j = 0; j < numberOfRipples; j++) {
518 if (ripples[j].state == dead) {
521 float(random(100)) / 100.0 * .1 + .4, 1000, 0);
528 nextSimulatedHeartbeat = millis() + simulatedHeartbeatBaseTime +
529 random(simulatedHeartbeatVariance);
533 if (millis() >= nextSimulatedEda) {
534 for (
int i = 0; i < 10; i++) {
535 for (
int j = 0; j < numberOfRipples; j++) {
536 if (ripples[j].state == dead) {
538 borderNodes[random(numberOfBorderNodes)];
539 byte direction = 255;
541 while (direction == 255) {
542 direction = random(6);
543 if (nodeConnections[targetNode][direction] < 0)
548 targetNode, direction, 0x1111EE,
549 float(random(100)) / 100.0 * .5 + 2, 300, 2);
556 nextSimulatedEda = millis() + simulatedEdaBaseTime +
557 random(simulatedEdaVariance);
CFastLED FastLED
Global LED strip management instance.
central include file for FastLED, defines the CFastLED class/object
void show(uint8_t scale)
Update all our controllers with the current led colors, using the passed in brightness.
static CLEDController & addLeds(CLEDController *pLed, struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset=0)
Add a CLEDController instance to the world.
Implements a simple red square effect for 2D LED grids.
Representation of an RGB pixel (Red, Green, Blue)