/* =========================================================
 Knihovna pro komunikaci s řadičem maticového LCD ovládající 
 LCD z mobilního telefonu Nokia 3310.řízené obvodem PCD 8544

 -----------------------------------------------------------
		Bakalářká práce: Driver maticového LCD displeje

 		   Vytvořil: Ondřej Satora, UREL VUTBR, 2010
		   		  xsator00@stud.feec.vutbr.cz
========================================================= */
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <string.h>
#include "3310_libary.h"

#define DDR_SPI	DDRB
#define MOSI	PINB3
#define MISO	PINB4
#define SCK		PINB5
#define SS		PINB2

/* -----------------------------------------------
 Instrukce sloužící k odeslání jednoho byte po SPI
 do řadiče.

 Parametry:	data	<0;255>
----------------------------------------------- */
void LCD_Send(unsigned char data)
{
	SPDR = data;							/* Start transmission */
	while ((SPSR & (1<<SPIF))==0);
}

/* -----------------------------------------------
 Instrukce sloužící k inicializaci SPI rozhraní v
 režimu master.
 Musí být provedena před zahájením komunikace s
 Displejem !

 Parametry:	[žádné]
----------------------------------------------- */
void LCD_Init_SPI(void)
{
	DDR_SPI = ((1<<MOSI)|(1<<SCK)|(1<<SS));	/* Set MOSI and SCK output, all others input */
	SPCR = ((1<<SPE)|(1<<MSTR)|(0<<SPR1)|(1<<SPR0));	/* Enable SPI, Master, set clock rate fck/8 = 1MHz*/
	LCD_Send(0x00);
}

/* -----------------------------------------------
 Instrukce sloužící k nastavení ukazatele pro
 výpis textu na pozici 0,0 (levý horní roh displeje)

 Parametry:	[žádné]
----------------------------------------------- */
void LCD_Home(void)
{
	LCD_Send(0x15);
	_delay_us(63);
}

/* -----------------------------------------------
 Instrukce sloužící ke smazání celého obsahu 
 displeje

 Parametry:	[žádné]
----------------------------------------------- */
void LCD_Cls(void)
{
	LCD_Send(0x14);
	_delay_ms(11);
}

/* -----------------------------------------------
 Instrukce sloužící k vypsání textového řetězce

 Parametry:	*text	<0;255>	(ukazatel na řetězec)
		rezim	<0;1>
----------------------------------------------- */
void LCD_Text(prog_char *text, char rezim)
{
	char znak = 0;

	if (rezim == 0)	LCD_Send(0x16);
	if (rezim == 1)	LCD_Send(0x17);
	_delay_us(17);
	
	while(znak=*text++)
	{
		LCD_Send(znak);
		_delay_us(185);
	}
	LCD_Send(0x00);
	_delay_us(17);
}

/* -----------------------------------------------
 Instrukce sloužící k vypsání jednoho znaku
 zadaného ASCII kódem

 Parametry:	znak	<0;255>
			rezim	<0;1>
----------------------------------------------- */
void LCD_Char(prog_char znak, char rezim)
{
	if (rezim == 0)	LCD_Send(0x16);
	if (rezim == 1)	LCD_Send(0x17);
	_delay_us(17);
	
	LCD_Send(znak);
	_delay_us(185);
	
	LCD_Send(0x00);
	_delay_us(17);
}

/* -----------------------------------------------
 Instrukce sloužící k vypsání čísla ve tvaru
 unsigned int da dysplej

 Parametry:	cislo	<0;65536>
			rezim	<0;1>
----------------------------------------------- */
void LCD_Int(unsigned int cislo, char rezim)
{
	unsigned int zbytek;
	unsigned char bylanula = 0;

	if (rezim == 0)	LCD_Send(0x16);
	if (rezim == 1)	LCD_Send(0x17);
	_delay_us(17);
	
	if (cislo/10000==0)
	{
		LCD_Send(' ');
		bylanula = 255;
	}
	else
	{
		LCD_Send(cislo/10000+0x30);	
		bylanula = 0;
	}
	_delay_us(185);

	zbytek=cislo%10000;
	if ((zbytek/1000==0)&&(bylanula==255))
	{
		LCD_Send(' ');
		bylanula = 255;
	}
	else
	{
		LCD_Send((zbytek/1000)+0x30);
		bylanula = 0;
	}
	_delay_us(185);

	zbytek=zbytek%1000;

	if ((zbytek/100==0)&&(bylanula==255))
	{
		LCD_Send(' ');
		bylanula = 255;
	}
	else
	{
		LCD_Send((zbytek/100)+0x30);
		bylanula = 0;
	}
	_delay_us(185);

	zbytek=zbytek%100;

	if ((zbytek/10==0)&&(bylanula==255))
	{
		LCD_Send(' ');
	}
	else
	{
		LCD_Send((zbytek/10)+0x30);
	}
	_delay_us(185);
	
	zbytek=zbytek%10;
	LCD_Send((zbytek)+0x30);
	_delay_us(185);	
	
	LCD_Send(0x00);
	_delay_us(17);
}

/* -----------------------------------------------
 Instrukce sloužící k vypsání čísla ve tvaru char

 Parametry:	cislo	<0;255>
			rezim	<0;1>
----------------------------------------------- */
void LCD_CharInt(unsigned char cislo, char rezim)
{
	unsigned char zbytek;

	if (rezim == 0)	LCD_Send(0x16);
	if (rezim == 1)	LCD_Send(0x17);
	_delay_us(17);

	if (cislo/100==0)
	{
		LCD_Send(' ');
	}
	else
	{
		LCD_Send(cislo/100+0x30);	
	}
	_delay_us(185);

	zbytek=cislo%100;
	LCD_Send((zbytek/10)+0x30);
	_delay_us(185);
	
	zbytek=zbytek%10;
	LCD_Send((zbytek)+0x30);
	_delay_us(185);	
	
	LCD_Send(0x00);
	_delay_us(17);
}

/* -----------------------------------------------
 Instrukce sloužící ke změně pozice vykreslování
 v matici 14x6

 Parametry:	x	<0;13>
			y	<0;5>
----------------------------------------------- */
void LCD_Pozice(unsigned char x, unsigned char y)
{
	LCD_Send(0x1D);
	_delay_us(17);
	LCD_Send(x);
	_delay_us(17);
	LCD_Send(y);
	_delay_us(67);
}

/* -----------------------------------------------
 Instrukce sloužící ke změně pozice vykreslování
 v matici 84x6

 Parametry:	x	<0;83>
			y	<0;5>
----------------------------------------------- */
void LCD_PoziceExt(unsigned char x, unsigned char y)
{
	LCD_Send(0x1C);
	_delay_us(17);
	LCD_Send(x);
	_delay_us(17);
	LCD_Send(y);
	_delay_us(67);
}

/* -----------------------------------------------
 Instrukce sloužící k zaslání pozice a počtu
 vykreslovaných byte v režimu bitmapa

 Parametry:	x	<0;83>
			y	<0;5>
			typ	<0;3>
			delka	<0;512>
----------------------------------------------- */
void LCD_BitmapaInfo(unsigned char x, unsigned char y,unsigned char typ,unsigned int delka)
{
	unsigned char delka1 = 0;
	unsigned char delka2 = 0;
	unsigned int temp = 0;
	
	if (delka > 0)
	{
		LCD_Pozice(x,y);
		switch(typ)
		{
			case 0:
			{
				LCD_Send(0x18);
				break;
			}
			case 1:
			{
				LCD_Send(0x19);
				break;
			}
			case 2:
			{
				LCD_Send(0x1A);
				break;
			}
			case 3:
			{
				LCD_Send(0x1B);
				break;
			}
			default:
			{
				LCD_Send(0x18);
				break;
			}
		}
		_delay_us(18);
		
		delka1=0x00FF & delka;
		temp = (0xFF00 & delka);
		temp >>=8;
		delka2=temp;
		
		LCD_Send(delka2);
		_delay_us(19);
		LCD_Send(delka1);
		_delay_us(19);
	}
}

/* -----------------------------------------------
 Instrukce sloužící k odesílání vlastních
 bitmapových obrazových dat. 
 Musí následovat po instrukci LCD_BitmapaInfo a
 musí jich být odeslán přesně stejný počet, 
 jaký byl uveden v instrukci LCD_BitmapaInfo!

 Parametry:	data	<0;255>
			...
----------------------------------------------- */
void LCD_BitmapaData(unsigned char data)
{
	LCD_Send(data);
	_delay_us(44);
}

/* -----------------------------------------------
 Instrukce sloužící k nahrání vlastího znaku do 
 RAM paměti řadiče (po vypnutí napájení se smaže)

 Parametry:	data[5]	<0;255>	(pole 5 sloupců)
		pozice	<1;31>
----------------------------------------------- */
void LCD_VlastniZnak(unsigned char data[5], unsigned char pozice)
{
	if ((pozice>0)&&(pozice<32))
	{
		LCD_Send(0x20);
		_delay_us(19);
		LCD_Send(data[0]);
		_delay_us(19);
		LCD_Send(data[1]);
		_delay_us(19);
		LCD_Send(data[2]);
		_delay_us(19);
		LCD_Send(data[3]);
		_delay_us(19);
		LCD_Send(data[4]);
		_delay_us(19);
		LCD_Send(pozice-1);
		_delay_us(26);
	}
}


/* -----------------------------------------------
 Instrukce sloužící k zobrazení jednoho bodu na 
 displeji zadaném souřadnicemi

 Parametry:	x	<0;83>
			y	<0;47>
----------------------------------------------- */
void LCD_ZobrazPixel(unsigned char x,unsigned char y)
{
	if ((x>83)||(y>47)) {return;}

	LCD_Send(0x22);
	_delay_us(17);
	LCD_Send(x);
	_delay_us(17);
	LCD_Send(y);
	_delay_us(92);
}
