#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/sfr_defs.h>
#include <stdlib.h>
 
 //LCD DEFS
#define LCD_VEE PB0
#define LCD_RS 	PB1
#define LCD_RW 	PB2
#define LCD_E 	PB3
#define CLR_DISP 0X01
#define C_ON_NBLINK_DISP 0X0E
#define C_off_DISP 0X0C
#define SEC_ROW_DISP 0XC0
#define RET_HOME_DISP 0X02


// KBD DEFS
#define row1 PD2
#define row2 PD3

#define col1 PD5
#define col2 PD4
#define col3 PD1
#define col4 PD0

//OTHER DEFS
#define snd  PD6



// CONST DEFS
#define show_time 255
#define kbd_scan_times 20



/*#define new_b 7
#define kbd_flag 7
*/

// GLOBAL VARS
volatile char kbd_button = 0;
volatile char kbd_flag =0;
volatile char time	= 0;

 

// KBD PROTOTYPES
char p_code_get(void);
void timer_init(void);
char read_collums(char);
void scan_kbd(void);



// LCD PROTOTYPES
void LCD_command_4(char command);
void LCD_putchar_4(char data);
char LCD_getaddr_4(void);
void LCD_wait_4(void);
void LCD_init_4(void);
void LCD_write_4(char* dstring);



//OTHER PROTOTYPES
void delay(char temp );
void sound (char s_dur);


void main (void)
{


DDRB|=0X01;
PORTB = 0X00;

// T0 INIT
timer_init();

sound (100);

// LCD INIT

LCD_init_4();
LCD_wait_4();
LCD_write_4( "STARTING");
LCD_wait_4();
LCD_command_4(SEC_ROW_DISP);
LCD_wait_4();
for (char I =0; I<8; I++)
{
LCD_command_4(C_ON_NBLINK_DISP);
LCD_wait_4();
LCD_putchar_4(0xff);
LCD_wait_4();
//LCD_command_4(C_off_DISP);
//LCD_wait_4();
for(char j=0; j<20; j++) delay(255);
}
LCD_command_4(CLR_DISP);
LCD_wait_4();
LCD_write_4("ENTER");
LCD_wait_4();
LCD_command_4(SEC_ROW_DISP);
LCD_wait_4();

// KBD INIT
DDRD |= (1<<row1)|(1<<row2)|(1<<snd); // outputs

DDRD &=(~(1<<col1))|(~(1<<col2))|(~(1<<col3))|(~(1<<col4));// inputs

PORTD |=(1<<col1)|(1<<col2)|(1<<col3)|(1<<col4);//pull up

 // START
 //*************************************************
 //
 //*************************************************
sei();
// main control loop
do{
if (kbd_flag == 1)
{
cli();
sound(5);
LCD_command_4(C_ON_NBLINK_DISP);
LCD_wait_4();
LCD_putchar_4( kbd_button | 0x50);
LCD_wait_4();
LCD_command_4(C_off_DISP);
LCD_wait_4();
LCD_command_4(RET_HOME_DISP);
LCD_wait_4();
LCD_command_4(SEC_ROW_DISP);
LCD_wait_4();
for(char i=0;i<20;i++) delay(255);
sound(5);
kbd_flag = 0;
sei();
}
else

asm volatile ("nop");

}while(1);

}

//***********************************************
//
//*************************************************


// INTERRUPTs

INTERRUPT(SIG_OVERFLOW0 )
{


if( kbd_flag==1)
{
time++;
return;
}
else
//scan kbd
scan_kbd();


}





// func's

// kbd support

void scan_kbd(void)
{

static char p_code  ;
static char new_b ;
static char kbd_count ;
static char button ;

// check for any button
PORTD &= (~(1<<row2));
PORTD &= (~(1<<row1));
asm volatile("nop");
if(((PIND & 0xbf)^0x33)==0)// read pind mask sound check for button
{
new_b = 0;// no button detected
return;
}

else

p_code = p_code_get();	//  button detected

if (!(new_b))			// 1st time detected
{
new_b = 1;
kbd_count = kbd_scan_times;			// 20 times for detection same button 80 ms
button = p_code;
return;
}
else					//  no 1st time detected
if( p_code== button)	// is last time the same button
{
	if(--kbd_count)	// not enough times dettected
	return;
	else				//  enough times dettected
{
	kbd_flag = 1;		// use  P_code
	kbd_button = p_code;	// export p_code
	new_b = 0;				// prepare for next button cycle
	return;
}
}
else					// last time was not the same button
{
new_b = 0;
return;
}


}

// take position code of button
char p_code_get(void)
{
char temp=0;


PORTD &=(~ (1<<row1));		// 1st row -> 0
PORTD |= (1<<row2);		// 2nd row -> 1


temp = read_collums( 1);
if (temp == 0xff)
// read and mask collums
{
PORTD &=(~ (1<<row2));		// 2st row -> 0
PORTD |= (1<<row1);		// 1st row -> 1

temp = read_collums( 2);

return( temp);
}
else
return (temp);

}
 
 
 
 
 
 
 
 
 
 // coll reader
 char read_collums( char a_row)
 {
 
 
 char temp1;
 
 // read and mask collums
switch (PIND & 0x33) {

case 0x32:
	{
	switch (a_row){
	case 1:
	temp1 = 1;
	break;
	case 2:
	temp1 = 5;
	break;
	default:
	temp1 = 0xff;
	break;
	}
	}
	break;
case 0x31:
	{
	switch (a_row) {
	case 1:
	temp1 = 2;
	break;
	case 2:
	temp1 = 6;
	break;
	default:
	temp1 = 0xff;
	break;
	}
	}
	break;

case 0x23:
	{
	switch (a_row) {
	case 1:
	temp1 = 3;
	break;
	case 2:
	temp1 = 7;
	break;
	default:
	temp1 = 0xff;
	break;
	}
	}
	break;
case 0x13:
	{
	switch (a_row){
	case 1:
	temp1 = 4;
	break;
	case 2:
	temp1 = 8;
	break;
	default:
	temp1 = 0xff;
	break;
	}
	}
	break;	
default:
	temp1 = 0xff;
	break;
	}

 return (temp1);
 }
 
 
 
 //lcd support

//FUNCS

void LCD_command_4(char command )
{
DDRB |= 0xFe;    //pb0 free
PORTB &= 0x01;    
PORTB|=(command &0xF0);  // high nibble of the comm
PORTB |= (1<<LCD_E);
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
PORTB &= ~(1<<LCD_E);
PORTB &= 0x01;
PORTB |= ((command << 4)& 0xF0);
PORTB |= (1<<LCD_E);
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
PORTB &= ~(1<<LCD_E);
DDRB &= 0x0F;
PORTB &= 0x01; 
}
//**************************************************************************8
void LCD_putchar_4(char data)

{
DDRB |= 0xFe;    //pb0 free
PORTB &= 0x01;    
PORTB|=(data &0xF0);  // high nibble of the comm

PORTB|=( (1<<LCD_E) | ( 1<< LCD_RS));

asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");

PORTB &= ~(1<<LCD_E);
PORTB &= 0x0F;
PORTB |= ((data << 4)& 0xF0);
PORTB|= (1<<LCD_E) ;

asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");

PORTB &= ~( (1<<LCD_E) | ( 1<< LCD_RS));

DDRB &= 0x0F;
PORTB &= 0x01;
}

//*******************************************************************


char LCD_getaddr_4(void)
{
int temp =0;
DDRB &=0X0F;
DDRB|= 0X0E;


PORTB &= ~(1<<LCD_RS);

PORTB|=( (1<<LCD_E) | ( 1<< LCD_RW));

asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");

temp = (PINB & 0XF0);

PORTB &= ~(1<<LCD_E);

asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");

PORTB |= (1<<LCD_E);

asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");

temp|= ((PINB>>4)&0X0F);

PORTB &= ~( (1<<LCD_E) | ( 1<< LCD_RW));

DDRB &=0X0F;
	return (temp);
}

//*****************************************************************

void LCD_wait_4(void)
{

while((LCD_getaddr_4()&0X80) == 0X80);

}


//*************************************************************
void LCD_init_4(void)
{

DDRB |= 0XFE;
PORTB &= 0X01;

delay(255);


for(char i =0;i<4;i++)
	{
	if(i==3) PORTB = ((PORTB & 0X0F)| 0X20);
	
	else PORTB = ((PORTB & 0X0F)| 0X30);
	
	
	PORTB |= (1<<LCD_E);
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");
	asm volatile ("nop");

	PORTB &= ~ (1<<LCD_E);
	asm volatile ("nop");
	delay(255-(0X0C<<i));
	}
LCD_command_4(0x28);	
LCD_wait_4();	

LCD_command_4(0x06);	
LCD_wait_4();	

LCD_command_4(0x0F);	
LCD_wait_4();	

LCD_command_4(0x01);	
LCD_wait_4();


}		

 //*************************************************************************
 void LCD_write_4(char* dstring)
{
//is the character pointed at by dstring a zero? If not, write character to LCD
while(*dstring)
{
//if the LCD is bus, let it finish the current operation
LCD_wait_4();
//the write the character from dstring to the LCD, then post-inc the dstring is pointing at.
LCD_putchar_4(*dstring++);
}
}





// other funcs


//*************************************************************************
void sound (char s_dur)
 {
char temp =0;
 #define snd PD6
 DDRD |=(1<<snd);
 PORTD|=(1<<snd);
 
 do {
 loop_until_bit_is_set(TIFR,TOV0);
temp ++;
 TIFR|=(1<<TOV0);
 }while (temp<s_dur);
 
 PORTD&=(~(1<<snd));
 }

//***************************************************************
// 4 ms interrupt
 void timer_init(void)
 {
 TCCR0 = 3;
 TIMSK |= (1<<TOIE0);
 TIFR |=(1<< TOV0);
 }
 
 //************************************************************
void delay(char temp)
{
 while (temp)
 {
 unsigned char i = 255;
 while (i)
 i -- ;
 temp -- ;
 }
 }
 
 