Ok so this is a succinct as I can get it and show the problem. It's obviously a butchered version of the full code but it does the same broken thing.
#include <SPI.h>
#include <Wire.h>
#include <avr/sleep.h> // For low power sleep mode
#include <movingAvg.h> // https://github.com/JChristensen/movingAvg
#include <FastLED.h> // https://github.com/FastLED/FastLED
#include <FastLED_GFX.h> // https://github.com/Jorgen-VikingGod/FastLED-GFX
#include <LEDMatrix.h> // https://github.com/Jorgen-VikingGod/LEDMatrix
#include <kxtj3-1057.h>
#include <Coordinates.h>
//Timers
volatile unsigned long last_motion = 0; // Holds millis value and is set every time new motion is detected
volatile unsigned long last_rest = 0; // Holds millis value and is set every time no motion is detected
volatile unsigned long last_press = 0; // Holds millis value and is set every time button is pressed
volatile unsigned long last_release = 0; // Holds millis value and is set every time button is released
int q_mode_start_delay = 3000; // Duration in milliseconds to wait before starting a q mode after selection.
int mode_exit_delay = 1500; // Duration in milliseconds to wait before starting a q mode after selection.
int hold_select_delay = 3000; // Duration in milliseconds to wait before switching between press and hold modes.
unsigned long mode_start_time = 0; // Holds millis value set when a mode starts
unsigned long q_mode_duration = 300000; // How long a q cycle will run for
// Control flow flags
volatile bool button_pressed = 0;
volatile bool button_latch = 0;
volatile bool in_motion = 0;
volatile bool run_q_mode_wait = 0;
volatile bool mode_active = 0;
volatile bool no_motion_wake = 0;
int mode = 0; // Used as the main logic switch for modes
// UI
// Colours
static int s_hue = 128;
static int c_hue = 20;
static int f_hue = 50;
static int tHue = 200;
// LED Patterns and Colour Maps
static int edge_chase[] = {0,1,2,3,4,5,6,7,15,23,31,39,47,55,63,62,61,60,59,58,57,56,48,40,32,24,16,8};
static int inner1_chase[] = {9,10,11,12,13,14,22,30,38,46,54,53,52,51,50,49,41,33,25,17,9};
static int colourWheelMap[] = {0,9,18,27,36,46,55,64,246,0,13,26,38,51,64,73,237,242,0,21,43,64,77,82,228,230,234,0,64,85,89,91,219,217,213,191,128,106,102,100,209,204,191,170,149,128,115,109,200,191,179,166,153,140,128,118,191,182,173,164,155,146,137,128};
// Define pins
#define SWINPUT 2
#define LEDENABLE 4
#define LEDTX 7
void setupPins()
{
pinMode(SWINPUT, INPUT);
attachInterrupt(digitalPinToInterrupt(SWINPUT), ISR_button, CHANGE);
pinMode(LEDENABLE, OUTPUT);
pinMode(LEDTX, OUTPUT);
}
#define COLOR_ORDER GRB
#define CHIPSET WS2812B
#define MATRIX_WIDTH 8
#define MATRIX_HEIGHT 8
#define MATRIX_TYPE HORIZONTAL_MATRIX
#define MATRIX_SIZE (MATRIX_WIDTH*MATRIX_HEIGHT)
#define NUMPIXELS MATRIX_SIZE
cLEDMatrix<MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_TYPE> matrix;
CRGB *leds = matrix[0];
int MASTER_BRIGHT = 255; // A master value for controlling brightness throughout the code
int edge_brightness = MASTER_BRIGHT/2; // Edge brightness in certain modes is always half the master
int ambientLight = 0; // 0 means low light - 1 means bright light
void setupMatrix(){
FastLED.addLeds<CHIPSET, LEDTX, COLOR_ORDER>(matrix[0], matrix.Size()).setCorrection(TypicalSMD5050);
FastLED.setCorrection(TypicalSMD5050);
FastLED.setTemperature(OvercastSky); // This colour corrects for the warm offwhite in the plastic shells
FastLED.setBrightness(MASTER_BRIGHT);
FastLED.setDither(1);
FastLED.clear(true);
}
void ISR_button(){
if (digitalRead(SWINPUT)==HIGH)
{
button_pressed = 1;
button_latch = 1;
last_press = millis();
} else {
button_pressed = 0;
last_release = millis();
}
}
void buttonHandler(){
if (button_pressed == 1 && button_latch == 1) { // Every time there's a new button press
while(button_pressed==1){ // While the button is being held
if(!mode_active){ // If not in a q mode then show the hold light
while (millis() - last_press < hold_select_delay){
/**BAILOUT**/ if(!button_pressed) break; /**BAILOUT**/
holdButton();
}
while(millis() - last_press > hold_select_delay && millis() - last_press < hold_select_delay*2) //Bedtime mode
{
/**BAILOUT**/ if(!button_pressed) break; /**BAILOUT**/
float hueShift = 7;
int hueStartPoint = 230;
float hueMidpoint = hueStartPoint + (14*hueShift);
for(int LED = 0; LED < 28; LED++){
/**BAILOUT**/ if(!button_pressed) break; /**BAILOUT**/
if(LED<14){
int hNow = hueStartPoint+(LED*hueShift);
leds[edge_chase[LED]].setHSV(hNow, 255, 255);
FastLED.show();
fadeToBlackBy(leds,NUMPIXELS,30);
FastLED.delay(25);
} else {
int hNow = hueMidpoint-((LED-14)*hueShift);
leds[edge_chase[LED]].setHSV(hNow, 255, 255);
FastLED.show();
fadeToBlackBy(leds,NUMPIXELS,30);
FastLED.delay(25);
}
}
if(millis() - last_press > hold_select_delay && millis() - last_press < hold_select_delay*2){
run_q_mode_wait = 1;
} else {
//Do this once to make the transition between the two modes easier to spot
if(millis() - last_press > hold_select_delay){run_q_mode_wait = 0;} // Conditional reset of flag
for(int LED = 0; LED < 28; LED++){
/**BAILOUT**/ if(!button_pressed) break; /**BAILOUT**/
leds[edge_chase[LED]].setHSV(0, 0, 255);
FastLED.show();
fadeToBlackBy(leds,NUMPIXELS,30);
FastLED.delay(15);
}
}
mode = 8;
}
while(millis() - last_press > hold_select_delay*2)
{
/**BAILOUT**/ if(!button_pressed) break; /**BAILOUT**/
while(button_pressed){
for(int LED = 0; LED < 28; LED++){
/**BAILOUT**/ if(!button_pressed) break; /**BAILOUT**/
int hNow = (255/27)*LED;
leds[edge_chase[LED]].setHSV(hNow, 255, 255);
FastLED.show();
fadeToBlackBy(leds,NUMPIXELS,30);
FastLED.delay(25);
}
}
mode = 7;
}
} else {
if (millis() - last_press < mode_exit_delay)
{
} else {
while(button_pressed){ // Pause here until released - Indicates an exit has been triggered
matrix.DrawRectangle(0, 0, 7, 7, CHSV(160, 255, 255));
matrix.DrawFilledRectangle(2, 2, 5, 5, CHSV(180, 200, 150));
FastLED.show();
}
mode_active = 0; // Flag as no active q mode
mode = 1; // Move to standby mode
button_latch = 0; // Skip the normal button release behaviour
}
}
}
}
if (button_latch == 1 && !mode_active){ // Normal button release behaviour (I.e. not when in an active mode or after a press and hold)
if (mode == 6) {mode = 3;}
else if (mode > 2 && mode < 7) {mode++;}
else if (mode < 3) {mode = 3;}
button_latch = 0;
}
}
void holdButton(){
FastLED.clear();
matrix.DrawRectangle(0, 0, 7, 7, CHSV(0, 0, MASTER_BRIGHT/2));
FastLED.show();
}
void selectWait(int h){
while(millis() - last_release < q_mode_start_delay && !mode_active){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
FastLED.clear();
matrix.DrawRectangle(0, 0, 7, 7, CHSV(h, 255, MASTER_BRIGHT/2));
FastLED.show();
}
if(millis() - last_release > q_mode_start_delay){
run_q_mode_wait = 1;
}
}
void qModeReady(int h){
run_q_mode_wait = 0; // Reset flag
while(!button_pressed){
for(int LED = 0; LED < 20; LED++){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
leds[inner1_chase[LED]].setHSV(h, 255, 255);
fadeToBlackBy(leds,NUMPIXELS,30);
FastLED.show();
FastLED.delay(35);
}
}
mode_active = 1; // Flag as actively in a q mode
}
void celebrate(){
}
static int low_offset = 30;
static int smooth_offset = 5;
void edgeFadeIn(int h){
int i = 0;
while(i < edge_brightness){
fadeToBlackBy(leds,NUMPIXELS,1);
matrix.DrawRectangle(0, 0, 7, 7, CHSV(h, 255, i));
FastLED.show();
FastLED.delay(4);
i++;
}
}
void qeIn(int h, int d) { //Duration is in seconds
Serial.println ("~ In q");
int targetVal = low_offset;
float full_seconds = d;
float updateDelaySpeed = (full_seconds*1000)/(MASTER_BRIGHT - low_offset);
matrix.DrawRectangle(0, 0, 7, 7, CHSV(h, 255, edge_brightness));
unsigned long temp = millis();
Serial.print ("~ Secs = ");
Serial.println (full_seconds);
Serial.print ("~ Speed millis = ");
Serial.println (updateDelaySpeed);
Serial.print ("~ Target val = ");
Serial.println (targetVal);
while(targetVal<MASTER_BRIGHT && !button_pressed){
EVERY_N_MILLISECONDS(updateDelaySpeed){
matrix.DrawFilledRectangle(3, 3, 4, 4, CHSV(h, 255, constrain(targetVal, low_offset, MASTER_BRIGHT)));
FastLED.show();
matrix.DrawRectangle(2, 2, 5, 5, CHSV(h, 255, constrain(targetVal+smooth_offset, low_offset, MASTER_BRIGHT)));
FastLED.show();
matrix.DrawRectangle(1, 1, 6, 6, CHSV(h, 255, constrain(targetVal+smooth_offset+smooth_offset, low_offset, MASTER_BRIGHT)));
FastLED.show();
targetVal++;
}
}
Serial.print ("~ In End = ");
Serial.println (millis()-temp);
}
void qeOut(int h, int d) { //Duration is in seconds
Serial.println ("~ Out q");
int targetVal = MASTER_BRIGHT;
float full_seconds = d;
float updateDelaySpeed = (full_seconds*1000)/(MASTER_BRIGHT - low_offset);
matrix.DrawRectangle(0, 0, 7, 7, CHSV(h, 255, edge_brightness));
unsigned long temp = millis();
Serial.print ("~ Secs = ");
Serial.println (full_seconds);
Serial.print ("~ Speed millis = ");
Serial.println (updateDelaySpeed);
Serial.print ("~ Target val = ");
Serial.println (targetVal);
while(targetVal>low_offset && !button_pressed){
EVERY_N_MILLISECONDS(updateDelaySpeed){
matrix.DrawFilledRectangle(3, 3, 4, 4, CHSV(h, 255, constrain(targetVal, low_offset, MASTER_BRIGHT)));
FastLED.show();
matrix.DrawRectangle(2, 2, 5, 5, CHSV(h, 255, constrain(targetVal+smooth_offset, low_offset, MASTER_BRIGHT)));
FastLED.show();
matrix.DrawRectangle(1, 1, 6, 6, CHSV(h, 255, constrain(targetVal+smooth_offset+smooth_offset, low_offset, MASTER_BRIGHT)));
FastLED.show();
targetVal--;
}
}
Serial.print ("~ Out End = ");
Serial.println (millis()-temp);
}
void holdIn(int h, int d) { //Duration is in seconds
matrix.DrawRectangle(0, 0, 7, 7, CHSV(h, 255, MASTER_BRIGHT/2));
for (float j = 0; j < d; j++) {
for (float i = MASTER_BRIGHT; i > (MASTER_BRIGHT-70); i--) {
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
matrix.DrawFilledRectangle(1, 1, 6, 6, CHSV(h, i, i));
FastLED.show();
FastLED.delay(1);
}
for (float i = (MASTER_BRIGHT-70); i < MASTER_BRIGHT; i++) {
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
matrix.DrawFilledRectangle(1, 1, 6, 6, CHSV(h, i, i));
FastLED.show();
FastLED.delay(1);
}
}
}
void holdOut(int h, int d) { //Duration is in seconds
matrix.DrawRectangle(0, 0, 7, 7, CHSV(h, 255, MASTER_BRIGHT/2));
for (float j = 0; j < d; j++) {
for (float i = low_offset; i < (low_offset+70); i++) {
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
matrix.DrawFilledRectangle(1, 1, 6, 6, CHSV(h, 255, i));
FastLED.show();
FastLED.delay(1);
}
for (float i = (low_offset+70); i > low_offset; i--) {
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
matrix.DrawFilledRectangle(1, 1, 6, 6, CHSV(h, 255, i));
FastLED.show();
FastLED.delay(1);
}
}
}
void s(){
Serial.println ("~ s");
while(mode == 3){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
selectWait(s_hue);
if(run_q_mode_wait){qModeReady(s_hue);}
mode_start_time = millis();
if (mode_active) edgeFadeIn(s_hue);
while(mode_active && (millis() - mode_start_time) < q_mode_duration){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
qeIn(s_hue, 4);
holdIn(s_hue, 4);
qeOut(s_hue, 4);
holdOut(s_hue, 4);
}
if((millis() - mode_start_time) > q_mode_duration){
celebrate();
mode_active = 0;
mode = 2;
button_latch = 0;
}
}
}
void c(){
Serial.println ("~ c");
while(mode == 4){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
selectWait(c_hue);
if(run_q_mode_wait){qModeReady(c_hue);}
mode_start_time = millis();
if (mode_active) edgeFadeIn(c_hue);
while(mode_active && (millis() - mode_start_time) < q_mode_duration){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
qeIn(c_hue, 5);
safeDelay(500);
qeOut(c_hue, 5);
safeDelay(500);
}
if((millis() - mode_start_time) > q_mode_duration){
celebrate();
mode_active = 0;
mode = 2;
button_latch = 0;
}
}
}
void f(){
Serial.println ("~ f");
while(mode == 5){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
selectWait(f_hue);
if(run_q_mode_wait){qModeReady(f_hue);}
mode_start_time = millis();
if (mode_active) edgeFadeIn(f_hue);
while(mode_active && (millis() - mode_start_time) < q_mode_duration){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
qeIn(f_hue, 4);
holdIn(f_hue, 7);
qeOut(f_hue, 8);
safeDelay(200);
}
if((millis() - mode_start_time) > q_mode_duration){
celebrate();
mode_active = 0;
mode = 2;
button_latch = 0;
}
}
}
void t(){
Serial.println ("~ t");
while(mode == 6){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
selectWait(tHue);
if(run_q_mode_wait){qModeReady(tHue);}
mode_start_time = millis();
if (mode_active) edgeFadeIn(tHue);
while(mode_active && (millis() - mode_start_time) < q_mode_duration){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
qeIn(tHue, 4);
holdIn(tHue, 4);
qeOut(tHue, 4);
safeDelay(200);
}
if((millis() - mode_start_time) > q_mode_duration){
celebrate();
mode_active = 0;
mode = 2;
button_latch = 0;
}
}
}
void l(){
}
void standby(){
}
void pwrSave(){
}
void safeDelay(int delay){
long unsigned start = millis();
while((millis() - start) < delay){
/**BAILOUT**/ if(in_motion || button_pressed) break; /**BAILOUT**/
FastLED.delay(5);
}
}
void safeDelayNoMotion(int delay){
long unsigned start = millis();
while((millis() - start) < delay){
/**BAILOUT**/ if(button_pressed) break; /**BAILOUT**/
FastLED.delay(5);
}
}
void safeDelayButton(int delay){
long unsigned start = millis();
while((millis() - start) < delay){
/**BAILOUT**/ if(!button_pressed) break; /**BAILOUT**/
FastLED.delay(5);
}
}
void setup()
{
digitalWrite(LEDENABLE, 1); // Enable LED Matrix Power - this might NEED MOVING to wake and sleep functions but is here for now
FastLED.clear();
Serial.begin(19200);
setupPins();
setupMatrix();
delay(100);
mode = 2;
button_latch = 0;
}
void loop()
{
buttonHandler(); // Manages mode switches from button presses
switch (mode) {
case 0:
pwrSave();
break;
case 1:
standby();
if(in_motion) {mode = 2;}
break;
case 2:
l();
mode = 1;
break;
case 3:
s();
break;
case 4:
c();
break;
case 5:
f();
break;
case 6:
t();
break;
case 7:
break;
case 8:
break;
default:
FastLED.delay(10);
}
}
I have to be away from my computer for a few hours so I'll pick this back up when I get back...
Fingers crossed for something obvious