#include "display.h"
#include "board.h"
#include "chip.h"
#include "common_utils.h"
#include <stdio.h>

/* Global variables */
static const Pin LCD_DB[]  = {PINS_LCD_DB};
static const Pin LCD_E = PIN_LCD_E;
static const Pin LCD_RW = PIN_LCD_RW;
static const Pin LCD_RS = PIN_LCD_RS; 

int g_nCurrentLine = 0;
int token = 0;


void LCD_E_t(void)
{
    PIO_Set(&LCD_E);
    PIO_Clear(&LCD_E);
}

/* ---------------------------------------------------------------------------------------- */
uint8_t lcd_BUSY(void)
{
    uint32_t BUSY = 0;

    LCD_DB[7].pio->PIO_ODR = LCD_DB[7].mask; /* set BD7 as input */
    PIO_Set(&LCD_RW);
    PIO_Set(&LCD_E);
    BUSY = LCD_DB[7].pio->PIO_PDSR & LCD_DB[7].mask; 
    PIO_Clear(&LCD_E);
    PIO_Clear(&LCD_RW);

    LCD_DB[7].pio->PIO_OER = LCD_DB[7].mask;
    if (BUSY)
        return 1;
    else
        return 0;
}

void lcd_write(uint8_t data,uint8_t rs) 
{
	int i;

    while(lcd_BUSY()); /* if lcd is BUSY - wait */ 
    /* choosing write type */
    if (rs)    
       PIO_Set(&LCD_RS); /* write data */
    else     
       PIO_Clear(&LCD_RS);  /* write instruciton */
     
    /* set data pins */  
    for (i=0; i<8; i++)
    {
        if (data & (1<<i))
            PIO_Set(&LCD_DB[i]);
    }
    LCD_E_t();
    /* Deactive all pins */
    for (i=0; i<8; i++)
        PIO_Clear(&LCD_DB[i]);
    PIO_Clear(&LCD_RW);
    PIO_Clear(&LCD_RS);
}

void lcd_char(uint8_t data)
{
	token++;
    if (data=='\n') 
	{
		if (g_nCurrentLine >= 1)
			lcd_setline(0);
		else
			lcd_setline(g_nCurrentLine+1);
	}
	else
    {
        if ((token > 16)&&(g_nCurrentLine == 0))
            lcd_setline(1);
        lcd_write(data,1);
    }
} 

void lcd_instr(uint8_t instr)
{
	lcd_write(instr,0);
}

void lcd_init(void)
{
    int i;
    /* Inicialization port interface for LCD*/
    PIO_Configure(LCD_DB, PIO_LISTSIZE(LCD_DB));
    PIO_Configure(&LCD_E, PIO_LISTSIZE(LCD_E));
    PIO_Configure(&LCD_RW, PIO_LISTSIZE(LCD_RW));
    PIO_Configure(&LCD_RS, PIO_LISTSIZE(LCD_RS));
    for (i=0; i<8; i++)
        PIO_Clear(&LCD_DB[i]);
    PIO_Clear(&LCD_E);
    PIO_Clear(&LCD_RW);
    PIO_Clear(&LCD_RS); 
    /* wait 16ms or more after power-on (according to doc.: wait time > 15 ms) */
    Delay(16);
    /* initial write to lcd */
    PIO_Set(&LCD_DB[4]);
    PIO_Set(&LCD_DB[5]);
    LCD_E_t();
    /* wait 5 ms (according to doc.: wait time > 4.1 ms), BF can not be checked */
    Delay(5);
    /* repeat last command  */
    LCD_E_t();     
    Delay(2);  //110us
    /* Configure to 8bit interface by repeating last command */
    LCD_E_t();
    /* BF can be checked now */
    Delay(10);           // zatim jen pro jistotu       1000us
    for (i=0; i<8; i++)
        PIO_Clear(&LCD_DB[i]);
	/* start config (according to doc.) */
	lcd_instr(0x38); /* 2 lines, 5x8 dots format */
    lcd_instr(0x08); /* display off */
    lcd_clrscr();  /* display clear */
    lcd_instr(0x06);  /* Entry Mode Set: moves to right; Shift of entire display disabled */ 
    lcd_instr(0x0D);  /* display on; cursor on and blink */
 
	
/*  lcd_home;//set cursor to home and clear the cursor
	*/
}

void lcd_setline(uint8_t _line)
{
	switch(_line)
	{
		case 0: lcd_instr((1<<0x07) | start_adress_line1); break;
		case 1: lcd_instr((1<<0x07) | start_adress_line2); break;
		default:lcd_instr((1<<0x07) | start_adress_line1); break;
	}
	g_nCurrentLine = _line;
    token = 0;
}


void lcd_string(char *text)
{
	char c;
    while ( (c = *text++) )  lcd_char(c);
}

void lcd_number(uint8_t data)
{
    lcd_char(data/100 + 48);
    lcd_char((data%100)/10 + 48);
    lcd_char(data%10 + 48);                
}


void lcd_gotoxy(uint8_t x, uint8_t y)
{
   	switch (y) 
	{
		case 0:lcd_instr((1<<0x07) | (start_adress_line1+x)); /*0x07 set DD RAM address, */
               g_nCurrentLine = 0; 
               break;  
    	case 1:lcd_instr((1<<0x07) | (start_adress_line2+x));
               g_nCurrentLine = 1;
               break;
		default: break;
	}
    token = x;
} 

void lcd_clrscr(void)
{
	g_nCurrentLine = 0;
    token = 0;
   	lcd_instr(1<<0);    
}

void lcd_home(void)
{
	g_nCurrentLine = 0;
    lcd_instr(1<<1);
}

void lcd_clearline(uint8_t _line)
{
    lcd_setline(_line);
    lcd_string("                ");
    lcd_setline(_line);
}                       
