// seznam vysokourovnovych funkci pro praci s displejem :

// LCD_init();
// LCD_mode_set(mode);
// LCD_display_mode(cursor, display, line);
// LCD_cursor_xy(x,y);
// LCD_text_xy(x,y);
// LCD_char('A');
// LCD_string("aaa");
// LCD_clr_text();
// LCD_clr_gr(0x00);
// LCD_set_pixel(x,y,show);
// LCD_line(x1,y1,x2,y2,show);
// LCD_circle(x, y, radius, show);
// LCD_box(x1,y1,x2,y2,show);
// LCD_box_fill(x1,y1,x2,y2,show);
// LCD_diacritics_generate();
// LCD_char_diacritic(0x80);

#define	E_HACEK_M 0x80
#define	A_DLOUHE_M 0x81
#define	R_HACEK_M 0x82
#define	I_DLOUHE_M 0x83
#define SIPKA_NAHORU 0x84
#define SIPKA_DOLU 0x85
#define SIPKA_VPRAVO 0x86
#define SIPKA_VLEVO 0x87
#define E_DLOUHE_M 0x88
#define C_HACEK_M 0x89
#define STUPEN 0x8A

#define LCD_MODE_EXOR 0x81
#define LCD_MODE_OR 0x80
#define LCD_MODE_AND 0x83
#define LCD_CURS_OFF 0
#define LCD_CURS_ON_BLINK_OFF 1
#define LCD_CURS_ON_BLINK_ON 2
#define LCD_TEXT_ON_GRAPH_OFF 1
#define LCD_TEXT_OFF_GRAPH_ON 2
#define LCD_TEXT_ON_GRAPH_ON 3

#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>


#define LCD_RST PORTD.6
#define LCD_CD PORTD.5
#define LCD_WR PORTD.2
#define LCD_RD PORTD.3
#define LCD_CE PORTD.4
#define LCD_FS PORTD.7
#define LCD_DATAPORT_R PINC
#define LCD_DATAPORT_W PORTC
#define LCD_DATA_DIR DDRC
#define LCD_CONTROL_DIR DDRD

//***************************************** nizkourovnove funkce ************************************************************

// reset displeje

void LCD_reset(void)
{
    LCD_RST = 0;           /// je treba upravit, cas a cele jinak
    //delay_ms(200);
    delay_ms(1);
    LCD_RST = 1; 
    //delay_ms(1);
}

// precte status displeje, navrat z funkce teprve az ST0 a ST1 == 1

unsigned char LCD_status(void)     //unsigned char LCD_status(void)
{
    //unsigned char x;
    LCD_CD = 1;
    LCD_WR = 1;
    LCD_RD = 0;
    LCD_CE = 0;
    //delay_us(1);    /// zase moc pomale to je 
    LCD_DATA_DIR = 0x00;    // vstup    
    while (LCD_DATAPORT_R.0 != 1 || LCD_DATAPORT_R.1 != 1);    //aby se to nezacyklilo, upravit
    //do x = LCD_DATAPORT_R;
    //while (LCD_DATAPORT_R.0 == 0 || LCD_DATAPORT_R.1 == 0); 
    return(LCD_DATAPORT_R);
}

// funkce pro zapis instrukce displeji

void LCD_write_command(unsigned char a)
{
     LCD_DATA_DIR = 0xFF; //vystup
     LCD_DATAPORT_W = a; 
     LCD_CD = 1;
     LCD_RD = 1;
     LCD_WR = 0;
     
     LCD_CE = 0;
     //delay_us(1);   //zase moc pomale, zkusit bez toho
//     LCD_WR = 1;
     LCD_CE = 1; 
     //delay_us(100);
}

// funkce pro zapis jednoho bytu dat do displeje

void LCD_write_data(unsigned char a)     
{
     LCD_DATA_DIR = 0xFF; //vystup
     LCD_DATAPORT_W = a; 
     LCD_RD = 1;
     LCD_CD = 0;     
     LCD_WR = 0;
     
     LCD_CE = 0;
     //delay_us(1);   //zase moc pomale, zkusit bez toho
     
     LCD_WR = 1;
     LCD_CE = 1;
     LCD_CD = 1;
     //delay_us(100);
}

//****************************** funkce pro praci s displejem ****************************************************************

// LCD_init();
// inicializace displeje, 128x128 bodu, adresa textove pameti je 0x0000h az po 0x0160h
// na radku je 21 pozic, z posledni je videt jenom prvni dve rady pixelu
// graficka pamet zacina od 0x0C00h az po 0x16FFh
// display mode je defaultne EXOR mode, graphic a text ON, kurzor blika, tloustka 8 pixelu

void LCD_init(void)
{
    LCD_FS = 1;                           //vsechno je v klidu v 1
    LCD_RD = 1;
    LCD_CD = 1;
    LCD_WR = 1;
    LCD_CE = 1;     
     
    LCD_CONTROL_DIR=0xFF;            // ridici signaly - vystup
    DDRD=0xFF;      
    
    LCD_reset();                     //reset
    
    LCD_status();                    //cteni statusu
    LCD_write_data(0x00);             //nastaveni text home adress
    LCD_status();                     //  0000h
    LCD_write_data(0x00);
    LCD_status();
    LCD_write_command(0x40);
    LCD_status();  
    
    LCD_write_data(0x16);             //nastaveni text area
    LCD_status();                     //  0015h .... pro FS=1 
    LCD_write_data(0x00);
    LCD_status();
    LCD_write_command(0x41);
    LCD_status();  
    
    LCD_write_data(0x00);            // nastaveni graphic home adress
    LCD_status();                    // 0C00h
    LCD_write_data(0x0C);
    LCD_status();
    LCD_write_command(0x42);
    LCD_status();  

    LCD_write_data(0x16);    //15       // nastaveni graphic area
    LCD_status();                   // 0010h
    LCD_write_data(0x00);
    LCD_status();
    LCD_write_command(0x43);
    LCD_status();  
    
    LCD_write_command(0x81);        // mode set - internal CG ROM, EXOR
    LCD_status();  
    
    LCD_write_command(0x9F);        // display mode - graphic on, text on, kurzor, blika
    LCD_status();
    
    LCD_write_command(0xA7);        // kurzor - tloustka 8 pixelu
    LCD_status();
}

// LCD_mode_set(mode);
// nastaveni zobrazovaciho modu displeje... LCD_MODE_EXOR = EXOR, LCD_MODE_OR = OR, LCD_MODE_AND = AND

void LCD_mode_set(unsigned char mode)
{
    LCD_FS = 1;                           //vsechno je v klidu v 1
    LCD_RD = 1;
    LCD_CD = 1;
    LCD_WR = 1;
    LCD_CE = 1;     
     
    LCD_CONTROL_DIR=0xFF;            // ridici signaly - vystup
    DDRD=0xFF;    
    
    LCD_status();      
    LCD_write_command(mode);       // mode set - internal CG ROM, EXOR = 0x81, OR = 0x80, AND = 0x83
    LCD_status(); 
}

//  LCD_display_mode(cursor, display, line);
//  nastaveni kurzoru... cursor - LCD_CURS_OFF = kurz. vypnuty, LCD_CURS_ON_BLINK_OFF = kurz. on blink off, LCD_CURS_ON_BLINK_ON = kurz. on blink on
// nastaveni displeje... display - LCD_TEXT_ON_GRAPH_OFF = text on graph. off, LCD_TEXT_OFF_GRAPH_ON = text off graph. on, LCD_TEXT_ON_GRAPH_ON = text on graph. on
// nastaveni tloustky kurzoru... line = 1..8

void LCD_display_mode(unsigned char cursor,unsigned  char display,unsigned  char line)
{
    LCD_FS = 1;                           //vsechno je v klidu v 1
    LCD_RD = 1;
    LCD_CD = 1;
    LCD_WR = 1;
    LCD_CE = 1;     
     
    LCD_CONTROL_DIR=0xFF;            // ridici signaly - vystup
    DDRD=0xFF;    
    
    LCD_status();          
    LCD_write_command(144+(cursor+1)+(display*4));        // display mode
    LCD_status();
    LCD_write_command(159+line);        // kurzor - tloustka
    LCD_status(); 
}

// LCD_cursor_xy(x,y);
// nastaveni kurzoru a pozici X, Y - X pozice je od 0 do 20 (21 neni videt cela)
//                                   Y pozice je od 0 do 15
// kurzor se nenastavuje automaticky s textem, je trebo ho nastavit manualne !!!

void LCD_cursor_xy(unsigned char a, unsigned char b)
{
    LCD_status();   
    LCD_write_data(a);            // address pointer
    LCD_status();
    LCD_write_data(b);
    LCD_status();
    LCD_write_command(0x21);
    LCD_status(); 
}

// LCD_text_xy(x,y);
// nastavi pozici pro umisteni textu na danou adresu X, Y
//                                                   X pozice je od 0 do 20 (21 neni videt cela)
//                                                   Y pozice je od 0 do 15

void LCD_text_xy(unsigned char a, unsigned char b)
{
    unsigned int x;
    unsigned char y;
    x = a + b*22;    
    if(x>255) y=1;
    else y=0;
    
    LCD_status();   
    LCD_write_data(x);            // address pointer
    LCD_status();
    LCD_write_data(y);
    LCD_status();
    LCD_write_command(0x24);
    LCD_status();  
}

// LCD_char('A');
// vykresli znak z pameti ROM na nastavene pozici, automaticka inkrementace pointru

void LCD_char(unsigned char a)
{
    LCD_write_data(a-0x20);               // Znak, autoinkrementace pointru
    LCD_status();
    LCD_write_command(0xC0);
}

// LCD_string("aaa");
// vykresli retezec na nastavenou adresu

void LCD_string(char *a)
{
 unsigned char i,n;
 n = strlen(a);
 for(i=0;i!=n;i++) LCD_char(a[i]);
}

// LCD_clr_text();
// smaze obsah txtove pameti (vsude je 0x00h)

void LCD_clr_text(void)
{
    unsigned int i;
    LCD_status();   
    LCD_write_data(0x00);            // address pointer
    LCD_status();
    LCD_write_data(0x00);
    LCD_status();
    LCD_write_command(0x24);
    LCD_status();  
    
for(i=0;i<352;i++)
{   
    LCD_write_data(0x00);
    LCD_status();
    LCD_write_command(0xC0);           // auto inkrementace pointru
    LCD_status();
}
}

// LCD_clr_gr(0x00);
// smaze grafickou pamet, parametr je hodnota na kterou ji prepise - 0x00 - modre pozadi, 0xFF - bile pozadi

void LCD_clr_gr(unsigned char a)
{
    unsigned int i;
    LCD_write_data(0x00);            // address pointer
    LCD_status();
    LCD_write_data(0x0C);
    LCD_status();
    LCD_write_command(0x24);
    LCD_status();  
    
for(i=0;i<0xB00;i++)
{   
    LCD_write_data(a);
    LCD_status();
    LCD_write_command(0xC0);           // auto inkrementace pointru
    LCD_status();
} 
}

//LCD_set_pixel(x,y,show);
// zobrazi pixel na dane pozici
// x = 0..127, y = 0..127
// show = 1... zobrazi bod, show = 0... zhnasne bod

void LCD_set_pixel(unsigned char a, unsigned char b, unsigned char show)
{
    unsigned int x;
    unsigned int y = 0x0C;
    unsigned char z;  
    z = a;
    a = a/6;
    z = 5 - (z - a*6);
    x = a + b*22; 
    y = y + x/256;
    
    LCD_write_data(x);    //14        // address pointer
    LCD_status();
    LCD_write_data(y);     //12
    LCD_status();
    LCD_write_command(0x24);
    LCD_status();            
    LCD_write_command(0xF0+show*8+z);      // rozsvitim bod = F8, zhasnu = F0
    LCD_status(); 
}

// LCD_line(x1,y1,x2,y2,show);
// zobrazi lajnu z bodu (x1,y1) do bodu (x2,y2), vykresli i opacny smer
// show = 1 zobrazi pixely, show = 0 smaze pixely

void LCD_line(unsigned  char x1,unsigned  char y1,unsigned  char x2,unsigned  char y2, unsigned char show) 
{
  int dy ;
  int dx ;
  int stepx, stepy, fraction;
  dy = y2 - y1;
  dx = x2 - x1;
  if (dy < 0) 
  {
    dy = -dy;
    stepy = -1;
  }
  else 
  {
    stepy = 1;
  }
  if (dx < 0)
  {
    dx = -dx;
    stepx = -1;
  }
  else
  {
    stepx = 1;
  }
  dy <<= 1;
  dx <<= 1;
  LCD_set_pixel(x1,y1,show);
  if (dx > dy)
  {
    fraction = dy - (dx >> 1); 
    while (x1 != x2)
    {
      if (fraction >= 0)
      {
        y1 += stepy;
        fraction -= dx;
      }
      x1 += stepx;
      fraction += dy;  
      LCD_set_pixel(x1,y1,show);
    }
  }
  else
  {
    fraction = dx - (dy >> 1);
    while (y1 != y2)
    {
      if (fraction >= 0)
      {
        x1 += stepx;
        fraction -= dy;
      }
      y1 += stepy;
      fraction += dx;
      LCD_set_pixel(x1,y1,show);
    }
  }
}

// LCD_circle(x, y, radius, show);
// zobrazi kruznici, stred na x,y a radius je polomer
// show = 1 zobrazi pixely, show = 0 smaze pixely

void LCD_circle(unsigned char x,unsigned char y, unsigned char radius, unsigned char show)
{
  int xc = 0;
  int yc ;
  int p ;
  yc=radius;
  p = 3 - (radius<<1);
  while (xc <= yc)  
  {
    LCD_set_pixel(x + xc, y + yc, show);
    LCD_set_pixel(x + xc, y - yc, show);
    LCD_set_pixel(x - xc, y + yc, show);
    LCD_set_pixel(x - xc, y - yc, show);
    LCD_set_pixel(x + yc, y + xc, show);
    LCD_set_pixel(x + yc, y - xc, show);
    LCD_set_pixel(x - yc, y + xc, show);
    LCD_set_pixel(x - yc, y - xc, show);
    if (p < 0)
      p += (xc++ << 2) + 6;
    else
      p += ((xc++ - yc--)<<2) + 10;
  }
}

// LCD_box(x1,y1,x2,y2,show);
// zobrazi obdelnik z pozice x1,y1 do pozice x2,y2... bez vyplne, jenom obdelnik
// show = 1 zobrazi pixely, show = 0 smaze pixely

void LCD_box(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned char show)
{
LCD_line(x1,y1,x2,y1,show);  // up
LCD_line(x1,y2,x2,y2,show);  // down
LCD_line(x2,y1,x2,y2,show);  // right
LCD_line(x1,y1,x1,y2,show);  // left
}

// LCD_box_fill(x1,y1,x2,y2,show);
// zobrazi vyplneny obdelnik z pozice x1,y1 k pozici x2,y2           zda se mi vykreslovani hodne pomale !!!! i pri 12MHz !!!!
// show = 1 zobrazi pixely, show = 0 smaze pixely

void LCD_box_fill(unsigned char x1, unsigned char y1, unsigned char x2, unsigned char y2, unsigned char show)
{

unsigned char i;

for(i=0;i<(y2-y1);i++)
{
LCD_line(x1,y1+i,x2,y1+i,show);  // up
}
}

// LCD_char('A');
// vykresli znak z pameti RAM na nastavene pozici, automaticka inkrementace pointru
// je potreba znat nazev konstanty pro jednotlive znaky, na hore v definici #define je seznam vlastnich znaku

void LCD_char_diacritic(unsigned char a)
{
    LCD_write_data(a);               // napis A, autoinkrementace pointru
    LCD_status();
    LCD_write_command(0xC0);
}

// pomocna funkce pro generovani diakritiky
void data_auto_inc()
{
    LCD_status();
    LCD_write_command(0xC0);
    LCD_status();
}

void wr_comm()
{
    LCD_status();
    LCD_write_command(0x24); 
    LCD_status();
}

// generovani vlastnich znaku na dane adrese, tuto funkci je potreba pouzit pro pocatecni vygenerovani znaku
// offset registr je nastaveny na adresu 00000h takze je brana jako CG oblast adresa od 0000h az po 07FFh
// prvnich 128 znaku je z ROM (pokud je nastavena internal ROM gen.) a dalsi jsou uzivatelske od 80h nahoru (pointer na 80h je v celem adresnim prostoru 0400h, na 81h je to 0408h)
// pokud nepouzivam vsechny znaky tak je treba nepouzite zakomentovat
void LCD_diacritics_generate()
{   
    LCD_status();              // Set Offset Register - stejne jako text area, v ROM je 128 znaku, v RAM je dalsich 128 vlastnich znaku
    LCD_write_data(0x00);
    LCD_status();
    LCD_write_data(0x00);      // 18
    LCD_status();
    LCD_write_command(0x22);
    LCD_status();   
      
    LCD_write_data(0x00);      // address pointer prvniho znaku
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();  
    
    LCD_write_data(0x0A);      // e s hackem male - adresa 0x80
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x11);
    data_auto_inc();
    LCD_write_data(0x1F);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();       
    
    LCD_write_data(0x08);      // address pointer druheho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();         
    
    LCD_write_data(0x02);      // a dlouhe, male - adresa 0x81
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x01);
    data_auto_inc();
    LCD_write_data(0x0F);
    data_auto_inc();
    LCD_write_data(0x11);
    data_auto_inc();
    LCD_write_data(0x0F);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();    
    
    LCD_write_data(0x10);      // address pointer druheho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();         
    
    LCD_write_data(0x0A);      // r s hackem - adresa 0x82
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x16);
    data_auto_inc();
    LCD_write_data(0x19);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();  
    
    LCD_write_data(0x18);      // address pointer tretiho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x02);      // i dlouhe, male - adresa 0x83
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();
    LCD_write_data(0x0C);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();   
    
    LCD_write_data(0x20);      // address pointer pateho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x04);      // sipka nahoru - adresa 0x84
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x15);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();        
    
    LCD_write_data(0x28);      // address pointer sesteho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x04);      // sipka dolu - adresa 0x85
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x15);
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();      
    
    LCD_write_data(0x30);      // address pointer sedmeho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x00);      // sipka vpravo - adresa 0x86
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x02);
    data_auto_inc();
    LCD_write_data(0x3F);
    data_auto_inc();
    LCD_write_data(0x02);
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();    
    
    LCD_write_data(0x38);      // address pointer osmeho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x00);      // sipka vlevo - adresa 0x87
    data_auto_inc();
    LCD_write_data(0x08);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x3F);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x08);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();     
    
    LCD_write_data(0x40);      // address pointer devateho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x02);      // dlouhe e - adresa 0x88
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x11);
    data_auto_inc();
    LCD_write_data(0x1F);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x0E);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();       
    
    LCD_write_data(0x48);      // address pointer desateho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x0A);      // c s hackem male - adresa 0x89
    data_auto_inc();
    LCD_write_data(0x04);
    data_auto_inc();
    LCD_write_data(0x0F);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x10);
    data_auto_inc();
    LCD_write_data(0x0F);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();    
    
    LCD_write_data(0x50);      // address pointer jedenacteho znaku  (o 8 vyssi nez predchozi)
    LCD_status();
    LCD_write_data(0x04);      // 1C
    wr_comm();          
    
    LCD_write_data(0x0C);      // znak stupne - adresa 0x8A
    data_auto_inc();
    LCD_write_data(0x12);
    data_auto_inc();
    LCD_write_data(0x12);
    data_auto_inc();
    LCD_write_data(0x0C);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc();
    LCD_write_data(0x00);
    data_auto_inc(); 
          
}

