// dougp1
// From dougp, Introductory Tutorials: 'State machines', March 2019
// https://forum.arduino.cc/t/state-machines/580593
// Wokwi schematic, 16th September, Terry Pinnell

// The sketch simulates a simple motor-driven door opener/closer
// such as might be used on a garage, chicken coop, window blinds,
// etc. Starting from a known position a switch is pressed, the
// door opens, then stops.  When the switch is pressed again the
// door closes, then stops.
//
// A timer is used to simulate the delay while the door is being
// driven to its new position and LEDs simulate the up/down
// forward/reverse action of the the motor.

// The sketch uses the following I/O

const unsigned char switchInput = 10;   //  +5V--| |--SW-- Arduino pin 10
const unsigned char openLED = 9;  //  +5V--/\/\/- 330Ω -->|-- Arduino pin 9
const unsigned char closeLED = 7; //  +5V--/\/\/- 330Ω -->|-- Arduino pin 7

#define motorRun LOW
#define motorStop HIGH
#define accumulatedMillis millis() - timerMillis

const unsigned long motorTimerPreset = 2000;  // two seconds
unsigned long timerMillis;  // For counting time increments

// The door has four possible states it can be in
// Let's give the states descriptive names
enum {doorIsDown, doorIsUp, doorOpening, doorClosing};
unsigned char doorState;  // What the door is doing at any given moment.

void setup() {
  Serial.begin(115200);
  pinMode(switchInput, INPUT_PULLUP);
  pinMode(openLED, OUTPUT);
  digitalWrite(openLED, HIGH);
  pinMode(closeLED, OUTPUT);
  digitalWrite(closeLED, HIGH);
  //  doorState = 6;
}

void loop() {
  switch (doorState) {

    case doorIsDown: // Nothing happening, waiting for switchInput
      printState(doorIsDown, "door down");

      if (digitalRead(switchInput) == LOW) { // switchInput  pressed
        timerMillis = millis(); // reset the timer
        doorState = doorOpening; // Advance to the next state
        break;
      }
      else {   // Switch not pressed
        break; // State remains the same, continue with rest of the program
      }

    case doorOpening:
      printState(doorOpening, "door opening");

      digitalWrite(openLED, motorRun);
      //
      // The compare below would be replaced by a test of a limit
      // switch, or other sensor, in a real application.
      if (accumulatedMillis >= motorTimerPreset) { // Door up
        digitalWrite( openLED, motorStop); // Stop the motor
        doorState = doorIsUp; // The door is now open
        break;
      }
      else {
        break;
      }

    case doorIsUp:
      printState(doorIsUp, "door up");

      if (digitalRead(switchInput) == LOW) { // switchInput pressed
        timerMillis = millis(); // reset the timer
        doorState = doorClosing; // Advance to the next state
        break;
      }
      else { // switchInput was not pressed
        break;
      }

    case doorClosing:
      printState(doorClosing, "door closing");

      digitalWrite(closeLED, motorRun); // Down LED on
      if (accumulatedMillis >= motorTimerPreset) {
        digitalWrite(closeLED, motorStop); // Stop the motor
        doorState = doorIsDown;  // Back to start point
        break;
      }
      else {
        break;
      }
    default:
      Serial.println("\n We hit the default");
      delay(3000);
      doorState = doorIsDown;
      break;
  }
}

void printState(unsigned char theState, char *theText)
{
  static unsigned char printedState = 0xff;

  if (theState != printedState) {
    Serial.println(theText);
    printedState = theState;
  }
}