/* Driver k Alfanumerickemu LCD displayi s radicem HD44780 */

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#include "LCD_HD44780.h"
#include "PIN_config.h"				// Definice nazvu pinu a portu a makra pro jejich ovladani
#include "stm32f10x_rcc.h"
#include "DS18B20.h"				// Definice chybneho udaje o teplote
#include "delay.h"

volatile uint8_t souradnice_x = 0;
volatile uint8_t souradnice_y = 0;

// Vlastni znaky
const uint8_t znak_sipka_vpravo[] = {0x00, 0x04, 0x02, 0x1F, 0x02, 0x04, 0x00, 0x00};		 
const uint8_t znak_sipka_vlevo[] = 	{0x00, 0x04, 0x08, 0x1F, 0x08, 0x04, 0x00, 0x00};
const uint8_t znak_sipka_nahoru[] = {0x04, 0x0E, 0x15, 0x04, 0x04, 0x04, 0x04, 0x00};
const uint8_t znak_sipka_dolu[] = 	{0x04, 0x04, 0x04, 0x04, 0x15, 0x0E, 0x04, 0x00};
const uint8_t znak_stupen[] = 		{0x18, 0x1B, 0x04, 0x04, 0x04, 0x04, 0x03, 0x00};

extern uint8_t Time_Hodiny;
extern uint8_t Time_Minuty;
extern uint8_t Time_Vteriny;
extern uint8_t Time_Den;
extern uint8_t Time_Mesic;
extern uint16_t Time_Rok;
extern uint8_t Time_DenVTydnu;
extern u16 SummerTimeCorrect;

/* ---------------------------------------------
 Inicializace LCD do 4-bit modu s nastavenim
 smeru portu a smazanim obsahu LCD
 -------------------------------------------- */
void LCD_HD44780_Init(void)
{
	vTaskDelay(170*portTICK_FOR_1MS);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
	LCD_Out();						// Nastavi datove a ridici piny pripojene k LCD jako vystupy
	
	LCD_D7_High();
	LCD_D6_High();
	LCD_D5_High();
	LCD_D4_High();

	LCD_D7_Low();
	LCD_D6_Low();
	LCD_D5_Low();
	LCD_D4_Low();
												// PC6789 6789
	LCD_HD44780_Write(0x28,LCD_instrukce);		// 0b0010 1000
	LCD_HD44780_Write(0x28,LCD_instrukce);		// 0b0010 1000
	LCD_HD44780_Write(0x0C,LCD_instrukce);		// 0b0000 1100
	LCD_HD44780_Write(0x06,LCD_instrukce);		// 0b0000 0110

	LCD_HD44780_Write(0x28,LCD_instrukce);		// 0b0010 1000
	LCD_HD44780_Write(0x28,LCD_instrukce);		// 0b0010 1000
	LCD_HD44780_Write(0x0C,LCD_instrukce);		// 0b0000 1100
	LCD_HD44780_Write(0x06,LCD_instrukce);		// 0b0000 0110
	
	// Eventuelni nahrani lastnich znaku
	LCD_HD44780_NahratZnak(Char_SipkaVpravo,znak_sipka_vpravo);
	LCD_HD44780_NahratZnak(Char_SipkaVlevo,znak_sipka_vlevo);
	LCD_HD44780_NahratZnak(Char_SipkaNahoru,znak_sipka_nahoru);
	LCD_HD44780_NahratZnak(Char_SipkaDolu,znak_sipka_dolu);
	LCD_HD44780_NahratZnak(Char_StupenCelsia,znak_stupen);

	LCD_HD44780_Clear();
	LCD_HD44780_Home();
}

/* --------------------------------------------
 Zapsani instrukce nebo obrazovych dat do LCD
 ------------------------------------------- */
void LCD_HD44780_Write(uint8_t cmd, uint8_t typ)
{
	uint8_t		cmd_cast;
	uint8_t 	del;		// promenna pro delay u pulzu na Enable LCD

	if (typ==LCD_instrukce)
	{
		LCD_RS_Low();		// Nastaveni RS podle toho jestli se posila instrukce nebo obrazova data
	}
	else
	{
		LCD_RS_High();
	}

	cmd_cast=cmd&0xF0;						// Vymaskovani hornich 4-bitu - odesilaji se nejdrive
	if(cmd_cast&(1<<7))
	{ 
		LCD_D7_High()
	}
	else
	{
		LCD_D7_Low();
	};
	if(cmd_cast&(1<<6))
	{
		LCD_D6_High();
	}
	else
	{
		LCD_D6_Low();
	}
	if(cmd_cast&(1<<5))
	{
		LCD_D5_High();
	}
	else
	{
		LCD_D5_Low();
	}
	if(cmd_cast&(1<<4))
	{
		LCD_D4_High();
	}
	else
	{
		LCD_D4_Low();
	}

	LCD_E_Pulz;

	cmd_cast=cmd&0x0F;						// Vymaskovani dolnich 4-bitu - odesilaji se nejdrive
	if(cmd_cast&(1<<3))
	{ 
		LCD_D7_High()
	}
	else
	{
		LCD_D7_Low();
	}
	if(cmd_cast&(1<<2))
	{
		LCD_D6_High();
	}
	else
	{
		LCD_D6_Low();
	}
	if(cmd_cast&(1<<1))
	{
		LCD_D5_High();
	}
	else
	{
		LCD_D5_Low();
	}
	if(cmd_cast&(1<<0))
	{
		LCD_D4_High();
	}
	else
	{
		LCD_D4_Low();
	}

	LCD_E_Pulz;

	_delay_us(550);			// Melo by byt 60us
}

/* --------------------------------------------
 Smazani obsahu LCD
 ------------------------------------------- */
void LCD_HD44780_Clear(void)
{
	LCD_HD44780_Write(LCD_Instrukce_Clear,LCD_instrukce);
	souradnice_x = 0;
	souradnice_y = 0;

	vTaskDelay(2*portTICK_FOR_1MS);
}

/* --------------------------------------------
 Nastavi pozici ukazatele na 0,0
 (levy horni roh)
 ------------------------------------------- */
void LCD_HD44780_Home(void)
{
	LCD_HD44780_Write(LCD_Instrukce_Home,LCD_instrukce);
	souradnice_x = 0;
	souradnice_y = 0;
	vTaskDelay(2*portTICK_FOR_1MS);
}

/* --------------------------------------------
 Nastavi pozici ukazatele na souradnice x a y
 ------------------------------------------- */
void LCD_HD44780_GoTo(uint8_t x, uint8_t y)
{
	if( y == 0 )
    {	LCD_HD44780_Write(( 1<<7 ) + 0x00 + x ,LCD_instrukce) ;
		souradnice_y = 0 ;
	}
    else if( y == 1 )
    {	LCD_HD44780_Write(( 1<<7 ) + 0x40 + x ,LCD_instrukce) ;
		souradnice_y = 1 ;
	}	
	souradnice_x = x;
	_delay_us(600);			// Melo by byt 40us
}

/* --------------------------------------------
 Zapise jeden znak na LCD
 ------------------------------------------- */
void LCD_HD44780_PutChar(uint8_t znak)
{
	if(( souradnice_x == 20 ) && ( souradnice_y == 0 ))
	{
		LCD_HD44780_GoTo(0,1);
	}
	else if(( souradnice_x == 20 ) && ( souradnice_y == 1 ))
	{
		LCD_HD44780_GoTo(0,0);
	}
	LCD_HD44780_Write(znak,LCD_data);
	souradnice_x++;
}

/* --------------------------------------------
 Zapise retezec na LCD
 ------------------------------------------- */
void LCD_HD44780_PutString(const char *s)
{
    register char c ;

    while(( c = *s++ ))
        LCD_HD44780_PutChar( c ) ;
}

/* --------------------------------------------
 Zapne nebo vypne kurzor LCD
 ------------------------------------------- */
void LCD_HD44780_Cursor(uint8_t stav)
{
	if(stav==ON)
	{
		LCD_HD44780_Write(LCD_Instrukce_CursorON,LCD_instrukce);
	}
	else
	{
		LCD_HD44780_Write(LCD_Instrukce_CursorOFF,LCD_instrukce);
	}	
	_delay_us(400);			// Melo by byl 40us
}

/* --------------------------------------------
 Nahraje vlastni znak do generator uznaku
 ------------------------------------------- */
void LCD_HD44780_NahratZnak(uint8_t pozice, const uint8_t data[8])
{
	uint8_t i=0;

	for (i=0;i<8;i++)
	{
		LCD_HD44780_Write((pozice*8+i) | (1<<6),LCD_instrukce);
		LCD_HD44780_Write(data[i],LCD_data);
	}
}

/* ---------------------------------------------
 Vypise na LCD 16-bit cislo se zadanym poctem
 cifer
 -------------------------------------------- */
void LCD_HD44780_PutInt16(uint16_t cislo,uint8_t cifer)
{
	uint16_t temp;

	temp=cislo/10000;
	if(cifer>=5) LCD_HD44780_PutChar('0'+temp);
	cislo = cislo - temp*10000;

	temp=cislo/1000;
	if(cifer>=4) LCD_HD44780_PutChar('0'+temp);
	cislo = cislo - temp*1000;

	temp=cislo/100;
	if(cifer>=3) LCD_HD44780_PutChar('0'+temp);
	cislo = cislo - temp*100;

	temp=cislo/10;
	if(cifer>=2) LCD_HD44780_PutChar('0'+temp);
	if(cifer>=1) LCD_HD44780_PutChar('0'+cislo - temp*10);
}

/* ---------------------------------------
 Vypise na LCD datum kompilace ve 
 formatu DD.MM.RRRR
 -------------------------------------- */
void LCD_HD44780_PutBuildDate(void)
{
	uint8_t temp[] = __DATE__;		// Datum ve formatu MMM DD RRRR
	uint8_t out[] = "00.00.0000";	// Datum ve formatu DD.MM.RRRR

	// Den
	LCD_HD44780_PutChar(temp[4]);
	LCD_HD44780_PutChar(temp[5]);		
	LCD_HD44780_PutChar('.');
	
	//Mesic	
	out[3] = '0';
	switch(temp[0])
	{
		case 'J':					// Mesic = 1, 6 nebo 7
		{
			if(temp[1]=='a')		// Mesic = 1
			{
				out[4] = '1';	
			}
			else if(temp[2]=='n')	// Mesic = 6
			{
				out[4] = '6';
			}
			else					// Mesic = 7
			{
				out[4] = '7';
			}
			break;
		}
		case 'F':					// Mesic = 2
		{
			out[4] = '2';
			break;
		}
		case 'M':					// Mesic = 3 nebo 5
		{
			if(temp[2]=='r')		// Mesic = 3
			{
				out[4] = '3';
			}
			else					// Mesic = 5
			{
				out[4] = '5';
			}
			break;
		}
		case 'A':					// Mesic = 4 nebo 8
		{
			if(temp[1]=='p')		// Mesic = 4
			{
				out[4] = '4';
			}
			else					// Mesic = 8
			{
				out[4] = '8';
			}
			break;
		}
		case 'S':					// Mesic = 9
		{
			out[4] = '9';
			break;
		}
		case 'O':					// Mesic = 10
		{
			out[3] = '1';
			out[4] = '0';
			break;
		}
		case 'N':					// Mesic = 11
		{
			out[3] = '1';
			out[4] = '1';
			break;
		}
		case 'D':					// Mesic = 12
		{
			out[3] = '1';
			out[4] = '2';
			break;
		}
	}	
	LCD_HD44780_PutChar(out[3]);
	LCD_HD44780_PutChar(out[4]);
	LCD_HD44780_PutChar('.');
	
	// Rok
	LCD_HD44780_PutChar(temp[7]);
	LCD_HD44780_PutChar(temp[8]);
	LCD_HD44780_PutChar(temp[9]);
	LCD_HD44780_PutChar(temp[10]);
}

/* --------------------------------------
   Prepise teplotu na TFT vcetne znamenka
   pri zaporne teplote
   ----------------------------------- */
void LCD_HD44780_TeplotaNaLCD(int16_t hodnota)
{
	uint16_t tmp = 0;
	uint8_t bylanula = 0;
	// Proskrtnuti pri neplatne hodnote teploty
	if(hodnota==DS18X20_INVALID_TEMP)
	{
		LCD_HD44780_PutString(" Err ");
		return;
	}
	// Znamenko
	if(hodnota < 0)		// zaporna teplota
	{
		LCD_HD44780_PutChar('-');
		hodnota = -hodnota;					// prevod zaporneho cisla na kladne
	}
	// Stovky
	tmp = hodnota / 1000;
	if (tmp==0)
	{
		LCD_HD44780_PutChar(' ');
		bylanula = 1;
	}
	else
	{
		LCD_HD44780_PutChar('0'+tmp);
		bylanula = 0;
	}
	// Desitky
	hodnota = hodnota - (tmp * 1000);
	tmp = hodnota / 100;
	if ((tmp==0) && (bylanula == 1))
	{
		LCD_HD44780_PutChar(' ');
		bylanula = 1;
	}
	else
	{
		LCD_HD44780_PutChar('0'+tmp);
		bylanula = 0;
	}
	// Jednotky
	hodnota = hodnota - (tmp * 100);
	tmp = hodnota / 10;
	if ((tmp==0) && (bylanula == 1))
	{
		LCD_HD44780_PutChar(' ');
		bylanula = 1;
	}
	else
	{
		LCD_HD44780_PutChar('0'+tmp);
		bylanula = 0;
	}
	// Desetiny
	tmp = hodnota - (tmp * 10);
	LCD_HD44780_PutChar(',');
	LCD_HD44780_PutChar('0'+tmp);
}

/* --------------------------------------
   Vyresli aktualni datum a cas na LCD
   ----------------------------------- */
void LCD_HD44780_TimeToLCD(void)
{
	BinToTFT(Time_Hodiny);
	LCD_HD44780_PutChar(':');
	BinToTFT(Time_Minuty);
	LCD_HD44780_PutChar(':');
	BinToTFT(Time_Vteriny);
	LCD_HD44780_PutChar(' ');
	BinToTFT(Time_Den);
	LCD_HD44780_PutChar('.');
	BinToTFT(Time_Mesic);
	LCD_HD44780_PutChar('.');
}

/* --------------------------------------
   Zobrazi binarni osmibitove cislo TFT
   v rozsahu 00 az 99 
   ----------------------------------- */
void BinToTFT(uint8_t cislo)
{
	LCD_HD44780_PutChar(cislo/10 + '0');
	LCD_HD44780_PutChar(cislo%10 + '0');
}

/* --------------------------------------
   Prevod binarniho cisla na HEX
   ----------------------------------- */
uint8_t BinToHex(uint8_t bin)
{
	return ((bin)%16) | (((bin)/16)<<4); /* Binary 2 HEX conversion */
}

/* --------------------------------------
 Zobrazi na LCD HEX cislo
 ------------------------------------- */
void LCD_HD44780_HexToLCD(uint8_t hex)
{
	uint8_t tmp;
	uint8_t i;
	for(i=0;i<2;i++)
	{
		if (i==0)
		{
			tmp = (BinToHex(hex)&0xF0) >> 4;
		}
		else
		{
			tmp = (BinToHex(hex)&0x0F);
		}
		if (tmp>9)
		{
			LCD_HD44780_PutChar('A' + tmp-10);
		}
		else
		{
			LCD_HD44780_PutChar('0' + tmp);
		}
	}
}
// Konec souboru ===================================================
