#define F_CPU 16000000UL		/* Define CPU Frequency e.g. here its 8MHz */
#include <avr/io.h>		/* Include AVR std. library file */
#include <util/delay.h>		/* Include inbuilt defined Delay header file */
#include <util/atomic.h>
#include <avr/interrupt.h>

#include "millis.h"

#define LCD_Data_Dir DDRD	/* Define LCD data port direction */
#define LCD_Command_Dir DDRB	/* Define LCD command port direction register */
#define LCD_Data_Port PORTD	/* Define LCD data port */
#define LCD_Command_Port PORTB	/* Define LCD data port */
#define RS PB4			/* Define Register Select signal pin */
#define RW PB2			/* Define Read/Write signal pin */
#define EN PB3			/* Define Enable signal pin */

// Pins definition for Time Set Buttons
#define Buttons_Port PORTB
#define Buttons_Dir DDRB
#define HRs PB1 // Pin PB1 for Hours Setting
#define MINs PB0 // Pin PB0 for Minutes/Preset Seconds(0) Setting

///CLOCK VARIABLES
	// initial Time display is 24:59:45 PM
	char h=24;
	char m=59;
	char s=45; //was int
	int flag=1; //PM

	// Time Set Buttons
	int buttonHR;
	int buttonMIN;

	// For accurate Time reading, use Arduino Real Time Clock and not just delay()
	static uint32_t last_time, now = 0; // RTC
	uint32_t current_timeElapsed = 0;
///END OF CLOCK VARIABLES

ISR(TIMER1_COMPA_vect){
	timer1_millis++;
}

int main(){
	LCD_init();
	millis_init(F_CPU);
	sei();
	CLK_init();

//	LCD_CatAni();

	while(1){
		CLK_main();
	}
	
}

void CLK_init (){
		//Sets PB1 and PB0 as input
		Buttons_Dir &= (~(1<<HRs)) & (~(1<<MINs)); 
		//Enables pull-up resistor for PB1 and PB0 
		Buttons_Port |= (1<<HRs) | (1<<MINs);
		now=time_Elapsed_ms();
}

void CLK_main (){
	LCD_Clear();
	// Update LCD Display
	// Print TIME in Hour, Min, Sec 
	LCD_Command(0x80); //setcursor to line 1
	
	LCD_String("Time ");
	if(h<10)LCD_String("0"); // always 2 digits
	char hrs[2];
	sprintf(hrs, "%d", h);
	LCD_String(hrs);

	LCD_String(":");
	if(m<10)LCD_String("0");
	char mins[2];
	sprintf(mins, "%d", m);
	LCD_String(mins);

	LCD_String(":");
	if(s<10)LCD_Char("0");
	char secs[2];
	sprintf(secs, "%d", s);
	LCD_String(secs);

 	LCD_Command(0xc0); //setcursor to line 2
	LCD_String("Gan Ke Yi PD12");


//running
	// improved replacement of delay(1000) 
	// Much better accuracy, no more dependant of loop execution time

	for ( int i=0 ;i<5 ;i++)// make 5 time 200ms loop, for faster Button response
	{

		while ((now-last_time)<200) //delay200ms
		{ 
			now=time_Elapsed_ms();
		}
	// inner 200ms loop
	last_time=now; // prepare for next loop 

	// read Setting Buttons
	buttonHR= (PINB & HRs);// Read Buttons
	buttonMIN= (PINB & MINs);


	// Process Button 1 or Button 2 when hit 

	if(buttonHR==0){
		h=h+1;
	}

	if(buttonMIN==0){
		s=0;
		m=m+1;
  }

	//manage seconds, minutes, hours overflow 
	if(s==60){
		s=0;
		m=m+1;
	}
	if(m==60){
		m=0;
		h=h+1;
	}
	if(h==24){
		h=0;
		flag=flag;
		}


	if((buttonHR==0)|(buttonMIN==0))// Update display if time set button pressed
	{
		// Update LCD Display
		// Print TIME in Hour, Min, Sec 
		LCD_Command(0x80); //setcursor to line 1
		LCD_String("Time ");

		if(h<10)LCD_String("0");// always 2 digits
		LCD_String(hrs);
		LCD_String(":");

		if(m<10)LCD_String("0");
		LCD_String(mins);
		LCD_String(":");

		if(s<10)LCD_String("0");
		LCD_String(secs);

		
		LCD_Command(0xc0); //setcursor to line 2
		LCD_String("Precision clock");
	}

	} // end for

	// outer 1000ms loop
	s=s+1; //increment sec. counting
			
	// ---- manage seconds, minutes, hours am/pm overflow ----
	if(s==60){
		s=0;
		m=m+1;
	}
	if(m==60){
		m=0;
		h=h+1;
	}
	if(h==24){
		h=0;
		flag=flag;
	} 

///END running

}



void millis_init(unsigned long f_cpu){
  unsigned long ctc_match_overflow;
	//when timer1 is this value, 1ms has passed
  ctc_match_overflow = ((f_cpu / 1000) / 8); 

  // (Set timer to clear when matching ctc_match_overflow) | (Set clock divisor to 8)
  TCCR1B |= (1 << WGM12) | (1 << CS11);

  // high byte first, then low byte
  OCR1AH = (ctc_match_overflow >> 8);
  OCR1AL = ctc_match_overflow;

  // Enable the compare match interrupt
  TIMSK1 |= (1 << OCIE1A);
}

unsigned long time_Elapsed_ms(){
	unsigned long millis_return;

  // Ensure this cannot be disrupted
  ATOMIC_BLOCK(ATOMIC_FORCEON) {
    millis_return = timer1_millis;
  }
  return millis_return;

}


void LCD_Command(unsigned char cmnd){
	LCD_Data_Port= cmnd;
	LCD_Command_Port &= ~(1<<RS);	/* RS=0 command reg. */
	LCD_Command_Port &= ~(1<<RW);	/* RW=0 Write operation */
	LCD_Command_Port |= (1<<EN);	/* Enable pulse */
	_delay_us(1);
	LCD_Command_Port &= ~(1<<EN);
	_delay_ms(2);
}

//LCD data write function 
void LCD_Char (unsigned char char_data){
	LCD_Data_Port= char_data;
	LCD_Command_Port |= (1<<RS);	/* RS=1 Data reg. */
	LCD_Command_Port &= ~(1<<RW);	/* RW=0 write operation */
	LCD_Command_Port |= (1<<EN);	/* Enable Pulse */
	_delay_us(1);
	LCD_Command_Port &= ~(1<<EN);
	_delay_ms(2);			/* Data write delay */
}


//LCD initialize function 
void LCD_init (void){
	LCD_Command_Dir = 0xFF;		/* Make LCD command port direction as o/p */
	LCD_Data_Dir = 0xFF;		/* Make LCD data port direction as o/p */
	_delay_ms(20);			/* LCD Power ON delay always >15ms */
	
	LCD_Command (0x38);		/* Initialization of 16X2 LCD in 8bit mode */
	LCD_Command (0x0C);		/* Display ON Cursor OFF */
	LCD_Command (0x06);		/* Auto Increment cursor */
	LCD_Command (0x01);		/* clear display */
	_delay_ms(2);			/* Clear display command delay> 1.63 ms */
	LCD_Command (0x80);		/* Cursor at home position */
}

//Send string to LCD function 
void LCD_String (char *str){
	int i;
	for(i=0;str[i]!=0;i++)		/* Send each char of string till the NULL */
	{
		LCD_Char (str[i]);
	}
}
//Send string to LCD with xy position 
void LCD_String_xy (char row, char pos, char *str){
	if (row == 0 && pos<16)
	LCD_Command((pos & 0x0F)|0x80);	/* Command of first row and required position<16 */
	else if (row == 1 && pos<16)
	LCD_Command((pos & 0x0F)|0xC0);	/* Command of first row and required position<16 */
	LCD_String(str);		/* Call LCD string function */
}

void LCD_Clear(){
	LCD_Command (0x01);		/* clear display */
	LCD_Command (0x80);		/* cursor at home position */
}

void LCD_Custom_Char (unsigned char loc, byte *msg){
	unsigned char i;
	if(loc<8)
	{
		LCD_Command (0x40 + (loc*8));	/* Command 0x40 and onwards forces the device to point CGRAM address */
		for(i=0;i<8;i++)	/* Write 8 byte for generation of 1 character */
		LCD_Char(msg[i]);
	}
}

void LCD_CatAni (){			
	LCD_Command(0x80); //setcursor to line 1
	///FRAME 1
		
		byte image00[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B01000, B00100};
		byte image01[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00011, B00011};	
		byte image02[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00100, B11100};
		byte image03[8] = {B00000, B00000, B00000, B00000, B11011, B11111, B01110, B00100};
		
		LCD_Custom_Char(0, image00); 
		LCD_Custom_Char(1, image01);  
		LCD_Custom_Char(2, image02);  
		LCD_Custom_Char(3, image03);  

		LCD_Command(0x80 | 0x01);
		LCD_Char(0);
		LCD_Command(0x80 | 0x02);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x03); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x04);
		LCD_Char(3);

		byte image04[8] = {B01000, B01000, B00100, B00010, B00001, B00001, B00001, B00010};
		byte image05[8] = {B00011, B00111, B00001, B00011, B11111, B11111, B10000, B10000};
		byte image06[8] = {B11100, B11110, B11000, B11000, B11000, B11000, B01100, B00100};

		LCD_Custom_Char(4, image04);  
		LCD_Custom_Char(5, image05);  
		LCD_Custom_Char(6, image06);  

		LCD_Command(0xc0 | 0x01);
		LCD_Char(4);
		LCD_Command(0xc0 | 0x02);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x03);
		LCD_Char(6);
		_delay_ms(1000);

	///FRAME 2 
		LCD_Clear();
		byte image10[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00100, B00010};
		byte image11[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00110, B00111};
		byte image12[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B01000, B11000};
		byte image13[8] = {B00000, B00000, B00000, B00000, B00000, B10100, B01000, B00000};

		LCD_Custom_Char(0, image10); 
		LCD_Custom_Char(1, image11);  
		LCD_Custom_Char(2, image12);  
		LCD_Custom_Char(3, image13);  

		LCD_Command(0x80 | 0x02);
		LCD_Char(0);
		LCD_Command(0x80 | 0x03);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x04); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x05);
		LCD_Char(3);

		byte image14[8] = {B00001, B00010, B00100, B00100, B00011, B00011, B00010, B00010};
		byte image15[8] = {B00111, B01111, B00011, B00111, B11111, B11111, B00000, B00000};
		byte image16[8] = {B11000, B11100, B10000, B10000, B10000, B10000, B10000, B10000};

		LCD_Custom_Char(4, image14);  
		LCD_Custom_Char(5, image15);  
		LCD_Custom_Char(6, image16); 

		LCD_Command(0xc0 | 0x02);
		LCD_Char(4);
		LCD_Command(0xc0 | 0x03);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x04);
		LCD_Char(6);
		_delay_ms(1000); 

	///FRAME 3 
		LCD_Clear();
		byte image20[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00100, B00010};
		byte image21[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B01100, B01111};
		byte image22[8] = {B00000, B00000, B00000, B00000, B00001, B00001, B10000, B10000};
		byte image23[8] = {B00000, B00000, B00000, B00000, B01100, B11100, B11000, B10000};
		
		LCD_Custom_Char(0, image20); 
		LCD_Custom_Char(1, image21);  
		LCD_Custom_Char(2, image22);  
		LCD_Custom_Char(3, image23);  

		LCD_Command(0x80 | 0x03);
		LCD_Char(0);
		LCD_Command(0x80 | 0x04);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x05); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x06);
		LCD_Char(3);

		byte image24[8] = {B01000, B10000, B10000, B01000, B00111, B00111, B01100, B01010};
		byte image25[8] = {B01111, B11111, B00111, B01111, B11111, B11111, B00011, B00010};
		byte image26[8] = {B10000, B11000, B00000, B00000, B00000, B00000, B10000, B10000};

		LCD_Custom_Char(4, image24);  
		LCD_Custom_Char(5, image25);  
		LCD_Custom_Char(6, image26); 

		LCD_Command(0xc0 | 0x03);
		LCD_Char(4);
		LCD_Command(0xc0 | 0x04);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x05);
		LCD_Char(6);
		_delay_ms(1000); 

	///FRAME 4
		LCD_Clear();
		byte image30[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00100, B00010};
		byte image31[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00110, B00111};
		byte image32[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B01000, B11000};
		byte image33[8] = {B00000, B00000, B00000, B00000, B00000, B10100, B01000, B00000};

		LCD_Custom_Char(0, image30); 
		LCD_Custom_Char(1, image31);  
		LCD_Custom_Char(2, image32);  
		LCD_Custom_Char(3, image33);  

		LCD_Command(0x80 | 0x04);
		LCD_Char(0);
		LCD_Command(0x80 | 0x05);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x06); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x07);
		LCD_Char(3);

		byte image34[8] = {B00001, B00010, B00100, B00100, B00011, B00011, B00010, B00010};
		byte image35[8] = {B00111, B01111, B00011, B00111, B11111, B11111, B00000, B00000};
		byte image36[8] = {B11000, B11100, B10000, B10000, B10000, B10000, B10000, B10000};

		LCD_Custom_Char(4, image34);  
		LCD_Custom_Char(5, image35);  
		LCD_Custom_Char(6, image36); 

		LCD_Command(0xc0 | 0x04);
		LCD_Char(4);
		LCD_Command(0xc0 | 0x05);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x06);
		LCD_Char(6);
		_delay_ms(1000); 

	///FRAME 5
		LCD_Clear();

		byte image40[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B01000, B00100};
		byte image41[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00011, B00011};
		byte image42[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00100, B11100};
		byte image43[8] = {B00000, B00000, B00000, B00000, B11011, B11111, B01110, B00100};

		LCD_Custom_Char(0, image40); 
		LCD_Custom_Char(1, image41);  
		LCD_Custom_Char(2, image42);  
		LCD_Custom_Char(3, image43);  

		LCD_Command(0x80 | 0x05);
		LCD_Char(0);
		LCD_Command(0x80 | 0x06);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x07); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x08);
		LCD_Char(3);

		byte image44[8] = {B01000, B01000, B00100, B00010, B00001, B00001, B00001, B00010};
		byte image45[8] = {B00011, B00111, B00001, B00011, B11111, B11111, B10000, B10000};
		byte image46[8] = {B11100, B11110, B11000, B11000, B11000, B11000, B01100, B00100};

		LCD_Custom_Char(4, image44);  
		LCD_Custom_Char(5, image45);  
		LCD_Custom_Char(6, image46); 

		LCD_Command(0xc0 | 0x05);
		LCD_Char(4);
		LCD_Command(0xc0 | 0x06);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x07);
		LCD_Char(6);
		_delay_ms(1000); 

	///FRAME 6
		LCD_Clear();

		byte image50[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00000, B01100};
		byte image51[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00011, B00011};
		byte image52[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00100, B11100};
		byte image53[8] = {B00000, B00000, B00000, B00000, B00000, B10100, B01000, B00000};

		LCD_Custom_Char(0, image50); 
		LCD_Custom_Char(1, image51);  
		LCD_Custom_Char(2, image52);  
		LCD_Custom_Char(3, image53);  

		LCD_Command(0x80 | 0x06);
		LCD_Char(0);
		LCD_Command(0x80 | 0x07);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x08); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x09);
		LCD_Char(3);
		
		byte image54[8] = {B00010, B00100, B00100, B00010, B00001, B00001, B00001, B00001};
		byte image55[8] = {B00011, B00111, B00001, B00011, B11111, B11111, B00000, B00000};
		byte image56[8] = {B11100, B11110, B11000, B11000, B11000, B11000, B01000, B01000};

		LCD_Custom_Char(4, image54);  
		LCD_Custom_Char(5, image55);  
		LCD_Custom_Char(6, image56); 

		LCD_Command(0xc0 | 0x06);
		LCD_Char(4);
		LCD_Command(0xc0 | 0x07);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x08);
		LCD_Char(6);
		_delay_ms(1000); 

	///FRAME 7
		LCD_Clear();

		byte image60[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00010, B00001};
		byte image61[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00011, B00011};
		byte image62[8] = {B00000, B00000, B00000, B00000, B00000, B00000, B00100, B11100};
		byte image63[8] = {B00000, B00000, B00000, B01010, B11111, B01110, B00100, B00000};

		LCD_Custom_Char(0, image60); 
		LCD_Custom_Char(1, image61);  
		LCD_Custom_Char(2, image62);  
		LCD_Custom_Char(3, image63);  

		LCD_Command(0x80 | 0x07);
		LCD_Char(0);
		LCD_Command(0x80 | 0x08);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x09); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x0A);
		LCD_Char(3);
		
		byte image64[8] = {B00010, B00100, B00100, B00010, B00001, B00001, B00011, B00010};
		byte image65[8] = {B00011, B00111, B00001, B00011, B11111, B11111, B00000, B00000};
		byte image66[8] = {B11100, B11110, B11000, B11000, B11000, B11000, B11100, B10100};

		LCD_Custom_Char(4, image64);  
		LCD_Custom_Char(5, image65);  
		LCD_Custom_Char(6, image66); 

		LCD_Command(0xc0 | 0x07);
		LCD_Char(4);
		LCD_Command(0xc0 | 0x08);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x09);
		LCD_Char(6);
		_delay_ms(1000); 		

	///FRAME 8, TEXT BEGINS
		LCD_Clear();
		LCD_Command(0x80);
		LCD_String("Hello!");

		
		byte image80[8] = {B00000, B00000, B00000, B10100, B01000, B00000, B00000, B00000};
		byte image81[8] = {B00000, B01010, B11111, B01110, B00100, B00000, B00100, B01010};
		byte image82[8] = {B00000, B00000, B00000, B00110, B00111, B00111, B00111, B01111};
		byte image83[8] = {B00000, B00000, B00000, B01000, B11000, B11001, B11010, B11101};
		byte image84[8] = {B00000, B10100, B01000, B00000, B00000, B00000, B00101, B00010};
		
		LCD_Custom_Char(0, image80); 
		LCD_Custom_Char(1, image81);  
		LCD_Custom_Char(2, image82);  
		LCD_Custom_Char(3, image83);  
		LCD_Custom_Char(4, image84);  

		LCD_Command(0x80 | 0x09);
		LCD_Char(0);
		LCD_Command(0x80 | 0x0A);   
		LCD_Char(1);
		LCD_Command(0x80 | 0x0B); 
		LCD_Char(2);
		LCD_Command(0x80 | 0x0C);
		LCD_Char(3);
		LCD_Command(0x80 | 0x0D);
		LCD_Char(4);

		byte image85[8] = {B00110, B01000, B10000, B10001, B01011, B00111, B00011, B00001};
		byte image86[8] = {B00111, B00111, B11111, B11111, B11111, B11111, B11111, B11111};
		byte image87[8] = {B10000, B11000, B11000, B11000, B11000, B11000, B11100, B11100};

		LCD_Custom_Char(5, image85);  
		LCD_Custom_Char(6, image86);  
		LCD_Custom_Char(7, image87); 

		LCD_Command(0xc0 | 0x0A);
		LCD_Char(5);
		LCD_Command(0xc0 | 0x0B);
		LCD_Char(6);
		LCD_Command(0xc0 | 0x0C);
		LCD_Char(7);
		_delay_ms(3000); 
}







//Information
/* 
Key base code and functions: 
https://www.electronicwings.com/avr-atmega/lcd-custom-character-display-using-atmega-16-32-

Original Inspirations:
https://www.hackster.io/milespeterson101/an-lcd-dog-friend-b0bdee
https://create.arduino.cc/projecthub/mavrakis_the_optimist/simplest-24h-uno-digital-clock-ever-200342

Custom Glyph Generator:
https://tusindfryd.github.io/screenduino/

Arduino Uno Pinout Diagram:
https://upload.wikimedia.org/wikipedia/commons/c/c9/Pinout_of_ARDUINO_Board_and_ATMega328PU.svg

SetCursor equivalent in pure C:
https://www.microchip.com/forums/m861309.aspx

millis equivalent in pure C:
https://github.com/monoclecat/avr-millis-function 

For the usual 2x16 LCD the cursor addressing takes one command byte computed like this:
For line 1: 0x80 + Column
For line 2: 0xc0 + Column
Where column ranges from 0 (0x00) to 15 (0x0f)

why Serial cannot be used:
https://forum.arduino.cc/t/serial-begin-9600-interfering-with-16x2-dispaly/390029

0, 1 are used by the Serial. You can't use for LCD at the same time.

*/