/**
 * @file hv_app_ddcci.c
 * @brief ddcci c file.
 * @details This file provides the following functions: \n
 *          (1) A Group of functions to parse incomming messages and form the reply. \n
 *          (2) Hv_App_Ddcci_HandleMsg as the main entry. \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2023-01-31
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                   <th>Date        <th>Change Description
 * <tr><td>HiView SoC Software Team <td>2023-01-31  <td>create
 * </table>
 */


#include "hv_comm_Assert.h"
#include "hv_comm_Log.h"

#include "hv_mw_Audio.h"
#include "hv_mw_OsdOperation.h"
#include "hv_mw_Factory.h"
#include "hv_mw_Channel_Manager.h"
#include "hv_mw_AppInterface.h"
#include "hv_mw_PowerManager.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_PanelManager.h"
#include "hv_mw_Hdmi.h"
#include "hv_comm_DataBase.h"
#include "hv_app_Function.h"
#include "hv_app_Osd.h"
#include "hv_app_PQ.h"
#include "hv_app_OsdDialog.h"
#include "hv_app_Ddcci.h"
#include "hv_app_DdcciOTA.h"
#include "hv_app_DdcciPQ.h"
#include "hv_app_DdcciFactory.h"
#include "hv_app_DdcciRegister.h"
#include "hv_app_OsdConvert.h"


//****************************************************************************
// DEFINITIONS / MACROS
//****************************************************************************

#define DDCCI_FIRMWARE_VERSION                     0x01

//****************************************************************************
// VARIABLE DECLARATIONS
//****************************************************************************

UCHAR8 gucDdcLongMsg[8 * 1024];

static UCHAR8 s_ucDdcciNewControlValue = 1;

/**
 * @brief Global Capabilities Strings of HDMI.
 */
static const UCHAR8 s_aucCapStringHdmi[] =
{
    DDCCI_CAPABILITIES_HDMI
};

/**
 * @brief Global Capabilities Strings of DP.
 */
static const UCHAR8 s_aucCapStringDp[] =
{
    DDCCI_CAPABILITIES_DP
};

DDCCI_PROC_HANDLE gpfProcOtherDdcciMsg;

/**
 * @brief Initial TX variables and Send Null-Message.
 * @param[in] enDdcciPort 表征是哪个通道.
 * @return None.
 */
VOID Hv_App_Ddcci_SendNullMsg(DdcciPortEnum enDdcciPort)
{
    UCHAR8 aucNullMsg[DDCCI_HEADER_LEN] = {0};
    
    // Send Null-Message
    aucNullMsg[DDCCI_SOURCE] = DDCCI_DEST_ADDRESS;
    aucNullMsg[DDCCI_LENGTH] = DDCCI_CONTROL_STATUS_FLAG;
    aucNullMsg[DDCCI_COMMAND] = Hv_App_Ddcci_CalCheckSum(aucNullMsg);

    Hv_App_Ddcci_SendData(enDdcciPort, aucNullMsg, DDCCI_HEADER_LEN);

    return;
}

/**
 * @brief 根据偏移量获取指定长度的能力字符串.
 * @param[out] pucDest 保存取到的字符串.
 * @param[in] enDdcciPort 表征是要获取哪个通道的能力字符串.
 * @param[in] usStartIndex 表征是从哪个偏移量开始取字符串.
 * @param[in] ucLength 表征要取多长的字符串.
 * @return None.
 */
static VOID Hv_App_Ddcci_GetCapStringData(UCHAR8 *pucDest, DdcciPortEnum enDdcciPort, USHORT16 usStartIndex, UCHAR8 ucLength)
{
    switch(enDdcciPort)
    {
        case DDCCI_PORT_HDMI0:
        case DDCCI_PORT_HDMI1:
        {
            HV_MEMCPY(pucDest, &s_aucCapStringHdmi[usStartIndex], ucLength);
            break;
        }
        case DDCCI_PORT_DP0:
        case DDCCI_PORT_DP1:
        {
            HV_MEMCPY(pucDest, &s_aucCapStringDp[usStartIndex], ucLength);
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}


/**
 * @brief 获取指定通道上的能力字符串的总长度.
 * @param[in] enDdcciPort 表征是要获取哪个通道的能力字符串.
 * @return UINT32 该通道的能力字符串的总长度.
 */
static UINT32 Hv_App_Ddcci_GetCapStringSize(DdcciPortEnum enDdcciPort)
{
    switch(enDdcciPort)
    {
        case DDCCI_PORT_HDMI0:
        case DDCCI_PORT_HDMI1:
        {
            return (sizeof(s_aucCapStringHdmi) - 1);
        }
        case DDCCI_PORT_DP0:
        case DDCCI_PORT_DP1:
        {
            return (sizeof(s_aucCapStringDp) - 1);
        }
        default:
        {
            return 0;
        }
    }
}


/**
 * @brief 配置VCP Feature Reply的数据.
 * @param[in] pucData Pointer to the reply data.
 * @param[in] ucTypeOpcode OPCODE.
 * @param[in] usMax 最大值.
 * @param[in] usPresent 当前值.
 * @return Status Always return HV_SUCCESS.
 */
static VOID Hv_App_Ddcci_SetVcpReplyValue(UCHAR8 *pucData, UCHAR8 ucTypeOpcode, USHORT16 usMax, USHORT16 usPresent)
{
    if (NULL != pucData)
    {
        pucData[DDCCI_TYPE_CODE] = ucTypeOpcode;
        pucData[DDCCI_MAX_HIGH_BYTE] = HIBYTE(usMax);
        pucData[DDCCI_MAX_LOW_BYTE] = LOBYTE(usMax);
        pucData[DDCCI_PRESENT_HIGH_BYTE] = HIBYTE(usPresent);
        pucData[DDCCI_PRESENT_LOW_BYTE] = LOBYTE(usPresent);
    }

    // DDC_PRINT("set reply current(high low): %d %d", s_aucDdcciTxBuf[DDCCI_PRESENT_HIGH_BYTE], s_aucDdcciTxBuf[DDCCI_PRESENT_LOW_BYTE]);
    return;
}


/**
 * @brief DDCCI Get VCP Feature & VCP Feature Reply for input timing.
 * @param[in] enPort type of input source.
 * @param[in] pucData Pointer to the reply data.
 * @param[in] ucOpCode type of timing info.
 * @return None.
 */
static VOID Hv_App_Ddcci_GetVcpFeatureTimingInfo(DdcciPortEnum enPort, UCHAR8 *pucData, UCHAR8 ucOpCode)
{
    BOOL bInterlacedMode = HV_FALSE;
    UINT32 uiRefreshRate = 0;
    USHORT16 usFrameRate = 0;
    
    ChannelData stChannelData = {0};
    Hv_Mw_InputPort_GetVideoPara(enPort, &stChannelData);
    bInterlacedMode = stChannelData.stRxVideoTiming.bInterlacedMode;
    
    uiRefreshRate = Hv_Mw_InputPort_GetCurrentFrameRate(enPort);
    usFrameRate = (uiRefreshRate + 500) / 1000;
    if (bInterlacedMode)
    {
        usFrameRate /= 2;
    }

    switch(ucOpCode)
    {
        case DDCCI_OPCODE_VCP_HFREQ:
        {
            // Hv_App_Ddcci_SetVcpReplyValue(pucData, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0xFFFF, stTimingInfo.usVFreq * 10);
            break;
        }
        case DDCCI_OPCODE_VCP_VFREQ:
        {
            Hv_App_Ddcci_SetVcpReplyValue(pucData, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, LOWORD((UINT32)usFrameRate * 100), HIWORD((UINT32)usFrameRate * 100));
            break;
        }
        default:
            break;
    }
    return;
}


/**
 * @brief DDCCI Get VCP Feature & VCP Feature Reply.
 * @param[in] enDdcciPort 表征是哪个通道.
 * @param[in] pucData Pointer of the data.
 * @param[in] ucLen Length of the data.
 * @return None.
 */
static VOID Hv_App_Ddcci_GetVcpFeature(DdcciPortEnum enDdcciPort, UCHAR8 *pucData, UCHAR8 ucLen)
{
    UCHAR8 pucTemp[2] = {0};
    /*
        标准规定返回值总是11字节，
        0x6E--Len--0x02--RC--CP--TP--MH--ML--SH--SL--CRC
          0   1     2    3   4   5   6   7   8   9   10 
    */
    UCHAR8 aucResp[DDCCI_GET_VCP_DATA_LEN+DDCCI_HEADER_LEN] = {0};

    aucResp[DDCCI_SOURCE] = DDCCI_DEST_ADDRESS;
    aucResp[DDCCI_LENGTH] = DDCCI_CONTROL_STATUS_FLAG | DDCCI_GET_VCP_DATA_LEN;
    aucResp[DDCCI_COMMAND] = DDCCI_CMD_GET_VCP_FEATURE_REPLY;
    aucResp[DDCCI_RESULT_CODE] = DDCCI_CMD_GETVCP_RC_NO_ERROR;
    aucResp[DDCCI_SINK_OPCODE] = pucData[DDCCI_SOURCE_OPCODE];

    switch (pucData[DDCCI_SOURCE_OPCODE])
    {
        case DDCCI_OPCODE_VCP_NEW_CONTROL_VALUE:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x0002, s_ucDdcciNewControlValue);
            break;
        }
        case DDCCI_OPCODE_VCP_FACTORY_RESET:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_MOMENTARY, 0x0001, 0x00);
            break;
        }
        case DDCCI_OPCODE_VCP_RECAL_BRI_CON:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_MOMENTARY, 0x0001, 0x00);
            break;
        }
        case DDCCI_OPCODE_VCP_GEOMETRY_RESET:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_MOMENTARY, 0x0001, 0x00);
            break;
        }
        case DDCCI_OPCODE_VCP_COLOR_RESET:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_MOMENTARY, 0x0001, 0x00);
            break;
        }
        case DDCCI_OPCODE_VCP_COLOR_TEMP_INCREMENT:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x0000, 100);
            break;
        }
        case DDCCI_OPCODE_VCP_COLOR_TEMP_REQUEST:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_CLOCK:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_BACKLIGHT:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdBrightnessMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucBrightness));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_CONTRAST:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdContrastMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucContrast));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_SELECT_COLOR_PRESET:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdColorTempMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucColorTemperature));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_RED_GAIN:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdRedGainMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucRed));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_GREEN_GAIN:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdGreenGainMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucGreen));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_BLUE_GAIN:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdBlueGainMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucBlue));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_AUTO_SET_UP:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_MOMENTARY, 0x0001, 0x00);
            break;
        }
        case DDCCI_OPCODE_VCP_HPOSITION:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_VPOSITION:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_CLOCK_PHASE:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_ACTIVE_CONTROL:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_INPUT_SOURCE:
        {
            // mccs defs: 0x0F-DP1, 0x10-DP2, 0x11-HDMI1, 0x12-HDMI2
            UCHAR8 ucGetSource = HV_COMMON_DATABASE_GET(UserData, ucVideoSource);
            UINT32 uiVal;
            
            if (LINK_PORT_INDEX_HDMI_RX0 == ucGetSource)
            {
                ucGetSource = 0x11;
            }
            else if (LINK_PORT_INDEX_HDMI_RX1 == ucGetSource)
            {
                ucGetSource = 0x12;
            }
            else if (LINK_PORT_INDEX_DP_RX0 == ucGetSource)
            {
                ucGetSource = 0x0F;
            }
            else if (LINK_PORT_INDEX_DP_RX1 == ucGetSource)
            {
                ucGetSource = 0x10;
            }
            else
            {
                ucGetSource = 0xFF;
            }
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x12, ucGetSource);
            break;
        }
        case DDCCI_OPCODE_VCP_AUDIO_VOLUME:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdAudioVolumeMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, Hv_Mw_Audio_GetVolume());
            }
            break;
        }
        case DDCCI_OPCODE_VCP_RED_BLACK_LEVEL:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_GREEN_BLACK_LEVEL:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_BLUE_BLACK_LEVEL:
        {
            break;
        }
        case DDCCI_OPCODE_VCP_PRODUCTKEY:
        {
            aucResp[DDCCI_LENGTH] = DDCCI_CONTROL_STATUS_FLAG | 9;
            aucResp[DDCCI_COMMAND] = DDCCI_CMD_GET_VCP_FEATURE_REPLY;
            break;
        }
        case DDCCI_OPCODE_VCP_HFREQ:
        {
            Hv_App_Ddcci_GetVcpFeatureTimingInfo(enDdcciPort, aucResp, DDCCI_OPCODE_VCP_HFREQ);
            break;
        }
        case DDCCI_OPCODE_VCP_VFREQ:
        {
            Hv_App_Ddcci_GetVcpFeatureTimingInfo(enDdcciPort, aucResp, DDCCI_OPCODE_VCP_VFREQ);
            break;
        }
        case DDCCI_OPCODE_VCP_PANEL_TYPE:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x01, 1);
            break;
        }
        case DDCCI_OPCODE_VCP_MONITOR_TYPE:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x05, 3);
            break;
        }
        case DDCCI_OPCODE_VCP_APPLICATION_ENABLE:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0xFF, 0x5a);
            break;
        }
        case DDCCI_OPCODE_VCP_CONTROLLER_TYPE:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x00FF, 0x00FF);
            break;
        }
        case DDCCI_OPCODE_VCP_FW_LEVEL:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0xFFFF, DDCCI_FIRMWARE_VERSION);
            break;
        }
        case DDCCI_OPCODE_VCP_OSD_ON_OFF:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x02, pucTemp[0]);
            break;
        }
        case DDCCI_OPCODE_VCP_OSD_LANGUAGE:
        {
            //CC(0d 02 01 06 07 09 04 03 0a 05 08 0c 1e 24 1a 15)
            //   0d 02 01 06 07 09 04 03 0a 05 08 0c 1e 24 1a 08
            //   00 01 02 03 04 05 06 07 08 09 0A 0b 0c 0d 0e 0f
            USHORT16 uclanguage = 0xFF;
            UCHAR8 aucLangMap[] = { 
                0x0d, 0x02, 0x01, 0x06, 0x07, 0x09, 0x04, 0x03,
                0x0a, 0x05, 0x08, 0x0c, 0x1e, 0x24, 0x1a, 0x0b};
            UCHAR8 ucOsdLang = HV_COMMON_DATABASE_GET(UserData, ucOsdLanguage);

            if (ucOsdLang <= 0x0f)
            {
                uclanguage = aucLangMap[ucOsdLang];
            }
            
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x24, uclanguage);
            break;
        }
        case DDCCI_OPCODE_VCP_POWER_MODE:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0x0005, pucTemp[0]);
            break;
        }
        case DDCCI_OPCODE_VCP_VERSION:
        {
            Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, 0xFFFF, 0x0202);
            break;
        }
        case DDCCI_OPCODE_VCP_SHARPNESS:
        {
            UINT32 uiVal;
                        
            if (HV_SUCCESS == Hv_App_OsdSharpnessMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucSharpness));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_GAMMA:
        {
            UINT32 uiVal;
                        
            if (HV_SUCCESS == Hv_App_OsdGammaMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(UserData, ucGamma));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_MANUFACTURER_ENERGY_LEVEL:
        {
            UINT32 uiVal;
            
            if (HV_SUCCESS == Hv_App_OsdBrightnessMaxValGet(&uiVal))
            {
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_SET_PARAMETER, uiVal, HV_COMMON_DATABASE_GET(FactoryData, ucFactoryBrightness));
            }
            break;
        }
        case DDCCI_OPCODE_VCP_AMD_FREE_SYNC_ON_OFF:
        {
            PxpMode enPxpMode = Hv_Mw_Channel_GetPxpMode();
            BOOL bVrrEn;

            // 首先根据osd设置返回VRR状态
            if (HV_COMMON_DATABASE_GET(UserData, ucFreeSync))
                bVrrEn = HV_TRUE;
            else
                bVrrEn = HV_FALSE;
#if ((HV_CONFIG_ON == HV_PROJECT_CONFIG_PXP) || (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY))
            if (enDdcciPort >= DDCCI_PORT_HDMI0 && enDdcciPort <= DDCCI_PORT_DP1)
            {
                switch (enPxpMode)
                {
                    case PXP_MODE_PBP_ENABLE:
                        // PBP模式不支持VRR
                        bVrrEn = HV_FALSE;
                        break;
                    case PXP_MODE_PIP_ENABLE:
                        if (HV_COMMON_DATABASE_GET(UserData, ucPxPVideoSource) == enDdcciPort)
                        {
                            // 判断当前通道是否是辅通道，如果是辅通道，关闭VRR
                            bVrrEn = HV_FALSE;
                        }
                        else
                        {
                            // 否则根据osd设置返回VRR状态
                            // do nothing
                        }
                        break;
                    default:
                        // 根据osd设置返回VRR状态
                        // do nothing
                        break;
                }
                
            }
            else
            {
                // 根据osd设置返回VRR状态
                // do nothing
            }
#endif
            if (bVrrEn)
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_MOMENTARY, 0x0001, 0x0001); // enable
            else
                Hv_App_Ddcci_SetVcpReplyValue(aucResp, DDCCI_CMD_GETVCP_TP_MOMENTARY, 0, 0); // disable
            break;
        }
        default:
        {
            aucResp[DDCCI_RESULT_CODE] = DDCCI_CMD_GETVCP_RC_UNSUPPORTED;
            break;
        }
    }
    aucResp[DDCCI_PRESENT_LOW_BYTE + 1] = Hv_App_Ddcci_CalCheckSum(aucResp);

    Hv_App_Ddcci_SendData(enDdcciPort, aucResp, DDCCI_GET_VCP_DATA_LEN + DDCCI_HEADER_LEN);

    return;
}



/**
 * @brief Check DDCCI Set VCP Feature.
 * @param[in] pucData Pointer to the ddcci data.
 * @return BOOL 如果队列非空则返回true(1).
 */
static BOOL Hv_App_Ddcci_SetVcpFeatureCheck(UCHAR8 *pucData)
{
    switch (pucData[DDCCI_SOURCE_OPCODE])
    {
        case DDCCI_OPCODE_VCP_FACTORY_RESET:
        case DDCCI_OPCODE_VCP_RECAL_BRI_CON:
        case DDCCI_OPCODE_VCP_GEOMETRY_RESET:
        case DDCCI_OPCODE_VCP_COLOR_RESET:
        {
            if (pucData[DDCCI_SET_LOW_BYTE] == 0)
            {
                return HV_FALSE;
            }

            break;
        }
        case DDCCI_OPCODE_VCP_NEW_CONTROL_VALUE:
        case DDCCI_OPCODE_VCP_AUTO_SET_UP:
        case DDCCI_OPCODE_VCP_AUTO_COLOR:
        {
            if ((pucData[DDCCI_SET_LOW_BYTE] == 0) || (pucData[DDCCI_SET_LOW_BYTE] >= 3))
            {
                return HV_FALSE;
            }

            break;
        }
        case DDCCI_OPCODE_VCP_SELECT_COLOR_PRESET:
        {

            break;
        }
        case DDCCI_OPCODE_VCP_OSD_LANGUAGE:
        {
            if((pucData[DDCCI_SET_HIGH_BYTE] != 0) || (pucData[DDCCI_SET_LOW_BYTE] > 0x10))
            {
                return HV_FALSE;
            }

            break;
        }
        case DDCCI_OPCODE_VCP_POWER_MODE:
        {
            if ((pucData[DDCCI_SET_LOW_BYTE] == 0) || (pucData[DDCCI_SET_LOW_BYTE] >= 0x06))
            {
                return HV_FALSE;
            }

            break;
        }
        default:
        {
            break;
        }
    }

    return HV_TRUE;
}



/**
 * @brief DDCCI Set VCP Feature.
 * @param[in] enDdcciPort 表征是哪个通道.
 * @param[in] pucData Pointer of the data.
 * @param[in] ucLen Length of the data.
 * @return None.
 */
static VOID Hv_App_Ddcci_SetVcpFeature(DdcciPortEnum enDdcciPort, UCHAR8 *pucData, UCHAR8 ucLen)
{
    UCHAR8 ucMappingVal = 0;
    OsdTimingInfo *pstTiming = Hv_App_OsdGetCurrentTimingInfo();
    const PanelManager *pstPanel = Hv_Mw_Panel_GetManagerPtr();
    BOOL bNeedDisable = HV_FALSE;

    if (Hv_App_Ddcci_SetVcpFeatureCheck(pucData) == HV_FALSE)
    {
        Hv_App_Ddcci_SendNullMsg(enDdcciPort);
    }
    else
    {
        // DDC_PRINT("SET - opcode: 0x%x, setVal: %02d %02d\n", pucData[DDCCI_SOURCE_OPCODE], pucData[DDCCI_SET_HIGH_BYTE], pucData[DDCCI_SET_LOW_BYTE]);
        switch (pucData[DDCCI_SOURCE_OPCODE])
        {
            case DDCCI_OPCODE_VCP_NEW_CONTROL_VALUE:
            {
                if (pucData[DDCCI_SET_LOW_BYTE] == 0x01)
                {
                    s_ucDdcciNewControlValue = 0x01;
                }

                break;
            }
            case DDCCI_OPCODE_VCP_SHARPNESS:
            {
                UINT32 uiVal;
                            
                if (HV_SUCCESS != Hv_App_OsdSharpnessMaxValGet(&uiVal))
                {
                    break;
                }
                
                if (pucData[DDCCI_SET_LOW_BYTE] > uiVal)
                {
                    pucData[DDCCI_SET_LOW_BYTE] = uiVal;
                }
                Hv_App_OsdSharpnessValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_INPUT_SOURCE:
            {
                // mccs defs: 0x0F-DP1, 0x10-DP2, 0x11-HDMI1, 0x12-HDMI2
                UCHAR8 ucInpSrc = pucData[DDCCI_SET_LOW_BYTE];
                if (0x11 == ucInpSrc)
                {
                    DDC_PRINT("Set Source: HDMI0");
                    ucInpSrc = LINK_PORT_INDEX_HDMI_RX0;
                }
                else if (0x12 == ucInpSrc)
                {
                    DDC_PRINT("Set Source: HDMI1");
                    ucInpSrc = LINK_PORT_INDEX_HDMI_RX1;
                }
                else if (0x0F == ucInpSrc)
                {
                    DDC_PRINT("Set Source: DP0, really DP1");
                    ucInpSrc = LINK_PORT_INDEX_DP_RX1;
                }
                else if (0x10 == ucInpSrc)
                {
                    DDC_PRINT("Set Source: DP1");
                    ucInpSrc = LINK_PORT_INDEX_DP_RX1;
                }
                else
                {
                    ucInpSrc = 0xFF;
                }

                if (ucInpSrc <= LINK_PORT_INDEX_DP_RX1)
                {
                    Hv_App_OsdVideoSourceValSet(ucInpSrc);
                }
                
                break;
            }
            case DDCCI_OPCODE_VCP_FACTORY_RESET:
            {
                Hv_App_ResetToFactorySetting();
                break;
            }
            case DDCCI_OPCODE_VCP_RECAL_BRI_CON:
            {
                Hv_App_OsdBrightnessValSet(80);
                Hv_App_OsdContrastValSet(50);
                break;
            }
            case DDCCI_OPCODE_VCP_GEOMETRY_RESET:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_COLOR_RESET:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_COLOR_TEMP_REQUEST:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_CLOCK:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_BACKLIGHT:
            {
                UINT32 uiVal;
                
                if (HV_SUCCESS != Hv_App_OsdBrightnessMaxValGet(&uiVal))
                {
                    break;
                }
                
                if (pucData[DDCCI_SET_LOW_BYTE] > uiVal)
                {
                    pucData[DDCCI_SET_LOW_BYTE] = uiVal;
                }
                Hv_App_OsdBrightnessValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_CONTRAST:
            {
                UINT32 uiVal;
            
                if (HV_SUCCESS != Hv_App_OsdContrastMaxValGet(&uiVal))
                {
                    break;
                }
                if (pucData[DDCCI_SET_LOW_BYTE] > uiVal)
                {
                    pucData[DDCCI_SET_LOW_BYTE] = uiVal;
                }
                Hv_App_OsdContrastValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_SELECT_COLOR_PRESET:
            {
                Hv_App_OsdColorTempValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_RED_GAIN:
            {
                Hv_App_OsdRedGainValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_GREEN_GAIN:
            {
                Hv_App_OsdGreenGainValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_BLUE_GAIN:
            {
                Hv_App_OsdBlueGainValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            // VGA
            case DDCCI_OPCODE_VCP_AUTO_SET_UP:
            case DDCCI_OPCODE_VCP_HPOSITION:
            case DDCCI_OPCODE_VCP_VPOSITION:
            case DDCCI_OPCODE_VCP_CLOCK_PHASE:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_ACTIVE_CONTROL:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_AUDIO_VOLUME:
            {
                UINT32 uiVal;

                if (HV_SUCCESS != Hv_App_OsdAudioVolumeMaxValGet(&uiVal))
                {
                    break;
                }
                if (pucData[DDCCI_SET_LOW_BYTE] > uiVal)
                {
                    pucData[DDCCI_SET_LOW_BYTE] = uiVal;
                }
                Hv_App_OsdAudioVolumeValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_RED_BLACK_LEVEL:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_GREEN_BLACK_LEVEL:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_BLUE_BLACK_LEVEL:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_POWER_MODE:
            {
                break;
            }
            case DDCCI_OPCODE_VCP_OSD_LANGUAGE:
            {
                UCHAR8 uclanguage = 0xFF;
                UINT32 uiVal;
                
                if (HV_SUCCESS != Hv_App_OsdLanguageMaxValGet(&uiVal))
                {
                    break;
                }
               
                if (0x0d == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x00;
                }
                else if (0x02 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x01;
                }
                else if (0x01 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x02;
                }
                else if (0x06 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x03;
                }
                else if (0x07 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x4;
                }
                else if (0x9 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x5;
                }
                else if (0x04 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x6;
                }
                else if (0x03 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x07;
                }
                else if (0x0a == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x08;
                }
                else if (0x05 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0x9;
                }
                else if (0x08 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0xa;
                }
                else if (0x0c == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0xb;
                }
                else if (0x1e == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0xc;
                }
                else if (0x24 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0xd;
                }
                else if (0x1a == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0xe;
                }
                else if (0x08 == pucData[DDCCI_SET_LOW_BYTE])
                {
                    uclanguage = 0xf;
                }

                if (uclanguage <= uiVal)
                {
                    Hv_App_OsdLanguageValSet(uclanguage);
                }
                break;
            }
            case DDCCI_OPCODE_VCP_OSD_ON_OFF:
            {
                if (pucData[DDCCI_SET_LOW_BYTE] == 1)
                {
                    // OsdDispDisableOsd();
                }
                else if(pucData[DDCCI_SET_LOW_BYTE] == 2)
                {
                    // OsdFuncEnableOsd();
                }

                break;
            }
            case DDCCI_OPCODE_VCP_GAMMA:
            {
                Hv_App_OsdGammaValSet(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_MANUFACTURER_ENERGY_LEVEL:
            {
                Hv_Mw_Factory_SetFactoryDefaultBacklight(pucData[DDCCI_SET_LOW_BYTE]);
                break;
            }
            case DDCCI_OPCODE_VCP_AMD_FREE_SYNC_ON_OFF:
            {
                LinkPortIndex enPortIndex = (enDdcciPort == DDCCI_PORT_HDMI0) ? LINK_PORT_INDEX_HDMI_RX0 : LINK_PORT_INDEX_HDMI_RX1;

                if(pucData[DDCCI_SET_HIGH_BYTE] == 0x0 && pucData[DDCCI_SET_LOW_BYTE] == 0x0)
                {
                    Hv_Mw_HdmiRx_SetFreeSyncMccsCfg(enPortIndex, 0x0);// FreeSync Closed.
                }
                else
                {
                    Hv_Mw_HdmiRx_SetFreeSyncMccsCfg(enPortIndex, 0x1);// FreeSync Open.
                }

                break;
            }
            default:
            {
                Hv_App_Ddcci_SendNullMsg(enDdcciPort);
                break;
            }
        }
    }

    // Sync with OSD
    Hv_App_Ddcci_SendEventToOsd(OSD_EVENT_MCCS, 0);
    Hv_Mw_DataBase_DdcSync();

    return;
}


/**
 * @brief DDCCI Get and Reply Timing Report.
 * @param[in] enDdcciPort 表征是哪个通道.
 * @param[in] pucData Pointer of the data.
 * @param[in] ucLen Length of the data.
 * @return None.
 */
static VOID Hv_App_Ddcci_GetTimingReport(DdcciPortEnum enDdcciPort, UCHAR8 *pucData, UCHAR8 ucLen)
{

    return;
}


/**
 * @brief DDCCI Capabilities Request & Reply.
 * @param[in] enDdcciPort 表征是哪个通道.
 * @param[in] pucData Pointer of the data.
 * @param[in] ucLen Length of the data.
 * @return None.
 */
static VOID Hv_App_Ddcci_GetCapReq(DdcciPortEnum enDdcciPort, UCHAR8 *pucData, UCHAR8 ucLen)
{
    USHORT16 usOffset = 0;
    UCHAR8   ucSendLen = 0;
    USHORT16 usCreqLen = Hv_App_Ddcci_GetCapStringSize(enDdcciPort);
    UCHAR8   aucResp[DDCCI_HDMI_CAP_TX_LEN] = { 0 };
    UCHAR8   ucPktTotalLen = (enDdcciPort <= DDCCI_PORT_HDMI1) ? DDCCI_HDMI_CAP_TX_LEN : DDCCI_DP_CAP_TX_LEN;

    // calculate offset & length
    // DDC_PRINT("get cap, off high:%d, off low:%d", pucData[DDCCI_OFS_HIGH_BYTE], pucData[DDCCI_OFS_LOW_BYTE]);
    usOffset = TO_WORD(pucData[DDCCI_OFS_HIGH_BYTE], pucData[DDCCI_OFS_LOW_BYTE]);

    if (usOffset >= usCreqLen) // Has send all datas.
    {
        ucSendLen = 0;
    }
    else if (usCreqLen > (usOffset + ucPktTotalLen - DDCCI_GET_CAP_HEADER_LEN)) // Not sent completely, and the remaining data is still enough to fill the largest packet.
    {
        ucSendLen = ucPktTotalLen - DDCCI_GET_CAP_HEADER_LEN;
    }
    else // When the remaining data is not enough to fill the largest packet.
    {
        ucSendLen = usCreqLen - usOffset;
    }

    // DDC_PRINT("get cap, usCreqLen: %d, usOffset: %d, ucSendLen: %d", usCreqLen, usOffset, ucSendLen);

    aucResp[DDCCI_SOURCE] = DDCCI_DEST_ADDRESS;
    aucResp[DDCCI_LENGTH] = DDCCI_CONTROL_STATUS_FLAG | (ucSendLen + DDCCI_HEADER_LEN);
    aucResp[DDCCI_COMMAND] = DDCCI_CMD_CAPABILITIES_REQUEST_REPLY;
    aucResp[DDCCI_OFS_HIGH_BYTE] = pucData[DDCCI_OFS_HIGH_BYTE];
    aucResp[DDCCI_OFS_LOW_BYTE] = pucData[DDCCI_OFS_LOW_BYTE];

    Hv_App_Ddcci_GetCapStringData(&aucResp[DDCCI_OFS_LOW_BYTE + 1], enDdcciPort, usOffset, ucSendLen);

    aucResp[DDCCI_OFS_LOW_BYTE + 1 + ucSendLen] = Hv_App_Ddcci_CalCheckSum(aucResp);

    // DDC_BUF_PRINT("send cap datas", aucRspData, DDCCI_HDMI_CAP_TX_LEN);
    Hv_App_Ddcci_SendData(enDdcciPort, aucResp, ucSendLen + DDCCI_GET_CAP_HEADER_LEN);

    return;
}


/**
 * @brief Verify the CRC of incoming message. Used for any array with mccs header.
 * @param[in] pucData 指向待发送数据的指针.
 * @return Status.
 */
Status Hv_App_Ddcci_VerifyCheckSum(UCHAR8 *pucData)
{
    UCHAR8 ucCount = 0;
    UCHAR8 ucCheckLen = 0;
    UCHAR8 ucSum = DDCCI_DEST_ADDRESS;
    Status uiResult = HV_SUCCESS;

    ucCheckLen = (pucData[DDCCI_LENGTH] & 0x7F) + 2;

    for (ucCount = 0; ucCount < ucCheckLen; ucCount++)
    {
        ucSum = ucSum ^ pucData[ucCount];
    }

    if (ucSum != pucData[ucCheckLen + 1])
    {
        uiResult = HV_FAILURE;
    }
    return uiResult;
}


/**
 * @brief Calculate the CRC.
 * @param[in] pucData 指向待发送数据的指针.
 * @return UCHAR8  CRC value.
 */
UCHAR8 Hv_App_Ddcci_CalCheckSum(UCHAR8 *pucData)
{
    UCHAR8 ucCount = 0;
    UCHAR8 ucCheckLen = 0;
    UCHAR8 ucSum = DDCCI_VIRTUAL_HOST_ADDRESS;

    ucCheckLen = (pucData[DDCCI_LENGTH] & DDCCI_DATA_LEN_CTRL) + 2;

    for (ucCount = 0; ucCount < ucCheckLen; ucCount++)
    {
        ucSum = ucSum ^ pucData[ucCount];
    }

    return ucSum;
}


/**
 * @brief APP层发送数据的接口.
 * @param[in] enDdcciPort 表征是哪个通道.
 * @param[in] pucData 指向待发送数据的指针.
 * @param[in] ucLen 待发送数据的长度.
 * @return Status Always return HV_SUCCESS.
 */
Status Hv_App_Ddcci_SendData(DdcciPortEnum enDdcciPort, UCHAR8 *pucData, UINT32 uiLen)
{
    HV_ASSERT_TRUE(enDdcciPort < DDCCI_PORT_MAX);

    Hv_Mw_Ddcci_SendData(enDdcciPort, pucData, uiLen);
    DDC_BUF_PRINT("reply ", pucData, uiLen);

    return HV_SUCCESS;
}

Status Hv_App_Ddcci_HandleMsg(DdcciEvent *pstDdcEvt)
{
    static DDCCI_CMD_TYPE_E enCmdType;
    static UINT32 uiTotalLen;
    Status ret = HV_SUCCESS;
    static UCHAR8 *pucLongMsg = NULL;
    static UINT32 uiOffset = 0;
    static BOOL bLongMsg = HV_FALSE;

    //DDC_BUF_PRINT("Rcv Handle Msg -> ", pstDdcEvt->aucData, pstDdcEvt->ucLen);

    if (HV_FALSE == bLongMsg)
    {
        Hv_Mw_Ddcci_JudgeCmdParam(pstDdcEvt->aucData, &enCmdType, &uiTotalLen);
        if (enCmdType == DDCCI_TYPE_UNKNOWN)
        {
            Hv_App_Ddcci_SendNullMsg(pstDdcEvt->ucPort);
            ret = HV_FAILURE;
            goto ddcci_end;
        }
        
        if (uiTotalLen > 24)
        {
            pucLongMsg = gucDdcLongMsg;
            
            DDC_PRINT("long start, total Len: %u", uiTotalLen);
            bLongMsg = HV_TRUE;
            HV_MEMCPY(pucLongMsg, pstDdcEvt->aucData, pstDdcEvt->ucLen);
            uiOffset += pstDdcEvt->ucLen;
            return HV_SUCCESS;
        }
    }
    else
    {
        HV_MEMCPY(pucLongMsg + uiOffset, pstDdcEvt->aucData, pstDdcEvt->ucLen);
        uiOffset += pstDdcEvt->ucLen;
        if (uiOffset >= uiTotalLen)
        {
            DDC_PRINT("long end!");
            // DDC_BUF_PRINT("Ddcci Long -> ", pucLongMsg, uiTotalLen);
            
            if (enCmdType == DDCCI_TYPE_HIVIEW_TOOL)
            {
                Hv_App_Ddcci_ProcFactoryMsg(pstDdcEvt->ucPort, pucLongMsg, uiTotalLen);
            }
            else
            {
                if (gpfProcOtherDdcciMsg != NULL)
                {
                    gpfProcOtherDdcciMsg(pstDdcEvt->ucPort, pucLongMsg, uiTotalLen);
                }
            }
            
            bLongMsg = HV_FALSE;
            uiOffset = 0;
            uiTotalLen = 0;
        }
        return HV_SUCCESS;
    }

    // DP通道下无法直接获取到数据包长度，所以这里需要根据长度字节解析出真正的长度
    if ((DDCCI_PORT_DP0 == pstDdcEvt->ucPort) || (DDCCI_PORT_DP1 == pstDdcEvt->ucPort))
    {
        pstDdcEvt->ucLen = (pstDdcEvt->aucData[DDCCI_LENGTH] & DDCCI_DATA_LEN_CTRL) + DDCCI_HEADER_LEN;
    }

    /*
        Notice:
        G-Menu会发出一个字节0x00，这里根据Addr来做屏蔽，不做NULL回复(若回复NULL消息，则G-MENU不会继续交互)。
        ddc cmd: [1]=00 
        send [3]=6e 80 be
    */
    if (DDCCI_SRC_ADDRESS != pstDdcEvt->aucData[DDCCI_SOURCE])
    {
        return ret;
    }

    switch (enCmdType)
    {
        case DDCCI_TYPE_HIVIEW_TOOL:
        {
            DDC_PRINT("ddcci hiview fac tool");
            Hv_App_Ddcci_ProcFactoryMsg(pstDdcEvt->ucPort, pstDdcEvt->aucData, pstDdcEvt->ucLen);
            break;
        }
        case DDCCI_TYPE_HIVIEW_OTA:
        {
            DDC_PRINT("ddcci OTA");
            Hv_App_Ddcci_ProcessOTA(pstDdcEvt->ucPort, pstDdcEvt->aucData, pstDdcEvt->ucLen);
            break;
        }
        case DDCCI_TYPE_VCP_STANDARD:
        {
            DDC_PRINT("standard vcp cmd handle");
            switch(pstDdcEvt->aucData[DDCCI_COMMAND])
            {
                case DDCCI_CMD_GET_VCP_FEATURE:
                {
                    Hv_App_Ddcci_GetVcpFeature(pstDdcEvt->ucPort, pstDdcEvt->aucData, pstDdcEvt->ucLen);
                    DDC_PRINT("get feature");
                    break;
                }
                case DDCCI_CMD_SET_VCP_FEATURE:
                {
                    Hv_App_Ddcci_SetVcpFeature(pstDdcEvt->ucPort, pstDdcEvt->aucData, pstDdcEvt->ucLen);
                    DDC_PRINT("set feature");
                    break;
                }
                case DDCCI_CMD_GET_TIMING_REPORT:
                {
                    DDC_PRINT("get timing");
                    Hv_App_Ddcci_GetTimingReport(pstDdcEvt->ucPort, pstDdcEvt->aucData, pstDdcEvt->ucLen);
                    break;
                }
                case DDCCI_CMD_SAVE_CURRENT_SETTINGS:
                {
                    DDC_PRINT("save");
                    break;
                }
                case DDCCI_CMD_CAPABILITIES_REQUEST:
                {
                    DDC_PRINT("get cap");
                    Hv_App_Ddcci_GetCapReq(pstDdcEvt->ucPort, pstDdcEvt->aucData, pstDdcEvt->ucLen);
                    break;
                }
                default:
                {
                    DDC_PRINT("default");
                    Hv_App_Ddcci_SendNullMsg(pstDdcEvt->ucPort);
                    break;
                }
            }
            break;
        }
        default:
        {
            DDC_PRINT("Other cmd handle");
            if (gpfProcOtherDdcciMsg != NULL)
            {
                gpfProcOtherDdcciMsg(pstDdcEvt->ucPort, pstDdcEvt->aucData, pstDdcEvt->ucLen);
            }
            break;
        }
    }

ddcci_end:
    bLongMsg = HV_FALSE;
    return ret;
}

VOID Hv_App_Ddcci_Register(DDCCI_PROC_HANDLE pfHandle)
{
    gpfProcOtherDdcciMsg = pfHandle;
}

VOID Hv_App_Ddcci_Init(VOID)
{
    // register callback
    Hv_Mw_Ddcci_SetAppCallback(Hv_App_Ddcci_HandleMsg);
    Hv_App_Ddcci_ProductInit();
    return;
}

Status Hv_App_Ddcci_SendEventToOsd(USHORT16 usEventId, USHORT16 usValue)
{
    HV_VOS_QUEUE_S* pOsdQueue = Hv_Mw_System_GetOsdQueue();
    HV_ASSERT_VALID_PTR(pOsdQueue);

    OsdEvent stOsdEvent;
    HV_MEMSET(&stOsdEvent, 0, sizeof(OsdEvent));
    stOsdEvent.usEventId = usEventId;
    stOsdEvent.usValue = usValue;
    HV_ASSERT_TRUE(Hv_Vos_QueueSend(pOsdQueue, &stOsdEvent));

    return HV_SUCCESS;
}

VOID Hv_Mw_Ddcci_JudgeCmdParam(UCHAR8 *pucData, DDCCI_CMD_TYPE_E *penType, UINT32 *puiTotalLen)
{
    UINT32 uiMsgLen;

    *penType = DDCCI_TYPE_UNKNOWN;
    *puiTotalLen = 0;

    if (pucData == NULL)
    {
        // unknown
        return;
    }
    
    if (pucData[DDCCI_TYPE_JUDGE_BYTE] == DDCCI_FAC_CMD_TYPE_READ)
    {
        *penType = DDCCI_TYPE_HIVIEW_TOOL;
        uiMsgLen = pucData[DDCCI_FAC_OFFSET_LEN_HIGH] << 8 | pucData[DDCCI_FAC_OFFSET_LEN_LOW];
        *puiTotalLen = uiMsgLen + DDCCI_FAC_DDC_HEADER_LEN;
        return;
    }
    else if (pucData[DDCCI_TYPE_JUDGE_BYTE] == DDCCI_FAC_CMD_TYPE_WRITE)
    {
        *penType = DDCCI_TYPE_HIVIEW_TOOL;
        uiMsgLen = pucData[DDCCI_FAC_OFFSET_LEN_HIGH] << 8 | pucData[DDCCI_FAC_OFFSET_LEN_LOW];
        *puiTotalLen = uiMsgLen + DDCCI_FAC_DDC_HEADER_LEN;
        return;
    }
    else if (pucData[DDCCI_TYPE_JUDGE_BYTE] < DDCCI_CONTROL_STATUS_FLAG)
    {
        // unknown
        return;
    }
    else
    {
        // DDCCI_TYPE_HIVIEW_OTA, DDCCI_TYPE_VCP_STANDARD, DDCCI_TYPE_VCP_TPV, DDCCI_TYPE_VCP_AUO
        uiMsgLen = pucData[DDCCI_LENGTH] - DDCCI_CONTROL_STATUS_FLAG;
        *puiTotalLen = uiMsgLen + DDCCI_HEADER_LEN;
    }

    if (pucData[DDCCI_TYPE_JUDGE_BYTE + 1] == DDCCI_CMD_MANUFACTURER_FW_UPDATE)
    {
        // DP OTA：工具先写寄存器，后发OTA指令通知写入完毕，OTA指令中携带bin长度
        // HDMI OTA：未实现
        *penType = DDCCI_TYPE_HIVIEW_OTA;
    }
    else if (pucData[DDCCI_TYPE_JUDGE_BYTE + 1] == DDCCI_CMD_GET_VCP_FEATURE ||
        pucData[DDCCI_TYPE_JUDGE_BYTE + 1] == DDCCI_CMD_SET_VCP_FEATURE)
    {
#if 0
        if (pucData[DDCCI_TYPE_JUDGE_BYTE + 2] == 0xFB)
        {
            *penType = DDCCI_TYPE_VCP_AUO;
            return;
        }
#else
        if (pucData[DDCCI_TYPE_JUDGE_BYTE + 2] == 0xF8 ||
            pucData[DDCCI_TYPE_JUDGE_BYTE + 2] == 0xFE)
        {
            *penType = DDCCI_TYPE_VCP_TPV;
            return;
        }
        if (pucData[DDCCI_TYPE_JUDGE_BYTE + 2] == 0xFB)
        {
            *penType = DDCCI_TYPE_VCP_CTX;
            return;
        }
#endif
        *penType = DDCCI_TYPE_VCP_STANDARD;
    }
    else if (pucData[DDCCI_TYPE_JUDGE_BYTE + 1] == DDCCI_CMD_GET_TIMING_REPORT ||
        pucData[DDCCI_TYPE_JUDGE_BYTE + 1] == DDCCI_CMD_SAVE_CURRENT_SETTINGS ||
        pucData[DDCCI_TYPE_JUDGE_BYTE + 1] == DDCCI_CMD_CAPABILITIES_REQUEST)
    {
        *penType = DDCCI_TYPE_VCP_STANDARD;
    }
    else if(((pucData[DDCCI_TYPE_JUDGE_BYTE] == 0x89) && (pucData[DDCCI_TYPE_JUDGE_BYTE + 1] == 0x6E))   /* CTX白平衡工具总是为51 89 6E */
            || (pucData[DDCCI_TYPE_JUDGE_BYTE + 2] == 0xFB))  /* CTX EDID工具第三字节总是FB */
    {
        *penType = DDCCI_TYPE_VCP_CTX;
    }
    else
    {
        *puiTotalLen = 0;
    }
    return;
}

