const byte    OnBoard_LED = 13;

const byte sm_aktion1 = 1;
const byte sm_warten1 = 2;

const byte sm_aktion2 = 3;
const byte sm_warten2 = 4;

const byte sm_aktion3 = 5;
const byte sm_warten3 = 6;

byte myState = sm_aktion1;  // weise der Variablen "myState" den Wert von "sm_aktion1" zu

unsigned long myWarteTimer;
unsigned long myPrintTimer;

void setup() {
  Serial.begin(115200);
  Serial.println("Setup-Start");
}


void loop() {
  // blinke eine LED als visuelles Feedback "Programm läuft"
  BlinkHeartBeatLED(OnBoard_LED, 250);

  meinAblauf();

}


void meinAblauf() {

  switch (myState) {

    case sm_aktion1:
      Serial.println("führe Aktion 1 aus");
      myWarteTimer = millis(); // speichere aktuelle StartZeit
      myPrintTimer = millis(); // speichere aktuelle StartZeit
      myState = sm_warten1;
      Serial.println("1 fange an zu warten");
      break; // springe sofort runter zu ENDE-VON-switch-case

    case sm_warten1:
      // prüfe ob schon 5000 Millisekunden vergangen sind
      if (TimePeriodIsOver(myWarteTimer, 5000) ) {
        // wenn WIRKLICH 5000 Millisekunden vergangen sind
        myState = sm_aktion2; // setze myState auf Aktion 2
      }
      printEin_mal_pro_Sekunde();
      break; // springe sofort runter zu ENDE-VON-switch-case


    case sm_aktion2:
      Serial.println("führe Aktion 2 aus");
      myWarteTimer = millis(); // speichere aktuelle StartZeit
      myPrintTimer = millis(); // speichere aktuelle StartZeit
      myState = sm_warten2;
      Serial.println("2 fange an zu warten");
      break; // springe sofort runter zu ENDE-VON-switch-case

    case sm_warten2:
      // prüfe ob schon 5000 Millisekunden vergangen sind
      if (TimePeriodIsOver(myWarteTimer, 5000) ) {
        // wenn WIRKLICH 5000 Millisekunden vergangen sind
        myState = sm_aktion3; // setze myState auf Aktion 3
      }
      printEin_mal_pro_Sekunde();
      break; // springe sofort runter zu ENDE-VON-switch-case


    case sm_aktion3:
      Serial.print("führe Aktion 3 aus");
      myWarteTimer = millis(); // speichere aktuelle StartZeit
      myPrintTimer = millis(); // speichere aktuelle StartZeit
      myState = sm_warten3;
      Serial.println("3 fange an zu warten");
      break; // springe sofort runter zu ENDE-VON-switch-case

    case sm_warten3:
      // prüfe ob schon 5000 Millisekunden vergangen sind
      if (TimePeriodIsOver(myWarteTimer, 5000) ) {
        // wenn WIRKLICH 5000 Millisekunden vergangen sind
        myState = sm_aktion1; // setze myState auf Aktion 1
        Serial.println("warten3 zu Ende fange von vorne an");
      }
      printEin_mal_pro_Sekunde();
      break; // springe sofort runter zu ENDE-VON-switch-case

  } // ENDE-VON-switch-case

}


void printEin_mal_pro_Sekunde() {
  printPunkteVerlangsame();
  // prüfe ob 1000 Millisekunden vergangen sind
  if (TimePeriodIsOver( myPrintTimer, 1000) ) {
    // wenn WIrkLICH 1000 Millisekunden vergangen sind
    Serial.print ("myState=");
    Serial.print (myState);
    Serial.print (" Seit Beginn des Wartens ");
    Serial.print (millis() - myWarteTimer);
    Serial.println(" Millisekunden vergangen");
  }
}


// function die dafür sorgt dass der serielle Monitor NICHT völlig zugeballert wird
void printPunkteVerlangsame() {
    Serial.print(".");
    delay(50);
}

// easy to use helper-function for non-blocking timing
// explanation see here
// https://forum.arduino.cc/t/example-code-for-timing-based-on-millis-easier-to-understand-through-the-use-of-example-numbers-avoiding-delay/974017
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}



void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}