#include "r_typedefs.h" /* Renesas basic types, e.g. uint32_t */
#include "LCD_BUS.h"
#include "api_tft.h"
#include "r_bsp_api.h"
#include "r_dev_api.h"
#include "r_lcbi_api.h"
#include "LCD_MonoTFT.h"
#include "r_gpio_api.h"
#include "r_gpio_sys.h"
#include "sflash.h"

#define LCBI_NUM    0
#define LCBI_BASE   0xFFFB0000
#define LCBInSTATUS 0x00000474
#define LCBInIRQCLR 0x00000480

static const r_dev_ClkSelConfig_t loc_LcbiClkSelCfg [] =
    /*   Cks                   SrcId                Divider     tpReqMsk      */
    {
        {R_DEV_CKS_LCBI, R_DEV_CKS_SRC_CLKJIT, 0, 0},
        /* delimiter - do not remove */
        {R_DEV_CKS_LAST, R_DEV_CKS_SRC_MOSC, 0, 0}};

/*******************************************************************************
  Constant: loc_LcbiTftMode_PinConfig

  LCBI pin config
*/
/*  Port Pin Func      Dir      Feedback     Pull        OpenDrain   HiCurr   HiSpeed  InputType */
static const r_dev_PinConfig_t loc_LcbiNonTftMode_PinConfig [] = {
    /* LCBI0 Non-TFT mode (8bit) - port setup 0 */
    // Port pin Func dir feedback  pull OpenDrain  CurrLimit HiSpeed InputType
    {43, 0, 4u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* X_LCBI0CS */
    {45, 0, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* X_LCBI0RDE */
    {44, 4, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* X_LCBI0WRRW */
    {45, 1, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* LCBI0A0DE */
    {44, 7, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* LCBI0D0 */
    {44, 8, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* LCBI0D1 */
    {44, 9, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* LCBI0D2 */
    {44, 10, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1}, /* LCBI0D3 */
    {44, 11, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1}, /* LCBI0D4 */
    {45, 2, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* LCBI0D5 */
    {45, 3, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* LCBI0D6 */
    {45, 4, 3u, R_DEV_PIN_DIRECT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 1u, R_DEV_PIN_CMOS1},  /* LCBI0D7 */
    /* delimiter - do not remove */
    {0u, R_DEV_PIN_LAST, 0u, R_DEV_PIN_OUT, 0u, R_DEV_PIN_PULLNO, 0u, 0u, 0u, R_DEV_PIN_CMOS1}};

typedef union
{
    struct
    {
        uint32_t TIAD      : 4;
        uint32_t TIDZ      : 4;
        uint32_t TIDW      : 4;
        uint32_t Reserved0 : 4;
        uint32_t TIWR      : 8;
        uint32_t TIRD      : 8;
    } bits;
    uint32_t reg;
} LCBI_BCYC_t;

uint8_t updateVramIndex;
uint8_t LCDBUS_Init = 0;

void VsyncDetectionInit(void);

/*******************************************************************************
  Section: Local functions
*/

static uint8_t Lcbi_ReadData(void);
static void    VsyncDetectCallBack(uint8_t channel);

void Eic_Disable(void)
{
    R_SYS_GPIO_DisableInt(3);
    R_GPIO_DeInitInt(3);    // Disable  VSYNC
}

static void VsyncDetectCallBack(uint8_t channel)
{
    LCD_ActiveCheckTime = 0;
    updateVramIndex     = Draw_GetCurrentVram( );
    updateVramIndex     = (updateVramIndex + 1) % 2;
    if ( Draw_CheckCompleteVram(updateVramIndex) )
    {
        LCDPanelGraphicRAM = Draw_GetVramAddress(updateVramIndex);

        LCD_Panel_Update_Req(0, 160);
        return;
    }
    updateVramIndex = Draw_GetCurrentVram( );
    if ( Draw_CheckCompleteVram(updateVramIndex) )
    {
        LCDPanelGraphicRAM = Draw_GetVramAddress(updateVramIndex);
        LCD_Panel_Update_Req(0, 160);
    }
}

/*-------------------------------------------------------------------------
* Function Name  : VsyncDetectionInit
* Description    : 3?��??����a2??D?? ?a��?VSYNC��?2?
* Input          :
* Output         : None
* Return         : None
* onther         : WindowY:page Number
--------------------------------------------------------------------------*/
void VsyncDetectionInit(void)
{
    /* non-tft vsync detect */
    r_gpio_IntConfig_t GPIO_INT3_VSYNC;
    GPIO_INT3_VSYNC.Trigger  = R_GPIO_INT_FALLING_EDGE;
    GPIO_INT3_VSYNC.Callback = &VsyncDetectCallBack;
    GPIO_INT3_VSYNC.Port     = 44;
    GPIO_INT3_VSYNC.Pin      = 6;
    R_SYS_GPIO_EnableInt(3);
    R_GPIO_InitInt(3, ( r_gpio_IntConfig_t * )&GPIO_INT3_VSYNC);
}

LCBI_BCYC_t LCBI_BCYC;

void LCD_BUS_Init(void)
{
    uint32_t           u32_temp;
    r_lcbi_Parameter_t loc_r_lcbi_Param;
#if 0
    /* what is the current frequency */
    u32_temp = R_DEV_ClkFrequencyHz(R_DEV_CKS_LCBI);

    if (u32_temp == 0)
    {
        // error
        //while(1);
    }
#endif
    /* Select LCBI ports for TFT mode */
    R_DEV_PinInit(loc_LcbiNonTftMode_PinConfig);

    R_LCBI_Init(LCBI_NUM);

    R_LCBI_DisableInt(LCBI_NUM, R_LCBI_INT_RDY);
    R_LCBI_DisableInt(LCBI_NUM, R_LCBI_INT_EMPT);
    R_LCBI_DisableInt(LCBI_NUM, R_LCBI_INT_QTR);
    R_LCBI_DisableInt(LCBI_NUM, R_LCBI_INT_HALF);
    R_LCBI_DisableInt(LCBI_NUM, R_LCBI_INT_3QTR);
    R_LCBI_DisableInt(LCBI_NUM, R_LCBI_INT_FULL);

    // R_LCBI_SetIsrCallback(LCBI_NUM, R_LCBI_INT_EMPT, LcdBus_InstrFifo_isr);
    // R_LCBI_EnableInt(LCBI_NUM, R_LCBI_INT_EMPT);

    /* LCBI - Set non-TFT Mode */
    loc_r_lcbi_Param.WorkMode   = R_LCBI_WM_NONTFT;
    loc_r_lcbi_Param.CycleSpeed = R_LCBI_BUSCYCLE_SLOW;    // R_LCBI_BUSCYCLE_FAST;//
    loc_r_lcbi_Param.CycleType  = R_LCBI_BUSCYCLE_RAM;
    loc_r_lcbi_Param.TransMode  = R_LCBI_DIRECT;
    loc_r_lcbi_Param.AccessBit  = R_LCBI_8BIT;
    loc_r_lcbi_Param.ShiftBit   = R_LCBI_SHIFT1;

    R_LCBI_StopLcdBIF(LCBI_NUM);

    R_LCBI_SetClock(LCBI_NUM, R_LCBI_CLKDIV_1); /* LCBInCKSEL */

    R_LCBI_InvertOutput(LCBI_NUM, 0x00000000);                /* LCBInOUTLEV */
    R_LCBI_SetTConParam(LCBI_NUM, &loc_r_lcbi_Param);         /* LCBInTCONTROL */
    R_LCBI_SetBusCycle(LCBI_NUM, loc_r_lcbi_Param.CycleType); /* LCBInBCYCT */

    LCBI_BCYC.bits.TIRD = 4;
    LCBI_BCYC.bits.TIWR = 13;
    LCBI_BCYC.bits.TIDW = 4;
    LCBI_BCYC.bits.TIAD = 0;
    LCBI_BCYC.bits.TIDZ = 0;
    R_LCBI_SetNonTFTCycleSpec(LCBI_NUM, LCBI_BCYC.reg);  /* LCBInBCYC  #define R_LCBI_NONTFT_CYCLE   0x04040444 */
    R_LCBI_SetWorkingParam(LCBI_NUM, &loc_r_lcbi_Param); /* LCBInOPMODE  : CycleSpeed / WorkMode */

    VsyncDetectionInit( );

    LCDBUS_Init = 1;
}

/*******************************************************************************
  Function: LCD_BUS_DeInit

*/
void LCD_BUS_DeInit(void)
{
    /* LCBI - Stop and de-Init */
    R_LCBI_StopLcdBIF(LCBI_NUM);
    R_LCBI_DeInit(LCBI_NUM);
}

/*******************************************************************************
  Function: Lcbi_WriteControl

*/
void Lcbi_WriteControl(uint8_t Reg)
{
    R_LCBI_WriteData8_A0C(LCBI_NUM, Reg);
}

/*******************************************************************************
  Function: Lcbi_WriteData8

*/
void Lcbi_WriteData8(uint8_t Value)
{
    R_LCBI_WriteData8_A0S(LCBI_NUM, Value);
}

/*******************************************************************************
  Function: Lcbi_WriteControlData

*/
void Lcbi_WriteControlData(uint8_t Reg, uint8_t Para [], uint8_t ParaLen)
{
    uint8_t i = 0;
    Lcbi_WriteControl(Reg);
    for ( i = 0; i < ParaLen; i++ )
    {
        Lcbi_WriteData8(Para [ i ]);
    }
}

typedef union
{
    struct
    {

        uint32_t LCBInTCIDLE : 1;
        uint32_t LCBInTCLOCK : 1;
        uint32_t LCBInTCRPG  : 1;
        uint32_t Reserved1   : 29;
    } bits;
    uint32_t reg;
} LCBInSTATUS_t;

LCDBUS_opr_t LCDBUS_GetOperationStatus(void)
{
    LCDBUS_opr_t  opr_mode = Notidle;
    LCBInSTATUS_t LCBInSTATUS_str;
    LCBInSTATUS_str.reg = READ_REG(32, 0xFFFB0474);
    if ( LCBInSTATUS_str.bits.LCBInTCIDLE )
    {
        opr_mode = Idle;
    }
    return opr_mode;
}


void LCDBUS_Check_RealTime(void)
{/* Task 10ms */
    //if(QSPI_Init == 1)
    //{
        if((LCD_ActiveCheckTime >= 300) || (LCDBUS_Init == 0))
        {/* 3S */
            LCD_ActiveCheckTime = 0;
            LCD_BUS_Init();
            LCD_Panel_Start_Up();       
        }
        else
        {
            LCD_ActiveCheckTime ++;
        }
    //}
}

void LCDBUS_Monitor_Time_ISR(void)
{/* task 50us */
    if(QSPI_Init == 0)
    {
        if(QSPI_InitTime < 500)
        {
            QSPI_InitTime += 10;
        }
        LCD_ActiveCheckTime = 0;
    }
    else
    {
        // if(Font_InitTime < 1000)
        // {
        //     Font_InitTime += 10;
        // }
        LCD_ActiveCheckTime ++;
    }
}