/*
  Arduino Forum
  Topics:       Measure time that a condition is true to then enable and action
  Category:     Using Arduino
  Sub-Category: Programming Questions
  Link:         https://forum.arduino.cc/t/measure-time-that-a-condition-is-true-to-then-enable-and-action/1159366/22
*/

// Pin definitions
#define buttonPin 12  // Pin connected to the button
#define ledPin  13    // Pin connected to the LED

// Timing constants
#define DEBOUNCE_PERIOD 10    // Debounce period in milliseconds
#define TIME_DELAY      3000  // Delay time in milliseconds

// State enum
enum state_t : bool {STOP, START};  // Enumeration for states

bool enable;              // Flag to indicate if the system is enabled
unsigned long startTime;  // Time when the system was last started
unsigned long currTime;   // Current time

// Setup function
void setup() {
  Serial.begin(115200);               // Start the serial communication
  pinMode(buttonPin, INPUT_PULLUP);   // Set button pin as input with pull-up resistor
  pinMode(ledPin, OUTPUT);            // Set LED pin as output
  Serial.println("Press the PB!");    // Print initial message
}

// Main loop
void loop() {
  // Check if the system is enabled
  if (enable) {
    currTime = millis();
    // If the elapsed time since the last action exceeds the delay time, disable the system and perform the STOP action
    if (currTime - startTime >= TIME_DELAY) {
      enable = false;
      Action(STOP);  // Perform STOP action
    }
  } else {
    // If the button is pressed, record the current time, enable the system, and perform the START action
    if (isPressed()) {
      startTime = millis();
      enable = true;
      Action(START);  // Perform START action
    }
  }
}

// Perform action based on the given state
void Action(state_t value) {
  switch (value) {
    case START:
      // Turn on the LED when the START state is received
      digitalWrite(ledPin, HIGH);
      // Indicate the delay time before the next action
      Serial.println("Delay Time: " + String(TIME_DELAY) + " milliseconds.");
      break;
    default:  // case STOP:
      // Turn off the LED when the STOP state is received
      digitalWrite(ledPin, LOW);
      // Calculate and display the elapsed time since the last action and prompt for the next action
      Serial.println("Elapsed Time: " + String(currTime - startTime) + " milliseconds.nPress the PB!");
      break;
  }
}

// Function to check if the button is pressed, considering debouncing
bool isPressed() {
  static bool buttonState; // Holds the current state of the button
  static bool input; // Holds the current input value
  static unsigned long startDebounceTime; // Records the start time for debounce

  bool prevInput = input; // Stores the previous input value
  input = digitalRead(buttonPin); // Reads the current input value from the button pin

  // Check for a change in input to start the debounce timer
  if (input != prevInput) {
    startDebounceTime = millis(); // Resets the debounce timer
  }

  // If input is different from button state and debounce period has passed
  if (input != buttonState) {
    if (millis() - startDebounceTime >= DEBOUNCE_PERIOD) {
      buttonState = input; // Updates the button state
      // Returns true if the button is pressed (considering pull-up/pull-down configuration)
      return buttonState == LOW;  // Returns true if the button is pressed (assuming pin mode is INPUT_PULLUP); returns false otherwise
    }
  }
  // Return false if the button is not pressed
  return LOW;
}