/****************************************/
/*					*/
/*	C driver for sdcc compiler. 	*/
/*	40*4 lcd display		*/
/*					*/
/****************************************/

// line 1 0x00 - 0x27  controller 1
// line 2 0x40 - 0x67  controller 1
// line 3 0x00 - 0x27  controller 2
// line 4 0x40 - 0x67  controller 2

#define DB7	PORTCbits.RC7
#define DB6	PORTCbits.RC6
#define DB5	PORTCbits.RC5
#define DB4	PORTCbits.RC4

#define TB7	TRISCbits.TRISC7
#define TB6	TRISCbits.TRISC6
#define TB5	TRISCbits.TRISC5
#define TB4	TRISCbits.TRISC4

#define E1	PORTCbits.RC2
#define E2	PORTCbits.RC3
#define RW	PORTCbits.RC1
#define RS	PORTCbits.RC0

#define TE1	TRISCbits.TRISC2
#define TE2	TRISCbits.TRISC3
#define TRW	TRISCbits.TRISC1
#define TRS	TRISCbits.TRISC0



/******************* MACRO's *******************/

#define setE	E1 = 1;	
	/*
	if (activeDisplay == 1) 		
		E1 = 1;				
	else					
		E2 = 1;	
	*/

#define clearE	E1 = 0;
	/*
	if (activeDisplay == 1) 		
		E1 = 0;				
	else					
		E2 = 0;	
	*/



#define setWrite  \
	if (modeRW == 1) { \
	TB7 = 0;	\
	TB6 = 0;	\
	TB5 = 0;	\
	TB4 = 0;	\
	RW = 0; 	\
	modeRW = 0;}


#define setRead \
	if (modeRW == 0) { \
	TB7 = 1;	\
	TB6 = 1;	\
	TB5 = 1;	\
	TB4 = 1;	\
	RW = 1;		\
	modeRW = 1;}

	





/*********************** Globals ************************/

unsigned char activeDisplay;
unsigned char modeRW;	 // 0 = write, 1 = read




/************************* Functions ***********************/


void delay_us(unsigned int delay) {
	unsigned int x;
	delay = delay / 8;
	for( x = 0; x < delay; x++ ) { //; Core runs at 48Mhz/12 equals 250ns per cycle
		_asm
		
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		_endasm;
	}

}
void delay_ms(unsigned int delay)
{
	int idx;
	for(idx = 0; idx < delay; idx++ )
		delay_us(1000);
}

void putByte(char byte)	// be sure to set the registers for writing
{	
	setWrite
			
	setE	
	DB7 = (byte >> 7) & 1;
	DB6 = (byte >> 6) & 1;
	DB5 = (byte >> 5) & 1;
	DB4 = (byte >> 4) & 1;
	delay_us(1000);
	clearE	

	// En nu low nibble
	setE
	DB7 = (byte >> 3) & 1;
	DB6 = (byte >> 2) & 1;
	DB5 = (byte >> 1) & 1;
	DB4 = byte & 1;
	delay_us(1000);
	clearE	

}

void nibble()
{
	setE
	delay_us(1000);
	clearE
}


void busyTest(void)
{
	char bit = 0;
		
	RS = 0;
	led_pin = 0;
	setRead
	
	delay_us(500);
	
	while (bit != 0)
	{
		setE
		delay_us(200);
		bit = DB7;
		clearE
		delay_us(200);
	}
	led_pin = 1;
}


void LCDClr()
{
	RS = 0;
	putByte(0x1);
	busyTest();
}

void LCDHome()
{
	RS = 0;
	putByte(0x2);
	busyTest();
}


void LCDPutChar(char character)
{
	RS = 1;
	putByte(character);
	busyTest();
}

void WriteLCD( unsigned char* message )
{
	unsigned char i;
	for( i=0; i<40; i++ )
	{
		if( !message[i] )
			break;
		LCDPutChar(message[i]);
	}
}



void LCD_init()		// make sure that the display is configured accordingly
{	
	TE1 = 0;
	TE2 = 0;
	TRW = 0;
	TRS = 0;
	
	
	RS = 0;
	modeRW = 0;
	activeDisplay = 1;
	
	delay_ms(20);
	
	putByte(0x03);
	delay_ms(10);
	putByte(0x03);
	delay_us(100);
	putByte(0x03);
	delay_us(100);
	
	putByte(0x02);
	delay_us(100);
	putByte(0x02);
	
	delay_ms(10);


	putByte(0x2C);		// write the data interface length, 4-bit, 2 lines, character font: 0b001DNF**, 0x2C
	busyTest();
	
	putByte(0x08);		// turn off the display
	busyTest();
		
	putByte(0x01);		// clear the display
	busyTest();
		
	putByte(0x10);		// cursor move direction: right, no display increment. 0  0  0  1  SC RL *  *     (00010000)
	busyTest();
		
	putByte(0x0F);		// display on, cursor on, blink on. 0x00001DCB
	busyTest();
	
	LCDClr();
}