#include <FastLED.h>
#define NUM_LEDS 30 // the number of LEDs that will light
#define DATA_PINA 6 // Connect to the data wires on the pixel strips
#define DATA_PINB 7
#define DATA_PINC 8
CRGB ledsA[NUM_LEDS]; // sets number of pixels that will light on each strip.
CRGB ledsB[NUM_LEDS];
CRGB ledsC[NUM_LEDS];
int buttons[] = {
22, // SF6
23, // SCC
24, // OLCS
};
int buttonCount = 3;
int lastButtonStates[] = {HIGH, HIGH, HIGH}; // stores the last known state of the buttons
bool chaseActive[] = {false, false, false}; // flags to track if the chase should be running
// Array to hold the current position of the chase for each strip
static int startPos[3] = {NUM_LEDS - 1, NUM_LEDS - 1, NUM_LEDS - 1};
// Timing variables
unsigned long lastUpdate[3]; // Last update time for each strip
const unsigned long updateInterval = 30; // Interval for updating the chase
void setup() {
FastLED.addLeds<WS2812B, DATA_PINA, GRB>(ledsA, NUM_LEDS);
FastLED.addLeds<WS2812B, DATA_PINB, GRB>(ledsB, NUM_LEDS);
FastLED.addLeds<WS2812B, DATA_PINC, GRB>(ledsC, NUM_LEDS);
Serial.begin(9600); // Initialize Serial communication
for (int i = 0; i < buttonCount; i++) {
pinMode(buttons[i], INPUT_PULLUP);
}
// Initialize lastUpdate times
for (int i = 0; i < 3; i++) {
lastUpdate[i] = 0;
}
}
int inputIndex = 0; // To keep track of the current index for the input
char receivedChars[10]; // Buffer to hold incoming characters
void loop() {
// Check for button presses
for (int i = 0; i < buttonCount; i++) {
checkActiveButton(buttons[i], i + 1, i); // Check each button and corresponding strip
}
// Continue running the chase on active strips
for (int i = 0; i < buttonCount; i++) {
if (chaseActive[i]) {
unsigned long currentMillis = millis();
// Update the chase only if the time has elapsed
if (currentMillis - lastUpdate[i] >= updateInterval) {
fillChaseForButton(i + 1); // Continue running the chase if the flag is set
lastUpdate[i] = currentMillis; // Update the last update time
}
}
}
// Check for an integer in Serial input
if (Serial.available() > 0) {
char receivedChar = Serial.read(); // Read a single character
Serial.print("Received: ");
Serial.println(receivedChar);
// Check if the received character is a digit
if (isdigit(receivedChar)) {
// Store the character in the buffer
if (inputIndex < sizeof(receivedChars) - 1) { // Ensure we don't overflow
receivedChars[inputIndex++] = receivedChar; // Add to buffer
receivedChars[inputIndex] = '\0'; // Null-terminate the string
}
} else if (receivedChar == '\n') { // Check for newline to process the number
// Convert the buffered string to an integer
int index = atoi(receivedChars); // Convert to integer
// Debugging: print the parsed integer
Serial.print("Parsed index: ");
Serial.println(index);
// Trigger chase action for the corresponding index (index - 1 for array)
if (index >= 1 && index <= buttonCount) {
chaseActive[index - 1] = true; // Start the chase on the specified index
Serial.print("Integer command received: ");
Serial.println(index);
} else {
Serial.println("Invalid index! Must be between 1 and buttonCount.");
}
// Reset the buffer and index for the next input
inputIndex = 0; // Reset the index
memset(receivedChars, 0, sizeof(receivedChars)); // Clear the buffer
} else {
// Reset if the input is invalid
Serial.println("Invalid input! Please enter a number.");
inputIndex = 0; // Reset the index for next input
memset(receivedChars, 0, sizeof(receivedChars)); // Clear the buffer
}
}
delay(50);
}
void checkActiveButton(int buttonPin, int buttonIndex, int chaseIndex) {
int currentButtonState = digitalRead(buttonPin); // read the current state of the button
// Check for a falling edge (HIGH to LOW transition)
if (lastButtonStates[buttonIndex] == HIGH && currentButtonState == LOW) {
// Only activate the chase if it's not already active
if (!chaseActive[chaseIndex]) {
chaseActive[chaseIndex] = true; // Set the flag to start/continue the chase
Serial.print("Button pressed: Starting chase on index ");
Serial.println(chaseIndex + 1);
}
}
// Update the last state for the next loop iteration
lastButtonStates[buttonIndex] = currentButtonState;
}
//**************************************************
void fillStrip(int number, const struct CRGB &color) {
switch (number) {
case 1:
fillChase(ledsA, NUM_LEDS, color, 0);
break;
case 2:
fillChase(ledsB, NUM_LEDS, color, 1);
break;
case 3:
fillChase(ledsC, NUM_LEDS, color, 2);
break;
}
FastLED.show();
}
void fillChaseForButton(int stripNumber) {
switch (stripNumber) {
case 1:
fillChase(ledsA, NUM_LEDS, CRGB::Green, 0);
break;
case 2:
fillChase(ledsB, NUM_LEDS, CRGB::Red, 1);
break;
case 3:
fillChase(ledsC, NUM_LEDS, CRGB::Red, 2);
break;
}
}
//**************************************************
void fillChase(CRGB leds[], int numLeds, const CRGB color, int chaseIndex) {
int chaseLength = 4; // Number of LEDs lit up at any time
// Turn off the LED that's leaving the chase
int tailPos = (startPos[chaseIndex] + chaseLength) % numLeds;
leds[tailPos] = CRGB::Black;
// Light up the LEDs in the current chase
for (int i = 0; i < chaseLength; i++) {
int ledPos = (startPos[chaseIndex] - i + numLeds) % numLeds; // Wrap around backwards
leds[ledPos] = color;
}
FastLED.show();
// Removed delay to avoid blocking
// Move the chase position backward
startPos[chaseIndex] = (startPos[chaseIndex] - 1 + numLeds) % numLeds; // Decrement the position, with wrap-around
}