#include <stdio.h>
#include <inlines/pc.h>

//parallel port definition
#define PARALLEL_PORT		0x378
#define DATA	 		PARALLEL_PORT
#define STATUS	 		PARALLEL_PORT+1
#define CONTROL 		PARALLEL_PORT+2

unsigned char read_ac(unsigned char i);
unsigned char read_ram(unsigned char i);
void initialize_lcm(void);
void clear_lcm(void);
void backlight_on(void);
void backlight_off(void);
void showlcmdata(unsigned char *);

static int	backlight_status=0x00;	//0x00=on, 0x01=off

main(int argc, char *argv[])
{   
	unsigned char	str[20];
	int	i;
	
	
	//Set DD RAM to  and readback the Address Counter
	//If readback = FF, that's mean LCM malfunction
	//Give it 5 shots
	for(i=0; i<5; i++)
	{
		if(read_ac((unsigned char)(i))!=i)	
		{
			printf("!!!!!! LCM no connect or malfunction\n");
			exit(1);
		}
	}
	printf("^_____^   LCM function well\n");
	
	
	sprintf(str,"%s","0123456789abcdefghij");
//	sprintf(str,"%s","ABCDEFGHIJKLMNOPQRST");
	initialize_lcm();
	clear_lcm();
	backlight_on();
	showlcmdata(str);
	delay(1000);
	backlight_off();
	
	for(i=0; i<20; i++)
	{
		//cannot read RAM0 ?????
		printf("The ram %d = %x\n", i, read_ram((unsigned char)(i)));
	}

	
	return;	
}

unsigned char read_ac(unsigned char i)
{	
	
	//Set data ram to 0
    outportb(CONTROL, 0xc8);
    outportb(DATA ,(0x80|i));
    outportb(CONTROL, 0xca);
    delay(1);
    outportb(CONTROL, 0xc8);
    delay(10);
    	
	//try to readback character
    outportb(CONTROL, inportb(CONTROL) | 0x08);	//set LCM to command mode(bit3)
    outportb(CONTROL, inportb(CONTROL) | 0x04);	//set LCM to read mode(bit2)
    outportb(CONTROL, inportb(CONTROL) | 0x20);	//set LPT to read mode(bit5)
    
	outportb(CONTROL, (inportb(CONTROL) | 0x02));
	delay(1);
	outportb(CONTROL, (inportb(CONTROL) & 0xFD));
	delay(10);
 	return inportb(DATA);
}
unsigned char read_ram(unsigned char i)
{	
	//Set data ram to 0
    outportb(CONTROL, 0xc8);
    if(i==0) i=40;
    outportb(DATA ,(0x80|i));
    outportb(CONTROL, 0xca);
    delay(1);
    outportb(CONTROL, 0xc8);
    delay(10);
    	
	//try to readback character
    outportb(CONTROL, inportb(CONTROL) & 0xf7);	//set to data mode(bit3)
    outportb(CONTROL, inportb(CONTROL) | 0x04);	//set to read mode(bit2)
    outportb(CONTROL, inportb(CONTROL) | 0x20);	//set LPT to  read mode(bit5)
    
	outportb(CONTROL, (inportb(CONTROL) | 0x02));
	delay(1);
	outportb(CONTROL, (inportb(CONTROL) & 0xFD));
	delay(10);
 	return inportb(DATA);
}


static void initialize_lcm(void)
{
    outportb(CONTROL, 0xc8);
    outportb(DATA ,0x38);
    outportb(CONTROL, 0xca);
    delay(1);
    outportb(CONTROL, 0xc8);
    delay(10);
    
    outportb(DATA, 0x0c);
    outportb(CONTROL, 0xca);
    delay(1);
    outportb( CONTROL, (0xc8|backlight_status));

    delay(100);
    return;

}

void clear_lcm()
{
    int count;
    char init[10];
    init[0] = 0x0F;		//initialize the Display
    init[1] = 0x01;		//Clear Display
    init[2] = 0x38;		//Dual line 8 bits
    outportb(CONTROL, inportb(CONTROL) & 0xDF);	//set LPT DIR to write
//    delay(100);
    outportb(CONTROL, inportb(CONTROL) | 0x08); //set LCM to command mode
//    delay(100);

    for (count = 0; count <= 2; count++) {
	outportb(DATA, init[count]);
	outportb(CONTROL, (inportb(CONTROL) | 0x02));	//set Enable
	delay(1);
	outportb(CONTROL, (inportb(CONTROL) & 0xFD));	//reset Enable
	delay(100);
    }

}
void backlight_on()
{
    char backup_control;

    backup_control=inportb(CONTROL);
    backup_control&=0xfe;
    outportb(CONTROL, backup_control);
    backlight_status=0x00;	
}

void backlight_off()
{
    char backup_control;

    backup_control=inportb(CONTROL);
    backup_control|=0x01;
    outportb(CONTROL, backup_control);
    backlight_status=0x01;	
}

void showlcmdata(unsigned char *str)
{
    char init[10];
    int count;
    int len;
    
    outportb(CONTROL, inportb(CONTROL) & 0xf7);	//set LCM to data mode(bit3)
    
    len = strlen(str);
    int FLAG = 1;
    for (count = 0; count < len; count++) {
	if (count > 19 && FLAG) {
//	    printblank(19);
	    FLAG = 0;
	}
	outportb(DATA, str[count]);
	outportb(CONTROL, (inportb(CONTROL) | 0x02));
	delay(1);
	outportb(CONTROL, (inportb(CONTROL) & 0xFD));
	delay(10);
    }
    return;
}