/* BLOCK COMMENT
  ATTENTION: This Sketch contains elements of C++.
  https://www.learncpp.com/cpp-tutorial/
  Many thanks to LarryD
  https://europe1.discourse-cdn.com/arduino/original/4X/7/e/0/7e0ee1e51f1df32e30893550c85f0dd33244fb0e.jpeg
  https://forum.arduino.cc/t/changing-button-states-from-momentary-to-latch/993706
  Tested with Arduino: Mega[ ] - UNO [X] - Nano [ ]
  Copied from https://forum.arduino.cc/t/changing-button-states-from-momentary-to-latch/993706/20?u=davex
*/
#define ProjectName "Changing button states from momentary to latch"
// HARDWARE AND TIMER SETTINGS
// YOU MAY NEED TO CHANGE THESE CONSTANTS TO YOUR HARDWARE AND NEEDS
#define OutPutTest
constexpr  unsigned long OutPutTestTime {1000};
// VARIABLE DECLARATION AND DEFINITION
unsigned long currentTime;
enum {Stop, Start, Blink};
struct TIMER {              // has the following members
  unsigned long duration;   // memory for interval time
  unsigned long stamp;      // memory for actual time
  int onOff;               // control for stop/start/blink
};
// data struct for button handler -----------
enum ButtonStatus {Released, Pressed};
enum Action {NoneLatch, Latch};
struct BUTTONOUTPUT {    // has the following members
  byte buttonPin;        // port number for button
  byte outputPin;        // port number for output
  bool action;           // action either latch or none latch
  TIMER scan;            // timer for button debouncing
  int   statusQuo;       // current button state
};
BUTTONOUTPUT buttonOutputs[] {
  {A0, 2, NoneLatch, 20, 0, Blink, false},
  {A1, 3, NoneLatch, 20, 0, Blink, false},
  {A2, 4, Latch, 20, 0, Blink, false},
};
// time handler ------------------------------------------------------
bool timerEvent (TIMER &timer) {
  bool reTurn = currentTime - timer.stamp >= timer.duration && timer.onOff;
  if (reTurn) timer.onOff == Blink ? timer.stamp = currentTime : timer.onOff = Stop;
  return reTurn;
}
// -------------------------------------------------------------------
void setup() {
  Serial.begin(115200);
  Serial.println(F("."));
  Serial.print(F("File   : ")), Serial.println(__FILE__);
  Serial.print(F("Date   : ")), Serial.println(__DATE__);
  Serial.print(F("Project: ")), Serial.println(ProjectName);
  pinMode (LED_BUILTIN, OUTPUT);  // used as heartbeat indicator
  //  https://www.learncpp.com/cpp-tutorial/for-each-loops/
  for (auto buttonOutput : buttonOutputs) pinMode(buttonOutput.buttonPin, INPUT_PULLUP);
  for (auto buttonOutput : buttonOutputs) pinMode(buttonOutput.outputPin, OUTPUT);
#ifdef OutPutTest
  // check outputs
  Serial.print("Output test... ");
  for (auto buttonOutput : buttonOutputs) digitalWrite(buttonOutput.outputPin, HIGH), delay(OutPutTestTime);
  for (auto buttonOutput : buttonOutputs) digitalWrite(buttonOutput.outputPin, LOW), delay(OutPutTestTime);
  Serial.println("Complete.");
#endif
}
void loop () {
  currentTime = millis();
  digitalWrite(LED_BUILTIN, (currentTime / 500) % 2);
  // get access to the structured array
  for (auto &buttonOutput : buttonOutputs) {
    // check debounce time
    if (timerEvent (buttonOutput.scan)) {
      // check current button state. Attention: pinMode=INPUT_PULLUP
      int stateNew = !digitalRead(buttonOutput.buttonPin);
      // check button state change
      if (buttonOutput.statusQuo != stateNew) {
        // save new state
        Serial.print(buttonOutput.outputPin);
        buttonOutput.statusQuo = stateNew;
        // take action what shall happens to the different states and desired function
        switch (stateNew) {
          case Pressed:
            switch (buttonOutput.action) {
              case Latch:
                Serial.print("toggle");
                digitalWrite(buttonOutput.outputPin, !digitalRead(buttonOutput.outputPin));
                break;
              case NoneLatch:
                Serial.print("on");
                digitalWrite(buttonOutput.outputPin, HIGH);
                break;
            }
            break;
          case Released:
            switch (buttonOutput.action) {
              case Latch:
                Serial.print("released");
                break;
              case NoneLatch:
                digitalWrite(buttonOutput.outputPin, LOW);
                Serial.print("off");
                break;
            }
            break;
        }
        Serial.println();
      }
    }
  }
}