//Kevin Rye 2018
//still to do:
////add date calculations
////fix chimne on hour sounding while time is being set

//shifting code modified from a sketch by Nicu Florica
#include <Wire.h>
#include <Sodaq_DS3231.h>
#include <EEPROM.h>

//MAX6921 interface
byte clk = 9;
byte load = 10;
byte din = 8;

//digit arrays

//pm / alarm ind
byte pmInd[20] = {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
byte alarmInd[20] = { 0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0 };
byte alarmMenu[20] = {  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0 };

//tens of hours
byte zeroHT[20] = {  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1,  1 };
byte oneHT[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  1 };
//byte twoHT[20] = {  1,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1,  1 };  //will never be displayed
//byte threeHT[20] = {  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1,  1 }; //will never be displayed
//byte fourHT[20] = { 1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  0,  1 }; //will never be displayed
//byte fiveHT[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1,  0 }; //will never be displayed
//byte sixHT[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1,  0 }; //will never be displayed
//byte sevenHT[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1,  1 }; //will never be displayed
//byte eightHT[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1,  1 }; //will never be displayed
//byte nineHT[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1,  1 }; //will never be displayed

//ones of hours
byte zeroHO[20] = {  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1,  1 };
byte oneHO[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  1 };
byte twoHO[20] = {  1,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1 };
byte threeHO[20] = {  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1 };
byte fourHO[20] = { 1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  0,  1 };
byte fiveHO[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1,  0 };
byte sixHO[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1,  0 };
byte sevenHO[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1,  1 };
byte eightHO[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1,  1 };
byte nineHO[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1,  1 };

//colon
byte colonTop[20] = {  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0 };
byte colonBottom[20] = {  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0 };
//both colons are hard-wired to each other

//tens of minutes
byte zeroMT[20] = {  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,  1 };
byte oneMT[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  1 };
byte twoMT[20] = {  1,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1 };
byte threeMT[20] = {  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1 };
byte fourMT[20] = { 1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  0,  1 };
byte fiveMT[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,  0 };
//byte sixMT[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,  0 }; //will never be displayed
//byte sevenMT[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1,  1 }; //will never be displayed
//byte eightMT[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,  1 }; //will never be displayed
//byte nineMT[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1,  1 }; //will never be displayed

//ones of minutes
byte zeroMO[20] = {  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  1,  1 };
byte oneMO[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  1 };
byte twoMO[20] = {  1,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1 };
byte threeMO[20] = {  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1 };
byte fourMO[20] = { 1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  0,  1 };
byte fiveMO[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  1,  0 };
byte sixMO[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  1,  0 };
byte sevenMO[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  1,  1 };
byte eightMO[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  1,  1 };
byte nineMO[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1,  1,  1 };

//tens of seconds
byte zeroST[20] = {  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1 };
byte oneST[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  1 };
byte twoST[20] = {  1,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  1 };
byte threeST[20] = {  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  1 };
byte fourST[20] = { 1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  1 };
byte fiveST[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  0 };
//byte sixST[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  0 }; //will never be displayed
//byte sevenST[20] = {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1,  1 }; //will never be displayed
//byte eightST[20] = {  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1 }; //will never be displayed
//byte nineST[20] = { 1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1 }; //will never be displayed

//ones of seconds
byte zeroSO[20] = {  0,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1 };
byte oneSO[20] = {  0,  1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1 };
byte twoSO[20] = {  1,  0,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1 };
byte threeSO[20] = {  1,  1,  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1 };
byte fourSO[20] = { 1,  1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  1 };
byte fiveSO[20] = { 1,  1,  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0 };
byte sixSO[20] = {  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0 };
byte sevenSO[20] = {  0,  1,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1 };
byte eightSO[20] = {  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1 };
byte nineSO[20] = { 1,  1,  1,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1 };

//bools
bool timeMode = true;
bool dateMode = false;
bool alarmMode = false;
bool pm = false;
boolean saveNewAlarmHours = false;
boolean saveNewAlarmMinutes = false;
boolean saveNewAlarmStatus = false;

//RTC data
byte hours = 12;
byte hh = 0;
byte minutes = 0;
byte seconds = 0;
byte dayOfMonth = 2;
byte month = 7;
byte year = 17;
byte dayOfWeek = 0; //not used, but given a value for push to RTC function

//time variables for shiting
byte hoursTens = 0;
byte hoursOnes = 0;
byte minutesTens = 0;
byte minutesOnes = 0;
byte secondsTens = 0;
byte secondsOnes = 0;

//I/O
byte hourMonthButton = 3;
byte minDayButton = 2;
byte secYearButton = A3;
byte alarmButton = A2;
byte enableButton = A1;
byte modeButton = A0;

//saved alarm settings
byte savedHours;
byte savedHoursAddress = 0;
byte savedMinutes;
byte savedMinutesAddress = 1;
byte savedAlarmMode;
byte savedAlarmModeAddress = 2;

//alarm
bool setAlarmActive = false; //set up default condition, will be saved or recalled from EEPROM
byte alarmHours = 0; //set up default condition
byte adjAlarmHours;
byte alarmMinutes = 0; //set up default condition
boolean alarmIsActive = false; //when the alarm is actually sounding

//audio
byte amplifier = 7;
byte numTones = 2;
int alarmTones[] = {800, 600 };
int chimeTones[] = {1200, 1200 };
byte enableAmplifier = 10; //shutdown function

// Variables will change:
int speakerState = LOW;             // ledState used to set the LED

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change:
const long interval = 500;           // interval at which to blink (milliseconds)

void setup() {
  pinMode(din, OUTPUT);
  pinMode(load, OUTPUT);
  pinMode(clk, OUTPUT);

  digitalWrite(clk, LOW);
  digitalWrite(load, LOW);
  digitalWrite(din, LOW);

  pinMode(hourMonthButton, INPUT);
  pinMode(minDayButton, INPUT);
  pinMode(secYearButton, INPUT);
  pinMode(alarmButton, INPUT);
  pinMode(enableButton, INPUT);
  pinMode(modeButton, INPUT);

  pinMode(enableAmplifier, OUTPUT);
  digitalWrite(enableAmplifier, LOW);

  //pull in alarm time from EEPROM
  //read saved hours for alarm from EEPROM
  savedHours = EEPROM.read(savedHoursAddress);
  if (savedHours != 0) {
    alarmHours = savedHours;
  }
  else {
    alarmHours = 0;
  }

  //read saved minutes for alarm from EEPROM
  savedMinutes = EEPROM.read(savedMinutesAddress);
  if (savedMinutes != 0) {
    alarmMinutes = savedMinutes;
  }
  else {
    alarmMinutes = 0;
  }

  //read saved alarm mode from EEPROM
  savedAlarmMode = EEPROM.read(savedAlarmModeAddress);
  if (savedAlarmMode == 0) { //0 = NO //1 = YES
    setAlarmActive = false;
  }
  else {
    setAlarmActive = true;
  }

  Wire.begin();
  rtc.begin();
  //Serial.begin(9600);

}

void loop() {

  //poll the DS3231 for the date and time
  get_time();
  get_date();

  //pass RTC values into a new variable -
  //this way one variable stores time in 24 hour mode and another that can be converted to 12 hour mode
  //time is monitored 'in the background' in 24 hour mode using the RTC, but is displayed in an adjusted 12-hr format
  hh = hours;

  //convert to 12 hr mode for display
  if (hours < 1) {
    hh = 12;
  }

  if ((hours > 12) && (hours < 24)) {
    hh = hours - 12;
  }

  //pm ind
  if ((hours > 11) && (true == timeMode)) {
    pm = true;
  }
  else {
    pm = false;
  }

  //handle button presses
  //TIME MODE
  //hour/month button pressed
  if ((digitalRead(hourMonthButton) == LOW) && (timeMode == true)) {

    //debounce
    delay(200);

    hours++;

    if (hours > 23) {
      hours = 0;
    }

    set_time();
  }

  //min/day button pressed
  if ((digitalRead(minDayButton) == LOW) && (timeMode == true)) {

    //debounce
    delay(200);

    minutes++;
    seconds = 0;

    if (minutes > 59) {
      minutes = 0;
    }

    set_time();
  }

  //sec/year button pressed
  if ((digitalRead(secYearButton) == LOW) && (timeMode == true)) {

    //debounce
    delay(200);

    seconds = 0;
    set_time();
  }

  //mode button pressed
  if ((digitalRead(modeButton) == LOW) && (timeMode == true)) {

    //debounce
    delay(200);

    timeMode = false;
    alarmMode = false;
    dateMode = true;
  }

  if ((digitalRead(modeButton) == LOW) && (dateMode == true)) {

    //debounce
    delay(200);

    timeMode = true;
    alarmMode = false;
    dateMode = false;
  }

  if ((digitalRead(modeButton) == LOW) && (alarmMode == true)) {

    //debounce
    delay(200);

    timeMode = false;
    alarmMode = false;
    dateMode = true;
  }

  //in alarmMode
  if (alarmMode == true) {

    //adjust alarm time for 12 hours
    adjAlarmHours = alarmHours;

    if (adjAlarmHours > 12) {
      adjAlarmHours = alarmHours - 12;
    }
    if (adjAlarmHours == 0) {
      adjAlarmHours = 12;
    }

    //enable am/pm nixie as appropriate
    if (alarmHours > 11) {
      pm = true;
    }
    else {
      pm = false;
    }
  }

  //ALARM MODE
  //hour/month button pressed
  if ((digitalRead(hourMonthButton) == LOW) && (alarmMode == true)) {

    //debounce
    delay(200);

    alarmHours++;

    if (alarmHours > 23) {
      alarmHours = 0;
    }

    if (alarmHours != savedHours ) {

      saveNewAlarmHours = true;
      writeToEEPROM();
    }
  }

  //min/day button pressed
  if ((digitalRead(minDayButton) == LOW) && (alarmMode == true)) {

    //debounce
    delay(200);

    alarmMinutes++;

    if (alarmMinutes > 59) {
      alarmMinutes = 0;
    }

    if (alarmMinutes != savedMinutes ) {

      saveNewAlarmMinutes = true;
      writeToEEPROM();
    }
  }

  if ((digitalRead(secYearButton) == LOW) && (alarmMode == true)) {

    //does nothing, seconds remain at 0 in alarm mode
  }

  //enable button pressed
  if (digitalRead(enableButton) == LOW) {

    //debounce
    delay(200);

    //toggle alarm status
    setAlarmActive = !setAlarmActive;

    //save new setting
    saveNewAlarmStatus = true;
    writeToEEPROM();
  }

  //alarm menu button pressed
  if ((digitalRead(alarmButton) == LOW) && (alarmMode == true)) {

    //debaounce
    delay(200);

    timeMode = true;
    alarmMode = false;
    dateMode = false;
  }

  if ((digitalRead(alarmButton) == LOW) && (alarmMode == false)) {

    //debaounce
    delay(200);

    timeMode = false;
    alarmMode = true;
    dateMode = false;
  }

  //DATE MODE
  //hour/month button pressed
  if ((digitalRead(hourMonthButton) == LOW) && (dateMode == true) && (alarmMode == false)) {

    //debounce
    delay(200);

    //set month
    month++;
    if (month > 12) month = 1;

    //send update to RTC
    set_date();
  }

  //min/day button pressed
  if ((digitalRead(minDayButton) == LOW) && (dateMode == true) && (alarmMode == false)) {

    //debounce
    delay(200);

    //set day
    dayOfMonth++;

    //if feb
    if (month == 2) {
      if (dayOfMonth > 28) dayOfMonth = 1;
    }

    //if leap year
    //is it worth it?

    //if month has 30 days: Apr, Jun, Sep, Nov
    if ((month == 4) || (month == 6) || (month == 9) || (month == 11))  {
      if (dayOfMonth > 30) dayOfMonth = 1;
    }

    //if month has 31 days: Jan, Mar, May, Jul, Aug, Oct, Dec
    if ((month == 1) || (month == 3) || (month == 5) || (month == 7) || (month == 8) || (month == 10)) {
      if (dayOfMonth > 31) dayOfMonth = 1;
    }

    //send update to RTC
    set_date();
  }

  //year button pressed
  if ((digitalRead(secYearButton) == LOW) && (dateMode == true) && (alarmMode == false)) {

    //debounce
    delay(200);

    year++;
    if (year > 99) year = 0;

    //send update to RTC
    set_date();
  }

  //chime on hour
  //chime only when in time mode and when not alarming
  if ((minutes == 0) && (seconds < 1) && (timeMode == true) && (alarmIsActive == false) ) {

    digitalWrite(enableAmplifier, HIGH);
    unsigned long currentMillis = millis();

    if (currentMillis - previousMillis >= 300) {
      previousMillis = currentMillis;

      if (speakerState == LOW) {
        speakerState = HIGH;
        for (int i = 0; i < numTones; i++)
        {
          tone(amplifier, chimeTones[i]);
        }
      } else {
        speakerState = LOW;
        noTone(amplifier);
      }
    }
  } else {
    digitalWrite(enableAmplifier, LOW);
  }

  //handle alarm
  //alarm only when in normal mode and when alarm is active
  if ((adjAlarmHours == hh) && (alarmMinutes == minutes) && (seconds < 20)) {

    if ((setAlarmActive == true) && (timeMode == true) ) {

      unsigned long currentMillis = millis();

      alarmIsActive = true;

      if (currentMillis - previousMillis >= interval) {
        previousMillis = currentMillis;

        if (speakerState == LOW) {
          speakerState = HIGH;
          for (int i = 0; i < numTones; i++)
          {
            tone(amplifier, alarmTones[i]);
          }
        } else {
          speakerState = LOW;
          noTone(amplifier);
        }
      }
    }

  } else {
    alarmIsActive = false;
  }

  if (true == alarmIsActive) {
    digitalWrite(enableAmplifier, HIGH);
  } else {
    digitalWrite(enableAmplifier, LOW);
  }

  //finally, push data to MAX6921
  pushData();

} // end loop

void pushData() {

  if (true == timeMode) {
    //disect time
    // hours
    hoursTens = hh / 10;
    hoursOnes = hh - 10 * hoursTens;
    // minutes
    minutesTens = minutes / 10;
    minutesOnes = minutes - 10 * minutesTens;
    // seconds
    secondsTens = seconds / 10;
    secondsOnes = seconds - 10 * secondsTens;
  }

  if (true == dateMode) {
    //disect date
    // month
    hoursTens = month / 10;
    hoursOnes = month - 10 * hoursTens;
    // day
    minutesTens = dayOfMonth / 10;
    minutesOnes = dayOfMonth - 10 * minutesTens;
    // year
    secondsTens = year / 10;
    secondsOnes = year - 10 * secondsTens;
  }

  if (true == alarmMode) {
    //disect time
    // hours
    hoursTens = adjAlarmHours / 10;
    hoursOnes = adjAlarmHours - 10 * hoursTens;
    // minutes
    minutesTens = alarmMinutes / 10;
    minutesOnes = alarmMinutes - 10 * minutesTens;
    // seconds
    secondsTens = 0;
    secondsOnes = 0;
  }

  //pm indicator
  if ((true == pm) && (false == dateMode)) {
    putDigit(7, pmInd);
  }

  //if alarm set
  if (true == setAlarmActive) {
    putDigit(7, alarmInd);
  }

  //if in alarm menu
  if (true == alarmMode) {
    putDigit(7, alarmMenu);
  }

  //hours / month
  if (hoursTens == 0) putDigit(6, zeroHT);
  if (hoursTens == 1) putDigit(6, oneHT);
  //if (hoursTens == 2) putDigit(6, twoHT);
  //if (hoursTens == 3) putDigit(6, threeHT);
  //if (hoursTens == 4) putDigit(6, fourHT);
  //if (hoursTens == 5) putDigit(6, fiveHT);
  //if (hoursTens == 6) putDigit(6, sixHT);
  //if (hoursTens == 7) putDigit(6, sevenHT);
  //if (hoursTens == 8) putDigit(6, eightHT);
  //if (hoursTens == 9) putDigit(6, nineHT);
delay(1); //mitigate brightness on last digit

  if (hoursOnes == 0) putDigit(5, zeroHO);
  if (hoursOnes == 1) putDigit(5, oneHO);
  if (hoursOnes == 2) putDigit(5, twoHO);
  if (hoursOnes == 3) putDigit(5, threeHO);
  if (hoursOnes == 4) putDigit(5, fourHO);
  if (hoursOnes == 5) putDigit(5, fiveHO);
  if (hoursOnes == 6) putDigit(5, sixHO);
  if (hoursOnes == 7) putDigit(5, sevenHO);
  if (hoursOnes == 8) putDigit(5, eightHO);
  if (hoursOnes == 9) putDigit(5, nineHO);
delay(1);//mitigate brightness on last digit

  //colon
  if (false == dateMode) { // in time or alarm mode

    putDigit(4, colonTop);
    putDigit(4, colonBottom);
  }

  if (true == dateMode) {

    putDigit(4, colonBottom);
  }

  //minutes / days
  if (minutesTens == 0) putDigit(3, zeroMT);
  if (minutesTens == 1) putDigit(3, oneMT);
  if (minutesTens == 2) putDigit(3, twoMT);
  if (minutesTens == 3) putDigit(3, threeMT);
  if (minutesTens == 4) putDigit(3, fourMT);
  if (minutesTens == 5) putDigit(3, fiveMT);
  //if (minutesTens == 6) putDigit(3, sixMT);
  //if (minutesTens == 7) putDigit(3, sevenMT);
  //if (minutesTens == 8) putDigit(3, eightMT);
  //if (minutesTens == 9) putDigit(3, nineMT);
delay(1);  //mitigate brightness on last digit

  if (minutesOnes == 0) putDigit(2, zeroMO);
  if (minutesOnes == 1) putDigit(2, oneMO);
  if (minutesOnes == 2) putDigit(2, twoMO);
  if (minutesOnes == 3) putDigit(2, threeMO);
  if (minutesOnes == 4) putDigit(2, fourMO);
  if (minutesOnes == 5) putDigit(2, fiveMO);
  if (minutesOnes == 6) putDigit(2, sixMO);
  if (minutesOnes == 7) putDigit(2, sevenMO);
  if (minutesOnes == 8) putDigit(2, eightMO);
  if (minutesOnes == 9) putDigit(2, nineMO);
delay(1); //mitigate brightness on last digit

  //seconds / year
  if (secondsTens == 0) putDigit(1, zeroST);
  if (secondsTens == 1) putDigit(1, oneST);
  if (secondsTens == 2) putDigit(1, twoST);
  if (secondsTens == 3) putDigit(1, threeST);
  if (secondsTens == 4) putDigit(1, fourST);
  if (secondsTens == 5) putDigit(1, fiveST);
  //if (secondsTens == 6) putDigit(1, sixST);
  //if (secondsTens == 7) putDigit(1, sevenST);
  //if (secondsTens == 8) putDigit(1, eightST);
  //if (secondsTens == 9) putDigit(1, nineST);
delay(1); //mitigate brightness on last digit

  if (secondsOnes == 0) putDigit(0, zeroSO);
  if (secondsOnes == 1) putDigit(0, oneSO);
  if (secondsOnes == 2) putDigit(0, twoSO);
  if (secondsOnes == 3) putDigit(0, threeSO);
  if (secondsOnes == 4) putDigit(0, fourSO);
  if (secondsOnes == 5) putDigit(0, fiveSO);
  if (secondsOnes == 6) putDigit(0, sixSO);
  if (secondsOnes == 7) putDigit(0, sevenSO);
  if (secondsOnes == 8) putDigit(0, eightSO);
  if (secondsOnes == 9) putDigit(0, nineSO);

} //end loop

//push data out MAX6921
void putDigit (byte digitPos, byte digit[20]) {
  //define position of digit
  for (int i = 0; i < 20; i++) {
    if (i == digitPos) digitalWrite(din, 1);
    else digitalWrite(din, 0);
    digitalWrite(clk, HIGH);
    digitalWrite(clk, LOW);
  }

  //populate digit with number
  for (int i = 19; i >= 0; i--) {
    digitalWrite(din, digit[i]);
    digitalWrite(clk, HIGH);
    digitalWrite(clk, LOW);
  }
  //digitalWrite(clk, LOW);
  // shift out digit
  digitalWrite(load, HIGH);
  digitalWrite(load, LOW);
}

//DS3231
void set_date() {

  Wire.beginTransmission(104);
  Wire.write(3);
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

void get_date() {

  Wire.beginTransmission(104);
  Wire.write(3);//set register to 3 (day)
  Wire.endTransmission();
  Wire.requestFrom(104, 4); //get 5 bytes(day,date,month,year,control);
  dayOfWeek   = bcdToDec(Wire.read());
  dayOfMonth  = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year  = bcdToDec(Wire.read());
}

void set_time() {

  Wire.beginTransmission(104);
  Wire.write(0);
  Wire.write(decToBcd(seconds));
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  Wire.endTransmission();
}

void get_time() {

  Wire.beginTransmission(104);
  Wire.write(0);//set register to 0
  Wire.endTransmission();
  Wire.requestFrom(104, 3);//get 3 bytes (seconds,minutes,hours);
  seconds = bcdToDec(Wire.read() & 0x7f);
  minutes = bcdToDec(Wire.read());
  hours = bcdToDec(Wire.read() & 0x3f);
}

byte decToBcd(byte val) {
  return ( (val / 10 * 16) + (val % 10) );
}

byte bcdToDec(byte val) {
  return ( (val / 16 * 10) + (val % 16) );
}

//save settings to EEPROM
void writeToEEPROM() {

  //only save the settings that were changed

  //save alarm hours if it was changed
  if (saveNewAlarmHours == true) {
    EEPROM.write(savedHoursAddress, alarmHours);
  }

  //save alarm minutes if it was changed
  if (saveNewAlarmMinutes == true) {
    EEPROM.write(savedMinutesAddress, alarmMinutes);
  }

  //save alarm status if it was changed
  if (saveNewAlarmStatus == true) {
    EEPROM.write(savedAlarmModeAddress, savedAlarmMode);
  }

  //set flags back to false, so subsequent changes will also be saved
  saveNewAlarmHours = false;
  saveNewAlarmMinutes = false;
  saveNewAlarmStatus = false;
}
