#include <avr/io.h>
#include <util/delay.h>

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif

#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

/* ================= Pin Definations stats here ================= */
#define	LCDBUS_PORT	PORTA
#define	LCDBUS_DDR	DDRA

//B.0 - used for LCD RS
//B.1 - used for LCD R/W
//B.2 - used for LCD EN

//D.0 - Increment key
//D.1 - Decrement key
//D.2 - Reset key
//D.3 - Enter/Escape key

/* ================= Function Defined here ================= */
void init_ports(void);
void LCD_init(void);
void LCD_cmd(void);
void LCD_data(void);
void display_msg1(void);
void display_msg2(void);
void delay_1sec(void);
void display_count(int);

/* ================= Program stats here ================= */

int main(void)
{
	init_ports();			//initialize all ports		
	LCD_init();				// LCD initialization routines
	
	int count = 0;
	
	display_msg1();
	delay_1sec();
	display_msg2();	
	
	display_count(count);
	
	while(1)
	{		
		if(bit_is_clear(PIND,0))
		{
			_delay_ms(10);				// debounce delay
			if(bit_is_clear(PIND,0))
			{
				if(count==99)
				{
					count=0;
				}
				else
				{
					count++;
				}
				
				display_count(count);
				
				while(bit_is_clear(PIND,0))
				{
						// wait till key is released
				}
			}
			else
			{
			}
		}			
		else
		{
		}
		if(bit_is_clear(PIND,1))
		{
			_delay_ms(10);				// debounce delay
			if(bit_is_clear(PIND,1))
			{
				if(count==00)
				{
					count=99;
				}
				else
				{
					count--;
				}
				
				display_count(count);
				
				while(bit_is_clear(PIND,1))
				{
						// wait till key is released
				}
			}
			else
			{
			}
		}
		else
		{
		}		
		if(bit_is_clear(PIND,2))
		{
			_delay_ms(10);				// debounce delay
			if(bit_is_clear(PIND,2))
			{
				count=0;
				
				display_count(count);
				
				while(bit_is_clear(PIND,2))
				{
						// wait till key is released
				}
			}
			else
			{
			}
		}
		else
		{
		}
	}
	return 0;
}

void init_ports(void)
{
	cbi(DDRA,0);	//set A.0 as input - Increment key
	cbi(DDRA,1);	//set A.1 as input - Decrement key
	cbi(DDRA,2);	//set A.2 as input - Reset key
	cbi(DDRA,3);	//set A.3 as input - Enter/Escape key
	
	LCDBUS_DDR = 0xFF;
	
	sbi(DDRB,0);	//set B.0 as output - used for LCD RS
	sbi(DDRB,1);	//set B.1 as output - used for LCD R/W
	sbi(DDRB,2);	//set B.2 as output - used for LCD EN
	
	_delay_ms(5000);
	_delay_ms(5000);
	
	return;
}


void LCD_init(void)
{
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x38;
	LCD_cmd();
	LCDBUS_PORT = 0x0c;
	LCD_cmd();
	LCDBUS_PORT = 0x01;
	LCD_cmd();
	LCDBUS_PORT = 0x06;
	LCD_cmd();
	return;				// not sure weather to use this or not
}

void LCD_cmd(void)
{
	cbi(PORTB,0);	//clear B.0 - used for LCD RS
	cbi(PORTB,1);	//clear B.1 - used for LCD R/W
	sbi(PORTB,2);	//set B.2 - used for LCD EN
	_delay_us(5);
	cbi(PORTB,2);	//clear B.2 - used for LCD EN
	_delay_ms(5);
	return;				// not sure weather to use this or not
}

void LCD_data(void)
{
	sbi(PORTB,0);	//clear B.0 - used for LCD RS
	cbi(PORTB,1);	//clear B.1 - used for LCD R/W
	sbi(PORTB,2);	//set B.2 - used for LCD EN
	_delay_us(5);
	cbi(PORTB,2);	//clear B.2 - used for LCD EN
	_delay_ms(5);
	return;				// not sure weather to use this or not
}


void display_msg1(void)
{
	unsigned char LCD_msg1[]="Welcome to      KeyCount Program";
	int char_count;
	LCDBUS_PORT = 0x01;
	LCD_cmd();	
	for(char_count=0;char_count<16;char_count++)
	{		
		LCDBUS_PORT = LCD_msg1[char_count];
		LCD_data();
	}

	LCDBUS_PORT = 0xc0;
	LCD_cmd();
	
	for(char_count=16;char_count<32;char_count++)
	{			
		LCDBUS_PORT = LCD_msg1[char_count];
		LCD_data();
	}
	return;
}

void display_msg2(void)
{
	unsigned char LCD_msg2[]="Pres Inc Dec KeyCount =         ";
	int char_count;
	LCDBUS_PORT = 0x01;
	LCD_cmd();	
	for(char_count=0;char_count<16;char_count++)
	{		
		LCDBUS_PORT = LCD_msg2[char_count];
		LCD_data();
	}

	LCDBUS_PORT = 0xc0;
	LCD_cmd();
	
	for(char_count=16;char_count<32;char_count++)
	{			
		LCDBUS_PORT = LCD_msg2[char_count];
		LCD_data();
	}
	return;
}

void delay_1sec(void)
{
	int delcnt;
	for(delcnt=0; delcnt<20; delcnt++)
	{
		_delay_ms(50);
	}
}

void display_count(int count_f)
{
	int count_in_hex_1;
	int count_in_hex_2;	
	int quot;
	int rem;
	
	quot = count_f / 10;
	rem = count_f % 10;
	
	count_in_hex_1 = quot + 48;
	count_in_hex_2 = rem + 48;

	LCDBUS_PORT = 0xc8;
	LCD_cmd();
	
	LCDBUS_PORT = count_in_hex_1;
	LCD_data();
	
	LCDBUS_PORT = 0xc9;
	LCD_cmd();
	
	LCDBUS_PORT = count_in_hex_2;
	LCD_data();
	
	return;
}

// ************* END of Program *************

