/*
 * LCD-Function-Code (181657-da-01-en-LCD_MOD_STN_BLAU_NEG_LED_WEISS_20X4)
 * 	EXAMPLES:
 * 				sendcharacter(0x56); 					//Display "V" (ASCII) (at current Cursor Position)
 * 				sendstring("Test");						//Displaying Test (at current Cursor Position)
 * 				sendintegertolocation(1,3,105); 		//(x,y,integer) Displaying as Decimal
 * 				senddecimalasbinarytolocation(1,4,c); 	//(x,y,integer) Displaying as Binary
 * 				sendstringtolocation(x,y,finished); 	//(x,y,char)	Displaying whole characterstring
 *
*/

#ifndef LCD
#define LCD

#include <stdio.h> // used for snprintf: store int into char


GPIO__OUTPUT(Enable, E, 4);				// Enable
GPIO__OUTPUT(ReadWrite, C, 13);			// R/W
GPIO__OUTPUT(FunctionSelect, E, 6);		// Rs

GPIO__IO(DB0, E, 5); //PIN E5 ist Input/Output PIN und unter DB0 erreichbar
GPIO__IO(DB1, E, 3);
GPIO__IO(DB2, B, 8);
GPIO__IO(DB3, B, 7);
GPIO__IO(DB4, B, 4);
GPIO__IO(DB5, B, 5);
GPIO__IO(DB6, D, 7);
GPIO__IO(DB7, D, 6);

void checkbusystate();
void transferinfo();
void sendcommand (unsigned char command);
void init_LCD ();
void sendcharacter(unsigned char character);
void sendstring(const char *characterstring);
void gotoLCDlocation(uint8_t x, uint8_t y);
void sendstringtolocation(uint8_t x, uint8_t y, const char *characterstring);
void sendintegertolocation(uint8_t x, uint8_t y, uint16_t IntegerToDisplay);
void senddecimalasbinarytolocation (uint8_t x, uint8_t y, uint16_t number);

char firstColumnPositionsForLCD[4] = {0, 64, 20, 84}; //Zeilenanfangs Index!!!


void checkbusystate()
{
	DB0::setInput();
	DB1::setInput();
	DB2::setInput();
	DB3::setInput();
	DB4::setInput();
	DB5::setInput();
	DB6::setInput();
	DB7::setInput();

	ReadWrite::setOutput(xpcc::gpio::HIGH);
	xpcc::delay_ms(1);
	FunctionSelect::setOutput(xpcc::gpio::LOW);

	while (DB7::read() == 1)
	{
		Enable::setOutput(xpcc::gpio::HIGH);
		asm volatile ("nop");
		asm volatile ("nop");
		Enable::setOutput(xpcc::gpio::LOW);

	}

	DB0::setOutput();
	DB1::setOutput();
	DB2::setOutput();
	DB3::setOutput();
	DB4::setOutput();
	DB5::setOutput();
	DB6::setOutput();
	DB7::setOutput();

}

void transferinfo()
{
	Enable::setOutput(xpcc::gpio::HIGH);
	asm volatile ("nop");
	asm volatile ("nop");
	Enable::setOutput(xpcc::gpio::LOW);
}

void sendcommand (unsigned char command)
{
	checkbusystate();

	if(command & 0x01) DB0::setOutput(xpcc::gpio::HIGH);
	else DB0::setOutput(xpcc::gpio::LOW);
	if(command & 0x02) DB1::setOutput(xpcc::gpio::HIGH);
	else DB1::setOutput(xpcc::gpio::LOW);
	if(command & 0x04) DB2::setOutput(xpcc::gpio::HIGH);
	else DB2::setOutput(xpcc::gpio::LOW);
	if(command & 0x08) DB3::setOutput(xpcc::gpio::HIGH);
	else DB3::setOutput(xpcc::gpio::LOW);
	if(command & 0x10) DB4::setOutput(xpcc::gpio::HIGH);
	else DB4::setOutput(xpcc::gpio::LOW);
	if(command & 0x20) DB5::setOutput(xpcc::gpio::HIGH);
	else DB5::setOutput(xpcc::gpio::LOW);
	if(command & 0x40) DB6::setOutput(xpcc::gpio::HIGH);
	else DB6::setOutput(xpcc::gpio::LOW);
	if(command & 0x80) DB7::setOutput(xpcc::gpio::HIGH);
	else DB7::setOutput(xpcc::gpio::LOW);

	ReadWrite::setOutput(xpcc::gpio::LOW);
	xpcc::delay_ms(1);
	FunctionSelect::setOutput(xpcc::gpio::LOW);

	transferinfo();

	DB0::setOutput(xpcc::gpio::LOW);
	DB1::setOutput(xpcc::gpio::LOW);
	DB2::setOutput(xpcc::gpio::LOW);
	DB3::setOutput(xpcc::gpio::LOW);
	DB4::setOutput(xpcc::gpio::LOW);
	DB5::setOutput(xpcc::gpio::LOW);
	DB6::setOutput(xpcc::gpio::LOW);
	DB7::setOutput(xpcc::gpio::LOW);
}

void init_LCD ()
{
		Enable::setOutput(xpcc::gpio::LOW);
		FunctionSelect::setOutput(xpcc::gpio::LOW);
		ReadWrite::setOutput(xpcc::gpio::LOW);

		xpcc::delay_ms(15);

		DB0::setOutput(xpcc::gpio::LOW);
		DB1::setOutput(xpcc::gpio::LOW);
		DB2::setOutput(xpcc::gpio::LOW);
		DB3::setOutput(xpcc::gpio::LOW);
		DB4::setOutput(xpcc::gpio::LOW);
		DB5::setOutput(xpcc::gpio::LOW);
		DB6::setOutput(xpcc::gpio::LOW);
		DB7::setOutput(xpcc::gpio::LOW);

		sendcommand(0x01); // == 0b.0000.0001 ->CLEAR-SCREEN
		xpcc::delay_ms(2);

		sendcommand(0x38); // == 0b.0011.1000 ->Turn to 8bit-Mode & 4 Lines-Display
		xpcc::delay_us(50);

		sendcommand(0x0C); // == 0b.0000.1100 ->Display is on , Cursor is OFF
		xpcc::delay_us(50);

}
void sendcharacter(unsigned char character)
{
	checkbusystate();

	if(character & 0x01) DB0::setOutput(xpcc::gpio::HIGH);
	else DB0::setOutput(xpcc::gpio::LOW);
	if(character & 0x02) DB1::setOutput(xpcc::gpio::HIGH);
	else DB1::setOutput(xpcc::gpio::LOW);
	if(character & 0x04) DB2::setOutput(xpcc::gpio::HIGH);
	else DB2::setOutput(xpcc::gpio::LOW);
	if(character & 0x08) DB3::setOutput(xpcc::gpio::HIGH);
	else DB3::setOutput(xpcc::gpio::LOW);
	if(character & 0x10) DB4::setOutput(xpcc::gpio::HIGH);
	else DB4::setOutput(xpcc::gpio::LOW);
	if(character & 0x20) DB5::setOutput(xpcc::gpio::HIGH);
	else DB5::setOutput(xpcc::gpio::LOW);
	if(character & 0x40) DB6::setOutput(xpcc::gpio::HIGH);
	else DB6::setOutput(xpcc::gpio::LOW);
	if(character & 0x80) DB7::setOutput(xpcc::gpio::HIGH);
	else DB7::setOutput(xpcc::gpio::LOW);

	ReadWrite::setOutput(xpcc::gpio::LOW);
	xpcc::delay_ms(1);
	FunctionSelect::setOutput(xpcc::gpio::HIGH);

	transferinfo();

	DB0::setOutput(xpcc::gpio::LOW);
	DB1::setOutput(xpcc::gpio::LOW);
	DB2::setOutput(xpcc::gpio::LOW);
	DB3::setOutput(xpcc::gpio::LOW);
	DB4::setOutput(xpcc::gpio::LOW);
	DB5::setOutput(xpcc::gpio::LOW);
	DB6::setOutput(xpcc::gpio::LOW);
	DB7::setOutput(xpcc::gpio::LOW);
}

void sendstring(const char *characterstring) //Without Location
{
	while(*characterstring > 0)
	{
		sendcharacter(*characterstring ++);
	}
}

void gotoLCDlocation(uint8_t x, uint8_t y)
{
	//x==Spalte(1-20)
	//y==Zeile(1-4)

	char XY = 0x80; // 0x80 for Cursorpositioncommand coming next 7 Bits
	XY += firstColumnPositionsForLCD[(y-1)] + (x-1); //7-Bits for Location
	sendcommand(XY); // 0x80 for Cursorpositioncommand coming next 7 Bits
}

void sendstringtolocation(uint8_t x, uint8_t y, const char *characterstring)
{
	gotoLCDlocation(x,y);
	sendstring(characterstring);
}

void sendintegertolocation(uint8_t x, uint8_t y, uint16_t IntegerToDisplay)
{
	char StringToDisplay[1];
	unsigned int count=0;

	int IntegerToDisplay_temp = IntegerToDisplay;
	do ++count; while(IntegerToDisplay_temp/=10);
	count++;


  	snprintf ( StringToDisplay, count, "%d", IntegerToDisplay);

	for (unsigned int i=0; i<count;i++) sendstring(" ");

	sendstringtolocation(x,y,StringToDisplay);
}

void senddecimalasbinarytolocation (uint8_t x, uint8_t y, uint8_t number)
{
	char result[] = {'0','0','0','0','0','0','0','0','\0'};
	//const size_t size = sizeof(number) * 8;

	uint8_t index = 8;
	do {
		result[--index] = '0' + (number & 1);
	} while (number >>= 1);

	char* finished = result;

	sendstringtolocation(x,y,finished);
}

#endif
