// Schnupperlehre: 2024-02-14  
// HW: MCU (ESP32-C3-Super Mini), Rotary Encoder & 24-er LED-Ring
// Mit dem Rotary Encoder können verschiedene Anzeigemodi gewählt werden:
// - Drehbewegung neuer Modus wählen
// - Mit Button gewählter Modus anzeigen

// Bibliotheken einbinden
#include <Adafruit_NeoPixel.h>    // <x.h> in Standard-Bibliotheks-Verzeichnis
#include "color.h"                // "x.h" eine eigene Bibliotheks-Datei im gleichen Projekt-Verzeichnis

// Rotary Encoder definieren
#define BTN_NEXT            0     // Button "Next" nächster Modus wählen
#define BTN_OK              1     // Tastern "OK" gewählter Modus anzeigen

#define MODE_MAX            12    // Anzahl Anzeigeeffekte
// Zeiten definieren => Wert * 10ms
#define TIME_INTERVAL_SLOW  100
#define TIME_INTERVAL_NORM  50 
#define TIME_INTERVAL_FAST  25 

// Funktions-Deklarationen (müssen vor dem erstmaligen benützen bekannt gemacht (deklariert) werden
void check_button_mode (void);
void check_button_show_mode (void);
byte step_next (byte limit);
byte step_previous (byte start);

// Variabeln deklarieren und initialisieren
// boolean (true or false), byte (0 ... 255), unsigned int (0 ... 65535)
boolean btn_next_bup = false;
boolean btn_ok_bup = false;
boolean show_mode = false;
boolean first = true;
byte i;
byte mode_nr = 0;
byte step_nr = 0;
boolean direction = false;
unsigned int time_counter = 0;
unsigned int time_interval = 0;
boolean interval = false;


// ------------------------------------------------------------------------------------
// SETUP
// ------------------------------------------------------------------------------------
void setup() {
  led_ring.begin(); // LED-Ring inititalisieren
  Serial.begin(115200);
  Serial.println("---------------------------------------------------------");

  pinMode(BTN_NEXT, INPUT_PULLUP);
  pinMode(BTN_OK, INPUT_PULLUP);

  // Power-On-Test => für 2s leuchten alle LEDs weiss
  setAllLedsToColor(0xFF, 0xFF, 0xFF);
  delay(2000);
  //led_ring.clear(); // Set all pixel colors to ’off’
  setDotRainbow(mode_nr);
}


// ------------------------------------------------------------------------------------
// LOOP
// ------------------------------------------------------------------------------------
void loop() {

  // **********************************************************************************
  // Abfrage der Taster
  // **********************************************************************************
  check_button_mode();
  check_button_show_mode();

  // **********************************************************************************
  // Anzeige ded gewählen Modus
  // **********************************************************************************
  if (show_mode == true) {
    switch (mode_nr) {

      // Modus "Alle LEDs rot"
      case 0:   // Wenn first = true ist, dann führen wir diesen Codeteil genau einmal aus
                if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_FAST;
                }
                if (interval == true) {
                  interval = false;
                  setDotRainbow(step_nr);
                  step_nr = step_next(NUM_PIXELS - 1);
                }
                break;

      // Modus "Alle LEDs grün"
      case 1:   if (first == true) {
                  first = false;
                  setAllLedsToColor(0x00, 0xFF, 0x00);
                }
                break;

      // Modus "Alle LEDs blau"
      case 2:   if (first == true) {
                  first = false;
                  setAllLedsToColor(0x00, 0x00, 0xFF);
                }
                break;
      
      // Modus "Alle LEDs weiss"
      case 3:   if (first == true) {
                  first = false;
                  setAllLedsToColor(0xFF, 0xFF, 0xFF);
                }
                break;

      // Modus "Alle LEDs in 24 Stufen durch den Regenbogen"
      case 4:   if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_SLOW;
                  r = 240;
                  g = 0;
                  b = 0;
                }

                // interval wird in gewissen Zeitabständen (TIME_INTERVAL_SLOW) true
                // und dann wollen wir diesen Codeteil ausführen
                if (interval == true) {
                  interval = false;
                  setAllLedsToColor(r, g, b);
                  Serial.print("Step: "); Serial.print(step_nr); Serial.print(" R: "); Serial.print(r); Serial.print(", G: "); Serial.print(g); Serial.print(", B: "); Serial.println(b);
                  if (step_nr < 8) {
                    r -= 30;
                    g += 30;
                  } else if (step_nr < 16 ) {
                    g -= 30;
                    b += 30;
                  } else {
                    b -= 30;
                    r += 30;
                  }
                  step_nr = step_next(23);
                }              
                break;
          
      // Modus "Alle LEDs der Reihen nach im Uhrzeigersinn und den Farben entsprechend einschalten"
      case 5:   if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_NORM;
                }
                if (interval == true) {
                  interval = false;
                  setBarGraphOneColor(step_nr, 255, 0, 255);
                  step_nr = step_next(NUM_PIXELS - 1);
                }
                break;
          
      // Modus "Alle LEDs der Reihen nach im Gegen-Uhrzeigersinn und in den 2 Farben entsprechend einschalten"
      case 6:   if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_NORM;
                  step_nr = NUM_PIXELS - 1;
                }
                if (interval == true) {
                  interval = false;
                  setBarGraphTwoColor(step_nr, 0, 0, 255, 255, 255, 0);
                  step_nr = step_previous(NUM_PIXELS - 1);
                }
                break;

      // Modus "Alle LEDs der Reihen nach im Gegen-Uhrzeigersinn und in den 2 Farben entsprechend einschalten"
      case 7:   if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_NORM;
                  step_nr = NUM_PIXELS - 1;
                }
                if (interval == true) {
                  interval = false;
                  setBarGraphMyColorArray(step_nr);
                  step_nr = step_previous(NUM_PIXELS - 1);
                }
                break;

      // Modus "Einen Punkt im Uhrzeigersinn wandern lassen und dann im Gegen-Uhrzeigersinn zurück"
      case 8:   if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_FAST;
                  direction = true;
                }
                if (interval == true) {
                  interval = false;
                  setDotOneColor(step_nr, 0, 255, 255);

                  if (direction == true) {
                    if (step_nr < (NUM_PIXELS - 1)) {
                      step_nr++;
                    } else {
                      direction = false;
                      step_nr = NUM_PIXELS - 2;
                    }
                  } else {
                    if (step_nr > 0) {
                      step_nr--;
                    } else {
                      direction = true;
                      step_nr = 1;
                    }
                  }
                }
                break;

      // Modus "Alle LEDs der Reihen nach im Uhrzeigersinn und den Farben im Array entsprechend einschalten"
      case 9:   if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_FAST;
                }
                if (interval == true) {
                  interval = false;
                  for(i = 0; i < NUM_PIXELS; i++) { 
                    if (i <= step_nr) {
                      led_ring.setPixelColor(i, led_ring.Color(rgb_array[i][0], rgb_array[i][1], rgb_array[i][2]));
                    } else {
                      led_ring.setPixelColor(i, led_ring.Color(0x00, 0x00, 0x00));
                    }
                  }
                  led_ring.show();   
                  step_nr = step_next(NUM_PIXELS - 1);
                }
                break;

      // Modus "Alle LEDs leuchten in den regenbogenfarben"
      case 10:  if (first == true) {
                  first = false;
                  setAllLedsToRainbow();
                }
                break;

      // Modus "Alle LEDs der Reihen nach im Uhrzeigersinn in den Regenbogen-Farben entsprechend einschalten"
      case 11:  if (first == true) {
                  first = false;
                  time_interval = TIME_INTERVAL_NORM;
                }
                if (interval == true) {
                  interval = false;
                  setDotRainbow(step_nr);
                  step_nr = step_next(NUM_PIXELS - 1);
                }
                break;


      case 23:   
      default:  break;
    }

    // Blinkzeit managen
    if (time_counter >= time_interval) {
      time_counter = 0;
      interval = true;
    } else {
      time_counter++;
    }
  }

  delay(10); // Warte 10ms
}


// --------------------------------------------------------------------------------------
// Funktion: check_button_mode()
// Frägt den Button für die Moduswahl ab und setzt die entsprechenden die Steuervariablen
// --------------------------------------------------------------------------------------
void check_button_mode (void) {
  if ((digitalRead(BTN_NEXT) == LOW) && (btn_next_bup == false)) {
    btn_next_bup = true;
    if (mode_nr < (MODE_MAX - 1)) {
      mode_nr++;
    } else {
      mode_nr = 0;
    }
    show_mode = false;
    setDotRainbow(mode_nr);
    Serial.print("State: "); Serial.println(mode_nr);
  }
  if ((digitalRead(BTN_NEXT) == HIGH) && (btn_next_bup == true)) {
    btn_next_bup = false;
  }
}


// --------------------------------------------------------------------------------------
// Funktion: check_button_show_mode()
// Frägt den Button für die Modusanzeige ab und setzt die entsprechenden die Steuervariablen
// --------------------------------------------------------------------------------------
void check_button_show_mode (void) {
  if ((digitalRead(BTN_OK) == LOW) && (btn_ok_bup == false)) {
    btn_ok_bup = true;
    first = true;
    show_mode = true;
    time_counter = 0;
    interval = true;
    step_nr = 0;    
    Serial.print("Show mode");
  }
  if ((digitalRead(BTN_OK) == HIGH) && (btn_ok_bup == true)) {
    btn_ok_bup = false;
  }
}


// --------------------------------------------------------------------------------------
// Funktion: step_next(limit)                                            => Uhrzeigersinn
// Erhöht step_nr um 1, bzw. beginnt wieder bei 0 wenn limit erreicht ist 
// --------------------------------------------------------------------------------------
byte step_next (byte limit) {
  if (step_nr < limit) {
    step_nr++;
  } else {
    step_nr = 0;
  }
  return step_nr;
}


// --------------------------------------------------------------------------------------
// Funktion: step_previos(start)                                   <= Gegen-Uhrzeigersinn
// Erniedrigt step_nr um 1, bzw. beginnt wieder bei start wenn 0 erreicht ist 
// --------------------------------------------------------------------------------------
byte step_previous (byte start) {
  if (step_nr > 0) {
    step_nr--;
  } else {
    step_nr = start;
  }
  return step_nr;
}
esp:0
esp:1
esp:2
esp:3
esp:4
esp:5
esp:6
esp:7
esp:8
esp:9
esp:10
esp:18
esp:19
esp:GND.1
esp:3V3.1
esp:3V3.2
esp:GND.2
esp:RST
esp:GND.3
esp:GND.4
esp:5V.1
esp:5V.2
esp:GND.5
esp:GND.6
esp:GND.7
esp:GND.8
esp:GND.9
esp:RX
esp:TX
esp:GND.10
btn1:1.l
btn1:2.l
btn1:1.r
btn1:2.r
ring1:GND
ring1:VCC
ring1:DIN
ring1:DOUT
btn2:1.l
btn2:2.l
btn2:1.r
btn2:2.r