// #include <Arduino.h>
#include <FastLED.h>
#define AVR false
#define do_half true
#if AVR==true
#include <EEPROM.h>
#endif
#define IDENTIFIER_DEFAULT "ADYSTRIP"
#define NUM_LEDS_PER_STRIP_DEFAULT 48
#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[10] = 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];
#if do_half==false
CRGB leds4[NUM_LEDS_PER_STRIP_DEFAULT];
CRGB leds5[NUM_LEDS_PER_STRIP_DEFAULT];
CRGB leds6[NUM_LEDS_PER_STRIP_DEFAULT];
#endif
const char HelpText[500] PROGMEM =
" Syntax:\n"
" H This help\n"
" T<TermID>:<State> Set Terminal state. TermID: 1-48 and State: 0-9\n"
" X Set all states to off (same as sending'A:0'\n"
" A:<State> Set state for all Terminals, state (0-9)\n"
" D Show current configuration\n"
" C<ltwi>:value Set config for leds per shelve, terminals per shelve, spacer-width, identifier.\n"
" S Store current configuration in EEPROM\n"
"\n"
;
const int MSG_MAX_NUMBER = 18;
const int MSG_MAX_SIZE = 48;
const char messages [MSG_MAX_NUMBER] [MSG_MAX_SIZE] PROGMEM = {
{ "-=[ USB LedStrip ]=-\n" },
{ "Invalid state, use 0-9\n" },
{ "Invalid Terminal-ID, use 1-48\n" },
{ "Syntax error: Use T<TERMINAL-ID>:<STATE>\n" },
{ "Syntax error: Use A:<STATE>\n" },
{ "Display configuration:\n" },
{ "Save configuration: " },
{ "Configuration saved in EEPROM.\n" },
{ "Reset all Terminal states.\n" },
{ "Startup loop shown.\n" },
{ "No such command.\n" },
{ "INVALD SYNTAX: Use <A-Z>, H for help.\n" },
{ "Identifier : " },
{ "LEDs per shelve : " },
{ "Groups per shelve : " },
{ "Shelves : " },
{ "Spacer width : " },
{ "No EEPROM on non AVR controller"}
};
void setup() {
Serial.begin(57600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
//Serial.println("-=[ USB LedStrip ]=-");
printMSG(0);
Serial.setTimeout(300);
// loadConfiguration();
updateConfiguration();
//startupAnimation();
StartupLoop();
// Show help & config:
ShowHelp();
displayConfiguration() ;
// Ready to go.:
Serial.println("> ");
}
void loop() {
if (Serial.available()) {
checkInput();
Serial.println("> ");
}
// delay(10);
SetLEDs();
}
// This does not work :-(
// char* ptrMSG (int i) {
// if (i <= MSG_MAX_NUMBER) {
// // sprintf(output,"Message: %d, ", i);
// // Serial.print(output);
// char *ptr=((const char *) &messages[i]);
// // sprintf(output,"Address: 0x%04X", ptr);
// // Serial.println(output);
// if (!ptr) {
// return 0;
// }
// return ptr;
// } else {
// return 0;
// }
// }
void printMSG (int i) {
if (i <= MSG_MAX_NUMBER) {
#if AVR==true
char *ptr=((const char *) &messages[i]);
#else
char *ptr=((char *) &messages[i]);
#endif
char chr;
if (!ptr)
return;
while ((chr = pgm_read_byte(ptr++))) {
Serial.print(chr);
}
}
}
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);
Serial.println(output);
} else {
//sprintf(output,"Invalid state, use 0-9.");
printMSG(1);
//sprintf(output,ptrMSG(1));
}
} else {
//sprintf(output,"Invalid Terminal-ID, use 1-%d.", MAX_TERMINALS);
printMSG(2);
//sprintf(output,ptrMSG(2));
}
} else {
//sprintf(output,"Syntax error: Use T<TERMINAL-ID>:<STATE>.",test);
printMSG(3);
//sprintf(output,ptrMSG(3));
}
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.");
printMSG(1);
//sprintf(output,ptrMSG(1));
}
} else
//sprintf(output,"Syntax error. Use A:<STATE>");
printMSG(4);
//sprintf(output,ptrMSG(4));
break;
case 'D':
//Serial.println("Display configuration:");
printMSG(5);
displayConfiguration();
break;
case 'S':
//Serial.println("Save configurartion:");
printMSG(6);
saveConfiguration();
break;
case 'X':
//Serial.println("Reset all Terminal states");
printMSG(8);
for(int i=0; i < MAX_TERMINALS; i++){
setGroupState(i,0);
}
SetAllLEDs(CRGB::Black);
break;
case 'W':
StartupLoop();
//sprintf(output,"Startup loop shown.");
printMSG(9);
//sprintf(output,ptrMSG(9));
break;
case 'H':
ShowHelp();
break;
default:
//printf(output,"No such command.");
printMSG(10);
//sprintf(output,ptrMSG(10));
break;
}
} else
printMSG(11);
// 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 do_half==false
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);
}
#endif
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);
#if do_half==false
FastLED.addLeds<WS2812B, 5, GRB>(leds4, numLedsPerStrip);
FastLED.addLeds<WS2812B, 6, GRB>(leds5, numLedsPerStrip);
FastLED.addLeds<WS2812B, 7, GRB>(leds6, numLedsPerStrip);
#endif
}
void displayConfiguration() {
char output[MAX_OUTPUT_LEN];
memset(output, '\0', sizeof(output));
//sprintf(output,"Identifier : %s",identifier);
//sprintf(output,ptrMSG(12),identifier);
printMSG(12);
sprintf(output,"%s",identifier);
Serial.println(output);
//sprintf(output,"LEDs per shelve : %d",numLedsPerStrip);
//sprintf(output,ptrMSG(13),numLedsPerStrip);
printMSG(13);
sprintf(output,"%d",numLedsPerStrip);
Serial.println(output);
//sprintf(output,"Terminals per shelve : %d",numGroupsPerStrip);
//sprintf(output,ptrMSG(14),numGroupsPerStrip);
printMSG(14);
sprintf(output,"%d",numGroupsPerStrip);
Serial.println(output);
//sprintf(output,"Shelves : %d",numStrips);
//sprintf(output,ptrMSG(15),numStrips);
printMSG(15);
sprintf(output,"%d",numStrips);
Serial.println(output);
//sprintf(output,"Spacer width : %d",spacerWidth);
//sprintf(output,ptrMSG(16),spacerWidth);
printMSG(16);
sprintf(output,"%d",spacerWidth);
Serial.println(output);
}
void saveConfiguration() {
#if AVR==true
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]);
// sprintf(output,"Configuration saved in EEPROM.");
printMSG(7);
//sprintf(output,ptrMSG(7));
#else
printMSG(17);
#endif
}
void loadConfiguration() {
#if AVR==true
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]);
#else
printMSG(18);
#endif
}
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);
#if do_half==false
leds4[i].nscale8(200);
leds5[i].nscale8(200);
leds6[i].nscale8(200);
#endif
}
}
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;
#if do_half==false
leds4[i] = 0x0080FF;
leds4[numLedsPerStrip -i -1] = 0x0080FF;
leds5[i] = 0x0080FF;
leds5[numLedsPerStrip -i -1] = 0x0080FF;
leds6[i] = 0x0080FF;
leds6[numLedsPerStrip -i -1] = 0x0080FF;
#endif
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(){
#if AVR==true
char *ptr=((const char *) &HelpText);
#else
char *ptr=((char *) &HelpText);
#endif
char chr;
if (!ptr)
return;
while ((chr = pgm_read_byte(ptr++))) {
Serial.print(chr);
}
// 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");
}