/******************************************************************************
文 件 名：TFT_LCD.c
功能描述：TFT彩色液晶显示屏控制函数库文件
作    者：张暄
版    本：V1.0
日    期：2017.4.8
******************************************************************************/

#include "TFT_LCD.h"

TFTLCDLayerStatusStruct   TFTLCDLayerStatus[YVC_LYR_NUM_CPU];
TFTLCDLayerBufferStruct   TFTLCDLayer[YVC_LYR_NUM_CPU];

TFTLCDUpdateCtrlStruct    TFTLCDUpdateCtrl;

/******************************************************************************
函数名：TFT_LCD_Display_Sprite
功  能：在TFT彩色液晶显示屏上贴图
参  数：LyrId   ：图层编号 0 - YVC_LYR_NUM_CPU(在YvcConfig.h中设置)
        SpriteID：图片编号(名称)
        PosX    ：图片显示于显示屏上的x坐标
        PosY    ：图片显示于显示屏上的y坐标
        Scale   : 图片缩放比例,精度为0.015625(1 / 64),设置为64时图片为原始比例
返回值：无
******************************************************************************/
void TFT_LCD_Display_Sprite(uint16_t LyrId, uint16_t SpriteID, uint16_t PosX, uint16_t PosY, uint8_t Scale)
{
  if (TFTLCDUpdateCtrl.Enable == 0)
    return;

  if (TFTLCDLayerStatus[LyrId].LyrEn)                 //如果该图层已经使用
  {
    if ((TFTLCDLayerStatus[LyrId].SpriteID == SpriteID) && \
        (TFTLCDLayerStatus[LyrId].PosX == PosX) && \
        (TFTLCDLayerStatus[LyrId].PosY == PosY) && \
        (TFTLCDLayerStatus[LyrId].Scale == Scale))    //如果图层上显示的图像与当前要求的一致
      return;                                           //则直接返回
  }

  TFT_LCD_Update_Layer_Buffer(LyrId, SpriteID, PosX, PosY, Scale);

  TFTLCDLayerStatus[LyrId].LyrEn = 1;
  TFTLCDLayerStatus[LyrId].SpriteID = SpriteID;
  TFTLCDLayerStatus[LyrId].PosX = PosX;
  TFTLCDLayerStatus[LyrId].PosY = PosY;
  TFTLCDLayerStatus[LyrId].Scale = Scale;
}

/******************************************************************************
函数名：TFT_LCD_Clear_Layer
功  能：清除指定图层上的图片显示
参  数：LyrId：图层编号 0 - YVC_LYR_NUM_CPU(在YvcConfig.h中设置)
返回值：无
******************************************************************************/
void TFT_LCD_Clear_Layer(uint16_t LyrId)
{
  uint8_t i;

  if (TFTLCDUpdateCtrl.Enable == 0)
    return;

  if (TFTLCDLayerStatus[LyrId].LyrEn)
  {
    //1.清除层Buffer之前先禁止传输当前层Buffer中的数据到YGV642
    TFTLCDLayer[LyrId].UpdateCnt = 0;

    //2.清除层Buffer数据
    for (i = 0; i < 12; i++)
      TFTLCDLayer[LyrId].Buffer[i] = TFTLCDBlankLayer[i];

    //3.重置层Buffer中的数据需要更新到YGV642中的次数
    TFTLCDLayer[LyrId].UpdateCnt = 2;                   //YGV642前台后台共两个显示表格需要更新

    TFTLCDLayerStatus[LyrId].LyrEn = 0;
  }
}

/******************************************************************************
函数名：TFT_LCD_Clear_Multi_Layer
功  能：清除指定的多个图层上的图片显示
参  数：LyrIdLo：起始图层编号 0 - YVC_LYR_NUM_CPU(在YvcConfig.h中设置)
        LyrIdHi：结束图层编号 0 - YVC_LYR_NUM_CPU(在YvcConfig.h中设置)
返回值：无
******************************************************************************/
void TFT_LCD_Clear_Multi_Layer(uint16_t LyrIdLo, uint16_t LyrIdHi)
{
  uint16_t LyrId;

  for (LyrId = LyrIdLo; LyrId <= LyrIdHi; LyrId++)
    TFT_LCD_Clear_Layer(LyrId);
}

/******************************************************************************
函数名：TFT_LCD_Startup
功  能：启动TFT彩色液晶显示屏
参  数：无
返回值：无
******************************************************************************/
void TFT_LCD_Startup(void)
{
  uint8_t i;
  
  YMA_CTL = 1;    //----hyq--20180317
  YGV642_Wait_ms(200);
  
  //1.开启电源前确保复位信号为低且背光关闭
  TFT_nRST = 0;
  LCD_BL   = 0;

  //2.开TFT屏和YGV642的电源
  //PWR_nVIOEN = 1;   //Power up VDD5 and then power up VDDIN.    常亮管脚
  PWR_3V3EN  = 1;

  //3.延时10ms
  wdt_reset();
  YGV642_Wait_ms(200);

  //4.释放复位信号
  TFT_nRST = 1;

  //5.初始化YGV642
  LCD_Init();
  YGV642_Init();
  //LCD_Init();   
  /*--- Transparent Color output (透明色设置) ---*/
  //透明色的设置值应与XFL converter导出文件时Transparent color的颜色值相对应
  YGV642_Set_Transparent_Color(0xFF, 0x00, 0xFF);

  /*--- Border Color output (边框色设置)---*/
  YGV642_Set_Border_Color(0x00, 0x00, 0x00);

  /*--- Host layer enable ---*/
  YGV642_Enable_Host_Controlled_Layer();

  //6.初始化数据标志
  for (i = 0; i < YVC_LYR_NUM_CPU; i++)
  {
    TFTLCDLayerStatus[i].LyrEn = 0;
    TFTLCDLayer[i].UpdateCnt   = 0;
  }

  TFTLCDUpdateCtrl.TblUpdate   = 0;
  TFTLCDUpdateCtrl.LyrBaseAddr = YGV642_Get_Updateable_Table();
  TFTLCDUpdateCtrl.Timer       = 0;
  TFTLCDUpdateCtrl.State       = 0;
  TFTLCDUpdateCtrl.Brightness  = 0;
  TFTLCDUpdateCtrl.Enable      = 1;

  //7.初始化液晶屏
  //LCD_Init();
  TFT_STB =1;
  PWM_Channel_Init(5, PWM_CLOCK_SA, PWM_POL_POS, PWM_LEFT_ALIGN, PWM5_PM1);
  PWM_Channel_Set_Freq(5, 500);
  PWM_Channel_Set_Duty_Cycle(5, 0);   //初始化为背光关闭,由后续应用程序开启
  PWM_Channel_Start(5); 
 }

void TFT_LCD_Shutdown(void)
{
  PWM_Channel_Stop(4);
  LCD_BL   = 0;
  TFT_STB = 0;
  TFTLCDUpdateCtrl.Enable = 0;
  //YMA_CTL = 0;
}

/******************************************************************************
函数名：TFT_LCD_Set_Brightness
功  能：TFT彩色液晶背光亮度控制
参  数：Br：亮度等级 0(最暗) - 100(最亮)
返回值：无
******************************************************************************/
void TFT_LCD_Set_Brightness(uint8_t Br)
{
  if (TFTLCDUpdateCtrl.Enable == 0)
    return;

  if (Br > 100)
    Br = 100;

  if (Br != TFTLCDUpdateCtrl.Brightness)
  {
    TFTLCDUpdateCtrl.Brightness = Br;
    PWM_Channel_Set_Duty_Cycle(4, Br);
  }
}

/******************************************************************************
函数名：TFT_LCD_Display_Update_Service
功  能：TFT彩色液晶显示屏显示更新服务
参  数：无
返回值：无
*******************************************************************************
注  意：该服务函数必须每2ms被调用一次
******************************************************************************/
void TFT_LCD_Display_Update_Service(void)
{
  if (TFTLCDUpdateCtrl.Enable == 0)
    return;

  if (TFTLCDUpdateCtrl.Timer < 0xFF)
    TFTLCDUpdateCtrl.Timer++;

  switch (TFTLCDUpdateCtrl.State)
  {
  case 0  :
    if (YGV642_Get_Table_Flip_Status() == YVC1_TBL_FLIP_COMPLETE)
      TFTLCDUpdateCtrl.State  = 1;
    break;

  case 1  :
    TFT_LCD_Start_Update_General_Table();
    TFTLCDUpdateCtrl.State  = 2;
    break;

  case 2  :
    if ((TFT_LCD_Get_General_Table_Update_Status() == 0) && \
        (TFTLCDUpdateCtrl.Timer >= 10))
    {
      TFTLCDUpdateCtrl.LyrBaseAddr = YGV642_Flip_Table();
      TFTLCDUpdateCtrl.Timer = 0;
      TFTLCDUpdateCtrl.State = 0;
    }
    break;

  default :
    TFTLCDUpdateCtrl.TblUpdate   = 0;
    TFTLCDUpdateCtrl.LyrBaseAddr = YGV642_Get_Updateable_Table();
    TFTLCDUpdateCtrl.Timer       = 0;
    TFTLCDUpdateCtrl.State       = 0;
    break;
  }
}

/******************************************************************************
函数名：TFT_LCD_Update_Layer_Buffer
功  能：更新TFT彩色液晶显示屏显示缓存
参  数：LyrId   ：图层编号 0 - YVC_LYR_NUM_CPU(在YvcConfig.h中设置)
        SpriteID：图片编号(名称)
        PosX    ：图片显示于显示屏上的x坐标
        PosY    ：图片显示于显示屏上的y坐标
        Scale   : 图片缩放比例,精度为0.015625(1 / 64),设置为64时图片为原始比例
返回值：无
******************************************************************************/
#pragma CONST_SEG __GPAGE_SEG DEFAULT
void TFT_LCD_Update_Layer_Buffer(uint16_t LyrId, uint16_t SpriteID, uint16_t PosX, uint16_t PosY, uint8_t Scale)
{
  uint8_t i;

  T_Y642_LYR_SPRTATTR  LyrSprtAttr;

  //1.取出对应图片的12字节属性字
  for (i = 0; i < 12; i++)
    LyrSprtAttr.BYTE[i] = tVc1hPatternData[SpriteID].SpriteAttributeData[i];

  //2.修改图片的x,y坐标
  LyrSprtAttr.BIT.DOX_0 = (uint8_t)( PosX       & 0x00FF);
  LyrSprtAttr.BIT.DOX_8 = (uint8_t)((PosX >> 8) & 0x0007);
  LyrSprtAttr.BIT.DOY_0 = (uint8_t)( PosY       & 0x00FF);
  LyrSprtAttr.BIT.DOY_8 = (uint8_t)((PosY >> 8) & 0x0007);

  //3.调整图片缩放比例
  LyrSprtAttr.BIT.MAGX  = Scale;
  LyrSprtAttr.BIT.MAGY  = Scale;

  //LyrSprtAttr.BIT.ALPHA_1  = 1;
  //LyrSprtAttr.BIT.ALPHA_0  = 0;

  //4.更新层Buffer之前先禁止传输当前层Buffer中的数据到YGV642
  TFTLCDLayer[LyrId].UpdateCnt = 0;

  //5.更新层Buffer数据
  for (i = 0; i < 12; i++)
    TFTLCDLayer[LyrId].Buffer[i] = LyrSprtAttr.BYTE[i];

  //6.重置层Buffer中的数据需要更新到YGV642中的次数
  TFTLCDLayer[LyrId].UpdateCnt = 2;                   //YGV642前台后台共两个显示表格需要更新
}
#pragma CONST_SEG DEFAULT

/******************************************************************************
函数名：TFT_LCD_Start_Update_General_Table
功  能：开始更新图形控制芯片内的显示数据表
参  数：无
返回值：无
******************************************************************************/
void TFT_LCD_Start_Update_General_Table(void)
{
  TFTLCDUpdateCtrl.TblUpdate  = 1;
  TFTLCDUpdateCtrl.CurrentLyr = 0;
  TFTLCDUpdateCtrl.Step       = 0;
}

/******************************************************************************
函数名：TFT_LCD_Get_General_Table_Update_Status
功  能：获取图形控制芯片内的显示数据表的更新状态
参  数：无
返回值：0 - 当前没有在更新
        1 - 当前正在更新
******************************************************************************/
uint8_t TFT_LCD_Get_General_Table_Update_Status(void)
{
  return TFTLCDUpdateCtrl.TblUpdate;
}

/******************************************************************************
函数名：TFT_LCD_General_Table_Write_Service
功  能：图形控制芯片内的显示数据表数据更新服务
参  数：无
返回值：无
*******************************************************************************
注  意：该服务函数必须每于系统空闲时实时调用
******************************************************************************/
void TFT_LCD_General_Table_Write_Service(void)
{
  uint8_t   i;
  uint16_t  TblAddr;

  if (TFTLCDUpdateCtrl.Enable == 0)
    return;

  if (TFTLCDUpdateCtrl.TblUpdate)
  {
    switch (TFTLCDUpdateCtrl.Step)
    {
      //Step 0  ：准备数据
    case 0  :
      if(TFTLCDUpdateCtrl.CurrentLyr < YVC_LYR_NUM_CPU)
      {
        if (TFTLCDLayer[TFTLCDUpdateCtrl.CurrentLyr].UpdateCnt)
        {
          TblAddr = TFTLCDUpdateCtrl.LyrBaseAddr + TFTLCDUpdateCtrl.CurrentLyr * Y642_LYR_SIZE;
          TFTLCDUpdateCtrl.AddrBuffer[0] = (uint8_t)(TblAddr >> 8);
          TFTLCDUpdateCtrl.AddrBuffer[1] = (uint8_t)TblAddr;

          for (i = 0; i < 12; i++)
            TFTLCDUpdateCtrl.Data[i] = TFTLCDLayer[TFTLCDUpdateCtrl.CurrentLyr].Buffer[i];

          TFTLCDLayer[TFTLCDUpdateCtrl.CurrentLyr].UpdateCnt--;
          TFTLCDUpdateCtrl.Step = 1;
        }
      }
      else
        TFTLCDUpdateCtrl.TblUpdate = 0;
      TFTLCDUpdateCtrl.CurrentLyr++;
      break;

      //Step  1：拉低nCS
    case 1  :
      YGV642_SPI_nCS_Low();
      TFTLCDUpdateCtrl.Step = 2;
      break;

      //Step  2：选择寄存器地址端口
    case 2  :
      YGV642_SPI_Byte_Write(YVC1_PORT_REG_SEL);
      TFTLCDUpdateCtrl.Step = 3;
      break;

      //Step  3：28H寄存器(General Table地址)+地址自增
    case 3  :
      YGV642_SPI_Byte_Write(REG_R28H | YVC1REG_AIRG);
      TFTLCDUpdateCtrl.Step = 4;
      break;

      //Step  4：拉高nCS
    case 4  :
      YGV642_SPI_nCS_High();
      TFTLCDUpdateCtrl.Step = 5;
      break;

      //Step  5：拉低nCS
    case 5  :
      YGV642_SPI_nCS_Low();
      TFTLCDUpdateCtrl.BytePtr = 0;
      TFTLCDUpdateCtrl.Step = 6;
      break;

      //Step  6：选择寄存器数据端口
    case 6  :
      YGV642_SPI_Byte_Write(YVC1_PORT_REG_DATA);
      TFTLCDUpdateCtrl.Step = 7;
      break;

      //Step  7：写General Table地址
    case 7  :
      YGV642_SPI_Byte_Write(TFTLCDUpdateCtrl.AddrBuffer[TFTLCDUpdateCtrl.BytePtr]);
      TFTLCDUpdateCtrl.BytePtr++;
      if (TFTLCDUpdateCtrl.BytePtr >= 2)
        TFTLCDUpdateCtrl.Step = 8;
      break;


      //Step  8：拉高nCS
    case 8  :
      YGV642_SPI_nCS_High();
      TFTLCDUpdateCtrl.Step = 9;
      break;

      //Step  9：拉低nCS
    case 9  :
      YGV642_SPI_nCS_Low();
      TFTLCDUpdateCtrl.BytePtr = 0;
      TFTLCDUpdateCtrl.Step = 10;
      break;

      //Step 10：选择General Table数据端口
    case 10 :
      YGV642_SPI_Byte_Write(Y642_PORT_GENTBL_DATA);
      TFTLCDUpdateCtrl.Step = 11;
      break;

      //Step 11：写General Table数据
    case 11 :
      YGV642_SPI_Byte_Write(TFTLCDUpdateCtrl.Data[TFTLCDUpdateCtrl.BytePtr]);
      TFTLCDUpdateCtrl.BytePtr++;
      if (TFTLCDUpdateCtrl.BytePtr >= 12)
        TFTLCDUpdateCtrl.Step = 12;
      break;

      //Step 12：拉高nCS
    case 12 :
      YGV642_SPI_nCS_High();
      TFTLCDUpdateCtrl.Step = 0;
      break;

    default :
      TFTLCDUpdateCtrl.TblUpdate = 0;
      break;
    }
  }
}