/**
 * @file Hv_Mw_Channel_SearchSource.c
 * @brief middlware channel Search source file.
 * @details This file provides the following functions: \n
 *          (1) Initialization and de-initialization functions \n
 *          (2) Start and stop functions \n
 *          (3) Feed functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-23
 * @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>2022-08-23   <td>init
 * </table>
*/
#include "hv_comm_DataBase.h"
#include "hv_comm_Assert.h"
#include "hv_drv_DpuCommon.h"
#include "hv_mw_Channel_SearchSource.h"
#include "hv_mw_InputPortManager.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_Video_TimingCheck.h"
#ifdef CONFIG_USER_USB_OTA_ON
#include "hv_mw_UsbTask.h"
#endif

static SearchStrategy s_astRealTimeMainSearchTable[] =
{
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID) 
    {0, 0, 0},
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
    {1, 0, 0},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
    {2, 0, 0},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
    {3, 0, 0},
#endif
};

static SearchStrategy stRealTimeSubSearchTable[] =
{
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID) 
    {0, 0, 0},
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
    {1, 0, 0},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
    {2, 0, 0},
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
    {3, 0, 0},
#endif

};

static LinkPortIndex aenNosignalSearchPortTable[] =
{
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID) 
    LINK_PORT_INDEX_HDMI_RX0,
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
    LINK_PORT_INDEX_HDMI_RX1,
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
    LINK_PORT_INDEX_DP_RX0,
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
    LINK_PORT_INDEX_DP_RX1,
#endif
};


static BOOL CheckPortOnUsing(ChannelType enCurrentSearch, LinkPortIndex enMwPortIndex)
{
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    HV_ASSERT_VALID_PTR_RET(pstChannelManager, HV_FALSE);
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    /*PIP关闭，端口必然未被占用*/
    if (0 == HV_COMMON_DATABASE_GET(UserData, ucPxPMode))
    {
        return HV_FALSE;
    }
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
    else if (1 == HV_COMMON_DATABASE_GET(UserData, bMagnifyGlassSw))
    {
        return HV_FALSE;
    }
#endif
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_DPU_BRIGHT_FRAME)
    else if (1 == HV_COMMON_DATABASE_GET(UserData, bBrightFrameEn))
    {
        return HV_FALSE;
    }
#endif
    else
#endif
    {
        /*当前搜索的通道是主通道，那么需要检查该端口是否被辅通道占用*/
        if (CHANNEL_TYPE_MAIN == enCurrentSearch)
        {
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
            return (enMwPortIndex == pstChannelManager->astChannelData[1].enChannelSrcLinkPortIndex);
#else
            return HV_FALSE;
#endif
        }
        else/*当前搜索的通道是辅通道，那么需要检查该端口是否被主通道占用*/
        {
            return (enMwPortIndex == pstChannelManager->astChannelData[0].enChannelSrcLinkPortIndex);
        }
    }
    return HV_FALSE;
}

UCHAR8 Hv_Mw_Channel_ConvertMwToGuiPortIndex(LinkPortIndex enPortIndex)
{
    UCHAR8 ucGuiPortIndex = 0;
    switch (enPortIndex)
    {
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)     
        case LINK_PORT_INDEX_HDMI_RX0:
        {
            ucGuiPortIndex = 0;
            break;
        }
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
        case LINK_PORT_INDEX_HDMI_RX1:
        {
            ucGuiPortIndex = 1;
            break;
        }
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        case LINK_PORT_INDEX_DP_RX0:
        {
            ucGuiPortIndex = 2;
            break;
        }
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
        case LINK_PORT_INDEX_DP_RX1:
        {
            ucGuiPortIndex = 3;
            break;
        }
#endif
        default:
        {
            break;
        }
    }
    return ucGuiPortIndex;
}

LinkPortIndex Hv_Mw_Channel_ConvertGuiToMwPortIndex(UCHAR8 ucGuiPortIndex)
{
    LinkPortIndex enPortIndex = LINK_PORT_INDEX_HDMI_RX0;
    switch (ucGuiPortIndex)
    {
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)    
        case 0:
        {
            enPortIndex = LINK_PORT_INDEX_HDMI_RX0;
            break;
        }
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
        case 1:
        {
            enPortIndex = LINK_PORT_INDEX_HDMI_RX1;
            break;
        }
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        case 2:
        {
            enPortIndex = LINK_PORT_INDEX_DP_RX0;
            break;
        }
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
        case 3:
        {
            enPortIndex = LINK_PORT_INDEX_DP_RX1;
            break;
        }
#endif
        default:
        {
            break;
        }
    }
    return enPortIndex;
}
static Status SendTimingNotSuportToOsd(UINT32 uiCheckResult, ChannelType enChannelTye, LinkPortIndex enPortIndex)
{
    HV_VOS_QUEUE_S *pOsdQueue = Hv_Mw_System_GetOsdQueue();
    HV_ASSERT_VALID_PTR(pOsdQueue);
    OsdEvent stOsdEvent = {0};
    stOsdEvent.usEventId = OSD_EVENT_SIGNAL_TIMING_NOT_SUPPORT;      /*给OSD发NOT_SUPPORT消息分为NOT_SUPPORT和OUT_OF_RANGE两种，通过value区分*/
    stOsdEvent.usValue |= uiCheckResult & 0x00FF;                    /*ERROR_RX_TIMING_FREQ_OUT_OF_RANGE  11,  ERROR_RX_TIMING_UNSUPPORT  14*/
    stOsdEvent.usValue |= (enChannelTye << 8) & 0x0F00;
    stOsdEvent.usValue |= (enPortIndex << 12) & 0xF000;
    HV_ASSERT_PEEK_TRUE(Hv_Vos_QueueSend(pOsdQueue, &stOsdEvent));
    HV_LOG_DEBUG(CHANNEL, "send OSD_EVENT_SIGNAL_TIMING_NOT_SUPPORT to OsdTask success usValue=0x%x!!!", stOsdEvent.usValue);
    return HV_SUCCESS;
}

static UINT32 GetCurrentPortSearchTimes(ChannelData* pstChannelData)
{
    if (Hv_Mw_InputPort_GetCableStatus(pstChannelData->enChannelSrcLinkPortIndex))
    {
        return HV_PROJECT_CONFIG_CURRENT_PORT_SEARCHE_TIMES;
    }
    else
    {
        return HV_PROJECT_CONFIG_EACH_PORT_DISCONNECT_SEARCHE_TIMES;
    }
}
static UINT32 GetAllPortSearchTotalTimes(ChannelData* pstChannelData)
{
    UINT32 uiAllPortSearchTotalTimes = 0;
    uiAllPortSearchTotalTimes += GetCurrentPortSearchTimes(pstChannelData);
    if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bAutoVideoSrcSelSw))
    {
#if (HV_BOARD_CONFIG_HDMI_0 == PORT_VALID)
        if ((Hv_Mw_InputPort_GetCableStatus(LINK_PORT_INDEX_HDMI_RX0)) && (LINK_PORT_INDEX_HDMI_RX0 != pstChannelData->enChannelSrcLinkPortIndex))
        {
            /*插线的端口搜索HV_PROJECT_CONFIG_EACH_PORT_SERARCH_MAX_TIMES*/
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_SERARCH_MAX_TIMES;
        }
        else if (LINK_PORT_INDEX_HDMI_RX0 != pstChannelData->enChannelSrcLinkPortIndex)
        {
            /*插线的端口搜索HV_PROJECT_CONFIG_EACH_PORT_DISCONNECT_SEARCHE_TIMES*/
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_DISCONNECT_SEARCHE_TIMES;
        }
#endif
#if (HV_BOARD_CONFIG_HDMI_1 == PORT_VALID)
        if ((Hv_Mw_InputPort_GetCableStatus(LINK_PORT_INDEX_HDMI_RX1)) && (LINK_PORT_INDEX_HDMI_RX1 != pstChannelData->enChannelSrcLinkPortIndex))
        {
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_SERARCH_MAX_TIMES;
        }
        else if (LINK_PORT_INDEX_HDMI_RX1 != pstChannelData->enChannelSrcLinkPortIndex)
        {
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_DISCONNECT_SEARCHE_TIMES;
        }
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_0 == PORT_VALID)
        if ((Hv_Mw_InputPort_GetCableStatus(LINK_PORT_INDEX_DP_RX0)) && (LINK_PORT_INDEX_DP_RX0 != pstChannelData->enChannelSrcLinkPortIndex))
        {
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_SERARCH_MAX_TIMES;
        }
        else if (LINK_PORT_INDEX_DP_RX0 != pstChannelData->enChannelSrcLinkPortIndex)
        {
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_DISCONNECT_SEARCHE_TIMES;
        }
#endif
#if (HV_BOARD_CONFIG_DISPLAYPORT_1 == PORT_VALID)
        if ((Hv_Mw_InputPort_GetCableStatus(LINK_PORT_INDEX_DP_RX1)) && (LINK_PORT_INDEX_DP_RX1 != pstChannelData->enChannelSrcLinkPortIndex))
        {
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_SERARCH_MAX_TIMES;
        }
        else if (LINK_PORT_INDEX_DP_RX1 != pstChannelData->enChannelSrcLinkPortIndex)
        {
            uiAllPortSearchTotalTimes += HV_PROJECT_CONFIG_EACH_PORT_DISCONNECT_SEARCHE_TIMES;
        }
#endif
    }
    HV_LOG_DEBUG(CHANNEL, "uiAllPortSearchTotalTimes=%u, enChannelSrcLinkPortIndex=%u", uiAllPortSearchTotalTimes, pstChannelData->enChannelSrcLinkPortIndex);
    return uiAllPortSearchTotalTimes;
}

static Status FixSearchInputPort(ChannelData* pstChannelData)
{
    HV_ASSERT_VALID_PTR(pstChannelData);
    LinkPortIndex enMwPortIndex = pstChannelData->enChannelSrcLinkPortIndex;
    /*绑定RX端口, for hdcp/mute/rxdpll*/
    const InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    pstInputPortManager->pfPreProcess(enMwPortIndex);
    Hv_Drv_DpuScaler_SetPortMux(pstChannelData->enChannelType, enMwPortIndex);
    pstInputPortManager->pfBindChannelPortIndex(pstChannelData->enChannelType, enMwPortIndex);      /*固定搜索及时没有接RX也要绑定port，解决PXP只有一个信号时的交换源问题*/
    if (Hv_Mw_InputPort_GetCableStatus(enMwPortIndex))
    {
        if (HV_SUCCESS == pstInputPortManager->pfGetVideoPara(enMwPortIndex,pstChannelData))
        {
            pstChannelData->uiErrorCode = Hv_Mw_Video_TimingCheck(enMwPortIndex,pstChannelData);
            if (HV_SUCCESS == pstChannelData->uiErrorCode)
            {
                /*端口timing check成功*/
                HV_LOG_DEBUG(CHANNEL, "Fix Search Port %u Success on Channel=%u", enMwPortIndex, pstChannelData->enChannelType);
                return HV_SUCCESS;
            }
            else
            {
                /*失败发消息给OSD并停止搜索， 取消给osd发送，统一由channelmanager发送，否则会一直重复发*/
                //SendTimingNotSuportToOsd(pstChannelData->uiErrorCode, pstChannelData->enChannelType, enMwPortIndex);
                HV_LOG_WARN(CHANNEL, "Fix Search Port %u fail on Channel %u,error code %u", enMwPortIndex, pstChannelData->enChannelType,pstChannelData->uiErrorCode);
                return HV_FAILURE;
            }
        }
        else
        {
            /*失败继续搜索*/
            HV_LOG_DEBUG(CHANNEL, "Fix Get portIndex=%u timing parameter fail, ChannelType=%u!!!", enMwPortIndex, pstChannelData->enChannelType);
        }
    }
    else
    {
        pstInputPortManager->pfGetVideoPara(enMwPortIndex,pstChannelData);
        HV_LOG_DEBUG(CHANNEL, "Fix Cable not connect!!! portIndex = %u", enMwPortIndex);
    }
    return HV_CONTINUE;
}


/*信号源自动搜索方案: Hw_Mw_SearchTableInit 函数将备份端口设置为搜索的最高优先界级别(图像显示后每次都会更新备份端口)。
生成的表包含未插线端口。
自动搜索时，按照不插线跳过，插线端口搜索一定次数后，如果信号可以并且通过了check那么搜索结束。
否则继续搜索表中的下一个插线端口。
搜索一轮都结束后，清空搜索次数从新调用Hw_Mw_SearchTableInit，在继续搜索。在总搜索次数未超时前均执行以上策略
对于一个端口开始未插线跳过了，之后动态插线，在搜索完本轮已插线端口后下一轮会搜索到该端口。
*/
static Status AutoSearchAllInputPort(ChannelData* pstChannelData)
{
    SearchStrategy* pastSearchStrategy = NULL;
    USHORT16 usSearchTableSize = 0;
    UINT32 uiSearchCheckTimes = 0;
    HV_ASSERT_VALID_PTR(pstChannelData);
    if (CHANNEL_TYPE_MAIN == pstChannelData->enChannelType)
    {
        pastSearchStrategy = s_astRealTimeMainSearchTable;
        usSearchTableSize = ARRAY_SIZE(s_astRealTimeMainSearchTable);
    }
    else
    {
        pastSearchStrategy = stRealTimeSubSearchTable;
        usSearchTableSize = ARRAY_SIZE(stRealTimeSubSearchTable);
    }
    /*自动搜索时遍历RealTimeSearchTable*/
    for (USHORT16 usLoopIndex = 0;  usLoopIndex < usSearchTableSize; usLoopIndex++)
    {
        LinkPortIndex enMwPortIndex = Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex);
        if (HV_TRUE == pastSearchStrategy[usLoopIndex].ucSearched)/*判决端口是否被search过，仅搜索未被search端口*/
        {
            HV_LOG_INFO(CHANNEL, "port %u has been searched,quit", enMwPortIndex);
            pastSearchStrategy[usLoopIndex].usSearchTimes = 0;
            continue;
        }
        else/*端口没有被search过本次search该端口*/
        {
            HV_LOG_DEBUG(CHANNEL, "ucGuiPortIndex %u ,enMwPortIndex = %u", pastSearchStrategy[usLoopIndex].ucGuiPortIndex,enMwPortIndex);
            if (Hv_Mw_InputPort_GetCableStatus(enMwPortIndex))
            {
#if (0 == HV_PROJECT_CONFIG_CHANNEL_USE_SAME_PORT)
                /*不允许使用相同端口*/
                if (CheckPortOnUsing(pstChannelData->enChannelType, enMwPortIndex))/*判决该端口是否被其他通道占用*/
                {
                    HV_LOG_INFO(CHANNEL, "Other Channel is using  portIndex=%u, current ChannelType=%u", enMwPortIndex, pstChannelData->enChannelType);
                    pastSearchStrategy[usLoopIndex].ucSearched = HV_TRUE;
                    continue;/*不允许主辅使用相同端口时,使用该端口正在被其他端口占用，跳过该端口的搜索*/
                }
#endif
                pastSearchStrategy[usLoopIndex].usSearchTimes++;
                /*设置DPU IP从哪个PORT接收数据*/
                /*记录该端口用于判决端口占用，以及后续配置通路mux使用*/
                const InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
                pstInputPortManager->pfPreProcess(enMwPortIndex);
                Hv_Drv_DpuScaler_SetPortMux(pstChannelData->enChannelType, enMwPortIndex);
                /*绑定RX端口, for hdcp*/
                pstInputPortManager->pfBindChannelPortIndex(pstChannelData->enChannelType, enMwPortIndex);
                if (HV_SUCCESS == pstInputPortManager->pfGetVideoPara(enMwPortIndex,pstChannelData))
                {
                    pstChannelData->uiErrorCode = Hv_Mw_Video_TimingCheck(enMwPortIndex,pstChannelData);
                    if (HV_SUCCESS == pstChannelData->uiErrorCode)
                    {
                        /*端口timing check成功*/
                        pstChannelData->enChannelSrcLinkPortIndex = enMwPortIndex;
                        HV_LOG_DEBUG(CHANNEL, "Auto Search Port %u Success on Channel=%u", enMwPortIndex, pstChannelData->enChannelType);
                        return HV_SUCCESS;
                    }
                    else
                    {
                        /*失败发消息给OSD并停止搜索， 取消给osd发送，统一由channelmanager发送，否则会一直重复发*/
                        //SendTimingNotSuportToOsd(pstChannelData->uiErrorCode, pstChannelData->enChannelType, enMwPortIndex);
                        HV_LOG_WARN(CHANNEL, "Auto Search Port %u fail on Channel %u,error code %u", enMwPortIndex, pstChannelData->enChannelType,pstChannelData->uiErrorCode);
                        return HV_FAILURE;
                    }
                }
                else
                {
                    /*失败继续搜索*/
                    HV_LOG_DEBUG(CHANNEL, "Auto Get portIndex=%u timing parameter fail, ChannelType=%u!!!", enMwPortIndex, pstChannelData->enChannelType);
                }

                if ((1 == HV_COMMON_DATABASE_GET(SystemData, bFactoryMode)) 
                && (1 == HV_COMMON_DATABASE_GET(SystemData, bBurnInEnable)))
                {
                    uiSearchCheckTimes = HV_PROJECT_CONFIG_BURN_IN_EACH_PORT_SEARCH_TIMES;
                }
                else
                {
                    if(pstChannelData->enChannelSrcLinkPortIndex == enMwPortIndex)
                    {
                        uiSearchCheckTimes = GetCurrentPortSearchTimes(pstChannelData);  /*UI菜单当前设置的通道，增加搜索次数，防止异常通道切换*/
                    }
                    else
                    {
                        uiSearchCheckTimes = HV_PROJECT_CONFIG_EACH_PORT_SERARCH_MAX_TIMES;
                    }
                }
                if (pastSearchStrategy[usLoopIndex].usSearchTimes > uiSearchCheckTimes)
                {
                    HV_LOG_INFO(CHANNEL, "reach max search times!!! portIndex = %u, SearchTimes=%u", enMwPortIndex, uiSearchCheckTimes);
                    pastSearchStrategy[usLoopIndex].usSearchTimes = 0;
                    pastSearchStrategy[usLoopIndex].ucSearched = HV_TRUE;
                }
                /*每次只搜索一个PORT端口, 运行此处说明已经判断完该端口跳出循环*/
                break;
            }
            else/*如果该端口未插线*/
            {
                /*清除使用标志，清空搜索次数*/
                HV_LOG_DEBUG(CHANNEL, "Auto Cable not connect!!! portIndex = %u", enMwPortIndex);
                pastSearchStrategy[usLoopIndex].usSearchTimes = 0;
                pastSearchStrategy[usLoopIndex].ucSearched = HV_FALSE;
                /*未插线更新一下stRxVideoTiming.bIsNoSignal*/
                const InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
                pstInputPortManager->pfGetVideoPara(enMwPortIndex,pstChannelData);
            }
        }
    }

    /*判决是否完成一轮已插线端口的的搜索，如果完成了一轮的搜索，重新初始化search table，再继续搜索*/
    BOOL bAllSearched = HV_TRUE;
    for (USHORT16 usLoopIndex = 0;  usLoopIndex < usSearchTableSize; usLoopIndex++)
    {
        LinkPortIndex enMwPortIndex = Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex);
        HV_LOG_DEBUG(CHANNEL, "enMwPortIndex[%u] searchTimes=%u,ChannelType=%u,", 
                                enMwPortIndex, 
                                pastSearchStrategy[usLoopIndex].usSearchTimes,
                                pstChannelData->enChannelType);
        HV_LOG_DEBUG(CHANNEL, "cable state=%u ChannelType=%u, ucSearched=%u", 
                                Hv_Mw_InputPort_GetCableStatus(enMwPortIndex), 
                                pstChannelData->enChannelType, 
                                pastSearchStrategy[usLoopIndex].ucSearched);

        if (Hv_Mw_InputPort_GetCableStatus(enMwPortIndex) && (HV_FALSE == pastSearchStrategy[usLoopIndex].ucSearched))
        {
            bAllSearched = HV_FALSE;
        }
    }
    if (bAllSearched)
    {
        HV_LOG_DEBUG(CHANNEL, "All Connect Port has searched,init table again!!! ChannelType=%u", pstChannelData->enChannelType);
        Hw_Mw_SearchTable_Init(pstChannelData);
    }
    return HV_CONTINUE;
}

VOID Hw_Mw_AudioPath_Mux(const ChannelData* pstChannelData,ChannelType enChannelType)
{
    HV_ASSERT_VALID_PTR_VOID(pstChannelData);
    const InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    UCHAR8          ucCurrentPortIndex  = 0;
    SearchStrategy* pastSearchStrategy  = NULL;
    USHORT16        usSearchTableSize   = 0;
    BOOL            bAudioFlag = HV_DISABLE;
    if (CHANNEL_TYPE_MAIN == enChannelType)
    {
        ucCurrentPortIndex = pstChannelData->enChannelSrcLinkPortIndex;
        pastSearchStrategy = s_astRealTimeMainSearchTable;
        usSearchTableSize = ARRAY_SIZE(s_astRealTimeMainSearchTable);
        if ((CHANNEL_TYPE_MAIN == HV_COMMON_DATABASE_GET(UserData, ucAudioSource)))
        {
            bAudioFlag = HV_ENABLE;
        }
    }
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    else
    {
        ucCurrentPortIndex = pstChannelData->enChannelSrcLinkPortIndex;
        pastSearchStrategy = stRealTimeSubSearchTable;
        usSearchTableSize = ARRAY_SIZE(stRealTimeSubSearchTable);
        if ((CHANNEL_TYPE_SUB == HV_COMMON_DATABASE_GET(UserData, ucAudioSource)))
        {
            bAudioFlag = HV_ENABLE;
        }
    }
#endif
    HV_ASSERT_TRUE_VOID(usSearchTableSize > 0);
    if(HV_ENABLE == bAudioFlag)
    {
        for (USHORT16 usLoopIndex = 0;  usLoopIndex < usSearchTableSize; usLoopIndex++)
        {
            if(pastSearchStrategy[usLoopIndex].ucGuiPortIndex != Hv_Mw_Channel_ConvertMwToGuiPortIndex(ucCurrentPortIndex))
            {
                HV_LOG_DEBUG(CHANNEL, "Stop port %u audio", Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex));
                pstInputPortManager->pfStopAudio(Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex));
            }
            else
            {
                if(LINK_PORT_INDEX_INVALID == pstChannelData->enChannelSrcLinkPortIndex)
                {
                    HV_LOG_DEBUG(CHANNEL, "Stop port %u audio", Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex));
                    pstInputPortManager->pfStopAudio(Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex));
                }
            }
        }
    }
    else
    {
        const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
        UCHAR8 ucAudioSource = HV_COMMON_DATABASE_GET(UserData, ucAudioSource);
        for (USHORT16 usLoopIndex = 0;  usLoopIndex < usSearchTableSize; usLoopIndex++)
        {
            HV_LOG_DEBUG(CHANNEL, "Stop port %u audio", Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex));
            if(pastSearchStrategy[usLoopIndex].ucGuiPortIndex != pstChannelManager->astChannelData[ucAudioSource].enChannelSrcLinkPortIndex) 
            {
                pstInputPortManager->pfStopAudio(Hv_Mw_Channel_ConvertGuiToMwPortIndex(pastSearchStrategy[usLoopIndex].ucGuiPortIndex));
            }
        }
    }
    return;
}

/*辅助函数：交换两个元素*/
static VOID SwapObject(USHORT16 *usA, USHORT16 *usB)
{
    USHORT16 usTemp = *usA;
    *usA = *usB;
    *usB = usTemp;
}

/*辅助函数：对数组进行排序（从小到大）*/
static VOID SortArray(USHORT16 ausArr[], USHORT16 usStart, USHORT16 usEnd)
{
    for (int i = usStart; i < usEnd - 1; i++)
    {
        for (int j = usStart; j < usEnd - 1; j++)
        {
            if (ausArr[j] > ausArr[j + 1])
            {
                SwapObject(&ausArr[j], &ausArr[j + 1]);
            }
        }
    }
}
static VOID CustomSortArr(USHORT16 ausPortArr[], USHORT16 usSearchTableSize)
{
    USHORT16 usPivot = ausPortArr[0];
    USHORT16 i, j;

    /* 分割数组*/
    USHORT16 ausLeft[usSearchTableSize], ausRight[usSearchTableSize];
    USHORT16 usLeftSize = 0, usRightSize = 0;

    for (i = 1; i < usSearchTableSize; i++)
    {
        if (ausPortArr[i] > usPivot)
        {
            ausRight[usRightSize++] = ausPortArr[i];
        } else {
            ausLeft[usLeftSize++] = ausPortArr[i];
        }
    }

    /*对分割后的数组进行排序*/
    SortArray(ausRight, 0, usRightSize);
    SortArray(ausLeft, 0, usLeftSize);

    /*合并结果*/
    USHORT16 usIndex = 1;
    for (i = 0; i < usRightSize; i++)
    {
        ausPortArr[usIndex++] = ausRight[i];
    }
    for (i = 0; i < usLeftSize; i++)
    {
        ausPortArr[usIndex++] = ausLeft[i];
    }
}
VOID Hw_Mw_SearchTable_Init(ChannelData* pstChannelData)
{
    HV_ASSERT_VALID_PTR_VOID(pstChannelData);
    UCHAR8 ucCurrentPortIndex = 0;
    SearchStrategy* pastSearchStrategy = NULL;
    USHORT16 usSearchTableSize = 0;
    if (CHANNEL_TYPE_MAIN == pstChannelData->enChannelType)
    {
        ucCurrentPortIndex = pstChannelData->enChannelSrcLinkPortIndex;
        pastSearchStrategy = s_astRealTimeMainSearchTable;
        usSearchTableSize = ARRAY_SIZE(s_astRealTimeMainSearchTable);
    }
#ifdef CONFIG_USER_DOUBLE_CHANNEL_ON
    else
    {
        ucCurrentPortIndex = pstChannelData->enChannelSrcLinkPortIndex;
        pastSearchStrategy = stRealTimeSubSearchTable;
        usSearchTableSize = ARRAY_SIZE(stRealTimeSubSearchTable);
    }
#endif
    HV_ASSERT_TRUE_VOID(usSearchTableSize > 0);

    for (USHORT16 usLoopIndex = 0;  usLoopIndex < usSearchTableSize; usLoopIndex++)
    {
        if(pastSearchStrategy[usLoopIndex].ucGuiPortIndex == ucCurrentPortIndex)
        {
            pastSearchStrategy[usLoopIndex].ucGuiPortIndex = pastSearchStrategy[0].ucGuiPortIndex;
            pastSearchStrategy[0].ucGuiPortIndex = ucCurrentPortIndex;
            break;
        }
    }

    USHORT16 ausPortArr[usSearchTableSize];
    for (USHORT16 usLoopIndex = 0; usLoopIndex < usSearchTableSize; usLoopIndex++)
    {
        ausPortArr[usLoopIndex] = pastSearchStrategy[usLoopIndex].ucGuiPortIndex;
    }
    CustomSortArr(ausPortArr, usSearchTableSize);
    for (USHORT16 usLoopIndex = 0; usLoopIndex < usSearchTableSize; usLoopIndex++)
    {
        pastSearchStrategy[usLoopIndex].ucGuiPortIndex = ausPortArr[usLoopIndex];
    }

    for (USHORT16 usLoopIndex = 0;  usLoopIndex < usSearchTableSize; usLoopIndex++)
    {
        pastSearchStrategy[usLoopIndex].usSearchTimes = 0;
        pastSearchStrategy[usLoopIndex].ucSearched = HV_FALSE;
    }
    return;
}

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
static Status MagnifyGlassSearchSourceMode(ChannelData* pstChannelData)
{
    HV_ASSERT_VALID_PTR(pstChannelData);
    const ChannelManager* pstChannelManager = Hv_Mw_Channel_GetManager();
    const InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    pstInputPortManager->pfGetVideoPara(pstChannelData->enChannelSrcLinkPortIndex, pstChannelData);
    /*放大镜使用PIP模式，辅通道的信号源使用主通道正常显示的信号源*/
    if (CHANNEL_STATE_ACTIVE == pstChannelManager->astChannelData[0].enCurrentCHState)
    {
        LinkPortIndex enMwPortIndex = pstChannelManager->astChannelData[0].enChannelSrcLinkPortIndex;
        pstInputPortManager->pfPreProcess(enMwPortIndex);
        Hv_Drv_DpuScaler_SetPortMux(pstChannelData->enChannelType, enMwPortIndex);
        /*绑定RX端口, for hdcp*/
        pstInputPortManager->pfBindChannelPortIndex(pstChannelData->enChannelType, enMwPortIndex);
        pstChannelData->enChannelSrcLinkPortIndex = enMwPortIndex;
        return HV_SUCCESS;
    }
    else
    {
        HV_LOG_DEBUG(CHANNEL, "sub magnify search, main not active.");
        /*do nothing*/
    }
    return HV_CONTINUE;
}
#endif

Status Hw_Mw_Channel_SearchSuitableSource(ChannelData* pstChannelData)
{
    HV_ASSERT_VALID_PTR(pstChannelData);
    Status uiResult = HV_CONTINUE;
    pstChannelData->usTotalSearchTimes++;

#ifdef CONFIG_USER_USB_OTA_ON
    if(USB_STATE_OTA_IN_PROCESSING == Hv_Mw_USB_GetUsbState())
    {
        return HV_CONTINUE;
    }
#endif

    if ((1 == HV_COMMON_DATABASE_GET(SystemData, bFactoryMode)) 
    && (1 == HV_COMMON_DATABASE_GET(SystemData, bBurnInEnable)))
    {
        if (pstChannelData->usTotalSearchTimes > HV_PROJECT_CONFIG_MAX_SEARCH_TIMERS_BURN_IN)
        {
            /*老化模式，加速失败切换到NoSignal态*/
            pstChannelData->usTotalSearchTimes = 0;
            return pstChannelData->uiErrorCode;
        }
    }
    else
    {
        if (pstChannelData->usTotalSearchTimes > GetAllPortSearchTotalTimes(pstChannelData))
        {
            /*失败切换到NoSignal态*/
            pstChannelData->usTotalSearchTimes = 0;
            return pstChannelData->uiErrorCode;
        }
    }

#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
    /*开启了放大镜模式辅助通道强制需要等待主通道显示正常，并且直接使用主通道的信号源*/
    if ((CHANNEL_TYPE_SUB == pstChannelData->enChannelType)
     && (PXP_MODE_MAGNIFY_GLASS_ENABLE == Hv_Mw_Channel_GetPxpMode()))
    {
        uiResult = MagnifyGlassSearchSourceMode(pstChannelData);
    }
    else /*非放大镜模式*/
#endif
    {
        if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bAutoVideoSrcSelSw))
        {
            if((PXP_MODE_CLOSE == Hv_Mw_Channel_GetPxpMode()) || (PXP_MODE_MAGNIFY_GLASS_ENABLE == Hv_Mw_Channel_GetPxpMode()))
            {
                uiResult = AutoSearchAllInputPort(pstChannelData);
            }
            else
            {
                uiResult = FixSearchInputPort(pstChannelData);
            }
        }
        else
        {
            uiResult = FixSearchInputPort(pstChannelData);
        }
    }
    return uiResult;
}

Status Hw_Mw_Channel_NoSignal_SearchPort(ChannelData* pstChannelData)
{
    HV_ASSERT_VALID_PTR(pstChannelData);
    USHORT16 usPortLoopIndex = 0;
    Status uiResult = HV_CONTINUE;
    HV_LOG_DEBUG(CHANNEL, "Nosignal SearchPort ChannelType= %u, port:%u", pstChannelData->enChannelType, pstChannelData->enChannelSrcLinkPortIndex);
    if (HV_TRUE == HV_COMMON_DATABASE_GET(UserData, bAutoVideoSrcSelSw) && (CHANNEL_TYPE_MAIN == pstChannelData->enChannelType))
    {
        const InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
        for (usPortLoopIndex = 0; usPortLoopIndex < ARRAY_SIZE(aenNosignalSearchPortTable); usPortLoopIndex++)
        {
            if (CheckPortOnUsing(pstChannelData->enChannelType, aenNosignalSearchPortTable[usPortLoopIndex]))/*判决该端口是否被其他通道占用*/
            {
                HV_LOG_INFO(CHANNEL, "Other Channel Is using  portIndex=%u, current ChannelType=%u", aenNosignalSearchPortTable[usPortLoopIndex], pstChannelData->enChannelType);
                continue;/*不允许主辅使用相同端口时,使用该端口正在被其他端口占用，跳过该端口的搜索*/
            }
            if (HV_SUCCESS == pstInputPortManager->pfGetVideoPara(aenNosignalSearchPortTable[usPortLoopIndex], pstChannelData))
            {
                pstChannelData->uiErrorCode = Hv_Mw_Video_TimingCheck(aenNosignalSearchPortTable[usPortLoopIndex],pstChannelData);
                if (HV_SUCCESS == pstChannelData->uiErrorCode)
                {
                    /*端口timing check成功*/
                    pstChannelData->enChannelSrcLinkPortIndex = aenNosignalSearchPortTable[usPortLoopIndex];
                    HV_LOG_DEBUG(CHANNEL, "Nosignal state Timing Check SUCCESS portIndex=%u ChannelType=%u",aenNosignalSearchPortTable[usPortLoopIndex], pstChannelData->enChannelType);
                    return HV_SUCCESS;
                }
                else
                {
                    /*失败发消息给OSD并停止搜索*/
                    //SendTimingNotSuportToOsd(pstChannelData->uiErrorCode, pstChannelData->enChannelType, aenNosignalSearchPortTable[usPortLoopIndex]);
                    HV_LOG_INFO(CHANNEL, "Nosignal state TimingCheck Error!!! uiCheckResult %u,portIndex= %u", pstChannelData->uiErrorCode,aenNosignalSearchPortTable[usPortLoopIndex]);
                    return HV_FAILURE;
                }
            }
            else
            {
                HV_LOG_DEBUG(CHANNEL, "get port status Error!!! portIndex= %u, ChannelType=%u", aenNosignalSearchPortTable[usPortLoopIndex],  pstChannelData->enChannelType);
            }
        }
    }
    else
    {
        if (CHANNEL_TYPE_MAIN == pstChannelData->enChannelType)
        {
            uiResult = FixSearchInputPort(pstChannelData);
        }
        else
        {
#if (HV_CONFIG_ON == HV_PROJECT_CONFIG_MAGNIFY)
            if (PXP_MODE_MAGNIFY_GLASS_ENABLE == Hv_Mw_Channel_GetPxpMode())
            {
                uiResult = MagnifyGlassSearchSourceMode(pstChannelData);
            }
            else
            {
                uiResult = FixSearchInputPort(pstChannelData);
            }
#else
            uiResult = FixSearchInputPort(pstChannelData);
#endif
        }
    }
    return uiResult;
}
