#pragma GCC push_options
#pragma GCC optimize ("O1")

// I2C
#include <Wire.h>
// RTC
#include <DS3231.h>
// Use 74HC164 shift registers

// Init DS3231 RTC
DS3231 rtc;
bool h12;
bool hPM;

int btnHr = 10;
int btnMin = 9;
int btnTemp = 8;
int regData = 5;
int regClk = 6;

void setup() {
       // Buttons
       for(int i = 8; i < 11; i++)
               pinMode(i,INPUT);
       // Shift register
       for(int i = 5; i < 7; i++)
               pinMode(i,OUTPUT);
       // RTC
       Wire.begin();
       rtc.setClockMode(false); // 24 hour

       // Check RTC for problems
       if(!rtc.oscillatorCheck()) {
               // RTC NOT OK, set values to known ones
               rtc.setMinute(0);
               rtc.setHour(12);
       }
}

byte minute, hour, previousMinute, previousHour, needsUpdate, previousTemp, decTemp;
const uint8_t seg[] = {
       //    gfedcba
       0b0111111, // 0
       0b0000110, // 1
       0b1011011, // 2
       0b1001111, // 3
       0b1100110, // 4
       0b1101101, // 5
       0b1111101, // 6
       0b0000111, // 7
       0b1111111, // 8
       0b1101111, // 9
       0b1100011, // degree
       0b0111001, // C
       0b1000000  // -
};

void loop() {
       // Get time from RTC
       minute = rtc.getMinute();
       hour = rtc.getHour(h12, hPM);

       // Avoid refreshing if possible since we have no latch
       if(previousMinute != minute || previousHour != hour || needsUpdate != 0) {
               previousMinute = minute;
               previousHour = hour;
               needsUpdate = 0;
               shiftOut(regData, regClk, MSBFIRST, seg[minute%10]);
               shiftOut(regData, regClk, MSBFIRST, seg[minute/10]);
               shiftOut(regData, regClk, MSBFIRST, seg[hour%10]);
               shiftOut(regData, regClk, MSBFIRST, seg[hour/10]);
       } else {delay(10);}
       // Hour up
       if(digitalRead(10)) {
               if(rtc.getHour(h12, hPM) == 23) {
                       rtc.setHour(0);
               } else {
                       rtc.setHour(rtc.getHour(h12, hPM) + 1);
               }
               while(digitalRead(10));
       }

       // Minute up, set seconds to 0
       if(digitalRead(9)) {
               if(rtc.getMinute() == 59) {
                       rtc.setMinute(0);
               }
               rtc.setSecond(0);
               rtc.setMinute(rtc.getMinute() + 1);
               while(digitalRead(9));
       }

       if(digitalRead(8)) { needsUpdate = 1; }
       // Show temperature reading from RTC
       while(digitalRead(8)) {
               decTemp = (int)rtc.getTemperature();
               if(previousTemp != decTemp || needsUpdate != 0) {
                       previousTemp = decTemp;
                       needsUpdate = 0;
                       if(decTemp > -9999) {
                               // OK
                               shiftOut(regData, regClk, MSBFIRST, seg[11]);
                               shiftOut(regData, regClk, MSBFIRST, seg[10]);
                               shiftOut(regData, regClk, MSBFIRST, seg[decTemp%10]);
                               shiftOut(regData, regClk, MSBFIRST, seg[decTemp/10]);
                       } else {
                               shiftOut(regData, regClk, MSBFIRST, seg[11]);
                               shiftOut(regData, regClk, MSBFIRST, seg[10]);
                               shiftOut(regData, regClk, MSBFIRST, seg[12]);
                               shiftOut(regData, regClk, MSBFIRST, seg[12]);
                       }
               } else {delay(10);}
               if(!digitalRead(8)) { needsUpdate = 1; break; }
       }
}

#pragma GCC pop_options