/*
  Arduino Forum
  Topics:       2 pushbutton on / off
  Sub-Category: Programming Questions
  Category:     Using Arduino
  Link:         https://forum.arduino.cc/t/2-pushbutton-on-off/1293385
*/

#define DIM_MAX 255         // Maximum dim Value
#define DIM_MIN 0           // Mininum dim value
#define DEBOUNCE_TIME 10    // Debounce time delay
#define REPEAT_RATE 50      // Repeat rate 50 millisecond delay
#define OFFSET 5            // Increase/Decrease offset

#define ledPin 5 

typedef struct {
  uint8_t pin;                // Button pin
  bool state;                 // Button State, FALSE = Pressed, TRUE = Released
  bool input;                 // Input State
  bool pressed;               // Pressed state
  unsigned long startTime;    // Start Time for buttonRead and repeat
} pullupButton;               // Pullup Button State

const uint8_t numberOfButtons = 2;                            // Number of LED/Button groups
const uint8_t pbPins[numberOfButtons] = {A0, A1};             // LED output pins
pullupButton buttons[numberOfButtons];                        // pullupButton state

int dimValue;   // Dimmer Value
bool increase;  // Dimmer operator, FALSE = decrease, TRUE = increase

enum dimmerOperator : bool {DECREASE, INCREASE};  // Dimmer Operator

void setup() {
  Serial.begin(115200);   // Serial baud rates
  increase = INCREASE;    // Dimmer operator
  dimValue = 255;         // Set dim value
  initial();              // Button & LED pin mode, with an initial state
}

void loop() {
  dimControl();     // Dim the LED
}

void initial() {
  for (uint8_t index = 0; index < numberOfButtons; index++) {
    buttons[index].pin= pbPins[index];          // Input Pin mode - INPUT_PULLUP: TRUE = PRESSED, FALSE = RELEASED
    pinMode(buttons[index].pin, INPUT_PULLUP);  // Input Pin mode - INPUT_PULLUP: TRUE = PRESSED, FALSE = RELEASED
    buttons[index].input = HIGH;                // Inital input with TRUE
  }
  pinMode(ledPin, OUTPUT);                      // LED Pin mode
}

void dimControl() {
  for (uint8_t index = 0; index < numberOfButtons; index++) {
    bool repeat = buttonRepeat(index);                                  // Get repeat action
    if (buttons[index].pressed) increase = !increase;                   // Toggle dim operator
    if (!repeat) return;                                              // Repeat condition
    increase == INCREASE ? dimValue += OFFSET : dimValue -= OFFSET;   // Increase/Decrease dim value
    if (dimValue > 255) dimValue = DIM_MAX;                           // Maximum limit
    else if (dimValue < 0) dimValue = DIM_MIN;                        // Minimum limit
  }
  analogWrite(ledPin, dimValue);                              // Set LED brightness
  serialPrint();  // Serial Print
}

bool buttonRepeat(uint8_t index) {
  buttonRead(index);
  if (buttons[index].state) return LOW;                                 // Return if the button is released - INPUT_PULLUP: TRUE = PRESSED, FALSE = RELEASED
  unsigned long currTime = millis();                                    // Set current time with "millis"
  if ( currTime - buttons[index].startTime < REPEAT_RATE) return LOW;   // Return FALSE if elapsed less than the repeat rate
  buttons[index].startTime = currTime;                                  // Reload start time with current "millis"
  return HIGH;
}

bool buttonRead(uint8_t index) {
  bool previnput = buttons[index].input;                                      // Set the previous state with the previous input value
  buttons[index].input = digitalRead(buttons[index].pin);                     // Read Input state
  buttons[index].pressed = LOW;                                               // Reset pressed state
  if (buttons[index].input == buttons[index].state) return LOW;               // Return TRUE if the current state is equal to the previous value.

  unsigned long currTime = millis();                                          // Set current time with "millis"
  if (buttons[index].input != previnput) buttons[index].startTime = currTime; // reload if button is pressed
  if ( currTime - buttons[index].startTime < DEBOUNCE_TIME) return LOW;       // Return FALSE if elapsed less than the repeat delay
  buttons[index].startTime = currTime;                                        // Reload start time with current "millis"
  buttons[index].state = buttons[index].input;                                // Button state
  buttons[index].pressed = buttons[index].state == LOW;                       // Pressed state
  return buttons[index].pressed;                                              // return pressed state
}

void serialPrint() {
  Serial.println(", Dimmer Value:= " + String(dimValue));   // Print dim value
}