// #include <Arduino.h>
#include <FastLED.h>
#include <EEPROM.h>
#define IDENTIFIER_DEFAULT "ADYSTRIP"
#define NUM_LEDS_PER_STRIP_DEFAULT 60
#define NUM_STRIPS_DEFAULT 3
#define NUM_GROUPS_PER_STRIP_DEFAULT 6
#define SPACER_WIDTH_DEFAULT 1
#define MAX_TERMINALS 48
#define BLINK_INTERVAL 250
#define MAX_INPUT_LEN 15
#define MAX_OUTPUT_LEN 60
char identifier[8] = IDENTIFIER_DEFAULT;
int numLedsPerStrip = NUM_LEDS_PER_STRIP_DEFAULT;
int numStrips = NUM_STRIPS_DEFAULT;
int numGroupsPerStrip = NUM_GROUPS_PER_STRIP_DEFAULT;
int spacerWidth = SPACER_WIDTH_DEFAULT;
// CRGB::OrangeRed
CRGB colors[5] = {CRGB::Black, CRGB::Green, CRGB::DarkOrange, CRGB::Red, CRGB::Blue}; // Default colors for states 0, 1, 2, 3 and 4 (5-8 is same but blinking)
bool BlinkState[MAX_TERMINALS] = {0};
CRGB BlinkColor[MAX_TERMINALS] = {0};
bool blink=false;
uint32_t lastToggleTimes;
//CRGB leds[numStrips][numLedsPerStrip];
//CRGB leds[NUM_STRIPS_DEFAULT][NUM_LEDS_PER_STRIP_DEFAULT];
CRGB leds1[NUM_LEDS_PER_STRIP_DEFAULT];
// CRGB leds2[NUM_LEDS_PER_STRIP_DEFAULT];
// CRGB leds3[NUM_LEDS_PER_STRIP_DEFAULT];
// CRGB leds4[NUM_LEDS_PER_STRIP_DEFAULT];
// CRGB leds5[NUM_LEDS_PER_STRIP_DEFAULT];
// CRGB leds6[NUM_LEDS_PER_STRIP_DEFAULT];
void setup() {
Serial.begin(57600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("-=[ USB LedStrip ]=-");
// Serial.setTimeout(0);
// loadConfiguration();
updateConfiguration();
//startupAnimation();
StartupLoop();
// Ready to go. show help:
// ShowHelp();
displayConfiguration() ;
Serial.println(">");
}
void loop() {
if (Serial.available()) {
checkInput();
Serial.println("> ");
}
// delay(10);
SetLEDs();
}
void checkInput() {
char input[MAX_INPUT_LEN];
char output[MAX_OUTPUT_LEN];
memset(input, '\0', sizeof(input));
memset(output, '\0', sizeof(output));
int test=0;
int State;
int TermID;
Serial.readBytesUntil('\n', input, MAX_INPUT_LEN);
//Serial.flush();
sprintf(output,"Input: [%s].",input);
Serial.println(output);
char Command = input[0];
char *Data = input +1;
if (Command >= 'A' && Command <= 'Z') {
sprintf(output,"Command [%c] with Data [%s]",Command, Data);
Serial.println(output);
switch(Command) {
// case 'C':
// Serial.print("Config - ");
// char Parameter;
// String Value;
// test = sscanf(Data, "%c:%c", &Parameter, &Value);
// if (test == 2) {
// switch (Parameter) {
// case 'l':
// Serial.print("Set lets per shelve:");
// Serial.print(Value);
// numLedsPerStrip = Value.toInt();
// Serial.println(numLedsPerStrip);
// break;
// case 'g':
// Serial.print("Set terminals per shelve:");
// numGroupsPerStrip = Value.toInt();
// Serial.println(numGroupsPerStrip);
// break;
// case 's':
// Serial.print("Set spacer width:");
// spacerWidth = Value.toInt();
// Serial.println(spacerWidth);
// break;
// case 'i':
// Serial.print("Set identifier code:");
// Serial.println(Value);
// Value.toCharArray(identifier, 8);;
// break;
// default:
// Serial.println("Syntax error.");
// break;
// }
// updateConfiguration();
// } else {
// sprintf(output,"Syntax parsing failed %d of 3 parameters detected.",test);
// }
// break;
case 'T':
test = sscanf(Data, "%2d:%d", &TermID, &State);
if ( test == 2) {
if (TermID >= 1 && TermID <= MAX_TERMINALS) {
if (State >= 0 && State <= 9) {
setGroupState(TermID -1,State);
sprintf(output,"Terminal %d state set to %d", TermID, State);
} else {
sprintf(output,"Invalid state, use 0-9.");
}
} else {
sprintf(output,"Invalid Terminal-ID, use 1-%d.", MAX_TERMINALS);
}
} else {
sprintf(output,"Syntax error: Use T<TERMINAL-ID>:<STATE>.",test);
}
break;
case 'A':
test = sscanf(Data, ":%d", &State);
if (test == 1) {
if (State >= 0 && State <= 9) {
sprintf(output,"All terminals set to state %d.",State);
for(int i=0; i < MAX_TERMINALS; i++){
setGroupState(i,State);
}
} else {
sprintf(output,"Invalid state, use 0-9.");
}
} else
sprintf(output,"Syntax error. Use A:<STATE>");
break;
case 'D':
Serial.println("Display configuration:");
displayConfiguration();
break;
case 'S':
Serial.println("Save configurartion:");
saveConfiguration();
sprintf(output,"Configuration saved in EEPROM.");
break;
case 'X':
Serial.println("Reset all Terminal states");
for(int i=0; i < MAX_TERMINALS; i++){
setGroupState(i,0);
}
SetAllLEDs(CRGB::Black);
break;
case 'W':
StartupLoop();
sprintf(output,"Startup loop shown.");
break;
case 'H':
ShowHelp();
break;
default:
sprintf(output,"No such command.");
break;
}
} else {
if (Command == 0)
sprintf(output,"INVALD SYNTAX: Use <A-Z>, H for help.", Command);
else
sprintf(output,"INVALD SYNTAX: Command=[%c], Use <A-Z>, H for help.", Command);
}
if (strlen(output) > 0 ) {
Serial.println(output);
}
}
void setGroupState(int group, int state) {
switch (state) {
case 0:
BlinkState[group]=false;
BlinkColor[group]=CRGB::Black;
break;
case 1:
BlinkState[group]=false;
BlinkColor[group]=colors[1];
break;
case 2:
BlinkState[group]=false;
BlinkColor[group]=colors[2];
break;
case 3:
BlinkState[group]=false;
BlinkColor[group]=colors[3];
break;
case 4:
BlinkState[group]=false;
BlinkColor[group]=colors[4];
break;
case 5:
BlinkState[group]=true;
BlinkColor[group]=colors[1];
break;
case 6:
BlinkState[group]=true;
BlinkColor[group]=colors[2];
break;
case 7:
BlinkState[group]=true;
BlinkColor[group]=colors[3];
break;
case 8:
BlinkState[group]=true;
BlinkColor[group]=colors[4];
break;
case 9:
BlinkColor[group]= CRGB::White;
break;
default:
break;
}
}
void SetLEDGroupColor(int group, CRGB color) {
int stripIndex = (group / numGroupsPerStrip)+1;
int groupIndex = group % numGroupsPerStrip;
int startLEDIndex = groupIndex * (numLedsPerStrip / numGroupsPerStrip);
int widthLED = (numLedsPerStrip / numGroupsPerStrip) - spacerWidth;
int endLEDIndex = startLEDIndex + widthLED;
// fill_solid(&(leds[stripIndex][startLEDIndex]), numLedsPerStrip / numGroupsPerStrip, color);
if (stripIndex == 1 ) {
fill_solid(&(leds1[startLEDIndex]), widthLED, color);
}
// if (stripIndex == 2 ) {
// fill_solid(&(leds2[startLEDIndex]), widthLED, color);
// }
// if (stripIndex == 3 ) {
// fill_solid(&(leds3[startLEDIndex]), widthLED, color);
// }
// if (stripIndex == 4 ) {
// fill_solid(&(leds4[startLEDIndex]), widthLED, color);
// }
// if (stripIndex == 5 ) {
// fill_solid(&(leds5[startLEDIndex]), widthLED, color);
// }
// if (stripIndex == 6 ) {
// fill_solid(&(leds6[startLEDIndex]), widthLED, color);
// }
FastLED.show();
}
// void updateConfiguration() {
// for (int i = 0; i < numStrips; i++) {
// FastLED.addLeds<WS2812, LED_PIN_1 + i, GRB>(leds[i], numLedsPerStrip);
// }
// }
void updateConfiguration() {
FastLED.addLeds<WS2812B, 2, GRB>(leds1, numLedsPerStrip);
// FastLED.addLeds<WS2812B, 3, GRB>(leds2, numLedsPerStrip);
// FastLED.addLeds<WS2812B, 4, GRB>(leds3, numLedsPerStrip);
// FastLED.addLeds<WS2812B, 5, GRB>(leds4, numLedsPerStrip);
// FastLED.addLeds<WS2812B, 6, GRB>(leds5, numLedsPerStrip);
// FastLED.addLeds<WS2812B, 7, GRB>(leds6, numLedsPerStrip);
}
void displayConfiguration() {
char output[MAX_OUTPUT_LEN];
memset(output, '\0', sizeof(output));
sprintf(output,"Identifier : %s",identifier);
Serial.println(output);
sprintf(output,"LEDs per shelve : %d",numLedsPerStrip);
Serial.println(output);
sprintf(output,"Groups per shelve : %d",numGroupsPerStrip);
Serial.println(output);
sprintf(output,"Shelves : %d",numStrips);
Serial.println(output);
sprintf(output,"Spacer width : %d",spacerWidth);
Serial.println(output);
}
void saveConfiguration() {
EEPROM.put(0, numLedsPerStrip);
EEPROM.put(sizeof(int), numGroupsPerStrip);
EEPROM.put(2 * sizeof(int), spacerWidth);
EEPROM.put(3 * sizeof(int), colors[1]);
EEPROM.put(3 * sizeof(int) + sizeof(uint32_t), colors[2]);
EEPROM.put(3 * sizeof(int) + 2 * sizeof(uint32_t), colors[3]);
}
void loadConfiguration() {
EEPROM.get(0, numLedsPerStrip);
EEPROM.get(sizeof(int), numGroupsPerStrip);
EEPROM.get(2 * sizeof(int), spacerWidth);
EEPROM.get(3 * sizeof(int), colors[1]);
EEPROM.get(3 * sizeof(int) + sizeof(uint32_t), colors[2]);
EEPROM.get(3 * sizeof(int) + 2 * sizeof(uint32_t), colors[3]);
}
void FadeAll(int StartLed=1, int EndLed=numLedsPerStrip) {
for(int i = StartLed; i < EndLed; i++) {
leds1[i].nscale8(200);
// leds2[i].nscale8(200);
// leds3[i].nscale8(200);
// leds4[i].nscale8(200);
// leds5[i].nscale8(200);
// leds6[i].nscale8(200);
}
}
void StartupLoop() {
// Boot animmation only on 1st strip.
// Blue ><><
#define DELAY (numLedsPerStrip/8)
for(int i = 0; i < numLedsPerStrip/2; i+=1) {
leds1[i] = 0x0080FF;
leds1[numLedsPerStrip -i -1] = 0x0080FF;
// leds2[i] = 0x0080FF;
// leds2[numLedsPerStrip -i -1] = 0x0080FF;
// leds3[i] = 0x0080FF;
// leds3[numLedsPerStrip -i -1] = 0x0080FF;
// leds4[i] = 0x0080FF;
// leds4[numLedsPerStrip -i -1] = 0x0080FF;
// leds5[i] = 0x0080FF;
// leds5[numLedsPerStrip -i -1] = 0x0080FF;
// leds6[i] = 0x0080FF;
// leds6[numLedsPerStrip -i -1] = 0x0080FF;
FastLED.show();
FadeAll(0,numLedsPerStrip);
delay(DELAY);
}
// White Flash
SetAllLEDs(CRGB::White);
FastLED.show();
delay(75);
for(int i = 0; i < 16; i++) {
FadeAll(0,numLedsPerStrip);
FastLED.show();
delay(65);
}
// All Off
SetAllLEDs(CRGB::Black);
}
void SetAllLEDs(CRGB color){
fill_solid(leds1, numLedsPerStrip, color);
// fill_solid(leds2, numLedsPerStrip, color);
// fill_solid(leds3, numLedsPerStrip, color);
// fill_solid(leds4, numLedsPerStrip, color);
// fill_solid(leds5, numLedsPerStrip, color);
// fill_solid(leds6, numLedsPerStrip, color);
FastLED.show();
}
void SetLEDs() {
// Check if it's time to toggle each group's state
if (millis() - lastToggleTimes >= BLINK_INTERVAL) { // Toggle every BLINK_INTERVAL ms
blink = blink == 0 ? 1 : 0;
lastToggleTimes = millis(); // Update last toggle time
for(int i=0; i < MAX_TERMINALS; i++){
if (BlinkState[i] == true) {
if (blink == true){
SetLEDGroupColor(i, BlinkColor[i]);
} else {
SetLEDGroupColor(i, CRGB::Black);
}
} else {
SetLEDGroupColor(i, BlinkColor[i]);
}
}
}
}
void ShowHelp(){
Serial.println("Syntax:");
Serial.println(" H This help");
Serial.println(" T<TermID>:<State> Where TermID: 1-48 and State: 0-9");
Serial.println(" X Set all states to off (same as sending'A:0'");
Serial.println(" A:<State> Set state for all Terminals");
Serial.println(" D Show current configuration");
Serial.println(" C<lgs>:value Set config for leds per strip, groups per strip or spacer-width.");
Serial.println(" S Store current configuration in EEPROM");
}