// Attempt at non-blocking version of FastLED classesTimer.ino example
// https://wokwi.com/projects/356666059490147329
// Discussion at
// https://forum.arduino.cc/t/make-some-fastled-code-non-blocking/1090335
//
// Based on sim from https://wokwi.com/projects/356665860602531841
// with code from https://github.com/s-marley/FastLED-basics/tree/main/5.%20Multiple%20patterns/classesTimer
// using a wokwi-neopixel-canvas
//
// Contribution of SRAM monitor from qbits-us per
// https://forum.arduino.cc/t/make-some-fastled-code-non-blocking/1090335/2
//
// Try to make non-blocking
//
// On Nano:
// A0 potentiometer: led speed 1-600 sec
// A1 potentiometer: report speed 1-1000 ms
//
// Note that the reading of the A0 report() happens frequently while the loop animations are going
#include <FastLED.h>
#define NUM_LEDS 18
const int LED_PIN = 2;
const int LED_speed_pin = A0;
const int report_speed_pin = A1;
const int verbose = 4;
CRGB leds[NUM_LEDS];
uint8_t patternCounter = 0;
bool isRunning = false;
bool changePattern = false;
void checkTimer();
int reportInterval = 500; // ms
int ledInterval = 1; // sec
#include "Fire2012.h"
#include "Pacifica.h"
#include "Pride2015.h"
void setup() {
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(100);
Serial.begin(115200);
pinMode(LED_speed_pin,INPUT);
pinMode(report_speed_pin,INPUT);
}
void loop() {
handleIO();
switch (patternCounter) {
case 0:
runFire2012();
break;
case 1:
if(1) runPacificaStatic(); else // XXX comment to use runPacifica
runPacifica();
break;
case 2:
runPride2015();
break;
}
report();
if(verbose >=0) LoopCounter();
}
/////////// diagnostic code for excercising doing several things at once
// An output line like this consists of several reports
// Pride2015.- SRAM left: 1514 400Hzdeleted
// ^ object intantiated
// ^ report triggered
// ^ Free SRAM report
// ^ loop() frequency
// ^ object deleted
void report(){
static uint32_t last=0;
//const int interval=1;
if(millis() - last > reportInterval){
last+=reportInterval;
if(verbose >= 3)Serial.print('.');
if(verbose >= 2)display_freeram();
}
}
int lastFreeRam = 0;
void display_freeram() {
int ramleft = freeRam();
if (ramleft!= lastFreeRam)
{
lastFreeRam = ramleft;
Serial.print(F("- SRAM left: "));
Serial.print(ramleft);
Serial.print(' ');
}
}
int freeRam() {
extern int __heap_start,*__brkval;
int v;
return (int)&v - (__brkval == 0
? (int)&__heap_start : (int) __brkval);
}
void LoopCounter() // tells the average response speed of void loop()
// code modified from https://forum.arduino.cc/t/while-loop-as-a-condition-for-limit-switches/963899/11
{ // inside a function, static variables keep their value from run to run
const unsigned long microsInOneSecond=1000000UL;
static unsigned long count, countStartMicros; // only this function sees these
count++; // adds 1 to count after any use in an expression, here it just adds 1.
if ( micros() - countStartMicros >= microsInOneSecond ) // 1 second
{
countStartMicros += microsInOneSecond; // for a regular second
Serial.print( count ); // 32-bit binary into decimal text = many micros
Serial.print("Hz");
count = 0; // don't forget to reset the counter
}
}
//////////// end diagnostic code
void handleIO(void){
const int interval = 250; //ms
static uint32_t last = -interval;
if(millis() - last >= interval){
ledInterval = map(analogRead(LED_speed_pin),0,1024,1,600); // seconds
reportInterval = map(analogRead(report_speed_pin),0,1024,1,1000); // ms
}
}
void checkTimer() {
static uint32_t last = 0;
if(millis() - last >= ledInterval*1000UL){
last = millis();
nextPattern();
}
}
void nextPattern() {
isRunning = false;
changePattern = true;
//patternCounter = (patternCounter + 1) % 3;
}
// These runXXXX commands were modified from the original to
// be non-blocking by keeping a static pointer to an object
// that persists between calls, and is destryed when finished.
void runFire2012(){
static Fire2012 *fire2012;
if(! fire2012) {
isRunning = true;
fire2012 = new Fire2012;
if(verbose>1)Serial.print(F("Fire2012"));
}
if(changePattern){ // shut things down and transition
isRunning = false;
if(fire2012){ // de-allocate
delete fire2012;
fire2012=NULL;
if(verbose>1)Serial.print(F("deleted\n"));
}
patternCounter = (patternCounter+1)%3;
changePattern=false; // oneshot
}
// Fire2012 fire2012 = Fire2012();
if(isRunning) fire2012->runPattern();
}
void runPacificaStatic(){
static bool wasRunning = false;
static Pacifica pacifica;
if(wasRunning == false){
isRunning = true;
wasRunning = isRunning;
if(verbose>1)Serial.print(F("Pacifica"));
}
if(changePattern){
isRunning = false;
wasRunning = false;
if(verbose>1)Serial.print(F("Over\n"));
patternCounter = (patternCounter+1)%3;
changePattern=false; // oneshot
}
if(isRunning) pacifica.runPattern();
}
void runPacifica(){
static Pacifica *pacifica;
// if( !isRunning || ! pacifica) {
if( ! pacifica) {
isRunning = true;
pacifica = new Pacifica;
if(verbose>1)Serial.print(F("Pacifica"));
}
if(changePattern){ // shut things down and transition
isRunning = false;
if(pacifica){
delete pacifica;
pacifica = NULL;
if(verbose>1)Serial.print(F("deleted\n"));
}
patternCounter = (patternCounter+1)%3;
changePattern=false; // oneshot
}
if(isRunning) pacifica->runPattern();
}
void runPride2015(){
static Pride2015 *pride2015;
if( ! pride2015) {
isRunning = true;
pride2015 = new Pride2015;
if(verbose>1)Serial.print(F("Pride2015"));
}
if(changePattern){ // shut things down and transition
isRunning = false;
if(pride2015){
delete pride2015;
pride2015 = NULL;
if(verbose>1)Serial.print(F("deleted\n"));
}
patternCounter = (patternCounter+1)%3;
changePattern=false; // oneshot
}
if(isRunning) pride2015->runPattern();
}
Pot1: LED Pattern change delay
0-600s
Pot2: Report Speed