/**
 * @file hv_mw_PanelManager.c
 * @brief PanelManager module driver
 * @details This module provide interfaces for Hiview-Madia-Ware.
 * @author HiView SoC Software Team
 * @version 0.0.1
 * @date 20220903
 * @copyright Copyright(c),2022-9, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                         <th>Date             <th>Details
 * <tr><td>HiView SoC Software Team   <td>20220903       <td>Create and first Version.
 * </table>
 **/

#include <string.h>
#include "hv_comm_Assert.h"
#include "hv_vos_Time.h"
#include "PanelConfig.h"
#include "hv_drv_EdpTxTraining.h"
#include "hv_drv_Osd.h"
#include "hv_drv_Ktx.h"
#include "hv_drv_Mprt.h"
#include "hv_drv_PLL.h"
#include "hv_chip_Irq.h"
#include "hv_mw_Factory.h"
#include "hv_mw_Channel_Manager.h"
#include "hv_mw_PanelManager.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_PowerManager.h"
#include "hv_mw_OsdDraw.h"
#include "hv_comm_DataBase.h"
#ifdef  CONFIG_USER_PANEL_SEQUENCE_ON
#include "hv_drv_Gpio.h"
#endif
#ifdef  CONFIG_USER_PANEL_TYPE_VBOTX
#include "hv_drv_VboTx.h"
#endif
#ifdef  CONFIG_USER_PANEL_TYPE_EDPTX
#include "hv_drv_EdpTx.h"
#endif
#include "hv_drv_PQ.h"
#include "hv_app_PQ.h"

typedef struct _PanelStateMachine
{
    USHORT16      usAcceptStates;
    PanelEventId  enEventId;
    Status        (*pfActionHandle)(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
    PanelState    enNextSuccessState;
    PanelState    enNextFailState;
}PanelStateMachine;

typedef struct
{
    HV_TIMER_S *pstPanelPowerOnTimer;           /* 系统上电到panel上电 */
    HV_TIMER_S *pstPanelDataOnTimer;            /* panel上电到data开始 */
    HV_TIMER_S *pstPanelBlkOnTimer;             /* data开始到背光亮起 */
    HV_TIMER_S *pstPanelBlkOffTimer;            /* data打开到背光关闭 */
    HV_TIMER_S *pstPanelDataOffTimer;           /* 背光关闭到data关闭 */
    HV_TIMER_S *pstPanelPowerOffTimer;          /* data关闭到电源关闭 */
    HV_TIMER_S *pstKtxPllLockStatusTimer;       /* 等待锁定 */
    HV_TIMER_S *pstPanelIdlePattTimer;          /* 发送idle pattern */

    HV_TIMER_S *pstPanelLdcVccOnTimer;           /* power on 到ldc vcc on*/
    HV_TIMER_S *pstPanelLdcVinOnTimer;           /* ldc vcc on到ldc vin on */
    HV_TIMER_S *pstPanelLdcPwmOnTimer;           /* ldc vcc on到ldc pwm on */
    HV_TIMER_S *pstPanelLdcLdEnTimer;            /* ldc vcc on到lden  on */
    HV_TIMER_S *pstPanelLdcSpiOnTimer;           /* ldc vcc on到ldc spi on */
    HV_TIMER_S *pstPanelLdcBlOnTimer;            /* ldc vcc on到ldc bl on */

    HV_TIMER_S *pstPanelLdcBlOffTimer;            /* poweroff到ldc bl off */
    HV_TIMER_S *pstPanelLdcSpiOffTimer;           /* ldc bl off到ldc spi of */
    HV_TIMER_S *pstPanelLdcLdEnOffTimer;           /* ldc bl off到lden  off */
    HV_TIMER_S *pstPanelLdcPwmOffTimer;           /* ldc bl off到ldc pwm off */
    HV_TIMER_S *pstPanelLdcVinOffTimer;           /* ldc bl off到ldc vin off */
    HV_TIMER_S *pstPanelLdcVccOffTimer;           /* ldc bl off 到ldc vcc off*/
}PanelTimer;

static PanelParam s_stPanelParam = {0};
static PanelManager s_stPanelManager;
static PanelTimer s_stPanelTimer = {0};

static Status PanelStateMachineHandler_PowerON(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
static Status PanelStateMachineHandler_DataON(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
static Status PanelStateMachineHandler_LockStatus(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
static Status PanelStateMachineHandler_IdlePatt(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
static Status PanelStateMachineHandler_PowerOFF(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
static Status PanelStateMachineHandler_BlkON(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
static Status PanelStateMachineHandler_BlkOFF(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);
static Status PanelStateMachineHandler_DataOFF(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager);

static const PanelStateMachine s_astPanelStateMachine[] = 
{
    /* 正常流程 当前可AcceptStates    PanelEventId                       回调函数                                成功后的状态                  失败后的状态 */
    {PANEL_STATE_OFF 
    |PANEL_STATE_BLK_OFF 
    |PANEL_STATE_DATA_OFF,   PANEL_EVENT_ID_PANEL_POWER_ON,       PanelStateMachineHandler_PowerON,   PANEL_STATE_POWER_ON,   PANEL_STATE_OFF},

    {PANEL_STATE_POWER_ON,   PANEL_EVENT_ID_TRAINING_START,       PanelStateMachineHandler_DataON,    PANEL_STATE_WAIT_LOCK,  PANEL_STATE_OFF},
    {PANEL_STATE_WAIT_LOCK,  PANEL_EVENT_ID_CHECK_TRAINING_STATUS,PanelStateMachineHandler_LockStatus,PANEL_STATE_IDLE_PATT,  PANEL_STATE_OFF},
    {PANEL_STATE_IDLE_PATT,  PANEL_EVENT_ID_IDLE_PATTERN,         PanelStateMachineHandler_IdlePatt,  PANEL_STATE_DATA_ON,    PANEL_STATE_OFF},
    {PANEL_STATE_DATA_ON,    PANEL_EVENT_ID_BLK_ON,               PanelStateMachineHandler_BlkON,     PANEL_STATE_BLK_ON,     PANEL_STATE_OFF},
    {PANEL_STATE_ANY,        PANEL_EVENT_ID_BLK_OFF,              PanelStateMachineHandler_BlkOFF,    PANEL_STATE_BLK_OFF,    PANEL_STATE_OFF},
    {PANEL_STATE_BLK_OFF,    PANEL_EVENT_ID_DATA_OFF,             PanelStateMachineHandler_DataOFF,   PANEL_STATE_DATA_OFF,   PANEL_STATE_OFF}, 
    {PANEL_STATE_DATA_OFF,   PANEL_EVENT_ID_POWER_OFF,            PanelStateMachineHandler_PowerOFF,  PANEL_STATE_OFF,        PANEL_STATE_OFF}, 
    {PANEL_STATE_DATA_OFF,   PANEL_EVENT_ID_TRAINING_START,       PanelStateMachineHandler_DataON,    PANEL_STATE_DATA_ON,    PANEL_STATE_OFF}, 
    {PANEL_STATE_BLK_OFF,    PANEL_EVENT_ID_BLK_ON,               PanelStateMachineHandler_BlkON,     PANEL_STATE_BLK_ON,     PANEL_STATE_OFF}, 
    {PANEL_STATE_ANY,        PANEL_EVENT_ID_EDP_BACK_LIGHT,       PanelStateMachineHandler_BlkON,     PANEL_STATE_ANY,        PANEL_STATE_ANY}, 
};


/* FIFO是否为满 */
static BOOL QueueIsFull(PanelInnerMsgQueue *pstQueue)
{
    return ((pstQueue->usWriteAddr + 1) % MAX_PANEL_QUEUE_SIZE == pstQueue->usReadAddr);
}
/* FIFO是否为空 */
static BOOL QueueIsEmpty(PanelInnerMsgQueue *pstQueue)
{
    return (pstQueue->usWriteAddr == pstQueue->usReadAddr);
}

/* FIFO复位 */
static VOID QueueReset(PanelInnerMsgQueue *pstQueue)
{
    pstQueue->usWriteAddr = 0;
    pstQueue->usReadAddr = 0;
    for(USHORT16 usIndex = 0; usIndex < MAX_PANEL_QUEUE_SIZE; usIndex++)
    {
        HV_MEMSET(&pstQueue->astFifo[usIndex], 0 , sizeof(pstQueue->astFifo[usIndex]));
    }
    return;
}

/* FIFO写入数据 */
static QueueStatus QueueWrite(PanelInnerMsgQueue *pstQueue, const PanelEvent *pstData)
{
    if (QueueIsFull(pstQueue))
    {
        HV_LOG_ERROR(DEFAULT,"Write failed, queue is full");
        return QUEUE_FULL;
    }
    HV_MEMCPY(&pstQueue->astFifo[pstQueue->usWriteAddr], pstData, sizeof(PanelEvent));
    pstQueue->usWriteAddr = (pstQueue->usWriteAddr + 1) % MAX_PANEL_QUEUE_SIZE;
    return QUEUE_OK;
}

/* FIFO读出数据 */
static QueueStatus QueueRead(PanelInnerMsgQueue *pstQueue, PanelEvent *pstdata)
{
    if (QueueIsEmpty(pstQueue))
    {
        return QUEUE_EMPTY;
    }
    HV_MEMCPY(pstdata, &pstQueue->astFifo[pstQueue->usReadAddr], sizeof(PanelEvent));
    pstQueue->usReadAddr = (pstQueue->usReadAddr + 1) % MAX_PANEL_QUEUE_SIZE;
    return QUEUE_OK;
}

/* FIFO内数据的个数 */
static USHORT16 QueueCount(PanelInnerMsgQueue *pstQueue)
{
    if (pstQueue->usReadAddr <= pstQueue->usWriteAddr)
    {
        return (pstQueue->usWriteAddr - pstQueue->usReadAddr);
    }
    return (MAX_PANEL_QUEUE_SIZE + pstQueue->usWriteAddr - pstQueue->usReadAddr);
}

Status Hv_Mw_Panel_SendInnerMsg(const PanelEvent* pstPanelEvent)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_Panel_SendInnerMsg");
    HV_ASSERT_TRUE(QUEUE_OK == QueueWrite(&s_stPanelManager.stPanelInnerMsgQueue, pstPanelEvent));
    return HV_SUCCESS;
}

#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
static inline VOID SetPanelSequenceTestPinLevel(GpioLevel enLevel)
{
#ifdef HV_BOARD_CONFIG_GPIO_PANEL_SEQUENCE_TEST
    Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_PANEL_SEQUENCE_TEST, enLevel);
    HV_LOG_INFO(PANEL, "#PIN%u -->%u", HV_BOARD_CONFIG_GPIO_PANEL_SEQUENCE_TEST, enLevel);
#endif
    return;
}

static inline VOID PanelSequenceTestStartFlag(VOID)
{
    /*PIN Init and Start*/
#ifdef HV_BOARD_CONFIG_GPIO_PANEL_SEQUENCE_TEST
    Hv_Drv_Gpio_SetDirection(HV_BOARD_CONFIG_GPIO_PANEL_SEQUENCE_TEST, GPIO_DIR_OUTPUT);
#endif

    SetPanelSequenceTestPinLevel(GPIO_LEVEL_LOW);
    Hv_Vos_Delayus(1000);
    SetPanelSequenceTestPinLevel(GPIO_LEVEL_HIGH);
    Hv_Vos_Delayus(1000);
    SetPanelSequenceTestPinLevel(GPIO_LEVEL_LOW);
    Hv_Vos_Delayus(1000);
    SetPanelSequenceTestPinLevel(GPIO_LEVEL_HIGH);
    Hv_Vos_Delayus(1000);
    SetPanelSequenceTestPinLevel(GPIO_LEVEL_LOW);
    Hv_Vos_Delayus(20000);
    return;
}
#endif

#define CHECK_HPD_TIME_PERIOD 20
static Status PanelStateMachineHandler_PowerON(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "PanelStateMachineHandler_PowerON, pstPanelManager->enCurrentPanelState: %d", pstPanelManager->enCurrentPanelState);
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_POWER_ON);
    /*背光亮起需要先出PWM在使能开关才行*/
    Hv_Drv_Ktx_SetBacklightPower(HV_PROJECT_CONFIG_BACKLIGHT_DISABLE);
    /* 为了加快亮屏，将panel power on 放到init中，data on timer可以设为0 */
    Hv_Drv_Ktx_PanelVideoPower(1);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelDataOnTimer, CHECK_HPD_TIME_PERIOD); /* 每20ms查一次hpd */
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelDataOffTimer);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelPowerOffTimer);

#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
    SetPanelSequenceTestPinLevel(GPIO_LEVEL_HIGH);
#endif

#if (HV_PROJECT_CONFIG_FULL_LOCALDIMMING == HV_CONFIG_ON)
    /* 开启ldc vcc Timer */
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcVccOnTimer, 0);
#endif
    return HV_SUCCESS;
}

static Status PanelStateMachineHandler_DataON(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "PanelStateMachineHandler_DataON, pstPanelManager->enCurrentPanelState: %d", pstPanelManager->enCurrentPanelState);
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_DATA_ON);

    static UCHAR8 ucPanelCheckNum = 0;
    UCHAR8 ucCheckPanelExistNum = roundup_div(s_stPanelParam.usPanelDataOnTime, CHECK_HPD_TIME_PERIOD);
    /* 每20ms查一次hpd */
    if (HV_TRUE == s_stPanelManager.stPanelControl.pfCheckPanelExist())
    {
        /* panel电源打开之后在0.2ms~10ms后开始data传输 */
        s_stPanelManager.stPanelControl.pfPanelEnable(HV_TRUE);
        Hv_Vos_Timer_Rstart(s_stPanelTimer.pstKtxPllLockStatusTimer, 0);
        ucPanelCheckNum = 0;
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
        SetPanelSequenceTestPinLevel(GPIO_LEVEL_LOW);
#endif
    }
    else
    {
        ucPanelCheckNum++;
        if (ucPanelCheckNum < ucCheckPanelExistNum)
        {
            HV_LOG_INFO(PANEL, "Panel Check hpd fail, total check: %d, curr count: %d", ucCheckPanelExistNum, ucPanelCheckNum);
            Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelDataOnTimer, CHECK_HPD_TIME_PERIOD);
            return HV_CONTINUE;
        }
        else
        {
            ucPanelCheckNum = 0;
            s_stPanelManager.stPanelControl.pfPanelEnable(HV_TRUE);
            Hv_Vos_Timer_Rstart(s_stPanelTimer.pstKtxPllLockStatusTimer, 0);
            HV_LOG_ERROR(PANEL, "Panel Check hpd fail, Forc continue");
            return HV_SUCCESS;
        }
    }
    return HV_SUCCESS;
}

static Status SendShowLogoMsgToOSDTask(VOID)
{
    const PowerManager *pstPowerManager = Hv_Mw_Power_GetManagerPtr();
#if (HV_PROJECT_CONFIG_FACTORYMODE_LOGO_BYPASS == HV_CONFIG_ON)
    /* By pass logo when in factory mode */
    if (HV_TRUE == HV_COMMON_DATABASE_GET(SystemData, bFactoryMode))
    {
        Hv_Mw_OsdSetLogoBypass();
    }
#endif

    if (HV_TRUE == Hv_Mw_OsdGetLogoBypass())
    {
        HV_LOG_DEBUG(PANEL, "No need display logo! PowerOnReasonType: %u", pstPowerManager->enPowerOnReasonType);
        return HV_SUCCESS;
    }

    if (POWER_ON_REASON_TYPE_POWER_ON == pstPowerManager->enPowerOnReasonType)
    {
        /*发信息给OSD去画logo*/
        HV_VOS_QUEUE_S *pOsdQueue = Hv_Mw_System_GetOsdQueue();
        HV_ASSERT_VALID_PTR(pOsdQueue);
        OsdEvent stOsdEvent;
        HV_MEMSET(&stOsdEvent, 0 ,sizeof(stOsdEvent));
        stOsdEvent.usEventId = OSD_EVENT_SHOW_LOGO;
        stOsdEvent.usValue = 1;
        HV_LOG_DEBUG(PANEL, "notify osd draw logo!");
        HV_ASSERT_TRUE(Hv_Vos_QueueSend(pOsdQueue, &stOsdEvent));
    }
    else
    {
        HV_LOG_DEBUG(PANEL, "Not AC on, No need display logo! PowerOnReasonType: %u", pstPowerManager->enPowerOnReasonType);
    }
    return HV_SUCCESS;
}

static Status PanelStateMachineHandler_LockStatus(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_PanelLockStatus, pstPanelManager->enCurrentPanelState: %d", pstPanelManager->enCurrentPanelState);
    static UINT32 uiCheckTrainingNum = 0;
    static UINT32 uiPanelRestartNum = 0;
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_WAIT_LOCK);
    if ((uiPanelRestartNum > 8) || (HV_FALSE == s_stPanelManager.stPanelControl.pfCheckPanelExist()))
    {
        HV_LOG_INFO(PANEL, "Force enable backlight on, PanelRestartNum: %u, panel exist: %u", uiPanelRestartNum, s_stPanelManager.stPanelControl.pfCheckPanelExist());
        Hv_Drv_Ktx_PanelVideoPower(1);
        Hv_Drv_MPRT_Init();
        Hv_Vos_Timer_Rstop(s_stPanelTimer.pstKtxPllLockStatusTimer);
        Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelIdlePattTimer, 0);
        uiPanelRestartNum = 0;
        Hv_Mw_OsdSetLogoBypass();
       if (HV_FALSE == pstPanelManager->bTimingChangeFlag)
       {
            SendShowLogoMsgToOSDTask();
       }
#ifdef  CONFIG_USER_PANEL_TYPE_EDPTX
       Hv_Drv_EdpTx_SetTps1Done(HV_TRUE);
       Hv_Drv_EdpTx_SetEqDone(HV_TRUE);
#endif
        return HV_SUCCESS;
    }
    if (HV_FAILURE == s_stPanelManager.stPanelControl.pfGetPanelStatus())
    {
        if (uiCheckTrainingNum <= 4)
        {
            uiCheckTrainingNum++;
            Hv_Vos_Timer_Rstart(s_stPanelTimer.pstKtxPllLockStatusTimer, 0);
            HV_LOG_WARN(PANEL, "panel training fail %u", uiCheckTrainingNum);
            return HV_CONTINUE; 
        }
        else
        {
            uiPanelRestartNum++;
            uiCheckTrainingNum = 0;
            Hv_Vos_Timer_Rstop(s_stPanelTimer.pstKtxPllLockStatusTimer);
            Hv_Drv_Ktx_PanelVideoPower(0);
            s_stPanelManager.stPanelControl.pfPanelEnable(HV_FALSE);
            HV_LOG_WARN(PANEL, "panel training fail,restart %u", uiPanelRestartNum);
            /*失败了重新给屏断电，在走一遍panel流程*/
            Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelPowerOnTimer, 0);
            return HV_FAILURE; 
        }
    }
    else
    {
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
        SetPanelSequenceTestPinLevel(GPIO_LEVEL_HIGH);
#endif
        HV_LOG_INFO(PANEL, "panel training ok!");
#if (HV_PROJECT_CONFIG_EDP_TX_HPD_IRQ_EN == HV_CONFIG_ON)
        if (NULL != s_stPanelManager.stPanelControl.pfPanelIrqEnable)
        {
            if (1 == s_stPanelParam.ucPanelPortNum)
            {
                s_stPanelManager.stPanelControl.pfPanelIrqEnable(HV_PROJECT_CONFIG_EDP_TX_HPD0_PORT);
            }
            else
            {
                s_stPanelManager.stPanelControl.pfPanelIrqEnable(HV_PROJECT_CONFIG_EDP_TX_HPD0_PORT);
                s_stPanelManager.stPanelControl.pfPanelIrqEnable(HV_PROJECT_CONFIG_EDP_TX_HPD1_PORT);
            }
        }
#endif
#if (HV_PROJECT_CONFIG_FULL_LOCALDIMMING == HV_CONFIG_ON)
        Hv_App_PQ_LdcBacklightStart();
#endif
    }
    if(HV_FALSE == pstPanelManager->bTimingChangeFlag)
    {
        /*初始化背光PWM，需要先出PWM，然后再开背光*/
        Hv_Drv_MPRT_Init();
        SendShowLogoMsgToOSDTask();
    }
    uiPanelRestartNum = 0;
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstKtxPllLockStatusTimer);
#ifdef  CONFIG_USER_PANEL_TYPE_EDPTX
    if (0 == s_stPanelParam.usPanelIdlePatternTime)
    {
        Hv_Drv_EdpTx_SendIdlePatternEn(EDP_TX_PROT_INDEX0, HV_FALSE);
        Hv_Drv_EdpTx_SendIdlePatternEn(EDP_TX_PROT_INDEX1, HV_FALSE);
    }
    else
    {
        Hv_Drv_EdpTx_SendIdlePatternEn(EDP_TX_PROT_INDEX0, HV_TRUE);
        Hv_Drv_EdpTx_SendIdlePatternEn(EDP_TX_PROT_INDEX1, HV_TRUE);
    }
#endif
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelIdlePattTimer, 0);
    return HV_SUCCESS; 
}

static Status PanelStateMachineHandler_IdlePatt(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
#ifdef  CONFIG_USER_PANEL_TYPE_EDPTX
    Hv_Drv_EdpTx_SendIdlePatternEn(EDP_TX_PROT_INDEX0, HV_FALSE);
    Hv_Drv_EdpTx_SendIdlePatternEn(EDP_TX_PROT_INDEX1, HV_FALSE);
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_IDLE_PATT);
#endif
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelIdlePattTimer);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelBlkOnTimer, 0);
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
    if (0 != s_stPanelParam.usPanelIdlePatternTime)
    {
        // 有idle状态则拉低，否则保持traing成功的高电平状态
        SetPanelSequenceTestPinLevel(GPIO_LEVEL_LOW);
    }
#endif
    return HV_SUCCESS;
}

static Status PanelStateMachineHandler_BlkON(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_PanelBlkON, pstPanelManager->enCurrentPanelState: %d, bTimingChangeFlag:%u", pstPanelManager->enCurrentPanelState, s_stPanelManager.bTimingChangeFlag);
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_BLK_ON);
    const PowerManager *pstPowerManager = Hv_Mw_Power_GetManagerPtr();
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    /* 开启背光 */
    if ((PANEL_STATE_DATA_ON == pstPanelManager->enCurrentPanelState)
    || (PANEL_STATE_IDLE_PATT == pstPanelManager->enCurrentPanelState))
    {
        if ((s_stPanelManager.bTimingChangeFlag == HV_FALSE) 
        && ((POWER_ON_REASON_TYPE_POWER_ON == pstPowerManager->enPowerOnReasonType) || (POWER_ON_REASON_TYPE_KEY == pstPowerManager->enPowerOnReasonType))
        && ((HV_FALSE == Hv_Mw_OsdGetLogoBypass()) || (HV_TRUE == Hv_Mw_OsdCheckIsShowing())))
        {
            HV_LOG_DEBUG(PANEL, "init show logo or osd enable blk");
            Hv_Drv_Ktx_SetBacklightPower(HV_PROJECT_CONFIG_BACKLIGHT_ENABLE);
        }
        else if (CHANNEL_STATE_ACTIVE == pstChannelManager->astChannelData[CHANNEL_TYPE_MAIN].enCurrentCHState)
        {
            Hv_Drv_Ktx_SetBacklightPower(HV_PROJECT_CONFIG_BACKLIGHT_ENABLE);
        }
        Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelBlkOnTimer);
    }
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
    if (0 != s_stPanelParam.usPanelIdlePatternTime)
    {
        // 有idle状态
        SetPanelSequenceTestPinLevel(GPIO_LEVEL_HIGH);
    }
    else
    {
        SetPanelSequenceTestPinLevel(GPIO_LEVEL_LOW);
    }
#endif
    return HV_SUCCESS;
}

static Status PanelStateMachineHandler_BlkOFF(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_PanelBlkOFF, pstPanelManager->enCurrentPanelState: %d", pstPanelManager->enCurrentPanelState);
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_BLK_OFF);
    /*Panel Power Off Test Start*/
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
    PanelSequenceTestStartFlag();
#endif
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelDataOnTimer);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelPowerOnTimer);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelBlkOnTimer);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstKtxPllLockStatusTimer);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelIdlePattTimer);

    Hv_Mw_Factory_SavePanelOnCountTime(HV_TRUE);
    /* 关背光 */
    Hv_Drv_Ktx_SetBacklightPower(HV_PROJECT_CONFIG_BACKLIGHT_DISABLE);
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
    SetPanelSequenceTestPinLevel(GPIO_LEVEL_HIGH);
#endif
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelDataOffTimer, 0);

#if (HV_PROJECT_CONFIG_FULL_LOCALDIMMING == HV_CONFIG_ON)
    /* 开启blen off Timer */
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcBlOffTimer, 0);
#endif

    return HV_SUCCESS;
}

static Status PanelStateMachineHandler_DataOFF(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_PanelDataOFF, pstPanelManager->enCurrentPanelState: %d", pstPanelManager->enCurrentPanelState);
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_DATA_OFF);
    /* 关Data */
    if (pstPanelManager->enCurrentPanelState == PANEL_STATE_BLK_OFF)
    {
#if (HV_PROJECT_CONFIG_EDP_TX_HPD_IRQ_EN == HV_CONFIG_ON)
        if (NULL != s_stPanelManager.stPanelControl.pfPanelIrqEnable)
        {
            if (1 == s_stPanelParam.ucPanelPortNum)
            {
                s_stPanelManager.stPanelControl.pfPanelIrqDisable(HV_PROJECT_CONFIG_EDP_TX_HPD0_PORT);
            }
            else
            {
                s_stPanelManager.stPanelControl.pfPanelIrqDisable(HV_PROJECT_CONFIG_EDP_TX_HPD0_PORT);
                s_stPanelManager.stPanelControl.pfPanelIrqDisable(HV_PROJECT_CONFIG_EDP_TX_HPD1_PORT);
            }
        }
#endif
        s_stPanelManager.stPanelControl.pfPanelEnable(HV_FALSE);
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
        SetPanelSequenceTestPinLevel(GPIO_LEVEL_LOW);
#endif
        Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelPowerOffTimer, 0);
    }
    return HV_SUCCESS;
}

static Status SendStandyMsgToPowerManager(VOID)
{
    HV_VOS_QUEUE_S *pstSystemQueue = Hv_Mw_System_GetSystemQueue();
    HV_ASSERT_VALID_PTR(pstSystemQueue);
    SystemEvent stEvent = {0};
    stEvent.enEventType = SYSTEM_REV_EVENT_TYPE_POWER;
    stEvent.usEventId = POWER_EVENT_ID_STSTEM_STANDBY_READY;

    HV_ASSERT_TRUE(Hv_Vos_QueueSend(pstSystemQueue, &stEvent));
    HV_LOG_DEBUG(CHANNEL, "send System standy ready to PowerManager,enEventType=%u usEventId=%u!!!", stEvent.enEventType, stEvent.usEventId);
    return HV_SUCCESS;
}

static Status PanelStateMachineHandler_PowerOFF(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_PanelPowerOFF, pstPanelManager->enCurrentPanelState: %d", pstPanelManager->enCurrentPanelState);
    Hv_Drv_Ktx_SetPanelState(PANEL_STATE_POWER_OFF);
    /* 关Panel */
    if (pstPanelManager->enCurrentPanelState == PANEL_STATE_DATA_OFF)
    {
        HV_LOG_DEBUG(PANEL, " Hv_Mw_PanelPowerOFF");
        Hv_Drv_Ktx_PanelVideoPower(0);
#ifdef HV_BOARD_CONFIG_GPIO_VLED2_FB_PWM
        Hv_Drv_Gpio_SetPinLevel(HV_BOARD_CONFIG_GPIO_VLED2_FB_PWM, GPIO_LEVEL_LOW);
#endif
#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
        SetPanelSequenceTestPinLevel(GPIO_LEVEL_HIGH);
#endif
        if (s_stPanelManager.bTimingChangeFlag == HV_FALSE)
        {
            /*关屏时序完成后，如果main搜索到信号则重新唤醒*/
            if (HV_SUCCESS == Hv_Mw_Channel_GetChannelNoSignalSearchStatus())
            {
                Hw_Mw_Channel_SendNoSignalMsgToPowerManager(HV_FALSE);
            }
            else
            {
                SendStandyMsgToPowerManager();
            }
        }
    }
    return HV_SUCCESS;
}

#if (HV_PROJECT_CONFIG_FULL_LOCALDIMMING == HV_CONFIG_ON)
/* 开屏的时序处理回调函数 */
static VOID TimerCallback_LdcVCCON(VOID* pvArgument, USHORT16 usTimerId)
{
    /* LDC Vcc 使能后开启 其他定时器延时 */
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcVinOnTimer, 0);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcPwmOnTimer, 0);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcLdEnTimer, 0);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcSpiOnTimer, 0);

    Hv_Drv_Ktx_SetLdcVcc(HV_ENABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcVccOnTimer);
    return;
}

static VOID TimerCallback_LdcVINON(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_Ktx_SetLdcVin(HV_ENABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcVinOnTimer);
    return;
}

static VOID TimerCallback_LdcPwmON(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_MPRT_Init();
    Hv_Drv_MPRT_SetOutHighFreqPwm(HV_PROJECT_CONFIG_MPRT_HIGHT_PORT);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcPwmOnTimer);
    return;
}

static VOID TimerCallback_LdcLdEN(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_Ktx_SetLdcEn(HV_ENABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcLdEnTimer);
    return;
}

static VOID TimerCallback_LdcSpiON(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_PQ_KspiEn(HV_PROJECT_CONFIG_KSPI_CHANNEL_NUM);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcSpiOnTimer);
    return;
}

static VOID TimerCallback_LdcBlON(VOID* pvArgument, USHORT16 usTimerId)
{
    /* blen 当前由屏参控制 */
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcBlOnTimer);
    return;
}



/* 关屏的时序处理回调函数 */
static VOID TimerCallback_LdcBlOFF(VOID* pvArgument, USHORT16 usTimerId)
{
    /* bl off使能后开启 其他定时器延时 */
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcSpiOffTimer, 0);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcLdEnOffTimer, 0);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcPwmOffTimer, 0);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcVinOffTimer, 0);
    Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelLdcVccOffTimer, 0);

    /* blen 当前由屏参控制 */
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcBlOffTimer);
    return;
}

static VOID TimerCallback_LdcSpiOFF(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_PQ_KspiEn(HV_DISABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcSpiOffTimer);
    return;
}

static VOID TimerCallback_LdcLdENOFF(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_Ktx_SetLdcEn(HV_DISABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcLdEnOffTimer);
    return;
}

static VOID TimerCallback_LdcPwmOFF(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_MPRT_PwmEnable(HV_PROJECT_CONFIG_MPRT_HIGHT_PORT, HV_DISABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcPwmOffTimer);
    return;
}

static VOID TimerCallback_LdcVINOFF(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_Ktx_SetLdcVin(HV_DISABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcVinOffTimer);
    return;
}

static VOID TimerCallback_LdcVCCOFF(VOID* pvArgument, USHORT16 usTimerId)
{
    Hv_Drv_Ktx_SetLdcVcc(HV_DISABLE);
    Hv_Vos_Timer_Rstop(s_stPanelTimer.pstPanelLdcVccOffTimer);
    return;
}
#endif

static Status PanelTimerInit(VOID)
{
    /*打开 panel power*/
    HV_TIMER_INIT_PARAMS stPanelPowerOnTimerParam = \
    {"PanelPowerOnTimer", s_stPanelParam.usPanelPowerOnTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_PANEL_POWER_ON};
    s_stPanelTimer.pstPanelPowerOnTimer = Hv_Vos_Timer_Create(&stPanelPowerOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelPowerOnTimer);

    /*打开data Timer*/
    HV_TIMER_INIT_PARAMS stPanelDataOnTimerParam = \
    {"PanelDataOnTimer", s_stPanelParam.usPanelDataOnTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_PANEL_DATA_ON};
    s_stPanelTimer.pstPanelDataOnTimer = Hv_Vos_Timer_Create(&stPanelDataOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelDataOnTimer);

    /*开背光 Timer*/
    HV_TIMER_INIT_PARAMS stPanelBlkOnTimerParam = \
    {"PanelBlkOnTimer", s_stPanelParam.usPanelBlkOnTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_PANEL_BLK_ON};
    s_stPanelTimer.pstPanelBlkOnTimer = Hv_Vos_Timer_Create(&stPanelBlkOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelBlkOnTimer);

    /*关背光 Timer*/
    HV_TIMER_INIT_PARAMS stPanelBlkOffTimerParam = \
    {"PanelBlkOffTimer", s_stPanelParam.usPanelBlkOffTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_PANEL_BLK_OFF};
    s_stPanelTimer.pstPanelBlkOffTimer = Hv_Vos_Timer_Create(&stPanelBlkOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelBlkOffTimer);

    /*关闭data Timer*/
    HV_TIMER_INIT_PARAMS stPanelDataOffTimerParam = \
    {"PanelDataOffTimer", s_stPanelParam.usPanelDataOfTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_PANEL_DATA_OFF};
    s_stPanelTimer.pstPanelDataOffTimer = Hv_Vos_Timer_Create(&stPanelDataOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelDataOffTimer);

    /*关闭 panel power*/
    HV_TIMER_INIT_PARAMS stPanelPowerOffTimerParam = \
    {"PanelPowerOffTimer", s_stPanelParam.usPanelPowerOffTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_PANEL_POWER_OFF};
    s_stPanelTimer.pstPanelPowerOffTimer = Hv_Vos_Timer_Create(&stPanelPowerOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelPowerOffTimer);

    /*waite KTX PLL lock Timer*/
    HV_TIMER_INIT_PARAMS stKtxPllLockStatusTimer = \
    {"KTXPllLockStatusTimer", s_stPanelParam.usPanelPllLockTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_CHECK_TRAINING_STATUS};
    s_stPanelTimer.pstKtxPllLockStatusTimer = Hv_Vos_Timer_Create(&stKtxPllLockStatusTimer);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstKtxPllLockStatusTimer);

    /*发送idle pattern*/
    HV_TIMER_INIT_PARAMS stPanelIdlePattTimerParam = \
    {"PanelIdlePattTimer", s_stPanelParam.usPanelIdlePatternTime, HV_FALSE, NULL, Hv_Common_Timer_DispatchEvent, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelIdlePattTimer = Hv_Vos_Timer_Create(&stPanelIdlePattTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelIdlePattTimer);

#if (HV_PROJECT_CONFIG_FULL_LOCALDIMMING == HV_CONFIG_ON)
    /* ldc vcc on Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcVccOnTimerParam = \
    {"PanelLdcVccOnTimer", s_stPanelParam.usPanelLdcVccOnTime, HV_FALSE, NULL, TimerCallback_LdcVCCON, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcVccOnTimer = Hv_Vos_Timer_Create(&stPanelLdcVccOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcVccOnTimer);

    /* ldc vin on Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcVinOnTimerParam = \
    {"PanelLdcVinOnTimer", s_stPanelParam.usPanelLdcVinOnTime, HV_FALSE, NULL, TimerCallback_LdcVINON, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcVinOnTimer = Hv_Vos_Timer_Create(&stPanelLdcVinOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcVinOnTimer);

    /* ldc pwm on Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcPwmOnTimerParam = \
    {"PanelLdcPwmOnTimer", s_stPanelParam.usPanelLdcPwmOnTime, HV_FALSE, NULL, TimerCallback_LdcPwmON, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcPwmOnTimer = Hv_Vos_Timer_Create(&stPanelLdcPwmOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcPwmOnTimer);

    /* ldc lden on Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcLdEnTimerParam = \
    {"PanelLdcLdEnTimer", s_stPanelParam.usPanelLdcLdEnTime, HV_FALSE, NULL, TimerCallback_LdcLdEN, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcLdEnTimer = Hv_Vos_Timer_Create(&stPanelLdcLdEnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcLdEnTimer);

    /* ldc spi on Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcSpiOnTimerParam = \
    {"PanelLdcSpiOnTimer", s_stPanelParam.usPanelLdcSpiOnTime, HV_FALSE, NULL, TimerCallback_LdcSpiON, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcSpiOnTimer = Hv_Vos_Timer_Create(&stPanelLdcSpiOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcSpiOnTimer);

    /* ldc Bl on Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcBlOnTimerParam = \
    {"PanelLdcBlOnTimer", s_stPanelParam.usPanelLdcBlOnTime, HV_FALSE, NULL, TimerCallback_LdcBlON, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcBlOnTimer = Hv_Vos_Timer_Create(&stPanelLdcBlOnTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcBlOnTimer);

    /* poweroff的关闭时序定时器 */

    /* ldc Bl on Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcBlOffTimerParam = \
    {"PanelLdcBlOffTimer", s_stPanelParam.usPanelLdcBlOffTime, HV_FALSE, NULL, TimerCallback_LdcBlOFF, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcBlOffTimer = Hv_Vos_Timer_Create(&stPanelLdcBlOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcBlOffTimer);

    /* ldc spi off Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcSpiOffTimerParam = \
    {"PanelLdcSpiOffTimer", s_stPanelParam.usPanelLdcSpiOffTime, HV_FALSE, NULL, TimerCallback_LdcSpiOFF, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcSpiOffTimer = Hv_Vos_Timer_Create(&stPanelLdcSpiOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcSpiOffTimer);

    /* ldc lden off Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcLdEnOffTimerParam = \
    {"PanelLdcLdEnOffTimer", s_stPanelParam.usPanelLdcLdEnOffTime, HV_FALSE, NULL, TimerCallback_LdcLdENOFF, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcLdEnOffTimer = Hv_Vos_Timer_Create(&stPanelLdcLdEnOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcLdEnOffTimer);

    /* ldc pwm off Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcPwmOffTimerParam = \
    {"PanelLdcPwmOffTimer", s_stPanelParam.usPanelLdcPwmOffTime, HV_FALSE, NULL, TimerCallback_LdcPwmOFF, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcPwmOffTimer = Hv_Vos_Timer_Create(&stPanelLdcPwmOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcPwmOffTimer);

    /* ldc vin off Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcVinOffTimerParam = \
    {"PanelLdcVinOffTimer", s_stPanelParam.usPanelLdcVinOffTime, HV_FALSE, NULL, TimerCallback_LdcVINOFF, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcVinOffTimer = Hv_Vos_Timer_Create(&stPanelLdcVinOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcVinOffTimer);

    /* ldc vcc off Timer */
    HV_TIMER_INIT_PARAMS stPanelLdcVccOffTimerParam = \
    {"PanelLdcVccOffTimer", s_stPanelParam.usPanelLdcVccOffTime, HV_FALSE, NULL, TimerCallback_LdcVCCOFF, SYS_EVENT_TIMER_PANEL_IDLE_PATT};
    s_stPanelTimer.pstPanelLdcVccOffTimer = Hv_Vos_Timer_Create(&stPanelLdcVccOffTimerParam);
    HV_ASSERT_VALID_PTR(s_stPanelTimer.pstPanelLdcVccOffTimer);


#endif
    return HV_SUCCESS;

}

static BOOL PullOneMsgFromPanelInnerMsgQueue(PanelInnerMsgQueue* pstPanelInnerMsgQueue, PanelEvent* pstEvent)
{
    if (QUEUE_OK == QueueRead(pstPanelInnerMsgQueue, pstEvent))
    {
        return HV_TRUE;
    }
    return HV_FALSE;
}
#ifdef HV_SCALER_DEBUG_VERSION
static CHAR8* StateMachineStateConvert(PanelState enType)
{
    UINT32 uiIndex = 0;
    UINT32 uiLoop = 0;
    CHAR8* paType[] =
    {
        "panel off",
        "panel power on",
        "panel data on",
        "panel wait lock",
        "panel idle patt",
        "panel blk on",
        "panel blk off",
        "panel data off",
        "panel power off",
        "panel any state",
    };
    if(0xFFFF == enType)
    {
        uiIndex = 8;
    }
    else
    {
        for(uiLoop = 0; uiLoop < 8; uiLoop++)
        {
            if((enType >> uiLoop) & 0x1)
            {
                uiIndex = uiLoop;
                break;
            }
        }
        if(uiLoop >= 8)
        {
            uiIndex = 8;
        }
    }
    return paType[uiIndex];
}

static CHAR8* PanelEventIdConvert(PanelEventId enType)
{
    CHAR8* paType[] =
    {
        "panel power on",
        "panel training start",
        "panel blk on",
        "panel idle pattern event",
        "panel blk off",
        "panel data off",
        "panel power off",
        "panel check training status",
        "edp backlight",
        "spi back light",
        "on first enter",
    };
    if(enType >= sizeof(paType)/sizeof(paType[0]))
    {
        return "NULL";
    }
    else
    {
        return paType[enType];
    }

}
#endif
static Status RunPanelStateMachine(const PanelEvent* pstPanelEvent, PanelManager* pstPanelManager)
{
    HV_LOG_DEBUG(PANEL, "RunPanelStateMachine");
    Status uiRet = HV_FAILURE;
    PanelState enNextState = PANEL_STATE_ANY;
    //*pbNeedInsertConvertEvent = HV_FALSE;/*很关键必须置位false，否则convert消息如果在for循环中无法找到则pbNeedChangeState无法赋值为false，导致while死循环*/
#ifdef HV_SCALER_DEBUG_VERSION
    HV_LOG_INFO(PANEL, "Panel %s , %s", StateMachineStateConvert(pstPanelManager->enCurrentPanelState), PanelEventIdConvert(pstPanelEvent->usEventId));
#endif
    for (USHORT16 usIndex = 0; usIndex < ARRAY_SIZE(s_astPanelStateMachine); ++usIndex)
    {
        if ((pstPanelEvent->usEventId == s_astPanelStateMachine[usIndex].enEventId)
         && (pstPanelManager->enCurrentPanelState & s_astPanelStateMachine[usIndex].usAcceptStates))
        {
            uiRet = s_astPanelStateMachine[usIndex].pfActionHandle(pstPanelEvent, pstPanelManager);
            if (HV_SUCCESS == uiRet)
            {
                enNextState = s_astPanelStateMachine[usIndex].enNextSuccessState;
            }
            else if (HV_FAILURE == uiRet)
            {
                enNextState = s_astPanelStateMachine[usIndex].enNextFailState;
            }
            else
            {
                /*continue*/
            }
            if ((enNextState != pstPanelManager->enCurrentPanelState) && (PANEL_STATE_ANY != enNextState))
            {
                pstPanelManager->enCurrentPanelState = enNextState;
            }

            break;
        }
    }
    return uiRet;
}

Status Hv_Mw_Panel_ProcInnerMsgs(VOID)
{
    PanelEvent stPanelEvent = {0};
    BOOL bHasMsg = HV_FALSE;
    do   
    {
        bHasMsg = PullOneMsgFromPanelInnerMsgQueue(&s_stPanelManager.stPanelInnerMsgQueue, &stPanelEvent);
        if (HV_TRUE == bHasMsg)
        {
            RunPanelStateMachine(&stPanelEvent, &s_stPanelManager);
        }

    } while ( bHasMsg );
    return HV_SUCCESS;
}

Status SystemEventConvertToPanelEvent(const SystemEvent* pstSystemEvent, PanelEvent * pstPanelEvent)
{
    HV_LOG_DEBUG(PANEL, "SystemEventConvertToPanelEvent pstSystemEvent->usEventId %d", pstSystemEvent->usEventId);
    Status uiConvertStatus = HV_SUCCESS;

    switch (pstSystemEvent->usEventId)
    {
        case SYS_EVENT_TIMER_PANEL_POWER_ON:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_PANEL_POWER_ON;
            break;
        }
        case SYS_EVENT_TIMER_PANEL_DATA_ON:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_TRAINING_START;
            break;
        }
        case SYS_EVENT_TIMER_PANEL_BLK_ON:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_BLK_ON;
            break;
        }
        case SYS_EVENT_TIMER_PANEL_BLK_OFF:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_BLK_OFF;
            break;
        }
        case SYS_EVENT_TIMER_PANEL_DATA_OFF:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_DATA_OFF;
            break;
        }
        case SYS_EVENT_TIMER_PANEL_POWER_OFF:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_POWER_OFF;
            break;
        }
        case SYS_EVENT_TIMER_CHECK_TRAINING_STATUS:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_CHECK_TRAINING_STATUS;
            break;
        }
        case SYS_EVENT_TIMER_PANEL_IDLE_PATT:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_IDLE_PATTERN;
            break;
        }
        case SYS_EVENT_TIMER_SPI_BACK_LIGHT:
        {
            pstPanelEvent->usEventId = PANEL_EVENT_ID_SPI_BACK_LIGHT;
            break;
        }
        default:
        {
            uiConvertStatus = HV_FAILURE;
            HV_LOG_ERROR(CHANNEL, "receive unknown PanelTimerId =%u", pstSystemEvent->usEventId);
            break;
        }
    }
    pstPanelEvent->usValue = pstSystemEvent->uiValue;
    HV_LOG_DEBUG(PANEL, "SystemEventConvertToPanelEvent pstPanelEvent->usEventId %d", pstPanelEvent->usEventId);
    return uiConvertStatus;
}

#ifdef HV_SCALER_DEBUG_VERSION
static CHAR8* EventTypeConvert(SystemRevEventType enEventType)
{
    CHAR8* paEventType[] =
    {
        "power",
        "osd",
        "channel",
        "inputport",
        "panel",
        "timer",
        "ddc/ci"    
    };
    if(enEventType >= sizeof(paEventType)/sizeof(paEventType[0]))
    {
        return "NULL";
    }
    else
    {
        return paEventType[enEventType];
    }
}
#endif


Status Hv_Mw_Panel_ProcSystemQueueMsg(const SystemEvent* pstSystemEvent)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_Panel_ProcSystemQueueMsg");
    PanelEvent stPanelEvent;
#ifdef HV_SCALER_DEBUG_VERSION
    if(SYSTEM_REV_EVENT_TYPE_TIMER == pstSystemEvent->enEventType)
    {
        HV_LOG_INFO(PANEL, "Panel %s,%s", EventTypeConvert(pstSystemEvent->enEventType),TimerEventIDConvert((TIMER_EVENT_E)pstSystemEvent->usEventId));
    }
#endif
    HV_MEMSET(&stPanelEvent, 0, sizeof(stPanelEvent));
    HV_ASSERT_SUCCESS(SystemEventConvertToPanelEvent(pstSystemEvent, &stPanelEvent));
    return Hv_Mw_Panel_SendInnerMsg(&stPanelEvent);
}

BOOL Hv_Mw_Panel_HasInnerMsgs( VOID )
{
    BOOL bHasMsgToProc = QueueIsEmpty(&s_stPanelManager.stPanelInnerMsgQueue);
    return !bHasMsgToProc;    
}

const PanelManager* Hv_Mw_Panel_GetManagerPtr(VOID)
{
    return &s_stPanelManager;
}

VOID Hv_Mw_Panel_SetTimingChangeFlag(BOOL bFlag)
{
    s_stPanelManager.bTimingChangeFlag = bFlag;
    return;
}

BOOL Hv_Mw_Panel_GetTimingChangeFlag(VOID)
{
    return s_stPanelManager.bTimingChangeFlag;
}

VOID Hv_Mw_Panel_StartPanelPowerOnTimer(VOID)
{
    if (Hv_Vos_Timer_IsTimerActive(s_stPanelTimer.pstPanelPowerOnTimer) == HV_FALSE)
    {
        HV_LOG_INFO(PANEL, "timing cheange start PanelPowerOnTimer");
        Hv_Vos_Timer_Rstart(s_stPanelTimer.pstPanelPowerOnTimer, 0);
    }
    return;
}

VOID PanelParamInit(VOID)
{
    UCHAR8 ucPanelIndex = HV_COMMON_DATABASE_GET(FactoryData, ucDynamicPanelIndex);
    PanelDataDBRegion *pstPanelDB = Hv_Common_Db_GetPanelDataDBRegionPtr();
    const PanelParam *pstPanelParamFlash = pstPanelDB->stPanelParam;
    
    if ((HV_TRUE == HV_COMMON_DATABASE_GET(FactoryData, bDynamicPanelEn)) && (ucPanelIndex < FLASH_PANLE_PARAM_SUIT_MAX_NUM))
    {
        s_stPanelParam = pstPanelParamFlash[ucPanelIndex];
    }
    else
    {
        strncpy(s_stPanelParam.ucPanelName, PANEL_NAME, HV_PANEL_NAME_BYTE_MAX -1);
        s_stPanelParam.ucPanelName[HV_PANEL_NAME_BYTE_MAX - 1] = '\0';
        s_stPanelParam.usPanelHtotalType      = PANEL_H_TOTAL_TYP;
        s_stPanelParam.usPanelHtotalMax       = PANEL_H_TOTAL_MAX;
        s_stPanelParam.usPanelHtotalMin       = PANEL_H_TOTAL_MIN;
        s_stPanelParam.usPanelVtotalType      = PANEL_V_TOTAL_TYP;
        s_stPanelParam.usPanelVtotalMax       = PANEL_V_TOTAL_MAX;
        s_stPanelParam.usPanelVtotalMin       = PANEL_V_TOTAL_MIN;
        s_stPanelParam.usPanelHactive         = PANEL_H_ACTIVE;
        s_stPanelParam.usPanelVactive         = PANEL_V_ACTIVE;
        s_stPanelParam.usPanelFrameRateType   = PANEL_FRAME_RATE_TYP;
        s_stPanelParam.usPanelFrameRateMax    = PANEL_FRAME_RATE_MAX;
        s_stPanelParam.usPanelFrameRateMin    = PANEL_FRAME_RATE_MIN;
        s_stPanelParam.ucPanelHsyncWidth      = PANEL_H_SYNC_WIDTH;
        s_stPanelParam.ucPanelVsyncWidth      = PANEL_V_SYNC_WIDTH;
        s_stPanelParam.ucPanelHsyncBackPorch  = PANEL_H_SYNC_BACK_PORCH;
        s_stPanelParam.ucPanelVsyncBackPorch  = PANEL_V_SYNC_BACK_PORCH;
        s_stPanelParam.ucPanelColorDepth      = PANEL_COLOR_DEPTH;
        s_stPanelParam.ucPanelLaneNum         = PANEL_LANE_NUM;
        s_stPanelParam.ucPanelPortNum         = PANEL_PORT_NUM;
        s_stPanelParam.ucPanelLaneRate        = PANEL_LANE_RATE;
        s_stPanelParam.uiPanelPixelClockType  = PANEL_PIXEL_CLOCK_TYP;
        s_stPanelParam.uiPanelPixelClockMax   = PANEL_PIXEL_CLOCK_MAX;
        s_stPanelParam.uiPanelPixelClockMin   = PANEL_PIXEL_CLOCK_MIN;
        s_stPanelParam.usPanelPowerOnTime     = PANEL_POWER_ON_TIME;
        s_stPanelParam.usPanelDataOnTime      = PANEL_DATA_ON_TIME;
        s_stPanelParam.usPanelBlkOnTime       = PANEL_BLK_ON_TIME;
        s_stPanelParam.usPanelBlkOffTime      = PANEL_BLK_OFF_TIME;
        s_stPanelParam.usPanelDataOfTime      = PANEL_DATA_OF_TIME;
        s_stPanelParam.usPanelPowerOffTime    = PANEL_POWER_OFF_TIME;
        s_stPanelParam.usPanelPllLockTime     = PANEL_KTX_PLL_LOCK_TIME;
        s_stPanelParam.usPanelIdlePatternTime = PANEL_IDLE_PATTERN_TIME;
        s_stPanelParam.bPanelSscgEn           = PANEL_SSC_EN;
        s_stPanelParam.usPanelSscgFreq        = PANEL_SSC_FREQ;
        s_stPanelParam.ucPanelSscgFrac        = PANEL_SSC_FRAC;
#ifdef PANEL_EDP_HPD0_SOFT_MODE
        s_stPanelParam.ucPanelEdpHpd0SoftMode = PANEL_EDP_HPD0_SOFT_MODE;
        s_stPanelParam.ucPanelEdpHpd1SoftMode = PANEL_EDP_HPD1_SOFT_MODE;
#endif
#ifdef PANEL_EDP_AUX0_PN_SWAP_EN
        s_stPanelParam.bPanelEdpAux0PnSwapEn  = PANEL_EDP_AUX0_PN_SWAP_EN;
        s_stPanelParam.bPanelEdpAux1PnSwapEn  = PANEL_EDP_AUX1_PN_SWAP_EN;
#endif
        s_stPanelParam.bPanelPhy0MuxEn        = PANEL_PHY0_MUX_EN;
        s_stPanelParam.ucPanelPhy0Lane0MuxSel = PANEL_PHY0_0_MUX_SEL;
        s_stPanelParam.ucPanelPhy0Lane1MuxSel = PANEL_PHY0_1_MUX_SEL;
        s_stPanelParam.ucPanelPhy0Lane2MuxSel = PANEL_PHY0_2_MUX_SEL;
        s_stPanelParam.ucPanelPhy0Lane3MuxSel = PANEL_PHY0_3_MUX_SEL;
        s_stPanelParam.bPanelPhy0Lane0PnSwap  = PANEL_PHY0_LANE0_PN_SWAP;
        s_stPanelParam.bPanelPhy0Lane1PnSwap  = PANEL_PHY0_LANE1_PN_SWAP;
        s_stPanelParam.bPanelPhy0Lane2PnSwap  = PANEL_PHY0_LANE2_PN_SWAP;
        s_stPanelParam.bPanelPhy0Lane3PnSwap  = PANEL_PHY0_LANE3_PN_SWAP;
        s_stPanelParam.bPanelPhy1MuxEn        = PANEL_PHY1_MUX_EN;
        s_stPanelParam.ucPanelPhy1Lane0MuxSel = PANEL_PHY1_0_MUX_SEL;
        s_stPanelParam.ucPanelPhy1Lane1MuxSel = PANEL_PHY1_1_MUX_SEL;
        s_stPanelParam.ucPanelPhy1Lane2MuxSel = PANEL_PHY1_2_MUX_SEL;
        s_stPanelParam.ucPanelPhy1Lane3MuxSel = PANEL_PHY1_3_MUX_SEL;
        s_stPanelParam.bPanelPhy1Lane0PnSwap  = PANEL_PHY1_LANE0_PN_SWAP;
        s_stPanelParam.bPanelPhy1Lane1PnSwap  = PANEL_PHY1_LANE1_PN_SWAP;
        s_stPanelParam.bPanelPhy1Lane2PnSwap  = PANEL_PHY1_LANE2_PN_SWAP;
        s_stPanelParam.bPanelPhy1Lane3PnSwap  = PANEL_PHY1_LANE3_PN_SWAP;
        s_stPanelParam.bPanelPhy2MuxEn        = PANEL_PHY2_MUX_EN;
        s_stPanelParam.ucPanelPhy2Lane0MuxSel = PANEL_PHY2_0_MUX_SEL;
        s_stPanelParam.ucPanelPhy2Lane1MuxSel = PANEL_PHY2_1_MUX_SEL;
        s_stPanelParam.ucPanelPhy2Lane2MuxSel = PANEL_PHY2_2_MUX_SEL;
        s_stPanelParam.ucPanelPhy2Lane3MuxSel = PANEL_PHY2_3_MUX_SEL;
        s_stPanelParam.bPanelPhy2Lane0PnSwap  = PANEL_PHY2_LANE0_PN_SWAP;
        s_stPanelParam.bPanelPhy2Lane1PnSwap  = PANEL_PHY2_LANE1_PN_SWAP;
        s_stPanelParam.bPanelPhy2Lane2PnSwap  = PANEL_PHY2_LANE2_PN_SWAP;
        s_stPanelParam.bPanelPhy2Lane3PnSwap  = PANEL_PHY2_LANE3_PN_SWAP;
#ifdef PANEL_INCH_WIDTH
        s_stPanelParam.usPanelInchWidth       = PANEL_INCH_WIDTH;
#endif
#ifdef PANEL_INCH_HEIGHT
        s_stPanelParam.usPanelInchHeight      = PANEL_INCH_HEIGHT;
#endif

#if (HV_PROJECT_CONFIG_FULL_LOCALDIMMING == HV_CONFIG_ON)
        s_stPanelParam.usPanelLdcVccOnTime    = PANEL_LDC_VCC_ON_TIME;
        s_stPanelParam.usPanelLdcVinOnTime    = PANEL_LDC_VIN_ON_TIME;
        s_stPanelParam.usPanelLdcPwmOnTime    = PANEL_LDC_PWM_ON_TIME;
        s_stPanelParam.usPanelLdcLdEnTime     = PANEL_LDC_LDEN_ON_TIME;
        s_stPanelParam.usPanelLdcSpiOnTime    = PANEL_LDC_SPI_ON_TIME;
        s_stPanelParam.usPanelLdcBlOnTime     = PANEL_LDC_BL_ON_TIME;

        s_stPanelParam.usPanelLdcBlOffTime     = PANEL_LDC_BL_OFF_TIME;
        s_stPanelParam.usPanelLdcSpiOffTime    = PANEL_LDC_SPI_OFF_TIME;
        s_stPanelParam.usPanelLdcLdEnOffTime   = PANEL_LDC_LDEN_OFF_TIME;
        s_stPanelParam.usPanelLdcPwmOffTime    = PANEL_LDC_PWM_OFF_TIME;
        s_stPanelParam.usPanelLdcVinOffTime    = PANEL_LDC_VIN_OFF_TIME;
        s_stPanelParam.usPanelLdcVccOffTime    = PANEL_LDC_VCC_OFF_TIME;
#endif
    }
    return;
}

const PanelParam Hv_Mw_Panel_GetCurrentPanelParam(VOID)
{
    return s_stPanelParam;
}

USHORT16 Hv_Mw_Panel_GetPanelHactive(VOID)
{
    return s_stPanelParam.usPanelHactive;
}

USHORT16 Hv_Mw_Panel_GetPanelVactive(VOID)
{
    return s_stPanelParam.usPanelVactive;
}

UCHAR8 Hv_Mw_Panel_GetPanelFrameRateType(VOID)
{
    return s_stPanelParam.usPanelFrameRateType;
}

static VOID PanelSscgInit(VOID)
{
    UCHAR8 ucPnlSscgFreq = s_stPanelParam.usPanelSscgFreq;
    UCHAR8 ucPnlSscgStep = s_stPanelParam.ucPanelSscgFrac;
    if ((ucPnlSscgFreq > 0 ||  ucPnlSscgStep > 0) && (1 == s_stPanelParam.bPanelSscgEn))
    {
#ifdef  CONFIG_USER_PANEL_TYPE_VBOTX
        Hv_Drv_Sscg_SetSscg(SSCG_VBO, ucPnlSscgStep, ucPnlSscgFreq);
        Hv_Drv_Sscg_Enalbe(SSCG_VBO, HV_ENABLE);
#endif
#ifdef  CONFIG_USER_PANEL_TYPE_EDPTX
        Hv_Drv_Sscg_SetSscg(SSCG_EDP, ucPnlSscgStep, ucPnlSscgFreq);
        Hv_Drv_Sscg_Enalbe(SSCG_EDP, HV_ENABLE);
#endif
    }
    return;
}

Status Hv_Mw_Panel_Init(VOID)
{
    HV_LOG_DEBUG(PANEL, "Hv_Mw_Panel_Init");
    PanelParamInit();
    s_stPanelManager.stPanelParam = s_stPanelParam;
    HV_Drv_Panel_Init(&s_stPanelManager.stPanelControl); 
    s_stPanelManager.stPanelControl.pfPanelInit(&s_stPanelParam);
    s_stPanelManager.bTimingChangeFlag = HV_FALSE;
    PanelSscgInit();

    QueueReset(&s_stPanelManager.stPanelInnerMsgQueue);

    PanelTimerInit();

    /* panel电源打开之后在0.2ms~10ms后开始data传输 */
    Hv_Drv_Ktx_PanelVideoPower(1);

#ifdef CONFIG_USER_PANEL_SEQUENCE_ON
    PanelSequenceTestStartFlag();
#endif
    /*设置panel状态PANEL_STATE_OFF*/
    s_stPanelManager.enCurrentPanelState = PANEL_STATE_OFF;

    /* 设置OSD H total： PANEL_H_TOTAL_TYP - 4 */
    Hv_Drv_OsdSetPanelHtotal(s_stPanelManager.stPanelParam.usPanelHtotalType - 4);

    return HV_SUCCESS;
}
