#define BASE 0x378
#define ENABLE_OFF 0
#define ENABLE_ON 4
#define I_REGISTER 2
#define D_REGISTER 0
#define WRITE_DATA 8
#define READ_DATA 0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <asm/io.h>
#include <time.h>

// LCD display control functions
void display_on(void);
void display_off(void);
void clear_display(void);
void return_home(void);
void entry_mode(void);
void cursor_display_shift(void);
void function_set(void);
void initialize_display(void);
void print_character(int character);

void display_on(void)
{
	outb(12, BASE); 				//Turn on D3 and D4
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn off C1 and C3
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn on C2 while C1 and C3 remains off
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Reset Control pins
	usleep(1);
}

void display_off(void)
{
	outb(8, BASE); 					//Turn on D3 and D4
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn off C1 and C3
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn on C2 while C1 and C3 remains off
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Reset Control pins
	usleep(1);
}

void clear_display(void)
{       
	outb(1, BASE); 					//Turn on D0
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn off C1 and C3
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2);	//Turn on C2 while C1 and C3 remains off
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Reset Control pins
	usleep(0);
}       


void return_home(void)
{       
	outb(2, BASE);					//Turn on D1
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn off C1 and C3
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2);	//Turn on C2 while C1 and C3 remains off
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Reset Control pins
	usleep(0);
}       

void entry_mode(void)
{       
	outb(6, BASE); 					//Turn on D1 and D2
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn off C1 and C3
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2);	//Turn on C2 while C1 and C3 remains off
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Reset Control pins
	usleep(0);
}       

void cursor_display_shift(void)
{       
	outb(20, BASE); 				//Turn on D2 and D4
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn off C1 and C3
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2);	//Turn on C2 while C1 and C3 remains off
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Reset Control pins
	usleep(0);
}       

void function_set(void)
{       
	outb(56, BASE); 				//Turn on D3, D4 and D5
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Turn off C1 and C3
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2);	//Turn on C2 while C1 and C3 remains off
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(I_REGISTER + WRITE_DATA, BASE + 2); 	//Reset Control pins
	usleep(0);
}      

void initialize_display(void)
{
	function_set();
	function_set();
	entry_mode();
	display_on();
	clear_display();
}

void print_character(int character)
{
	outb(D_REGISTER + WRITE_DATA, BASE + 2); 	//Set register to Write Data
	outb(character, BASE); 				// Set the character code
	outb(4 + D_REGISTER + WRITE_DATA, BASE + 2); 	//Enable High
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(D_REGISTER + WRITE_DATA, BASE + 2); 	//Enable Low
	usleep(0); //Wait while Enable (C2) is high so LCD will have time to load the info
}

void second_row(void)
{
	outb(I_REGISTER + WRITE_DATA, BASE + 2);
	outb(128 + 40, BASE);
	outb(4 + I_REGISTER + WRITE_DATA, BASE + 2); 	//Enable High
//	usleep(1); 					//Wait while Enable (C2) is high so LCD will have time to load the info
	outb(D_REGISTER + WRITE_DATA, BASE + 2); 	//Disable High
	usleep(0); //Wait while Enable (C2) is high so LCD will have time to load the info
}