#include "terasic_includes.h"
#include "mcu.h"
#include "it6613_sys.h"
#include "hdmitx.h"
#include "HDMI_TX.h"


int TX_HDP = FALSE;
extern BYTE bOutputColorMode;
extern BYTE bInputColorMode;
extern BOOL bChangeMode;
extern RX_CAP RxCapability;
extern BOOL bHDMIMode;
extern BOOL bAudioEnable;
BOOL ParseEDID();

INSTANCE InitInstanceData = 
{
        0,0,  //I2C_DEV, I2C_ADDR
        0, //bIntType (TxCLK active, Push-Pull Mode, INT active low)
        0,/* | T_MODE_CCIR656 | T_MODE_SYNCEMB | T_MODE_INDDR */ // bInputVideoSignalType
        
        B_AUDFMT_STD_I2S, // bOutputAudioMode, 0x00, standard i2s, rising edge to sample ws/i2s, not full packet mode   REG[0xE1]
        
        0,// bAudioChannelSwap
        B_AUD_EN_I2S0 | B_AUD_I2S | M_AUD_16BIT, // bAudioChannelEnable, 0x01, REG[0xE0], defined in it6613_drv.h
        AUDFS_48KHz, //0, //bAudFs,
        0,  // TMDSClock
        TRUE,//bAuthenticated  
        TRUE,// bHDMIMode
        FALSE,// bIntPOL
        FALSE // bHPD
} ;

bool HDMITX_ChipVerify(void){
    bool bPass = FALSE;
    alt_u8 szID[4];
    int i;
    
    
    for(i=0;i<4;i++)
        szID[i] = HDMITX_ReadI2C_Byte(i);
        
//    if (szID[0] == 0x00 && szID[1] == 0xCA && szID[1] == 0x13 && szID[1] == 0x06) szID[0] ???
    if ((szID[1] == 0xCA && szID[2] == 0x13 && szID[3] == 0x06) || (szID[1] == 0xCA && szID[2] == 0x13 && szID[3] == 0x16)){
        bPass = TRUE;
        printf("TX Chip Revision ID: %d\n", szID[0]);     
    }else{
        printf("NG, Read TX Chip ID:%02X%02X%02X%02Xh (expected:00CA1306h)\n", szID[0], szID[1], szID[2], szID[3]);     
    }
                    
    return bPass;
}

bool HDMITX_Init(void){
    bool bSuccess = TRUE;
    HDMITX_Reset();
    usleep(500*1000);
    if (!HDMITX_ChipVerify()){
        OS_PRINTF("Failed to find IT6613 HDMI-TX Chip.\n");
        bSuccess = FALSE;
        //return 0;
    }    

    HDMITX_InitInstance(&InitInstanceData) ;
    InitIT6613() ;
    
    
    return bSuccess;  
}        

bool HDMITX_HPD(void){
    if (TX_HDP)
        return TRUE;
    return FALSE;        
}


void HDMITX_SetAVIInfoFrame(alt_u8 VIC, alt_u8 OutputColorMode, bool b16x9, bool ITU709)
{
     AVI_InfoFrame AviInfo;
    alt_u8 pixelrep = 0;
    
    OS_PRINTF("HDMITX_SetAVIInfoFrame, VIC=%d, ColorMode=%d, Aspect-Ratio=%s, ITU709=%s\n",
        VIC, OutputColorMode, b16x9?"16:9":"4:3", ITU709?"Yes":"No");

    AviInfo.pktbyte.AVI_HB[0] = AVI_INFOFRAME_TYPE|0x80 ; 
    AviInfo.pktbyte.AVI_HB[1] = AVI_INFOFRAME_VER ; 
    AviInfo.pktbyte.AVI_HB[2] = AVI_INFOFRAME_LEN ; 
    
    switch(OutputColorMode)
    {
    case F_MODE_YUV444:
        // AviInfo.info.ColorMode = 2 ;
        AviInfo.pktbyte.AVI_DB[0] = (2<<5)|(1<<4) ;
        break ;
    case F_MODE_YUV422:
        // AviInfo.info.ColorMode = 1 ;
        AviInfo.pktbyte.AVI_DB[0] = (1<<5)|(1<<4) ;
        break ;
    case F_MODE_RGB444:
    default:
        // AviInfo.info.ColorMode = 0 ;
        AviInfo.pktbyte.AVI_DB[0] = (0<<5)|(1<<4) ;
        break ;
    }
    AviInfo.pktbyte.AVI_DB[1] = 8 ;
    AviInfo.pktbyte.AVI_DB[1] |= (!b16x9)?(1<<4):(2<<4) ; // 4:3 or 16:9
    AviInfo.pktbyte.AVI_DB[1] |= (!ITU709)?(1<<6):(2<<6) ; // 4:3 or 16:9
    AviInfo.pktbyte.AVI_DB[2] = 0 ;
    AviInfo.pktbyte.AVI_DB[3] = VIC ;
    AviInfo.pktbyte.AVI_DB[4] =  pixelrep & 3 ;
    AviInfo.pktbyte.AVI_DB[5] = 0 ;
    AviInfo.pktbyte.AVI_DB[6] = 0 ;
    AviInfo.pktbyte.AVI_DB[7] = 0 ;
    AviInfo.pktbyte.AVI_DB[8] = 0 ;
    AviInfo.pktbyte.AVI_DB[9] = 0 ;
    AviInfo.pktbyte.AVI_DB[10] = 0 ;
    AviInfo.pktbyte.AVI_DB[11] = 0 ;
    AviInfo.pktbyte.AVI_DB[12] = 0 ;

    EnableAVIInfoFrame(TRUE, (unsigned char *)&AviInfo) ;
}

void HDMITX_ChangeVideoTiming(int VIC){
    int OutputVideoTiming = VIC;
    int HdmiColorMode;
    
    switch(bOutputColorMode)
    {
    case F_MODE_YUV444:
        HdmiColorMode =  HDMI_YUV444;
        break ;
    case F_MODE_YUV422:
        HdmiColorMode =  HDMI_YUV422;
        break ;
    case F_MODE_RGB444:
    default:
        HdmiColorMode =  HDMI_RGB444;
        break ;
    }    
    
    HDMITX_ChangeDisplayOption(OutputVideoTiming, HdmiColorMode); // just modify variable. Take effect when HDMITX_SetOutput is called in HDMITX_DevLoopProc   
}

void HDMITX_ChangeVideoTimingAndColor(int VIC, COLOR_TYPE Color){
    int OutputVideoTiming = VIC;
    int HdmiColorMode;
    
    switch(Color)
    {
    case COLOR_YUV444:
        HdmiColorMode =  HDMI_YUV444;
        break ;
    case COLOR_YUV422:
        HdmiColorMode =  HDMI_YUV422;
        break ;
    case COLOR_RGB444:
    default:
        HdmiColorMode =  HDMI_RGB444;
        break ;
    }     
    HDMITX_ChangeDisplayOption(OutputVideoTiming, HdmiColorMode);    
}

void HDMITX_DisableVideoOutput(void){
    DisableVideoOutput();        
}

void HDMITX_EnableVideoOutput(void){
    HDMITX_SetOutput();
}

void HDMITX_SetColorSpace(COLOR_TYPE InputColor, COLOR_TYPE OutputColor){
   // DisableVideoOutput();
    bInputColorMode = InputColor;
    bOutputColorMode = OutputColor;
   // HDMITX_SetOutput();
}

bool HDMITX_IsSinkSupportYUV444(void){
    bool bSupport = FALSE;
    if (RxCapability.Valid && RxCapability.ValidHDMI && RxCapability.ValidCEA && 
       (RxCapability.VideoMode & CEA_SUPPORT_YUV444))
        bSupport = TRUE;
    return bSupport;
}

bool HDMITX_IsSinkSupportYUV422(void){
    bool bSupport = FALSE;
    if (RxCapability.Valid && RxCapability.ValidHDMI && RxCapability.ValidCEA && 
       (RxCapability.VideoMode & CEA_SUPPORT_YUV422))
        bSupport = TRUE;
    return bSupport;
}

bool HDMITX_IsSinkSupportColorDepth36(void){
    bool bSupport = FALSE;
    if (RxCapability.Valid && RxCapability.ValidHDMI && RxCapability.ValidCEA && 
       RxCapability.dc.info.DC_36Bit)
        bSupport = TRUE;
    return bSupport;    
}


bool HDMITX_IsSinkSupportColorDepth30(void){
    bool bSupport = FALSE;
    if (RxCapability.Valid && RxCapability.ValidHDMI && RxCapability.ValidCEA && 
       RxCapability.dc.info.DC_30Bit)
        bSupport = TRUE;
    return bSupport;     
}

void HDMITX_SetOutputColorDepth(int ColorDepth){
    SetOutputColorDepthPhase(ColorDepth, 0);
}



bool HDMITX_DevLoopProc()
{
    static BYTE PreHPDChange = 0;
    static BYTE PreHPD = 0;
    BYTE HPD, HPDChange ;

    // Richard CheckHDMI(&HPD,&HPDChange) ;
    CheckHDMITX(&HPD,&HPDChange) ;
    
    if (HPD == PreHPD && HPDChange)  // richard add
        return FALSE;
        
    TX_HDP = HPD;    
    PreHPD = HPD;    
    PreHPDChange = HPDChange;    
    
    if( HPDChange )
    {
      
        
        OS_PRINTF("HPDChange\n");
        if( HPD )
        {
            OS_PRINTF("HPD=ON\n");
            RxCapability.Valid = ParseEDID() ;
            //bOutputColorMode = F_MODE_YUV444; //F_MODE_RGB444; // richard node. users can change color space here according to HDMI sink 
            
            if( RxCapability.Valid && RxCapability.ValidHDMI )
            {
                OS_PRINTF("HDMI Display found\n");
                bHDMIMode = TRUE ;
                
                if(RxCapability.VideoMode & (1<<6))
                {
                    bAudioEnable = TRUE ;
                }
                
#if 0    // richard, don't care edid, the output always RGB444                    
                if( RxCapability.VideoMode & (1<<5))
                {
                    bOutputColorMode &= ~F_MODE_CLRMOD_MASK ;
                    bOutputColorMode |= F_MODE_YUV444;
                }
                else if (RxCapability.VideoMode & (1<<4))
                {
                    bOutputColorMode &= ~F_MODE_CLRMOD_MASK ;
                    bOutputColorMode |= F_MODE_YUV422 ;
                }
#endif           
            }
            else if (!RxCapability.Valid)
            {
                OS_PRINTF("Failed to read EDID\n");
                
                // enable it when edid fail
                bHDMIMode = TRUE ;
                bAudioEnable = TRUE ;
            }     
            else    
            {
                OS_PRINTF("Invalid HDMI Display\n");
                bHDMIMode = FALSE ;
                bAudioEnable = FALSE ;
            }

            OS_PRINTF("HDMITX_SetOutput\n");
            //HDMITX_SetOutput() ;
            
        }
        else
        {
            OS_PRINTF("HPD=OFF\n");
            // unplug mode, ...
            OS_PRINTF("DisableVideoOutput\n");
            //DisableVideoOutput() ;
            RxCapability.Valid = FALSE; // richard add
            RxCapability.ValidHDMI = FALSE; // richard add
            RxCapability.ValidCEA = FALSE; // richard add
        }
    }
    else // no stable but need to process mode change procedure
    {
        if(bChangeMode && HPD)
        {
            OS_PRINTF("HDMITX_SetOutput\n");
            HDMITX_SetOutput() ;
        }
    }
    
    return HPDChange;
}

   