#include "nokia_5110.h"
#include "english_6x8_pixel.h"
#include "write_chinese_string_pixel.h"

#include "stdio.h"
#include "stdlib.h"
#include "delay.h"
#include "SPI-SD/Lcd/font.h"
#include "SPI-SD/Fatfs/ff.h"

char n5110_string[6][14];	//6行，每行13byte

/*-----------------------------------------------------------------------
LCD_init          : 3310LCD初始化

编写日期          ：2004-8-10
最后修改日期      ：2004-8-10
-----------------------------------------------------------------------*/

void LCD_init ( void )
{
#if LCD_def
    // 产生一个让LCD复位的低电平脉冲
    LCD_RST = 0;
    delay_us ( 1 );

    LCD_RST = 1;

    // 关闭LCD
    LCD_CE = 0;
    delay_us ( 1 );
    // 使能LCD
    LCD_CE = 1;
    delay_us ( 1 );

    LCD_write_byte ( 0x21, 0 );	// 使用扩展命令设置LCD模式
    LCD_write_byte ( 0xc8, 0 );	// 设置偏置电压
    LCD_write_byte ( 0x06, 0 );	// 温度校正
    LCD_write_byte ( 0x13, 0 );	// 1:48
    LCD_write_byte ( 0x20, 0 );	// 使用基本命令
    LCD_clear();	        // 清屏
    LCD_write_byte ( 0x0c, 0 );	// 设定显示模式，正常显示

    // 关闭LCD
    LCD_CE = 0;

    //开启背光灯
    BACKLIGHT = 1;
#endif
}

/*-----------------------------------------------------------------------
LCD_clear         : LCD清屏函数

编写日期          ：2004-8-10
最后修改日期      ：2004-8-10
-----------------------------------------------------------------------*/
void LCD_clear ( void )
{
    unsigned int i;

    LCD_write_byte ( 0x0c, 0 );
    LCD_write_byte ( 0x80, 0 );

    for ( i = 0; i < 504; i++ )
        LCD_write_byte ( 0, 1 );
}

/*-----------------------------------------------------------------------
LCD_set_XY        : 设置LCD坐标函数

输入参数：X       ：0－83
          Y       ：0－5

编写日期          ：2004-8-10
最后修改日期      ：2004-8-10
-----------------------------------------------------------------------*/
void LCD_set_XY ( unsigned char X, unsigned char Y )
{
    LCD_write_byte ( 0x40 | Y, 0 );		// column
    LCD_write_byte ( 0x80 | X, 0 );          	// row
}

/*-----------------------------------------------------------------------
LCD_write_char    : 显示英文字符

输入参数：c       ：显示的字符；

编写日期          ：2004-8-10
最后修改日期      ：2004-8-10
-----------------------------------------------------------------------*/
void LCD_write_char ( unsigned char c )
{
    unsigned char line;

    c -= 32;

    for ( line = 0; line < 6; line++ )
        LCD_write_byte ( font6x8[c][line], 1 );
}

/*-----------------------------------------------------------------------
LCD_write_english_String  : 英文字符串显示函数

输入参数：*s      ：英文字符串指针；
          X、Y    : 显示字符串的位置,x 0-83 ,y 0-5

编写日期          ：2004-8-10
最后修改日期      ：2004-8-10
-----------------------------------------------------------------------*/
void LCD_write_english_string ( unsigned char X, unsigned char Y, char *s )
{
#if LCD_def

    LCD_set_XY ( X, Y );

    while ( *s )
    {
        LCD_write_char ( *s );
        s++;
    }

#endif
}
/*-----------------------------------------------------------------------
LCD_write_chinese_string: 在LCD上显示汉字

输入参数：X、Y    ：显示汉字的起始X、Y坐标；
          ch_with ：汉字点阵的宽度
          num     ：显示汉字的个数；
          line    ：汉字点阵数组中的起始行数
          row     ：汉字显示的行间距
编写日期          ：2004-8-11
最后修改日期      ：2004-8-12
测试：
	LCD_write_chi(0,0,12,7,0,0);
	LCD_write_chi(0,2,12,7,0,0);
	LCD_write_chi(0,4,12,7,0,0);
-----------------------------------------------------------------------*/
void LCD_write_chinese_string ( unsigned char X, unsigned char Y,
                                unsigned char ch_with, unsigned char num,
                                unsigned char line, unsigned char row )
{
    unsigned char i, n;

    LCD_set_XY ( X, Y );                         //设置初始位置

    for ( i = 0; i < num; )
    {
        for ( n = 0; n < ch_with * 2; n++ )      //写一个汉字
        {
            if ( n == ch_with )                  //写汉字的下半部分
            {
                if ( i == 0 ) LCD_set_XY ( X, Y + 1 );
                else
                    LCD_set_XY ( ( X + ( ch_with + row ) *i ), Y + 1 );
            }

            LCD_write_byte ( write_chinese[line + i][n], 1 );
        }

        i++;
        LCD_set_XY ( ( X + ( ch_with + row ) *i ), Y );
    }
}



/*-----------------------------------------------------------------------
LCD_draw_map      : 位图绘制函数

输入参数：X、Y    ：位图绘制的起始X、Y坐标；
          *map    ：位图点阵数据；
          Pix_x   ：位图像素（长）
          Pix_y   ：位图像素（宽）

编写日期          ：2004-8-13
最后修改日期      ：2004-8-13
-----------------------------------------------------------------------*/
void LCD_draw_bmp_pixel ( unsigned char X, unsigned char Y, unsigned char *map,
                          unsigned char Pix_x, unsigned char Pix_y )
{
    unsigned int i, n;
    unsigned char row;

    if ( Pix_y % 8 == 0 ) row = Pix_y / 8; //计算位图所占行数
    else
        row = Pix_y / 8 + 1;

    for ( n = 0; n < row; n++ )
    {
        LCD_set_XY ( X, Y );

        for ( i = 0; i < Pix_x; i++ )
        {
            LCD_write_byte ( map[i + n * Pix_x], 1 );
        }

        Y++;                         //换行
    }
}

/*-----------------------------------------------------------------------
LCD_write_byte    : 使用SPI接口写数据到LCD

输入参数：data    ：写入的数据；
          command ：写数据/命令选择；

编写日期          ：2004-8-10
最后修改日期      ：2004-8-13
-----------------------------------------------------------------------*/
void LCD_write_byte ( unsigned char dat, unsigned char command )
{
    unsigned char i;
    //PORTB &= ~LCD_CE ;		        // 使能LCD
    LCD_CE = 0;

    if ( command == 0 )
        // PORTB &= ~LCD_DC ;	        // 传送命令
        LCD_DC = 0;
    else
        // PORTB |= LCD_DC ;		        // 传送数据
        LCD_DC = 1;

    for ( i = 0; i < 8; i++ )
    {
        if ( dat & 0x80 )
            SDIN = 1;
        else
            SDIN = 0;

        SCLK = 0;
        dat = dat << 1;
        SCLK = 1;
    }

    // SPDR = data;			// 传送数据到SPI寄存器

    //while ((SPSR & 0x80) == 0);         // 等待数据传送完毕

    //PORTB |= LCD_CE ;			// 关闭LCD
    LCD_CE = 1;
}

void RefreshLCD ( void )
{
#if LCD_def
    u8 i;
    for ( i = 0; i < 6; i++ )
    {
        LCD_write_english_string ( 0, i, n5110_string[i] );
    }
#endif	
}

#define LCD_Clear(c)  LCD_clear()
/*********************************************************************************
	名称：void LCD_ShowCharString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t PenColor, uint16_t BackColor)
	参数：x，y      起始坐标
	      p         指向字符串起始地址
				PenColor  字符颜色
				BackColor 背景颜色
	功能：
	备注：用16字体，可以调节 此函数不能单独调用
*********************************************************************************/
void LCD_ShowCharString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t PenColor, uint16_t BackColor)
{   
	uint8_t size = 16;     /*---字符大小默认16*8---*/
	 
    if(x>MAX_CHAR_POSX){x=0;y+=size;}			         /*超出X轴字体最小单位，换行*/
    if(y>MAX_CHAR_POSY){y=x=0;LCD_Clear(WHITE);}	 /*超出Y轴字体最小单位，回到原点，并且清屏*/
    //LCD_ShowChar(x, y, *p, size, PenColor, BackColor);			   /*0表示非叠加方式*/
    LCD_set_XY ( x, y );
	LCD_write_char(*p);
}


/*********************************************************************************
	*名称: u16 findHzIndex(u8 *hz)
	*参数：hz
	*功能：索引汉字存储的内存地址
	*备注：
*********************************************************************************/
u16 findHzIndex(u8 *hz)                            /* 在自定义汉字库在查找所要显示 */
                                                      /* 的汉字的位置 */
{
	u16 i=0;
	FNT_GB16 *ptGb16 = (FNT_GB16 *)GBHZ_16;		  /*ptGb16指向GBHZ_16*/
	while(ptGb16[i].Index[0] > 0x80)
	{
	    if ((*hz == ptGb16[i].Index[0]) && (*(hz+1) == ptGb16[i].Index[1])) /*汉字用两位来表示地址码*/
			{
	      return i;
	    }
	    i++;
	    if(i > (sizeof((FNT_GB16 *)GBHZ_16) / sizeof(FNT_GB16) - 1))  /* 搜索下标约束 */
	    {
		    break;
	    }
	}
	return 0;
}

#if 0
/*********************************************************************************
	*名称：void WriteOneHz(uint16_t x0, uint16_t y0, uint8_t *pucMsk, uint16_t PenColor, uint16_t BackColor)
	*参数：x0,y0     起始坐标
		     *pucMsk   指向
				 PenColor	 字符颜色
				 BackColor 背景颜色
	*功能：
	*备注：此函数不能单独作为汉字字符显示											  
*********************************************************************************/					
void WriteOneHz(u16 x0, u16 y0, u8 *pucMsk, u16 PenColor, u16 BackColor)
{
    u16 i,j;
    u16 mod[16];                                      /* 当前字模 16*16 */
    u16 *pusMsk;                                      /* 当前字库地址  */
    u16 y;
		u16 size = 16;       /*汉字默认大小16*16*/

    pusMsk = (u16 *)pucMsk;

    for(i=0; i<16; i++)                                    /* 保存当前汉字点阵式字模       */
    {
			mod[i] = *pusMsk;                                /* 取得当前字模，半字对齐访问   */
			mod[i] = ((mod[i] & 0xff00) >> 8) | ((mod[i] & 0x00ff) << 8);/* 字模交换高低字节*/
			pusMsk = pusMsk+1;
    }
    y = y0;
		LCD_WindowMax(x0,y0,x0+size,y0+size);	 	/*设置窗口*/
		LCD_SetCursor(x0,y0);                       /*设置光标位置 */ 
		LCD_WriteRAM_Prepare();                     /*开始写入GRAM*/  
    for(i=0; i<16; i++)                                    /* 16行   */
    {                                              
      for(j=0; j<16; j++)                                /* 16列   */
      {
		    if((mod[i] << j) & 0x8000)       /* 显示第i行 共16个点 */
        { 
			    LCD_WriteRAM(PenColor);
        } 
				else 
				{
          LCD_WriteRAM(BackColor);      /* 用读方式跳过写空白点的像素*/
				}
      }
        y++;
    }
	LCD_WindowMax(0x0000,0x0000,240,320);  	/*恢复窗体大小*/
}
#endif
/*********************************************************************************
	*名称：void LCD_ShowHzString(u16 x0, u16 y0, u8 *pcStr, u16 PenColor, u16 BackColor)
	*参数：x0，y0    起始坐标
				 pcStr     指向
				 PenColor  字体颜色
				 BackColor 字体背景
	*功能：显示汉字字符串
	*备注：这个函数不能单独调用	       
*********************************************************************************/
void LCD_ShowHzString(u16 x0, u16 y0, u8 *pcStr, u16 PenColor, u16 BackColor)
{
 
	u16 usIndex;
	u8 size = 16; 
	FNT_GB16 *ptGb16 = 0;    
    ptGb16 = (FNT_GB16 *)GBHZ_16; 

	if(x0>MAX_HZ_POSX){x0=0;y0+=size;}			         /*超出X轴字体最小单位，换行*/
    if(y0>MAX_HZ_POSY){y0=x0=0;LCD_Clear(WHITE);}	   /*超出Y轴字体最小单位，回到原点，并且清屏*/

	usIndex = findHzIndex(pcStr);
	//WriteOneHz(x0, y0, (u8 *)&(ptGb16[usIndex].Msk[0]),  PenColor, BackColor); /* 显示字符 */
	LCD_draw_bmp_pixel(x0, y0, (u8 *)&(ptGb16[usIndex].Msk[0]),16, 16 );
}

/*********************************************************************************
	*名称：void LCD_ShowString(u16 x0, u16 y0, u8 *pcstr, u16 PenColor, u16 BackColor)
	*参数：x0 y0     起始坐标
				 pcstr     字符串指针
				 PenColor  字体颜色
				 BackColor 字体背景色
	*功能：调用字符和汉字显示函数，实现字符串显示
	*备注：	
*********************************************************************************/
void LCD_ShowString(u16 x0, u16 y0, u8 *pcStr, u16 PenColor, u16 BackColor)
{
	while(*pcStr!='\0')
	{
	 	if (x0>MAX_HZ_POSX)	/*保证剩余的空间能放下一个16*16的字，否则换行 */
			{
				y0+=16;
				x0=0;
			}
			if (y0>MAX_HZ_POSY)	/*保证剩余的空间能放下一个16*16的字，否则换行 */
			{
				y0=0;
			}
		if(*pcStr>0x80) /*显示汉字*/
		{
			LCD_ShowHzString(x0, y0, pcStr, PenColor, BackColor);
			pcStr += 2;
			x0 += 16;	
		}
		else           /*显示字符*/
		{
			LCD_ShowCharString(x0, y0, pcStr, PenColor, BackColor);	
			pcStr +=1;
			x0+= 8;
		}	
	}	
}


/*--------------下面三个函数 实现字库的调用及显示-------------------*/
FATFS fs;
FIL fsrc;      /* file objects  */
UINT br;         // File R/W count
static uint8_t Find_Chinese(uint8_t* str, uint8_t* p)
{
	uint8_t High8bit,Low8bit;
	FRESULT res;
	uint8_t error[]="Please put the sys folder which include the font file HZK16.bin into the SD  card  root directory. ";
	High8bit=*str;		 /*  高8位数据  */
	Low8bit=*(str+1);		 /*  低8位数据	*/
	
	f_mount(0, &fs);

	/* Infinite loop */
	res = f_open(&fsrc, "/sys/HZK16.bin", FA_OPEN_EXISTING | FA_READ);	 /* 在SD卡里搜索HZK16.bin*/
	if(res != 0)
	{
		LCD_ShowString(32,100,error,RED ,BLACK );
		return 1;
	}
	
	f_lseek(&fsrc,32*((High8bit-0xa0-1)*94+(Low8bit-0xa0-1)));
	f_read(&fsrc, p, 32, &br);
		
	f_close(&fsrc);	
	f_mount(0, NULL);
	return 0;	
}
/*********************************************************************************
* 名    称：void PutChinese(u16 x, u16 y, u8 *c, u32 PenColor, u32 BackColor)
* 入口参数：u16 x,u16 y 字符坐标位置
						u8  *c      汉字的指针
						u32 PenColor画笔颜色
						u32 BackColor背景颜色
* 出口参数：无
* 功    能：从SPI_FLASH里查找汉字基地址，
						并将32字节的点阵数据送到LCD显示
* 说    明：只能被GUI_Put调用
*********************************************************************************/
u8 buffer_r[32];
u8 *c_r;
void PutChinese(u16 x, u16 y, u8 *c, u32 PenColor, u32 BackColor)
{
	u16 i=0;
	u16 j=0;

	u8 buffer[32];
	u16 tmp_char=0;

	if(!Find_Chinese(c,buffer))
	{
		c_r = c;
		memcpy(buffer_r,buffer,32);
		LCD_draw_bmp_pixel(x,y,(u8 *)buffer,16,16);
		#if 0
		LCD_WindowMax(x,y,x+16,y+16);	 	/*设置窗口*/
		LCD_SetCursor(x,y);                       /*设置光标位置 */ 
		LCD_WriteRAM_Prepare();

		/* 16*16汉字点阵，共有16行 每行16个点，存储的时候是以字节为单位
			 需合并成字*/
		for (i=0;i<16;i++)		 
		{
			tmp_char=buffer[i*2];
			tmp_char=(tmp_char<<8);
			tmp_char|=buffer[2*i+1];  /*现在tmp_char存储着一行的点阵数据*/

			for (j=0;j<16;j++)
			{
				if((tmp_char<<j) & 0x8000)
					LCD_WriteRAM(PenColor);
				else
					LCD_WriteRAM(BackColor);
			}
		}
		LCD_WindowMax(0x00,0x00,240,320);  	/*恢复窗体大小*/
		#endif
	}
}

/*********************************************************************************
* 名    称：void GUI_Put(u16 x, u16 y, u8 *str,u32 PenColor, u32 BackColor)
* 入口参数：u16 x,u16 y 字符坐标位置
						u8  *c      汉字的指针
						u32 PenColor画笔颜色
						u32 BackColor背景颜色
* 出口参数：无
* 功    能：计算汉字显示坐标
* 说    明：
*********************************************************************************/
void GUI_Put(u16 x, u16 y, u8 *str,u32 PenColor, u32 BackColor)
{  
	do
	{
		if (x>MAX_HZ_POSX)	/*保证剩余的空间能放下一个16*16的字，否则换行 */
		{
			y+=16;
			x=0;
		}
		if (y>MAX_HZ_POSY)	/*保证剩余的空间能放下一个16*16的字，否则换行 */
		{
			y=0;
		}
		if ( *str < 0x80) /* 显示字符，字符点阵直接从font.h里调用，大小为16*8 */
		{	
			LCD_ShowCharString(x, y, str, PenColor, BackColor);
			x+= 8;
			str++;   
		}
		else	                /*大于等于0x80判断为汉字字符*/
		{ 
			PutChinese(x, y, str++, PenColor, BackColor);
			str++;		
			x+=16;      
		}
	}while(*str!=0);
}

