/*----------------------------------------------------------------------------
 * Nazev:   lcd_dogm132.c
 * Popis:   low level funkce grafického displeje EA DOGM132-X5 (132x32 pixels)
 * Pozn:
 *--------------------------------------------------------------------------*/

/* Incude ------------------------------------------------------------------*/
 #include "lcd_dogm132.h"

/* Uzite promenne ----------------------------------------------------------*/
  
  u8 page = 0;											// page adresa
  u8 col = 0;											// column adresa
  u8 sbyte = 0;											// byte pro odesilani
  u32 disp_buf[132] = {0};								// zobrazovaci buffer displeje
  extern u16 LCD_font1_offsets[];						// importované offsety fontu
  extern u8 LCD_font1_data[];  							// impotovany font
  extern u16 LCD_font2_offsets[];						// importované offsety fontu
  extern u8 LCD_font2_data[];  							// impotovany font

/* LCD Inicializace --------------------------------------------------------
vstupy:
zadne
----------------------------------------------------------------------------*/  
extern void LCD_init(void){
  GPIO_WriteBit(LCD_CS_port, LCD_CS, Bit_RESET);		// CS - enable
  LCD_SendByte(0x40); 									// pocatecni radek 0 
  LCD_SendByte(0xA1); 									// reversni rezim displeje 
  LCD_SendByte(0xC0); 									// nastavení COM vystupu 0 - 63 
  LCD_SendByte(0xA6); 									// neinverzni rezim displeje
  LCD_SendByte(0xA2);									// bias napeti displeje 1/9
  LCD_SendByte(0x2F); 									// booster, regulator a follower on 
  LCD_SendByte(0xF8); 									// nastavení pocatecnihi hodnoty boosteru 4x... 
  LCD_SendByte(0x00); 									// ... 
  LCD_SendByte(0x23); 									// nastavení interniho napetoveho regulatoru
  LCD_SendByte(0x81); 									// nastaveni kontrastu...
  LCD_SendByte(0x1F); 									// ... 
  LCD_SendByte(0xAC); 									// nastaveni statickeho indikatoru...
  LCD_SendByte(0x00); 									// ... 
  LCD_SendByte(0xAF); 									// displej on 
  GPIO_WriteBit(LCD_CS_port, LCD_CS, Bit_SET);  		// CS - disable

 }
/* LCD mazaní celeho displeje ------------------------------------------------
vstupy:
zadne
----------------------------------------------------------------------------*/
extern void LCD_clear(void)
{
  u8 i = 0;
  
  for( i=0 ; i<132 ; i++)
  {
  	disp_buf[i] = 0x00000000;							// nulovani vsech sloupcu bufferu displeje
  }
  LCD_redraw_buffer();
}
/* LCD nastaveni celeho displeje -------------------------------------------
vstupy:
zadne
----------------------------------------------------------------------------*/
extern void LCD_set_all(void)
{
  u8 i = 0;
  
  for( i=0 ; i<132 ; i++)
  {
 	disp_buf[i] = 0xFFFFFFFF;							// nastavení vsech sloupcu bufferu displeje
  }
  LCD_redraw_buffer();
}
/* LCD vykresleni bufferu displeje -------------------------------------------
vstupy:
----------------------------------------------------------------------------*/
extern void LCD_redraw_buffer(void)
{
  GPIO_WriteBit(LCD_CS_port, LCD_CS, Bit_RESET);		// CS - enable
  for(page=0xB0 ; page<0xB4 ; page++)					// zopakovani pro vsechny 4 page
  {	 
 	 GPIO_WriteBit(LCD_A0_port, LCD_A0, Bit_RESET);		// A0 = 0 - rezim odesilani prikazu
  	 LCD_SendByte(page); 								// nastavit page 
	 LCD_SendByte(0x00);								// nastavit column na zacatek - nizsi nibl
	 LCD_SendByte(0x10);								// nastavit column na zacatek - vyssi nibl
	 GPIO_WriteBit(LCD_A0_port, LCD_A0, Bit_SET);		// A0 = 1 - rezim odesilani dat
  	 for(col=0 ; col<132 ; col++)						// zopakovani pro vsechny column
  	 {
 		 sbyte = (disp_buf[col] >> (((page-0xB0)*8)));	// nastaveni bytu pro odeslani z bufferu despleje
		 LCD_SendByte(sbyte);							// smazat vybrany column ve vybrane page
 	 }
  }
  GPIO_WriteBit(LCD_CS_port, LCD_CS, Bit_SET);			// CS - disable
  GPIO_WriteBit(LCD_A0_port, LCD_A0, Bit_RESET);		// A0 = 0 - rezim odesilani prikazu
}
/* LCD vykresli pixel ------------------------------------------------------------
vstupy:
x (0-131) -	x souradnice - brano od leveho dolniho rohu
y (0-31)  - y souradnice - brano od leveho dolniho rohu
----------------------------------------------------------------------------*/
extern void LCD_draw_px(u8 x, u8 y)
{	
  disp_buf[x] |= (1 << (32-y));							// nastaveni pixelu v x sloupci y-ty bit v bufferu
  LCD_redraw_buffer();									// vykresleni zobrazovaciho bufferu na displeji
}

/* LCD vykresli caru ---------------------------------------------------------
vstupy: promenna (mozny rozsah) - popis
x1 (0-131) - x souradnice - levy spodni bod
y1 (0-31)  - y souradnice - levy spodni bod
x2 (0-131) - x souradnice - pravy horni bod
y2 (0-31)  - y souradnice - pravy horni bod
pozn: souradnice brany od leveho dolniho rohu
----------------------------------------------------------------------------*/
void LCD_line(u8 x1, u8 y1, u8 x2, u8 y2) 
{
  s32 dx = 0;
  s32 dy = 0;
  s32 a = 0;
  u8 x = 0;
  u8 y = 0;
  u8 s = 0;												// strmost - 0- klesajici / 1- stoupajici cara
  dx = x2 - x1;											// Vypocet delta x
  if(y1 < y2)											// Vypocet delta y
  {
  	dy = y2 - y1;
 	s = 1;												// strmost - stoupajici cara
  }
  else
  {
 	dy = y1 - y2;
  }
														
  if(dx > dy)											// cary s vice pixely v jednotlivych y hladinach
  {	
 	a = (10000*(dy+1))/dx;								// vypocet konstanty udavajici sklon
	for( x=x1 ; x<=x2 ; x++)							// pro vsechny x
	{ 			 		
	  	if(s == 1)										// vypocet rovnice primky pro stoupajici cary
	  		{y = y1 + a*(x-x1)/10000;}
	  	else											// vypocet rovnice primky pro klesajici cary
	  		{y = y1 - a*(x-x1)/10000;}
	  	disp_buf[x] |= (1 << (32-(y)));					// zapis pixelu do zobrazovaciho bufferu
	}
  } 
  else													// cary s vice pixely v jednotlivych x hladinach
  {
	a = (10000*(dx+1))/(dy);							// vypocet konstanty udavajici sklon
	if(s == 1)
	{
		for( y=y1 ; y<=y2 ; y++)						// pro vsechny y
		{
			x = x1 + ((y-y1)*a/10000);					// vypocet rovnice primky pro stoupajici cary
			disp_buf[x] |= (1 << (32-(y)));				// zapis pixelu do zobrazovaciho bufferu
		}
	 }
	else
	{
		for( y=y2 ; y<y1 ; y++)							// pro vsechny y
		{			  					
			x = x1 - ((y-y1)*a)/10000;					// vypocet rovnice primky pro klesajici cary
			disp_buf[x] |= (1 << (32-(y)));				// zapis pixelu do zobrazovaciho bufferu
		}
	}
  }				 
		
  LCD_redraw_buffer();									// vykresleni zobrazovaciho bufferu na displeji
}

/* LCD vykresli obdelnik -----------------------------------------------------
vstupy:
x1 (0-131)    - x souradnice - leveho dolniho rohu
y1 (0-31)     - y souradnice - leveho dolniho rohu
x2 (0-131)    - x souradnice - pravy horni rohu
y2 (0-31)     - y souradnice - pravy horni rohu
souradnice brany od leveho dolniho rohu
border (0-16) -	sirka okraje - smerem dovnitr od zadanych souradnic
filled (TRUE/FALSE) - TRUE - vyplneny obdelnik, FALSE - nevyplneny
----------------------------------------------------------------------------*/
extern void LCD_rect(u8 x1, u8 y1, u8 x2, u8 y2, u8 border, bool filled)
{
u32 i = 0;
u32 j = 0;

  if(filled)										// pokud ma byt obdelnik vyplneny nastavi border na 16
  {
  	border = 16;	
  
  if((x2-x1) < (y2-y1))								// upravi ramecek podle mensi delky strany obdelniku, 
  {													// tak aby nedoslo k prolnuti pres protejsi stranu
  	if((border > x2 -x1) && ~filled)
	{
		border = (x2 - x1);
	}
  }
  else
  {
  	if((border > y2 -y1) && ~filled)
	{
		border = (y2 - y1);
	}
  }	 	
  }
  for(j=0 ; j < border ; j++ )						// vykresli tolik obdelniku smerem dovnitr,
  {													// kolik je zadana sirka okraje
	for(i = x1 ; i < x2 ; i++)						// vykresleni vodorovnych car do bufferu displeje
	{
		disp_buf[i] |= (1 << (32-y1));	
	  	disp_buf[i] |= (1 << (32-y2));	
	}
	for(i = y1 ; i <= y2 ; i++)						// vykresleni svislych car do bufferu displeje
	{
		disp_buf[x1] |= (1 << (32-i));	
		disp_buf[x2] |= (1 << (32-i));	
	}
	x1++;											// zmenseni rohovych souradnic smerem dovnitr obdelniku
	x2--;
	y1++;
	y2--;
  }	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
  LCD_redraw_buffer();								// vykresleni zobrazovaciho bufferu na displeji
}
/* LCD vykresli progres bar---------------------------------------------------
vstupy: promenna (mozny rozsah) - popis
x1 (0-131) 	   - x souradnice - levy spodni roh obdelniku
y1 (0-31)  	   - y souradnice - levy spodni roh obdelniku
x2 (0-131)     - x souradnice - pravy horni roh obdelniku
y2 (0-31) 	   - y souradnice - pravy horni roh obdelniku
prog (0 - 100) - % zaplneni
dir (0 / 1)	   - smer - 0 - vertikalni 1 - horizontalni
pozn: souradnice brany od leveho dolniho rohu
					 obdelniku od rohovych bodu
----------------------------------------------------------------------------*/
extern void LCD_progress_bar(u8 x1, u8 y1, u8 x2, u8 y2, u8 prog, u8 dir)
{
  u8 i = 0;
  u32 mask = 0;
  u32 delmask = 0x0;
  delmask = ~(((1 << (y2 - y1-3))-1) << (33-y2)); 		// vypocet masky pro mazani obsahu indikatoru

  LCD_rect(x1, y1, x2, y2, 1, FALSE);					// vykresleni ramecku indikatoru

  x1 += 2;												// posun rohovych souradnic smerem doprostred indikatoru
  y1 += 2;
  x2 -= 2;
  y2 -= 2;

  if(dir == 0)											// vykrelseni vertikalniho indikatoru
  {	
  	prog = (y2 - y1)*prog/100;							// normalizace pomerne casti indikatoru y % na px
	mask = (1 << (prog+1))-1;							// vypocet masky indikatoru
	y2 = y1+prog;										// koncova souradnice pro vyplnenou cast indikatoru
	for(i = x1 ; i <= x2 ; i++)							// vykresleni vodorovnych car do bufferu displeje
	{
		disp_buf[i] &= (delmask );						// vymazani obsahu indikatoru
		disp_buf[i] |= (mask << (32-y2));				// vykresleni pomerne casti indikatoru
	}	
  }
  else													// vykresleni vertikalniho indikatoru
  {
 	prog = (x2 - x1)*prog/100;							// normalizace pomerne casti indikatoru y % na px
	mask = (1 << (y2-y1+1))-1;							// vypocet masky indikatoru
	mask = mask << (32-y2);
		
  	for(i = x1 ; i <= (x2) ; i++)						// vykresleni vodorovnych car do bufferu displeje
  	{
  		if(i<(x1+prog))									// pro pomernou cast 
		{
			disp_buf[i] |= (mask );						// vykresleni pomerne casti indikatoru
		}
		else
		{
			disp_buf[i] &= (~mask );					// vymayani zbytku idnidkatoru
		}
	}	
  }
  LCD_redraw_buffer();									// vykresleni zobrazovaciho bufferu na displeji
}

/* LCD vykresleni textu ------------------------------------------------------
vstupy:
			  - souradnice kotevniho bodu
x (0 - 131)   - x souradnice - brano od leveho dolniho rohu (displej i text)
y {0 - 31)    - y souradnice - brano od leveho dolniho rohu (displej i text)
txt[] (0-255) - retezec pismen ktere maji byt zobrazeny  
----------------------------------------------------------------------------*/
extern void LCD_print_string(u8 x, u8 y, u8 *txt) {

  u16 start_offset, end_offset;
  u16 i = 0;
  u8 j = 0;
  u8 k = x;
  y = 24 - y;  	 										// transormace y souradnic kotevniho bodu
  while(txt[j] != '\0')									// opakovani dokud se nedojde na konec retezce
  {
 	start_offset = LCD_font1_offsets[txt[j]];			// nacteni offsetu jednotlivych pismen
  	end_offset = LCD_font1_offsets[txt[j]+1];  
	for( i = start_offset ; i <end_offset ; i++ )		// vykresleni sloupcu znaku mezi offsety
	{		  	  
		disp_buf[k] |= (LCD_font1_data[i] << y);		// ulozeni do zobrazovaciho bufferu
		k++;
	}
	j++;
	k++;
	disp_buf[k] |= (0x00 << y);							// mezera za kazdym znakem
  }	
  LCD_redraw_buffer();									// vykresleni zobrazovaciho bufferu na displeji
} 

/* LCD vykresli graf ----------------------------------------------------------
vstupy: promenna (mozny rozsah) - popis
x (0-76) 	   - x souradnice - levy spodni roh grafu
yp (0 - 255)   - pole y hodnot
xscale  (0-255)- krok hodnot na ose x grafu
yscale1 (0-255)- dolni hranice y hodnot grafu
yscale2 (0-255)- horni hranice y hodnot grafu
variable (txt) - popisek grafu priblizne max 5 znaku
----------------------------------------------------------------------------*/
extern void LCD_graph(u8 xs,u8 *yp, u8 xscale, u8 yscale1, u8 yscale2, u8 *variable)
{
  u8 i = 0;
  u8 x = 0; 
  u32 y = 0;
  u8 xold = 0, yold = 0;
  char num[3] = {0x30, 0x30, 0x30};
  u32 osy[56] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x02108420,	   // txt		// definice os pro vykresleni
  0x7FFFFFF0, 0x42108420, 0x40000000, 0x40000000, 0x40000000,  // yosa
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 0-5
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 5-10
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 10-15
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 15-20
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 20-25
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 25-30
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 30-15
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, 0x40000000,  // xosa 35-20
  0xE0000000, 0x40000000, 0x40000000, 0x40000000, }; 		   // xosa 40-45
  
  for(i=0 ; i<(56) ; i++)								// ulozeni os do bufferu
  {
	disp_buf[i+xs+1] |= osy[i];	
  }

  LCD_print_string(xs + 30, 24, variable);				// vypsani popisku grafu
  sprintf(num,"%d",(int)yscale1);
  LCD_print_num_small(xs, 0, num); 
  sprintf(num,"%d",(int)yscale2);
  LCD_print_num_small(xs, 24, num); 
  sprintf(num,"%d",(int)xscale);
  LCD_print_num_small(xs+50, 3, num); 
  
  i = 0;
  xold = xs;
  while(yp[i] != '\0')									// vykreslovani samotneho prubehu
  {														
  	x = xs + i*5;										// posun o dilek na x
	y = (((yp[i]-yscale1)*25)/(yscale2 - yscale1)); 
	LCD_graph_cross(x+8,y+2);							// vykresleni krizku v bodech
	i++;
		LCD_line(xold+8,yold+2,x+8,y+2);				// vykresleni spojnic bodu
	
	xold = x;
	yold = y;

  }
  LCD_redraw_buffer();									// vykresleni zobrazovaciho bufferu na displeji

}

extern void LCD_graph_cross(u8 x,u8 y)					// funkce pro vykresleni bodu grafu
{
  disp_buf[x] |= (7 << (31-y));							// ulozeni krizku do zobrayovaciho bufferu
  disp_buf[x-1] |= (1 << (32-y));
  disp_buf[x+1] |= (1 << (32-y));
}

extern void LCD_print_num_small(u8 x, u8 y, u8 *txt) 	// funkce pro vypisovani cislic fontu 2 
{														// funkce identicka s LCD_print_string(...)
  u16 start_offset, end_offset;
  u16 i = 0;
  u8 j = 0;
  u8 k = x;
  y = 24 - y;  	 
  while(txt[j] != '\0')
  {
  	start_offset = LCD_font2_offsets[txt[j]-48];
  	end_offset = LCD_font2_offsets[txt[j]-47];  
	for( i = start_offset ; i <end_offset ; i++ )
	{		  	  
		disp_buf[k] |= (LCD_font2_data[i] << y);
		k++;
	}
	j++;
	k++;
	disp_buf[k] |= (0x00 << y);
  }	
  LCD_redraw_buffer();									
}

/* konec souboru -----------------------------------------------------------*/
