//***************************************************************************
//  File........: Nokia6610_lcd_lib.c
//  Author(s)...: Goncharenko Valery
//  URL(s)......: http://digitalchip.ru
//  Device(s)...: ATMega8
//  Compiler....: Winavr-20100110
//  Description.: Драйвер LCD Nokia6610 ( ONLY PCF8833 )
//  Data........: 21.06.12
//  Version.....: 1.0 
//******************************************************************************
#include "Nokia6610_lcd_lib.h"
#include <util/delay.h>             // Подключаем библиотеки
#include "Nokia6610_fnt8x8.h"
//******************************************************************************
//  Инициализация контроллера
void nlcd_Init(void)
{	
//  Инициализируем порт на вывод для работы с LCD-контроллером
	DDR_LCD |= (1<<SCLK_LCD_PIN)|(1<<SDA_LCD_PIN)|(1<<CS_LCD_PIN)|(1<<RST_LCD_PIN);

	CS_LCD_RESET;
	SDA_LCD_RESET;
	SCLK_LCD_SET;
	
	RST_LCD_SET;    //     ********************************************** 
	RST_LCD_RESET;  //     *                                             *
	_delay_ms(1);   //     *  Задержка для отработки апаратного сброса   *
	RST_LCD_SET;    //     *                                             *
                    //     **********************************************
    SCLK_LCD_SET;
    SDA_LCD_SET;
    SCLK_LCD_SET;
	
    nlcd_SendByte(CMD_LCD_MODE,SWRESET);   //    Программный сброс 
	nlcd_SendByte(CMD_LCD_MODE,SLEEPOUT);  //    Выход из режима сна
	nlcd_SendByte(CMD_LCD_MODE,BSTRON);    //    Вкл. повышающий преобразователь напряжения
	_delay_ms(10);                         //    Задержка для отработки команды и выравнивания напряжения
	nlcd_SendByte(CMD_LCD_MODE,DISPON);    //    Дисплей вкл.  
	nlcd_SendByte(CMD_LCD_MODE,NORON);     //    Дисплей нормальный - вкл.                        
	nlcd_SendByte(CMD_LCD_MODE,SETCON);    //            Контрастность                                  
	nlcd_SendByte(DATA_LCD_MODE,0x2D);     //         0x00-min   0x3F-max                                
	nlcd_SendByte(CMD_LCD_MODE,CASET);     //    Установка начального и конечного адреса колонки     
	nlcd_SendByte(DATA_LCD_MODE,0);        //                                                         
	nlcd_SendByte(DATA_LCD_MODE,0x83);      //                                                         
	nlcd_SendByte(CMD_LCD_MODE,PASET);     //     Установка начального и конечного адреса страницы   
	nlcd_SendByte(DATA_LCD_MODE,0);        //                                                        
	nlcd_SendByte(DATA_LCD_MODE,0x83);      //                                                       
                                           //    ******************************************************
    nlcd_SendByte(CMD_LCD_MODE,COLMOD);    //   *               Вывод цвета:                          *
//  nlcd_SendByte(DATA_LCD_MODE,0x02);     //   *     8 бит на пиксель- 256 цветов RGB 4:4:4           *  
	nlcd_SendByte(DATA_LCD_MODE,0x03);     //  *     12 бит на пиксель- 4096 цветов RGB 3:3:2          * 
//  nlcd_SendByte(DATA_LCD_MODE,0x05);     //  *     16 бит на пиксель-65535 цветов RGB 5:6:5           *
	                                       //  **********************************************************
	_delay_ms(5);
  nlcd_SendByte(CMD_LCD_MODE,MADCTL);     //    Команда доступа к условиям отображения памяти RAM 
   nlcd_SendByte(DATA_LCD_MODE,0x60);     //   1-byte, по умолчанию 0х00 - курим внимательно даташит 
	                                       //                на стр. 43
										 
	nlcd_SendByte(CMD_LCD_MODE,RAMWR);      //     Запись данных в RAM дисплея	
	_delay_ms(50);                          //     Немного ждем
	nlcd_SendByte(CMD_LCD_MODE,DISPOFF);    //     Выключаем дисплей чтобы не наблюдать мусор на экране
	nlcd_Box(0, 0, 131, 131, 1, BLACK);     //    Заливаем весь дисплей будущим фоном - можно выбрать любой
    nlcd_SendByte(CMD_LCD_MODE,DISPON);     //     Дисплей вкл.
}   

//******************************************************************************
//  Передача байта (команды или данных) на LCD-контроллер
//  mode: CMD_LCD_MODE  - передаем команду
//		  DATA_LCD_MODE - передаем данные
//  c:    значение передаваемого байта
void nlcd_SendByte(char mode,unsigned char c)
{
    CS_LCD_RESET;
    SCLK_LCD_RESET;
    if(mode) SDA_LCD_SET;
	else     SDA_LCD_RESET;
    
	SCLK_LCD_SET;

    for(unsigned char i=0;i<8;i++)
    {
    	SCLK_LCD_RESET;
        if(c & 0x80) SDA_LCD_SET;
        else	     SDA_LCD_RESET;
        SCLK_LCD_SET;
        c <<= 1;
        _delay_us(NLCD_MIN_DELAY);
    }

    CS_LCD_SET;
}

//******************************************************************************
//	Имя: 		 GotoXY(unsigned char x, unsigned char y)	 
// 	Описание:    Устанавливает в позицию x, y
//           	 GotoXY( x, y)
//	Параметры:   x: позиция 0-131
//			     y: позиция 0-131
//  Пример:		 GotoXY(32,17);        
//******************************************************************************
void nlcd_GotoXY(unsigned char x, unsigned char y)
{
   nlcd_SendByte(CMD_LCD_MODE,PASET);   // Команда адреса страницы RAM
   nlcd_SendByte(DATA_LCD_MODE,x);      // Старт
   nlcd_SendByte(DATA_LCD_MODE,x);      // Конец
  
   nlcd_SendByte(CMD_LCD_MODE,CASET);   // Команда адреса колонки RAM
   nlcd_SendByte(DATA_LCD_MODE,y);      // Старт
   nlcd_SendByte(DATA_LCD_MODE,y);      // Конец
}

//******************************************************************************
//	Имя: 		 nlcd_Pixel(unsigned char x, unsigned char y, int color)	 
// 	Описание:    Устанавливает Pixel в позицию x, y, цветом color
//           	 nlcd_Pixel( x, y,color)
//	Параметры:   x:     позиция 0-131
//			     y:     позиция 0-131
//               color: цвет (12-bit см. #define) 
//  Пример:		 nlcd_Pixel(21,45,BLACK);
//******************************************************************************
void nlcd_Pixel(unsigned char x, unsigned char y, int color)
{
   nlcd_GotoXY(x,y);
   nlcd_SendByte(CMD_LCD_MODE,RAMWR);                             
   CS_LCD_RESET;
  
   nlcd_SendByte(DATA_LCD_MODE, (unsigned char)((color>>4)& 0xff) );
   nlcd_SendByte(DATA_LCD_MODE, (unsigned char)((color&0xf)<<4)|0x00 );
   
   CS_LCD_SET;
   nlcd_SendByte(CMD_LCD_MODE,NOP);
}

//******************************************************************************
//	Имя: 		 nlcd_Line(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, int color)	 
// 	Описание:    Рисует линию из координаты x0, y0 в координату x1, y1 цветом color
//           	 nlcd_Line(x0, y0, x1, y1, color)
//	Параметры:   x:     позиция 0-131
//			     y:     позиция 0-131
//               color: цвет (12-bit см. #define) 
//  Пример:		 nlcd_Pixel(25,60,25,80,RED);
//******************************************************************************
void nlcd_Line(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, int color)
{ 
 
   int dy = y1 - y0; 
   int dx = x1 - x0; 
   int stepx, stepy; 
   if (dy < 0) { dy = -dy;  stepy = -1; } else { stepy = 1; } 
   if (dx < 0) { dx = -dx;  stepx = -1; } else { stepx = 1; } 
 
   dy <<= 1;                              // dy is now 2*dy 
   dx <<= 1;                              // dx is now 2*dx 
 
 
   nlcd_Pixel(x0, y0, color); 
 
   if (dx > dy) 
   { 
       int fraction = dy - (dx >> 1);     // same as 2*dy - dx 
       while (x0 != x1) 
	   { 
 	       if (fraction >= 0) 
		   { 
 		       y0 += stepy; 
               fraction -= dx;            // same as fraction -= 2*dx 
 		   } 
 		   x0 += stepx; 
           fraction += dy;                // same as fraction -= 2*dy 
           nlcd_Pixel(x0, y0, color); 
       } 
   } 
 	else
    { 
 	    int fraction = dx - (dy >> 1); 
        while (y0 != y1) 
		{ 
 		    if (fraction >= 0) 
		    { 
 		        x0 += stepx; 
 				fraction -= dy; 
            } 
            y0 += stepy; 
 			fraction += dx; 
            nlcd_Pixel(x0, y0, color); 
       } 
 	} 
 
} 

//******************************************************************************
//	Имя: 		 nlcd_Box(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char fill, int color) 
// 	Описание:    Рисует прямоугольник из координаты x0, y0 в координату x1, y1 с заливкой или нет, цветом color
//           	 nlcd_Line(x0, y0, x1, y1, fill, color)
//	Параметры:   x:     позиция 0-131
//			     y:     позиция 0-131
//               fill:  1-с заливкой, 0-без заливки
//               color: цвет (12-bit см. #define) 
//  Пример:		 nlcd_Box(20,30,40,50,1,RED);  // С заливкой
//******************************************************************************

void nlcd_Box(unsigned char x0, unsigned char y0, unsigned char x1, unsigned char y1, unsigned char fill, int color)
{ 
    unsigned char   xmin, xmax, ymin, ymax; 
    int   i;                                     
    if (fill == FILL)                          //  ******************************************************
    {                                          //  * Проверяем - будет прямоугольник с заливкой или нет  *              *
        xmin = (x0 <= x1) ? x0 : x1;          //  * В цикле используем 2 пикселя за 1 такт              *
 		xmax = (x0 > x1) ? x0 : x1;           //  *Расчитываем максимум и минимум для X и Y             *
		ymin = (y0 <= y1) ? y0 : y1;          //  ******************************************************* 
		ymax = (y0 > y1) ? y0 : y1; 
                                              //    *****************************************************
		nlcd_SendByte(CMD_LCD_MODE,PASET);    //   *            Координаты строки в RAM                 *
		nlcd_SendByte(DATA_LCD_MODE,xmin);    //   *  Указываем размеры прямоугольника в соответствии   *
		nlcd_SendByte(DATA_LCD_MODE,xmax);    //   *             с заданными пределами                  *
		nlcd_SendByte(CMD_LCD_MODE,CASET);    //   *            Координаты столбца в RAM                *
		nlcd_SendByte(DATA_LCD_MODE,ymin);    //   *                                                    *
		nlcd_SendByte(DATA_LCD_MODE,ymax);    //   ******************************************************
 
		nlcd_SendByte(CMD_LCD_MODE,RAMWR);     //        Пишем в RAM
		                                       //
                                               //      Цикл для общего количества пикселей / 2 
											   //
		for (i = 0; i < ((((xmax - xmin + 1) * (ymax - ymin + 1))/2 )+1 ); i++) 
		   { 
                  
  		      // Используем значение цвета для вывода 3 байтов данных - охватывают 2 пикселя 
              CS_LCD_RESET;
  		      nlcd_SendByte(DATA_LCD_MODE,(color >> 4) & 0xFF ); 
  		      nlcd_SendByte(DATA_LCD_MODE,((color & 0xF) << 4) | ((color >> 8) & 0xF) ); 
 		      nlcd_SendByte(DATA_LCD_MODE,color & 0xFF);
              CS_LCD_SET;
		   } 
           nlcd_SendByte(CMD_LCD_MODE,NOP); 
	} 
    else 
	   { 
          nlcd_Line(x0, y0, x1, y0, color); //Рисуем четыре линии прямоугольника
 	 	  nlcd_Line(x0, y1, x1, y1, color); 
 	 	  nlcd_Line(x0, y0, x0, y1, color); 
 	 	  nlcd_Line(x1, y0, x1, y1, color); 
       }
}

//******************************************************************************
//	Имя: 		 nlcd_Circle(unsigned char x0, unsigned char y0, unsigned char radius, int color)	 
// 	Описание:    Рисует круг из координаты x0, y0, с радиусом и цветом color
//           	 nlcd_Circle(x0, y0, radius, color)
//	Параметры:   x:       позиция 0-131
//			     y:       позиция 0-131
//               radius:  в пикселях 
//               color: цвет (12-bit см. #define) 
//  Пример:		 nlcd_Circle(10,55,2,BLUE);
//******************************************************************************
void nlcd_Circle(unsigned char x0, unsigned char y0, unsigned char radius, int color) 
{ 
    int f = 1 - radius; 
	int ddF_x = 0; 
    int ddF_y = -2 * radius; 
    unsigned char x = 0; 
    unsigned char y = radius; 
 
    nlcd_Pixel(x0, y0 + radius, color); 
    nlcd_Pixel(x0, y0 - radius, color); 
    nlcd_Pixel(x0 + radius, y0, color); 
    nlcd_Pixel(x0 - radius, y0, color); 
  
    while (x < y) 
	{ 
        if (f >= 0) 
		{ 
 
            y--; 
            ddF_y += 2; 
            f += ddF_y; 
        } 
		
    x++; 
    ddF_x += 2; 
    f += ddF_x + 1;
	
    nlcd_Pixel(x0 + x, y0 + y, color); 
    nlcd_Pixel(x0 - x, y0 + y, color); 
    nlcd_Pixel(x0 + x, y0 - y, color); 
    nlcd_Pixel(x0 - x, y0 - y, color); 
    nlcd_Pixel(x0 + y, y0 + x, color); 
    nlcd_Pixel(x0 - y, y0 + x, color); 
    nlcd_Pixel(x0 + y, y0 - x, color); 
    nlcd_Pixel(x0 - y, y0 - x, color); 

    } 
}

//******************************************************************************
//	Имя: 		nlcd_Char(char c, unsigned char x, unsigned char y, int fColor, int bColor)  	 
// 	Описание:    	 
//	Параметры:        
//  Пример:		 
//******************************************************************************  
void nlcd_Char(char c, unsigned char x, unsigned char y, int fColor, int bColor) 
{ 
   int    i; 
   int    j; 
   unsigned char   nCols; 
   unsigned char  nRows; 
   unsigned char  nBytes; 
   unsigned char   PixelRow; 
   unsigned char   Mask; 
   unsigned int   Word0; 
   unsigned char *pFont,   *pChar; 
  
   pFont = (unsigned char *)Nokia6610_fnt8x8;   
 
   nCols = pgm_read_byte(pFont); 
 
   nRows = pgm_read_byte(pFont + 1); 
 
   nBytes = pgm_read_byte(pFont + 2); 
   
   pChar = pFont + (nBytes * (c - 0x1F)); 
 
   for (i = 0; i<nRows; i++)
   {  
      PixelRow = pgm_read_byte(pChar++); 
      Mask = 0x80; 
      for (j = 0; j < nCols; j += 1) 
	  { 
         if ((PixelRow & Mask) == 0) 
         Word0 = bColor; 
         else 
         Word0 = fColor; 
         nlcd_Pixel( y+j,x+i, Word0);
         Mask = Mask >> 1; 
      }   
   } 
   nlcd_SendByte(CMD_LCD_MODE,NOP);  
} 
 
//******************************************************************************
//	Имя: 		nlcd_String(char *pString, unsigned char x, unsigned char  y,  int fColor, int bColor)  	 
// 	Описание:    	 
//	Параметры:  x:       позиция 0-131
//			    y:       позиция 0-131
//              fColor:  цвет (12-bit см. #define)
//              bColor:  цвет (12-bit см. #define)
//  Пример:		nlcd_String("Hello",40,12,WHITE,BLACK);
//****************************************************************************** 
void nlcd_String(char *pString, unsigned char x, unsigned char  y,  int fColor, int bColor) 
{ 
   while (*pString != 0x00) 
   { 
      nlcd_Char(*pString++, x, y, fColor, bColor); 
      y=y+8;
      if (x > 131) break; 
   } 
} 

