/******************************************************************************/
/* LCD_4bit.c: Functions for 2 line 16 character LCD, with 4-bit interface    */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools.                    */
/* Copyright (c) 2005-2007 Keil Software. All rights reserved.                */
/* This software may only be used under the terms of a valid, current,        */
/* end user licence from KEIL for a compatible version of KEIL software       */
/* development tools. Nothing else gives you the right to use this software.  */
/******************************************************************************/

#include "LPC13xx.h"                     /* LPC1343 definitions               */
#include "LCD.h"
#include "systick_pp.h"

/*------------------------- Speed dependant settings -------------------------*/
/* If processor works on high frequency delay has to be increased, it can be 
   increased by factor 2^N by this constant                                   */
#define DELAY_2N     6                       // zamik 8 procesorskih ciklov 

/* PINS: Na uLPC1000
   - DB4 = P2.0 = P11.9    
   - DB5 = P2.1 = P12.6
   - DB6 = P2.2 = P13.9  
   - DB7 = P2.3 = P10.2
   - E   = P2.6 = P11.4
   - RW  = P2.5 = P12.14
   - RS  = P2.4 = P12.11                                                      */

#define PIN_E                 (1      <<  6) // ...0100 0000
#define PIN_RW                (1      <<  5) // ...0010 0000
#define PIN_RS                (1      <<  4) // ...0001 0000
#define PINS_CTRL             (0x07   <<  4) // ...0111 0000
#define PINS_DATA             (0x0FUL <<  0) // ...0000 1111

/* pin E  setting to 0 or 1                                                   */
// #define LCD_E(x)              ((x) ? (LPC_GPIO2->DATA |= PIN_E)  : (LPC_GPIO2->DATA &= ~PIN_E) ); Delay_us(100);
#define LCD_E(x)              ((x) ? (LPC_GPIO2->DATA |= PIN_E)  : (LPC_GPIO2->DATA &= ~PIN_E) ); Delay(10);
/* Tole se bere takole: 
LCD_E je v primeru, da je x = 1  (LPC_GPIO2->DATA |= PIN_E) torej gre pin na 1
                          x = 0  (LPC_GPIO2->DATA &= ~PIN_E) torej gre pin na 0
Na koncu je neglede na to kaj smo izbrali še  dodan delay(100)

LCD_E(1) ali LCD_E(0) kličemo znotraj našega programa. Prevajalnik potem ta LCD_E(1) zamenja s kodo: 
LPC_GPIO2->DATA |= PIN_E; delay(100);
*/
/* pin RW setting to 0 or 1                                                   */
///#define LCD_RW(x)             ((x) ? (LPC_GPIO2->DATA |= PIN_RW) : (LPC_GPIO2->DATA &= ~PIN_RW)); Delay_us(100);
#define LCD_RW(x)             ((x) ? (LPC_GPIO2->DATA |= PIN_RW) : (LPC_GPIO2->DATA &= ~PIN_RW)); Delay(10);
/* pin RS setting to 0 or 1                                                   */
//#define LCD_RS(x)             ((x) ? (LPC_GPIO2->DATA |= PIN_RS) : (LPC_GPIO2->DATA &= ~PIN_RS)); Delay_us(100);
#define LCD_RS(x)             ((x) ? (LPC_GPIO2->DATA |= PIN_RS) : (LPC_GPIO2->DATA &= ~PIN_RS)); Delay(10);

/* Reading DATA pins                                                          */
#define LCD_DATA_IN           ((LPC_GPIO2->DATA >> 0) & 0xF)

/* Writing value to DATA pins   tule je definirana kar grupa pinov            */
//#define LCD_DATA_OUT(x)       LPC_GPIO2->DATA  = (LPC_GPIO2->DATA & ~PINS_DATA) | ((x & 0xF) << 0); Delay_us(100);
#define LCD_DATA_OUT(x)       LPC_GPIO2->DATA  = (LPC_GPIO2->DATA & ~PINS_DATA) | ((x & 0xF) << 0); Delay(10);

/* Setting all pins to output mode                                            */
//#define LCD_ALL_DIR_OUT       LPC_GPIO2->DIR |=  PINS_CTRL | PINS_DATA; Delay_us(100);
#define LCD_ALL_DIR_OUT       LPC_GPIO2->DIR |=  PINS_CTRL | PINS_DATA; Delay(10);

/* Setting DATA pins to input mode                                            */
//#define LCD_DATA_DIR_IN       LPC_GPIO2->DIR &= ~PINS_DATA; Delay_us(100);
#define LCD_DATA_DIR_IN       LPC_GPIO2->DIR &= ~PINS_DATA; Delay(10);


/* Setting DATA pins to output mode                                           */
//#define LCD_DATA_DIR_OUT      LPC_GPIO2->DIR |=  PINS_DATA; Delay_us(100);
#define LCD_DATA_DIR_OUT      LPC_GPIO2->DIR |=  PINS_DATA; Delay(10);

/******************************************************************************/
/* Definicija lokacij prvih znakov v posameznih vrsticah displeja             */
/* vrstica 1 = 0, vrstica 2  = 64 ......                                      */
/* te vrednosti se lahko od displeja do displeja razlikujejo. Preverimo lahko */
/* s programčkom, ki na vse lokacije vpiše en znak in vidimo kako se premika  */
/* po zaslonu. Moj displej je DMC20481 NY-LY                                  */
char LCD_frst_locations[4] = {0, 64, 20, 84};
/******************************************************************************/


/* 8 user defined characters to be loaded into CGRAM (used for bargraph)      */
const unsigned char UserFont[8][8] = {
  { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // prazen
  { 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10 }, // |
  { 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18 }, // ||
  { 0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C }, // |||
  { 0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E }, // ||||
  { 0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F }, // |||||
  { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, // prazen
  { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }  // prazen
};
/************************ Local auxiliary functions ***************************/
/*******************************************************************************
* Delay in while loop cycles                                                   *
*   Parameter:    cnt:    number of while cycles to delay                      *
*******************************************************************************/
static void Delay (int cnt) {
  cnt <<= DELAY_2N;                       // cnt zamaknjemo v levo za 2^Delay_2n
  while (cnt--);
}
/*******************************************************************************
* Read status of LCD controller                                                *
*   Return:       Status byte contains busy flag and address pointer           *
*******************************************************************************/
static unsigned char lcd_read_status (void) {
  unsigned char status;
  LCD_DATA_DIR_IN
  LCD_RS(0)
  LCD_RW(1)
//  Delay_us(100);
  Delay(10);
  LCD_E(1)
//  Delay_us(100);
  Delay(10);
  status  = LCD_DATA_IN << 4;
  LCD_E(0)
//  Delay_us(100);
  Delay(10);
  LCD_E(1)
//  Delay_us(100);
  Delay(10);
  status |= LCD_DATA_IN;
  LCD_E(0)
  LCD_DATA_DIR_OUT
  return (status);
}

/*******************************************************************************
* Wait until LCD controller busy flag is 0                                     *
*   Return:       Status byte of LCD controller (busy + address)               *
*******************************************************************************/
static unsigned char wait_while_busy (void) {
  unsigned char status;
  do  {
    status = lcd_read_status();
  }  while (status & 0x80);             /* Wait for busy flag                 */
  return (status);
}

/*******************************************************************************
* Write 4-bits to LCD controller                                               *
*   Parameter:    c:      command to be written                                *
*******************************************************************************/
void lcd_write_4bit (unsigned char c) {
  LCD_RW(0)
  LCD_E(1)
  LCD_DATA_OUT(c&0x0F)
  Delay(10);
  LCD_E(0)
  Delay(10);
}
/*******************************************************************************
* Write command to LCD controller                                              *
*   Parameter:    c:      command to be written                                *
*******************************************************************************/
void lcd_write_cmd (unsigned char c) {
  wait_while_busy();
  LCD_RS(0)
  lcd_write_4bit(c>>4);
  lcd_write_4bit(c);
}

/*******************************************************************************
* Write data to LCD controller                                                 *
*   Parameter:    c:      data to be written                                   *
*******************************************************************************/
static void lcd_write_data (unsigned char c) {
  wait_while_busy();
  LCD_RS(1)
  lcd_write_4bit(c>>4);
//  Delay_us(100);
  lcd_write_4bit(c);
}

/************************ Exported functions **********************************/
/*******************************************************************************
* Initialize the LCD controller                                                *
*******************************************************************************/
void LCD_init (void) { 
  int i;
  unsigned char const *p;
  LCD_ALL_DIR_OUT                       // vsi podatkovni pini so izhodi
//  Delay_us(15000);                      // čaka najmanj 15ms 
  Delay (2100);                         // čaka najmanj 15ms ~7,16us * 2100
  LCD_RS(0)                             // Sledi procedura inicializacije LCD
  lcd_write_4bit(0x3);                  // izbere 8 bitno vodilo
//  Delay_us (5000);                      // čaka več kot 4,1ms  - 5ms
   Delay (700);                          // čaka več kot 4,1ms ~ 7,16us * 700
  lcd_write_4bit(0x3);                  // izbere 8 bitno vodilo 
//  Delay_us(100);                        // čaka več kot 100us  
  Delay (16);                           // čaka več kot 100us ~7,16us * 16
  lcd_write_4bit(0x3);                  // izbere 8 bitno vodilo 
  lcd_write_4bit(0x2);                  // izbere 4 bitno vodilo 
  lcd_write_cmd(0x28);                  /* 2 lines, 5x8 character matrix      */
  lcd_write_cmd(0x0C);                  /* Display ctrl:Disp=ON,Curs/Blnk=OFF */
  lcd_write_cmd(0x06);                  /* Entry mode: Move right, no shift   */

 /* V pomnilnnik na LCD-ju naloži lastne znake - za bargraph                  */
  lcd_write_cmd(0x40);                  /* Set CGRAM address counter to 0     */
  p = &UserFont[0][0];
  for (i = 0; i < sizeof(UserFont); i++, p++)
  LCD_putc (*p);
  lcd_write_cmd(0x80);                  /* Set DDRAM address counter to 0     */
}

/*******************************************************************************
* Set cursor position on LCD display                                           *
*   Parameter:    column: column position                                      *
*                 line:   line position                                        *
*******************************************************************************/
void LCD_gotoxy (unsigned char x, unsigned char y) {
  unsigned char address;
//  address = (y * 40) + x;                           // originalna koda   
//  address = 0x80 + (address & 0x7F);             
  
  address = (0x80 + LCD_frst_locations[y-1] + (x-1)); // lokacija pisanja 
/* Kljub temu, da mi vidimo LCD kot 4 vrstice po 20 znakov bi bile te lahko 
  nanizane ena za drugo od 1 do 80 Vendar temu ni tako. Moj LCD ima prve znake v 
  posameznih vrsticah na teh lokacijah: 0, 64, 20, 84 - potrebno preverit!    */  
  lcd_write_cmd(address);               /* Set DDRAM address counter to 0     */
}

/*******************************************************************************
* Clear the LCD display                                                        *
*******************************************************************************/
void LCD_cls (void) {
  lcd_write_cmd(0x01);                  // ukaz za brisanje kompletnega displeja
  LCD_gotoxy(0, 0);
}

/*******************************************************************************
* Turn cursor off                                                              *
*******************************************************************************/
void LCD_cur_off (void) {
  lcd_write_cmd(0x0C);                  // ukaz za izklop kurzorja
}

/*******************************************************************************
* Print Character to current cursor position                                   *
*   Parameter:    c:      character to be printed                              *
*******************************************************************************/
void LCD_putc (unsigned char c) { 
  lcd_write_data(c);
}

/*******************************************************************************
* Print sting to LCD display                                                   *
*   Parameter:    string: pointer to output string                             *
*******************************************************************************/
void LCD_print (unsigned char x, unsigned char y, unsigned char *string) {
  LCD_gotoxy(x, y);
  while (*string)
    LCD_putc (*string++);
}

/*******************************************************************************
* Display bargraph on LCD display                                              *
*   Parameter:    string: pointer to output string                             *
*******************************************************************************/
void LCD_bargraph (unsigned char x, unsigned char y, unsigned char size, unsigned char val) {
  char i;
  val = val * size / 20;                /* Scale value for 5x8 characters     */
  LCD_gotoxy(x, y);
  for (i = 0; i < size; i++)  {
    if (val > 5) {
      LCD_putc(0x05);
      val -= 5;
    } else {
      LCD_putc(val);
      val  = 0;
    }
  }
}

/******************************************************************************/
