/*  Steuerung einer Taschenlampe mit einem Zustandsautomat 
 *  und PWM. Das PWM-Signal wird mit der LEDC-Baugruppe erzeugt,
 *  100Hz Frequenz und 12 Bit Auflösung werden gewählt. MAX_PWM = 2^12-1 = 4095
 *  Da die LED Active-LOW beschaltet ist, muss der PWM-Wert invertiert 
 *  werden => Ausgabe MAX_PWM - Sollwert
 */

//***** Portpins für Ein-/Ausgänge ****************************************
const int Enc_A = 34, Enc_B = 35, Enc_Taster = 0, NEO_Pin=26;
const int LED_rot = 32, LED_gruen = 33, Taster2 = 2, Taster4 = 4;

// ***** Datentyp für Zustände ********************************************
enum Zustaende_t { Aus, Low, Normal, High};
Zustaende_t Taschenlampe;    // Variable vom Typ Zustaende_t

// ***** Globale Variablen ************************************************
bool T2_neu, T2_alt, T4_neu, T4_alt;  // für Flankenerkennung
unsigned long nextMillis, Zeit;
bool bTaster;
#define PWM_Bits 12 
#define MAX_PWM 4095

// ***** Initialisierung **************************************************
void setup() {
  // Standard-Initialisierung für die blaue Patine
  Serial.begin(115200);            // Serielle Schnittstelle mit 115200Bit/s
  pinMode(LED_rot, OUTPUT);        // die LEDs beginnen danach
  pinMode(LED_gruen, OUTPUT);      // zu leuchten! (Active-LOW)
  digitalWrite(LED_rot, HIGH);     // also beide ausschalten
  digitalWrite(LED_gruen, HIGH);
  pinMode(Taster2, INPUT_PULLUP); // Taster brauchen hier den
  pinMode(Taster4, INPUT_PULLUP); // Pullup-Widerstand

  // LEDC Initialisieren
  ledcAttachChannel ( LED_gruen, 100, 12, 0); // 100Hz und 12 Bit Auflösung
  // ODER ledcAttach ( LED_gruen, 100, 12);  // Kanalvergabe macht der Compiler
  
  Taschenlampe = Aus;
  Serial.printf("Taschenlampe ist aus\n");   
  Serial.printf("Dimmer-Werte von 0 bis %d\n", MAX_PWM); 
}

// ***** Endlosschleife ***************************************************
void loop() {
  unsigned long currentMillis = millis( );
  if ( currentMillis >= nextMillis ) {
    nextMillis = currentMillis + 50;    // 20x pro Sekunde
    Einlesen( );
    Automat( );
    Ausgeben( );
  }
}
  

// ***** Eigene Funktionen ************************************************
// ***** Einlesenfunktion: liest alle Eingänge und speichert in globalen Variablen
void Einlesen ( ) {
  // Flankenerkennung für beide Taster
  T2_neu = digitalRead(Taster2);
  T4_neu = digitalRead(Taster4);
  if ( T4_neu == 0 && T4_alt == 1) {  // fallende Flanke = Tastendruck
    bTaster = true;
  }
  else {
    bTaster = false;
  }
  T2_alt = T2_neu;  // für Flankenerkennung
  T4_alt = T4_neu;  // für Flankenerkennung
}

// ***** Automaten-Funktion ***********************************************
void Automat ( ) {
 switch(Taschenlampe) {
  case Aus: ledcWrite (LED_gruen, MAX_PWM - 0);  // Ausschalten
            if (bTaster == true) {
              Taschenlampe = Low;
              Serial.println("Schalte niedrige Helligkeit ein");
            }
            break;
  case Low: ledcWrite (LED_gruen, MAX_PWM - 1024);  // 25%
            if (bTaster == true) {
              Taschenlampe = Normal;
              Serial.println("Schalte mittlere Helligkeit ein");
            }
            break;
  case Normal: ledcWrite (LED_gruen, MAX_PWM - 2048);  // 50%
            if (bTaster == true) {
              Taschenlampe = High;
              Zeit = millis( );   // maximale Helligkeit darf nur 5s an sein
              Serial.println("Schalte maximale Helligkeit ein");
            }
            break;
  case High: ledcWrite (LED_gruen, MAX_PWM - 4095);  // Maximale Helligkeit
            if (bTaster == true) {
              Taschenlampe = Aus;
              Serial.println("Schalte Taschenlampe aus");
            }
            if (millis()-Zeit >= 5000) {  // Zeitsteuerung als Überhitzungsschutz
              Taschenlampe = Normal;
              Serial.println("Zeit für High abgelaufen, schalte normale Helligkeit ein");
            }
            break;
  default:  break;
 }
}
// ***** Ausgabe-Funktion *************************************************
// ***** Schreibe den Wert der globalen Variablen an die Ausgänge *********
void Ausgeben( ) {
  // hier ist nur eine Ausgabe mit ledcWrite, daher keine extra Funktion
}

Taster2
Taster4
LED32
LED33
ESP32 Schulboard mit LEDs und Tastern, I2C-Bus mit Standard-Belegung
SSD1306 Display
WS2812 an Pin26