#include <DS3231M.h>
#include <avr/power.h>
#include <avr/io.h>

DS3231M_Class DS3231M;

const int button_pin = 2;

// LED matrix pins
const int anode[]   = {0, 1, 17, 3, 4, 5, 6, 7, 8};
const int cathode[] = {9, 10, 11, 12, 13, 14, 15, 16};

const int rows = sizeof(anode) / sizeof(anode[0]);
const int cols = sizeof(cathode) / sizeof(cathode[0]);

int hour, minute, second;
int sec_row, sec_col, min_row, min_col;
volatile bool wakeUp = false;
int hour_count = 0, adjusted_hour = 0;

void setup() {
  // ---------- Disable Unused Peripherals ----------
  power_adc_disable();       // Disable Analog-to-Digital Converter
  power_usart0_disable();    // Disable Serial
  power_timer1_disable();    // Disable 16-bit Timer1
  power_timer2_disable();    // Disable 8-bit Timer2
  power_spi_disable();       // Disable SPI (only used for programming)
  // Keep I2C (TWI) enabled for DS3231M RTC

  // ---------- Pin Initialization ----------
  for (int i = 0; i < rows; i++) {
    pinMode(anode[i], OUTPUT);
    digitalWrite(anode[i], LOW);   // Default low to save power
  }
  for (int j = 0; j < cols; j++) {
    pinMode(cathode[j], OUTPUT);
    digitalWrite(cathode[j], HIGH);  // Default high (turn off LEDs)
  }

  pinMode(button_pin, INPUT_PULLUP);

  // ---------- Initialize RTC ----------
  while (!DS3231M.begin()) {
    // Wait until RTC is found (no Serial printing for power saving)
  }

  // Set RTC time once if needed (comment out after first run)
  //DS3231M.adjust(DateTime(2025, 7, 22, 6, 0, 0));
}

void loop() {
  DateTime now = DS3231M.now();
  hour   = now.hour();
  minute = now.minute();
  second = now.second();

  // Refresh display
  turnOffAllLEDs();
  lightSecondLED(second);
  //delayMicroseconds(200);
  delayMicroseconds(100);

  turnOffAllLEDs();
  lightMinuteLED(minute);
  //delayMicroseconds(200);
  delayMicroseconds(100);

  turnOffAllLEDs();
  lightHourLED(hour);
  //delayMicroseconds(1);
  delayMicroseconds(1);

  // Reset time on button press, only hour can be adjusted
  // minute and second starts from zero
  if (digitalRead(button_pin) == LOW) {
    hour_count += 1;
    delay(200);
    if(hour_count>12) hour_count = 1;
    adjusted_hour = hour + hour_count;
    DS3231M.adjust(DateTime(2025, 7, 22, adjusted_hour, 0, 0));
    hour_count = 0;
  }
}

// ---------- LED Control Functions ----------
void lightSecondLED(int index) {
  sec_row = index / cols;
  sec_col = index % cols;
  digitalWrite(anode[sec_row], HIGH);
  digitalWrite(cathode[sec_col], LOW);
}

void lightMinuteLED(int index) {
  min_row = index / cols;
  min_col = index % cols;
  digitalWrite(anode[min_row], HIGH);
  digitalWrite(cathode[min_col], LOW);
}

void lightHourLED(int index) {
  if (index > 12) index -= 12;

  if (index < 4 || index == 12) {
    digitalWrite(7, HIGH);
    digitalWrite(8, LOW);
    if (index == 1)      digitalWrite(cathode[5], LOW);
    else if (index == 2) digitalWrite(cathode[6], LOW);
    else if (index == 3) digitalWrite(cathode[7], LOW);
    else if (index == 12) digitalWrite(cathode[4], LOW);
  } else if (index >= 4 && index < 12) {
    digitalWrite(8, HIGH);
    digitalWrite(7, LOW);
    digitalWrite(cathode[index - 4], LOW);
  }
}

void turnOffAllLEDs() {
  for (int i = 0; i < rows; i++) digitalWrite(anode[i], LOW);
  for (int j = 0; j < cols; j++) digitalWrite(cathode[j], HIGH);
}
