//Youtube channel: engineer2you
#include <Wire.h>
#include "DS3231.h"

RTClib RTC;
DS3231 Clock;

int hour;
int minute;
int second;

const int nixie_0 = 2;
const int nixie_1 = 3;
const int nixie_2 = 4;
const int nixie_3 = 5;  
const int nixie_4 = 6;
const int nixie_5 = 7;
const int nixie_6 = 8;
const int nixie_7 = 9;
const int nixie_8 = 10;
const int nixie_9 = 11;

const int row_1 = 0;
const int row_2 = 1;
const int row_3 = 14;
const int row_4 = 15;
const int row_5 = 16;
const int row_6 = 17;

const int button_up = 12;
const int button_dn = 13;
int button_up_value;
int button_dn_value;

boolean hour_blink, min_blink, sec_blink;
int blink_latch = 0;
int mode_step = 0;
int mode_counter = 0;
int change_counter = 0;

const int time_on = 2;  //time display each number of nixie tube

void setup() {
  pinMode(nixie_0, OUTPUT);
  pinMode(nixie_1, OUTPUT);
  pinMode(nixie_2, OUTPUT);
  pinMode(nixie_3, OUTPUT);
  pinMode(nixie_4, OUTPUT);
  pinMode(nixie_5, OUTPUT);
  pinMode(nixie_6, OUTPUT);
  pinMode(nixie_7, OUTPUT);
  pinMode(nixie_8, OUTPUT);
  pinMode(nixie_9, OUTPUT);
  pinMode(row_1, OUTPUT);
  pinMode(row_2, OUTPUT);
  pinMode(row_3, OUTPUT);
  pinMode(row_4, OUTPUT);
  pinMode(row_5, OUTPUT);
  pinMode(row_6, OUTPUT);
  pinMode(button_up, INPUT_PULLUP);
  pinMode(button_dn, INPUT_PULLUP);
  //Serial.begin(9600); //should NOT use seiral println, it will effect to output pin D0 & D1
  Wire.begin();
  hour_blink = false;
  min_blink = false;
  sec_blink = false;
}

void loop() {
    //-------------------get clock value---------------------------
    DateTime now = RTC.now();
    hour = now.hour();
    minute = now.minute();
    second = now.second();
    
    //-------------------show clock number ----------------------
    int j; //second number from right
    int k; //first number from right
    //-----------------------------------------------------------------------second number show
    j = second/10;
    k = second%10;
    if(sec_blink==false)
    {
      //-----------show first number of second
      off_all();
      on_number(0,k+2);
      delay(time_on);
      //-----------show second number of second
      off_all();
      on_number(1,j+2);
      delay(time_on);
    }
    else{
      if(blink_latch < 8){  //blink_latch: time for blinking
        off_all();
        delay(time_on);
        blink_latch++;
      }
      else{
        //-----------show first number of second/ blink display
        off_all();
        on_number(0,k+2);
        delay(time_on);
        //-----------show second number of second/ blink display
        off_all();
        on_number(1,j+2);
        delay(time_on);
        if (blink_latch < 16) blink_latch++;
        else blink_latch = 0;
      }
    }
    //-------------------------------------------------------------minute number show
    j = minute/10;
    k = minute%10;
    if(min_blink==false)
    {
      //-----------show first number of minute
      off_all();
      on_number(14,k+2);
      delay(time_on);
      //-----------show second number of minute
      off_all();
      on_number(15,j+2);
      delay(time_on);
    }
    else{
      if(blink_latch < 8){  //blink_latch: time for blinking
        off_all();
        delay(time_on);
        blink_latch++;
      }
      else{
        //-----------show first number of minute/ blink display
        off_all();
        on_number(14,k+2);
        delay(time_on);
        //-----------show second number of minute/ blink display
        off_all();
        on_number(15,j+2);
        delay(time_on);
        if (blink_latch < 16) blink_latch++;
        else blink_latch = 0;
      }
     }
    //-----------------------------------------------------------------hour number show
    j = hour/10;
    k = hour%10;
    if(hour_blink==false)
    {
      //-----------show first number of hour
      off_all();
      on_number(16,k+2);
      delay(time_on);
      //-----------show second number of hour
      off_all();
      on_number(17,j+2);
      delay(time_on);
    }
    else{
      if(blink_latch < 8){  //blink_latch: time for blinking
        off_all();
        delay(time_on);
        blink_latch++;
      }
      else{
        //-----------show first number of hour/ blink display
        off_all();
        on_number(16,k+2);
        delay(time_on);
        //-----------show second number of hour/ blink display
        off_all();
        on_number(17,j+2);
        delay(time_on);
        if (blink_latch < 16) blink_latch++;
        else blink_latch = 0;
      }
    }

  //---------------------------------------mode choosen: push two button same time
  button_up_value = digitalRead(button_up); //normal ON (1)
  button_dn_value = digitalRead(button_dn); //normal ON (1)

  if((button_up_value==0)&(button_dn_value==0)&(mode_step==0)){
    mode_step = 1;
  }
  //---------------------------allow to change second
  if(mode_step==1){
    if (mode_counter < 200){
      mode_counter++; // waiting time for changing value
    }
    else{
      mode_counter=0;
      mode_step=2;
      change_counter = 0;
    }
    sec_blink = true; // allow to change second
    min_blink = false;
    hour_blink = false;
  }
  //-------------------------allow to change minute
  if(mode_step==2){
    if (mode_counter < 200){
      mode_counter++; // waiting time for changing value
    }
    else{
      mode_counter=0;
      mode_step=3;
      change_counter = 0;
    }
    sec_blink = false;
    min_blink = true; // allow to change minute
    hour_blink = false;
  }
  //-------------------------allow to change hour
  if(mode_step==3){
    if (mode_counter < 200){
      mode_counter++; // waiting time for changing value
    }
    else{
      mode_counter=0;
      mode_step=4;
      change_counter = 0;
    }
    sec_blink = false;
    min_blink = false;
    hour_blink = true;  // allow to change hour
  }
  //--------------------------escape changing time
  if(mode_step==4){
    mode_step=0;  // escape changing time
    sec_blink = false;
    min_blink = false;
    hour_blink = false;
    change_counter = 0;
  }
  
  //----------------------------------------------------------------------change-second +/-
  if ((button_up_value==0)&(sec_blink==true)){
    second++;
    if (second>59) second = 0;
    change_counter++; //prevent value change too fast
    mode_counter = 0; //hold mode
    if(change_counter>5){
      Clock.setSecond(second);
      change_counter=0;
    }
  }
  if ((button_dn_value==0)&(sec_blink==true)){
    second--;
    if (second<0) second = 59;
    change_counter++; //prevent value change too fast
    mode_counter = 0; //hold mode
    if(change_counter>5){
      Clock.setSecond(second);
      change_counter=0;
    }
  }
  //----------------------------------------------------------------------change-minute +/-
  if ((button_up_value==0)&(min_blink==true)){
    minute++;
    if (minute>59) minute = 0;
    change_counter++; //prevent value change too fast
    mode_counter = 0; //hold mode
    if(change_counter>5){
      Clock.setMinute(minute);
      change_counter=0;
    }
  }
  if ((button_dn_value==0)&(min_blink==true)){
    minute--;
    if (minute<0) minute = 59;
    change_counter++; //prevent value change too fast
    mode_counter = 0; //hold mode
    if(change_counter>5){
      Clock.setMinute(minute);
      change_counter=0;
    }
  }
  //----------------------------------------------------------------------change-hour +/-
  if ((button_up_value==0)&(hour_blink==true)){
    hour++;
    if (hour>23) hour = 0;
    change_counter++; //prevent value change too fast
    mode_counter = 0; //hold mode
    if(change_counter>5){
      Clock.setHour(hour);
      change_counter=0;
    }
  }
  if ((button_dn_value==0)&(hour_blink==true)){
    hour--;
    if (hour<0) hour = 23;
    change_counter++; //prevent value change too fast
    mode_counter = 0; //hold mode
    if(change_counter>5){
      Clock.setHour(hour);
      change_counter=0;
    }
  }
}

void on_number(int row, int nixie){
  digitalWrite(row, HIGH);
  digitalWrite(nixie, HIGH);
}

void off_all(){
  digitalWrite(row_1, LOW);
  digitalWrite(row_2, LOW);
  digitalWrite(row_3, LOW);
  digitalWrite(row_4, LOW);
  digitalWrite(row_5, LOW);
  digitalWrite(row_6, LOW);
  digitalWrite(nixie_0, LOW);
  digitalWrite(nixie_1, LOW);
  digitalWrite(nixie_2, LOW);
  digitalWrite(nixie_3, LOW);
  digitalWrite(nixie_4, LOW);
  digitalWrite(nixie_5, LOW);
  digitalWrite(nixie_6, LOW);
  digitalWrite(nixie_7, LOW);
  digitalWrite(nixie_8, LOW);
  digitalWrite(nixie_9, LOW);

  delayMicroseconds(400);  //to prevent "ghost" effect to other tube
}
