/*
  Advanced countdown timer of which the time can be set with up/down/set buttons.
  https://home.et.utwente.nl/slootenvanf/2020/06/08/countdown-timers-tasks-in-parallel/

  Author: F. van Slooten
*/
#include <U8g2lib.h>
#include <Bounce2.h>

byte button_pins[] = {4, 5, 6 }; // button pins; 4/5 up/down, 6 = set

#define NUMBUTTONS sizeof(button_pins)

Bounce * buttons = new Bounce[NUMBUTTONS];

U8X8_SSD1306_128X64_NONAME_HW_I2C display(U8X8_PIN_NONE);

int min = 1, sec = 0; // start with one minute

unsigned long previousMillis = 0, previousMillis2 = 0; // will store last time timer was updated

const unsigned long interval = 1000; // 1 second

char buf[10]; // text buffer; to be able to use draw2x2String to show the value

int state = 0; // 0 = set minutes, 1 = set seconds, 2 = run timer (countdown), 3 = pause, 4 = finished

bool blink = true;

void setup() {
  Serial.begin(9600);

  // Make input & enable pull-up resistors on switch pins
  for (int i = 0; i < NUMBUTTONS; i++) {
    buttons[i].attach( button_pins[i] , INPUT_PULLUP  );       //setup the bounce instance for the current button
    buttons[i].interval(25);              // interval in ms
  }

  display.begin();
  display.setPowerSave(0);
  display.setFont(u8x8_font_pxplusibmcgathin_f);
  display.drawString(0, 7, "set minutes");
  sprintf(buf, "%02d:%02d", min, sec);
  display.draw2x2String(2, 3, buf);
}

void loop() {
  unsigned long currentMillis = millis();

  // blink time on display every 300ms when setting it:
  if (currentMillis - previousMillis2 > 300 ) { // 300ms passed?
    previousMillis2 = currentMillis; // save the last time
    blink = !blink;
    if (state == 0) { // set min
      if (blink) sprintf(buf, "%02d", min); // blink minutes
      else strcpy(buf, "  ");
      display.draw2x2String(2, 3, buf);
      sprintf(buf, "%02d", sec);
      display.draw2x2String(8, 3, buf);
    }
    else if (state == 1) { // set seconds
      sprintf(buf, "%02d", min);
      display.draw2x2String(2, 3, buf);
      if (blink) sprintf(buf, "%02d", sec);  // blink seconds
      else strcpy(buf, "  ");
      display.draw2x2String(8, 3, buf);
    }
  }

  // update countdown timer every second
  if (currentMillis - previousMillis > interval) { // interval passed?
    previousMillis = currentMillis; // save the last time
    if (state == 2) { // countdown running?
      if (min >= 0 && sec >= 0) { // if counter not finished
        sec--; // decrease timer
        if (sec < 0) {
          if (min > 0 ) {
            min--;
            sec = 59;
          }
          else sec = 0;
        }
      }
      if (min == 0 && sec == 0) { // if counter finished
        display.drawString(0, 7, "finished    ");
        state = 4;
      }
      sprintf(buf, "%02d:%02d", min, sec);
      display.draw2x2String(2, 3, buf);
    }
  }

  // check for pressed buttons
  for (int i = 0; i < NUMBUTTONS; i++) {
    // Update the Bounce instance :
    buttons[i].update();
    if ( buttons[i].fell() ) { // a button was pressed
      if (i == 2) { // select
        state++; // to next state
        if (state == 4) state = 2;
        if (state == 5) { // restart
          state = 0;
          min = 1; sec = 0;
          display.drawString(0, 7, "set minutes");
        }
        if (state == 1) display.drawString(0, 7, "set seconds");
        else if (state == 2) {
          sprintf(buf, "%02d:%02d", min, sec);
          display.draw2x2String(2, 3, buf);
          display.drawString(0, 7, "running     ");
        }
        else if (state == 3) display.drawString(0, 7, "pause       ");
      }
      else { // up / down
        if (state == 0) { // setting minutes
          if (i == 0) min++; // up
          else min--; // down
        }
        else { // setting seconds
          if (i == 0) sec++; // up
          else sec--; // down
          if (sec < 0) {
            sec = 59;
            min--;
          } else if (sec > 59) {
            sec = 0;
            min++;
          }
        }
        if (min < 0) min = 0;
      }
    }
  } // end for
}
$abcdeabcde151015202530354045505560fghijfghij