/*-------------------------------------------------------
  DISTINCTION TASK QUESTION1
  STUDENT ID:103495874
  SARAH SALEEM
  -----------------------------------------------------------
*/
#include "U8glib.h"



U8GLIB_SSD1306_128X64 u8g; // create an instant of OLED display
int hour, minute, second; //value of hours,minutes,seconds that will be printed on the oled
String user_entered_time;//the time from the serial will be stored in this
int alarm_min, alarm_sec; //to store the value of the time when alarm needs to start buzzing
int button = 19, buzzer = 8; //initialising the pin for push button and buzzer
unsigned long start_button, stop_button; //the millis() value when the button was pressed and when it was released will be stored

int h, m, s, msecond; //storing the value of hours, minute, seconds and milliseconds for stopwatch
unsigned long start_stopwatch, elapsed_time; //to store the time when the stopwatch started and the elapsed time

volatile bool time_flag;
volatile float time; //the time for which the push button has been pressed will be stored in this
volatile int lastState = HIGH;
bool is_stopwatch = 0, is_alarm = 0, set_stopwatch, stop_stopwatch, reset_stopwatch;
int count_stopwatch = 0, count_alarm = 0; //to store the amount of times the button has been pressed during the ararm and stopwatch mode
void setup() {
  Serial.begin(115200);
  u8g.setFont(u8g_font_courB18); // set the font for text

  Serial.println(">Enter the time you want your clock to set to");
  Serial.println(">>please add the time accroding to the example below ");
  Serial.println(">>>if u want to write 10hours 5minutes and 3seconds write 100503");
  while (Serial.available() == 0) {}
  user_entered_time = Serial.readString();
  //Serial.println((user_entered_time.substring(4, 6)).toInt());
  //hours are the first two characters, minutes are the third and forth
  //and seconds are fifth and sixth character of the user entered time
  //therefore we split the user entered string using .substring function according to the indexes mentioned above and convert it to int
  hour = (user_entered_time.substring(0, 2)).toInt();
  minute = (user_entered_time.substring(2, 4)).toInt();
  second = (user_entered_time.substring(4, 6)).toInt();


  cli();//stop interrupts
  //set timer1 interrupt at 1Hz
  TCCR1A = 0;// set entire TCCR1A register to 0
  TCCR1B = 0;// same for TCCR1B
  TCNT1  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR1A = 15624;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR1B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR1B |= (1 << CS12) | (1 << CS10);
  // enable timer compare interrupt
  TIMSK1 |= (1 << OCIE1A);
  sei();//allow interrupts

  //declaring the button pin as input pullup and using change interrupt
  //the change interrept will be triggered everytime when the button is pressed or released
  pinMode(button, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(button), timer, CHANGE);
  Serial.println();
  Serial.println(">Press the button for more than 3 sec but less than 6sec to switch between stopwatch and digital clock");
  Serial.println(">When it is a stopwatch:- ");
  Serial.println("  >pressing the button for the first time will start it");
  Serial.println("  >pressing the button second time will stop it");
  Serial.println("  >pressing the button third time will reset it");
  Serial.println("  >After it's resetted pressing the button in same pattern will   start stop and reset it");
  Serial.println();
  Serial.println(">Press the button for more than 6seconds to enable the alarm");
  Serial.println(">When it is in alarm mode pressing the button once will add 15 seconds to the alarm time");
  Serial.println(">So if you want alarm to buzz after 1 minute of selecting the alarm mode press the button 4 times");

}

void loop() {

  //using time_flag to make sure that for one button press mode_select function is triggered just once
  if (time_flag == 1) {
    mode_select(time);
  }
  time_flag = 0;
  //making time flag=0 once the mode select function has been triggered once for one button press

  if (is_alarm == 1) {
    alarm();
  }
  else if (is_stopwatch == 0) {

    digital_clock();
  }
  else if (is_stopwatch == 1) {

    stop_watch();
  }


}

ISR(TIMER1_COMPA_vect) {
  //as this interrupt will be triggered every second the value of second will increment
  //everytime this is triggered
  second++;
  if (second > 60) {
    minute++;
    second = 0;
    if (minute > 60) {
      minute = 0;
      hour++;
      if (hour > 24) {
        hour = 0;
      }
    }
  }
}
void timer() { //to find out the amount of time the button has been pressed
  int value = digitalRead(button);
  if (lastState != value) {
    lastState = value;
    if (value == LOW) {
      start_button = millis(); //the time when the button is pressed
      Serial.println("pressed");
    }
    else if (value == HIGH) {
      Serial.println("released");
      stop_button = millis(); //the time when the button is released
      time = (stop_button - start_button) / 1000.f; //subtracting the release time from the press time and fividing it with 1000 to obtain value in seconds
      Serial.println("time");
      Serial.println(time);
      time_flag = 1; //time flag is one to indicate that the button has been preesed, and a mode should be selected based on the amount of time for which it has been pressed


    }
  }
}
void mode_select(float time) {

  if (time >= 3 && time < 6) {
    //if the amount of time for which the button has been pressed is greater than 3 sec but less than 6 sec
    //then the mode will change from stopwatch to digital clock or digital clock to stopwatch
    is_stopwatch = !is_stopwatch;
    if (is_stopwatch) {
      reset_stopwatch = 1;
      set_stopwatch = 0;
      stop_stopwatch = 0;
      count_stopwatch = 0;
    }
  }
  else if (time >= 6) {
    //if the button has been pressed for more than 6sec then the alarm mode will be selected
    is_alarm = !is_alarm;
    alarm_sec = second;
    alarm_min = minute;
    if (is_alarm) {
      Serial.println("now alarm");
    }

  }
  else if (is_stopwatch == 1 && time < 3) {
    count_stopwatch++;//incrementing the value of count everytime button is pressed during stopwatch mode
    //during the stopwatch mode when the button is pressed first the stopwatch starts
    //when the buton will be pressed 2nd time the stopwatch stops
    //and when pressed third time it will reset
    //after reseting when the button is pressed again it will start, stop reset again in similar pattern

    if (count_stopwatch == 1) {
      //when the stopwatch is started the value of set_stopwatch will be set to 1
      //and the millis() value when it started will be stored
      set_stopwatch = 1;
      stop_stopwatch = 0;
      reset_stopwatch = 0;
      start_stopwatch = millis();
    }
    else if (count_stopwatch == 2) {
      //when the stopwatch is stopped the value of stop_stopwatch will be made 1
      stop_stopwatch = 1;
      reset_stopwatch = 0;
      set_stopwatch = 0;
    }
    else if (count_stopwatch == 3) {
      //and when it is resetted the value of reset_stopwatch will be one
      reset_stopwatch = 1;
      set_stopwatch = 0;
      stop_stopwatch = 0;
      //the couunt will be set to zero
      count_stopwatch = 0;
    }

  }
  else if (is_alarm == 1 && time < 3) {
    count_alarm++;//incrementing the value of count everytime button is pressed during alarm mode
    alarm_sec = 15 + alarm_sec; //with every button press the seconds will increment by 15
    Serial.println(alarm_sec);
    if (alarm_sec > 60) {
      alarm_min = 1 + alarm_min;
      alarm_sec = 0;
    }

  }

}
void alarm() {
  //when the actual time equals to them for which the alarm has been set the alrm with buzz
  if (alarm_min == minute && alarm_sec == second && count_alarm >= 1) {
    tone(buzzer, 300, 6000);
  }
  //display the time for which the alarm has been set
  OLED_display(hour, alarm_min, alarm_sec, 0, "Alarm is set for");
}
void stop_watch() {
  if (set_stopwatch == 1 && stop_stopwatch == 0) {
    //doing the following calculations to find the elapsed time when the stopwatch is started
    //and not stopped
    elapsed_time = millis() - start_stopwatch;

    unsigned long over;
    h = int(elapsed_time / 3600000);
    over = elapsed_time % 3600000;
    m = int(over / 60000);
    over = over % 60000;
    s = int(over / 1000);
    msecond = over % 100;
  }
  else if (reset_stopwatch == 1) {
    //setting the value of hours seconds and milliseconds to zero when it is resetted
    h = 0;
    m = 0;
    s = 0;
    msecond = 0;
  }
  OLED_display(h, m, s, msecond, "Stop watch");

}

void digital_clock() {
  OLED_display(hour, minute, second, 0, "Digital clock");

}
void OLED_display(int hours, int minutes, int seconds, int mseconds, String text) {
  u8g.firstPage(); //marks the beginning of the picture loop.
  do {
    u8g.setColorIndex(1);// set the colour to white
    u8g.setFont(u8g_font_courB18);
    //hours
    if (hours < 10) {
      u8g.setPrintPos(0, 61);
      u8g.print("0");
      u8g.setPrintPos(14, 61);
      u8g.print(hours);
    }
    else {
      u8g.setPrintPos(0, 61);
      u8g.print(hours);
    }
    u8g.setPrintPos(25, 61);
    u8g.print(":");
    //minutes
    if (minutes < 10) {
      u8g.setPrintPos(35, 61);
      u8g.print("0");
      u8g.setPrintPos(49, 61);
      u8g.print(minutes);
    }
    else {
      u8g.setPrintPos(35, 61);
      u8g.print(minutes);
    }
    u8g.setPrintPos(60, 61);
    u8g.print(":");
    //seconds
    if (seconds < 10) {
      u8g.setPrintPos(72, 61);
      u8g.print("0");
      u8g.setPrintPos(84, 61);
      u8g.print(seconds);

    }
    else {
      u8g.setPrintPos(72, 61);
      u8g.print(seconds);
    }

    if (is_stopwatch == 1) { //print milliseconds only for stopwatch
      //milli seconds
      u8g.setFont(u8g_font_courB14);
      u8g.setPrintPos(97, 61);
      u8g.print(":");
      if (mseconds < 10) {
        u8g.setPrintPos(107, 61);
        u8g.print("0");
        u8g.setPrintPos(116, 61);
        u8g.print(mseconds);
      }
      else {
        u8g.setPrintPos(107, 61);
        u8g.print(mseconds);
      }
    }

    u8g.setFont(u8g_font_7x13);
    u8g.setPrintPos(0, 20);
    u8g.print(text);

  } while (u8g.nextPage()); //end of picture loop

}