#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include "hardware.h"
#include "lcd.h"

void LCDcycEN() {
	LCD_EN_OUT |= (1 << LCD_EN_BIT);
	_delay_us(1);
	LCD_EN_OUT &= ~(1 << LCD_EN_BIT);
}

void LCDsetbits(uint8_t b) {
	LCD_D4_OUT = b & 0b0001 ? LCD_D4_OUT | ( 1 << LCD_D4_BIT ) : LCD_D4_OUT & ~( 1 << LCD_D4_BIT );
	LCD_D5_OUT = b & 0b0010 ? LCD_D5_OUT | ( 1 << LCD_D5_BIT ) : LCD_D5_OUT & ~( 1 << LCD_D5_BIT );
	LCD_D6_OUT = b & 0b0100 ? LCD_D6_OUT | ( 1 << LCD_D6_BIT ) : LCD_D6_OUT & ~( 1 << LCD_D6_BIT );
	LCD_D7_OUT = b & 0b1000 ? LCD_D7_OUT | ( 1 << LCD_D7_BIT ) : LCD_D7_OUT & ~( 1 << LCD_D7_BIT );
}

void LCDGotoXY(uint8_t x, uint8_t y)
{
	register uint8_t DDRAMAddr;
	switch(y)
	{
	case 0: DDRAMAddr = 0x00+x; break;
	case 1: DDRAMAddr = 0x40+x; break;
	case 2: DDRAMAddr = 0x14+x; break;
	case 3: DDRAMAddr = 0x54+x; break;
	default: DDRAMAddr = 0x00+x;
	}
	LCDsendcmd(1<<7 | DDRAMAddr);
	
}

void WriteLCD(char* data,unsigned char x,unsigned char y)
{
register uint8_t i;
unsigned char data_length;
	data_length = strlen(data);
	LCDGotoXY(x,y);
	if (!data) return;
	for(i=0; i<data_length; i++)
	{
		LCDsendchar(data[i]);
	}
}

void LCDsendcmd(uint8_t c) {
	LCD_RS_OUT &= ~(1 << LCD_RS_BIT);

	LCDsetbits(c >> 4);
	LCDcycEN();
	_delay_us(1);

	LCDsetbits(c);
	LCDcycEN();
	_delay_ms(3);
}

void ClearLCD(void)
{
	LCDsendcmd(1);
}

void LCDsendchar( uint8_t c ) {
	LCD_RS_OUT |= (1 << LCD_RS_BIT);

	LCDsetbits(c>>4);
	LCDcycEN();
	_delay_us(1);

	LCDsetbits(c);
	LCDcycEN();
	_delay_us(40);
}

void LCDinit() {
	LCD_D4_OUT &= ~(1<<LCD_D4_BIT);
	LCD_D5_OUT &= ~(1<<LCD_D5_BIT);
	LCD_D6_OUT &= ~(1<<LCD_D6_BIT);
	LCD_D7_OUT &= ~(1<<LCD_D7_BIT);

	LCD_EN_OUT &= ~(1<<LCD_EN_BIT);
	LCD_RS_OUT &= ~(1<<LCD_RS_BIT);


	LCD_D4_DDR |= 1<<LCD_D4_BIT;
	LCD_D5_DDR |= 1<<LCD_D5_BIT;
	LCD_D6_DDR |= 1<<LCD_D6_BIT;
	LCD_D7_DDR |= 1<<LCD_D7_BIT;

	LCD_EN_DDR |= 1<<LCD_EN_BIT;
	LCD_RS_DDR |= 1<<LCD_RS_BIT;

	_delay_ms(20);

	LCDsetbits(0b0011);
	LCDcycEN();

	_delay_ms(5);
	LCDcycEN();

	_delay_us(150);
	LCDcycEN();

	_delay_us(60);
	LCDsetbits(0b0010);
	LCDcycEN();

	_delay_us(60);

	LCDsendcmd(LCD_CMD_FUNCTION + LCD_CMD_FUNCTION_2LINES + LCD_CMD_FUNCTION_8X10);
	LCDsendcmd(LCD_CMD_DISPMODE + LCD_CMD_DISPMODE_ENTIRE_ON + LCD_CMD_DISPMODE_CURSOR_OFF + LCD_CMD_DISPMODE_BLINK_OFF );
	LCDsendcmd(LCD_CMD_ENTMODE + LCD_CMD_ENTMODE_INCREMENT + LCD_CMD_ENTMODE_NOSHIFT);
	LCDsendcmd(LCD_CMD_CLEAR);
}
