/**
 * @file hv_mw_UsbTask.c
 * @brief usb task source file
 * @details This file provides the following functions: \n
 *          (1) event dispatch \n
 *          (2) task handle \n
 *          (3) Feed functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-25
 * @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-25   <td>init
 * </table>
*/

#include "hv_vos_Comm.h"
#include "hv_comm_Define.h"
#include "hv_comm_Event.h"
#include "hv_comm_Assert.h"
#include "hv_comm_Timer.h"
#include "hv_chip_Config.h"
#include "hv_mw_SystemManager.h"
#include "hv_mw_DisplayPort.h"
#include "hv_mw_UsbTask.h"
#include "hv_drv_Gpio.h"
#include "FreeRTOS.h"
#include "task.h"
#include "hv_mw_UrgentTask.h"
#include "hv_drv_UsbComm.h"


#ifdef CONFIG_USER_USB_OTA_ON
#include "hv_drv_UsbCorePlatform.h"
#include "hv_drv_UsbCoreUtils.h"
#include "hv_drv_UsbCoreHub.h"
#include "hv_drv_Flash.h"
#include "hv_vos_Cache.h"
#include "hv_chip_Driver.h"
#include "OtaConfig.h"
#include "hv_comm_Ota.h"
#include "hv_mw_Led.h"
#endif

/**
 * @brief Define the variables for the USB upgrade process.
 */
typedef struct _HvMwUsbParams
{
    UsbState       enUsbCurState;
#ifdef CONFIG_USER_USB_OTA_ON
    OtaPartDef     enUsbOtaPart;        /*!< 此次更新要烧写到哪个分区，与当前程序的运行分区相反 */
    BOOL           bForceUpgradeFlag;   /*!< 强制升级的标志，用于强制升级流程中的条件判断 */
    UINT32         uiOTABinPktTotal;    /*!< 表示OTA bin中BOOT+CODE分区的packet总个数, 用于计算升级进度百分比 */
    UINT32         uiOTAPktCompleted;   /*!< 表示OTA过程中已经升级完成的packet个数，用于升级进度条 */
    HV_TIMER_S     *pstOTARstTimer;
    UINT32         uiCodeCrc;
    FATFS          stFs;
    FIL            stFile;
    UCHAR8         ucBinPartitionCnt;   /*!< 记录U盘bin文件中的分区个数 */
    UCHAR8         ucFlashPartitionCnt; /*!< 记录flash中的分区个数 */
    UINT32         uiOtaBinSize;        /*!< 记录U盘中bin的文件大小 */
#endif
    UsbWorkMode    enWorkMode;
}HvMwUsbParams;

/**
 * @brief Local USB-related variables. 
 */
static HvMwUsbParams s_stUsbParam = {0};

static TaskHandle_t stUsbTaskHandle;

#ifdef CONFIG_USER_USB_OTA_ON
/**
 * @brief The length of data that is read and written over USB each time.
 */
#define USB_OTA_PKT_LEN             (4096)

/**
 * @brief The max retry times when occers error.
 */
#define USB_OTA_MAX_RETRY           (8)

/**
 * @brief Erase size of flash by multi sector of 64K.
 */
#define USB_OTA_ERASE_MUL_SEC_SIZE  (65536)

/**
 * @brief Erase size of flash by sector of 4K.
 */
#define USB_OTA_ERASE_SEC_SIZE      (4096)


/**
 * @brief Check if the flash address is 64K aligned.
 */
#define IS_64K_ALIGNED(address)     (((address) & 0xFFFF) == 0)

/**
 * @brief The step of the progress bar.
 */
#define USB_OTA_PROGRESS_BAR_STEP   (5)

/**
 * @brief Data buffer that reads the data from the bin file. 
 */
static UCHAR8  s_aucBinBuf[USB_OTA_PKT_LEN] = {0};

/**
 * @brief Data buffer that reads the data from the flash. 
 */
static UCHAR8  s_aucReadFlashBuf[USB_OTA_PKT_LEN] = {0};

/**
 * @brief 保存接收到顶层传递的分区名字
 */
static UCHAR8 s_ucOtaPartitionName[MAX_RESERVED_PARTITIONS][SBLK_MAGIC_STRING_LENGTH];

/**
 * @brief 保存接收到顶层传递的分区个数，但实际升级分区个数并不等于此数值
 */
static UCHAR8 s_ucOtaPartitionCnt = 0;

/**
 * @brief 保存flash中SuperBlock信息的静态全局变量
          位于 PM51_DATA_ADDR(0x7009) 处
 */
static PartitionSBLKInfo s_astPartitionTable[MAX_RESERVED_PARTITIONS];

/**
 * @brief 从Flash中获取出所有的分区信息
 * @return Status
 */
static Status Hv_Mw_USB_FillPartitionTableFromBin(HvMwUsbParams *       pstUsbParam)
{
    Status  uiRet = HV_FAILURE;
    UINT32  uiByteRead = 0;
    UCHAR8  aucNull[SBLK_MAGIC_STRING_LENGTH] = {0, 0, 0, 0, 0, 0, 0, 0};

    HV_MEMSET(s_astPartitionTable, 0, sizeof(s_astPartitionTable));

    HV_LOG_INFO(DEFAULT, "-Parse bin sblk");
    Hv_Drv_USB_SetFileSeek(&pstUsbParam->stFile, SBLK_PARTATION_ADDR);
    Hv_Vos_InvalidAllDCache(); 
    Hv_Drv_USB_ReadFile(&pstUsbParam->stFile, s_aucBinBuf, MAX_SBLK_SIZE, &uiByteRead);
    Hv_Vos_InvalidAllDCache(); 

    for (UINT32 i = 0; i < MAX_RESERVED_PARTITIONS; i++)
    {
        if (0 == HV_MEMCMP(&s_aucBinBuf[i * SBLK_PER_SIZE], SBLK_HEADER, strlen(SBLK_HEADER)))
        {
            HV_MEMCPY(s_astPartitionTable[i].ucSBLKName, s_aucBinBuf + i * SBLK_PER_SIZE, SBLK_MAGIC_STRING_LENGTH);
            s_astPartitionTable[i].uiValidLen    = Hv_Comm_OTA_ConvertToUint32(s_aucBinBuf, i * SBLK_PER_SIZE + VALID_LEN_OFFSET);
            s_astPartitionTable[i].uiStartAddr   = Hv_Comm_OTA_ConvertToUint32(s_aucBinBuf, i * SBLK_PER_SIZE + START_ADDR_OFFSET);
            s_astPartitionTable[i].uiCRC         = Hv_Comm_OTA_ConvertToUint32(s_aucBinBuf, i * SBLK_PER_SIZE + CRC_OFFSET);

            if(0 == HV_MEMCMP(s_astPartitionTable[i].ucSBLKName, STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH))
            {
                pstUsbParam->uiCodeCrc = s_astPartitionTable[i].uiCRC;
            }
            
        }
        else
        {
            s_stUsbParam.ucBinPartitionCnt = i;
            break;
        }
    }
    
    for (UINT32 i = 0; i < s_stUsbParam.ucBinPartitionCnt; i ++)
    {
        //！！！最后一个分区使用有效长度来作为最大分区长度！！！
        if(i == (s_stUsbParam.ucBinPartitionCnt - 1))
        {
            s_astPartitionTable[i].uiTotalLen = Hv_Comm_OTA_ConvertToUint32(s_aucBinBuf, i * SBLK_PER_SIZE + VALID_LEN_OFFSET);
        }
        else
        {
            s_astPartitionTable[i].uiTotalLen = Hv_Comm_OTA_ConvertToUint32(s_aucBinBuf, (i + 1) * SBLK_PER_SIZE + START_ADDR_OFFSET) 
                                               - Hv_Comm_OTA_ConvertToUint32(s_aucBinBuf, i * SBLK_PER_SIZE + START_ADDR_OFFSET);
        }
    }
#if 1
    //Debug Info
    HV_LOG_INFO(DEFAULT, "bin partition cnt: %d", s_stUsbParam.ucBinPartitionCnt);
    for (UINT32 i = 0; i < s_stUsbParam.ucBinPartitionCnt; i ++)
    {
        if(0 != HV_MEMCMP(s_astPartitionTable[i].ucSBLKName, aucNull, SBLK_MAGIC_STRING_LENGTH))
        {
            HV_PRINTF("%d SBLK Name: ", i);
            for (UINT32 k = 0; k < SBLK_MAGIC_STRING_LENGTH; k++)
            {
                HV_PRINTF("%c", s_astPartitionTable[i].ucSBLKName[k]);
            }
            HV_PRINTF("\n");
            HV_LOG_INFO(DEFAULT, "ValidLen:0x%08x, Addr:0x%08x, Crc:0x%08x, Total:0x%08x, ", s_astPartitionTable[i].uiValidLen, s_astPartitionTable[i].uiStartAddr, s_astPartitionTable[i].uiCRC, s_astPartitionTable[i].uiTotalLen);
        }
    }
#endif
    if(s_stUsbParam.ucBinPartitionCnt > 0)
    {
        uiRet = HV_SUCCESS;
    }
    return uiRet;
}


/**
 * @brief 根据分区名字查找Flash上该分区的所有信息(必须先执行Hv_Comm_OTA_FillPartitionTableFromFlash)
 * @return Status
 */
static Status Hv_Mw_USB_GetPartitionInfoByName(UCHAR8* pucName, UCHAR8 ucLen, PartitionSBLKInfo *pInfo)
{
    Status uiRet = HV_FAILURE;
    
    for(UCHAR8 i = 0; i < MAX_RESERVED_PARTITIONS; i++)
    {
        if(0 == HV_MEMCMP(s_astPartitionTable[i].ucSBLKName, pucName, ucLen))
        {
            *pInfo = s_astPartitionTable[i];
            uiRet = HV_SUCCESS;
            break;
        }
    }
    return uiRet; 
}


/**
 * @brief 清除U盘升级的一些状态变量
 * @return none
 */
static VOID Hv_Mw_USB_ClearUsbOtaStatus(VOID)
{
    s_stUsbParam.enUsbCurState      = USB_STATE_IDLE;
    s_stUsbParam.enUsbOtaPart       = OTA_PART_MAX;
}

/**
 * @brief Send USB-OTA state to OSD also includes the percentage of the upgrade when it is in the OTA_PROCESSING state.
 * @param[in] enState Indicates the usb state for osd to display.
 * @param[in] ucValue It can have different meanings in different states.
 *                    EX:the percentage during OTA, and the number of connected devices.
 * @return Status
 */
static Status Hv_Mw_USB_SendStateToOsd(UsbState enState, UCHAR8 ucValue)
{
    HV_VOS_QUEUE_S *pstOsdQueue = Hv_Mw_System_GetOsdQueue();
    HV_ASSERT_VALID_PTR(pstOsdQueue);
    OsdEvent stOsdEvent = {0};

    stOsdEvent.usEventId = OSD_EVENT_USB_OTA;
    stOsdEvent.usValue |= enState & 0x00FF;
    stOsdEvent.usValue |= (ucValue << 8) & 0xFF00;
    HV_LOG_INFO(DEFAULT, "usb send to osd(value,state):0x%04x", stOsdEvent.usValue);
    HV_ASSERT_PEEK_TRUE(Hv_Vos_QueueSend(pstOsdQueue, &stOsdEvent));
    return HV_SUCCESS;
}


/**
 * @brief 立即复位系统
 * @param[in] pvArgument unused
 * @param[in] usTimerId unused
 * @return None
 */
static VOID Hv_Mw_USB_ResetSys(VOID* pvArgument, USHORT16 usTimerId)
{
    HV_UNUSED(pvArgument);
    HV_UNUSED(usTimerId);
    
    hv_chip_Reset();
    return;
}

/**
 * @brief Start the restart timer after the OTA is complete successfully.
 * @param[in] uiTimeoutMs Time in milliseconds
 * @return None.
 */
VOID Hv_Mw_USB_StartOTARstTimer(UINT32 uiTimeoutMs)
{
    HV_TIMER_INIT_PARAMS stOTARstTimerParam = \
        {"OTARstTimerParam", (UINT32)uiTimeoutMs, HV_FALSE, (VOID *)NULL, Hv_Mw_USB_ResetSys, EVENT_TIMER_MAX};
    s_stUsbParam.pstOTARstTimer = Hv_Vos_Timer_Create(&stOTARstTimerParam);
    HV_ASSERT_VALID_PTR_VOID(s_stUsbParam.pstOTARstTimer);
    
    Hv_Vos_Timer_Start(s_stUsbParam.pstOTARstTimer);
    return;
}

static VOID Hv_Mw_USB_EraseFlash(UINT32 uiFlashAddr, UINT32 uiLength)
{
    UINT32 uiEraseEndAddr = uiFlashAddr + uiLength;
    
    while (uiFlashAddr < uiEraseEndAddr)
    {
        if (IS_64K_ALIGNED(uiFlashAddr) && (uiFlashAddr + USB_OTA_ERASE_MUL_SEC_SIZE <= uiEraseEndAddr))
        {
            Hv_Drv_Flash_OnlyEraseMultiSector(uiFlashAddr);
            uiFlashAddr += USB_OTA_ERASE_MUL_SEC_SIZE;
        }
        else
        {
            Hv_Drv_Flash_OnlyErase(uiFlashAddr, USB_OTA_ERASE_SEC_SIZE);
            uiFlashAddr += USB_OTA_ERASE_SEC_SIZE;
        }
    }
}

static BOOL Hv_Mw_USB_ComparePm51(VOID)
{
    UINT32 uiByteRead = 0;
    BOOL   bResult = HV_TRUE;

    // PM51位于bin文件的0地址处
    Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, PM51_PARTATION_ADDR);
    
    for(UCHAR8 ucChunkCnt = 0; ucChunkCnt < PM51_PARTATION_LEN/USB_OTA_PKT_LEN; ucChunkCnt++)
    {
        Hv_Vos_InvalidAllDCache(); 
        Hv_Drv_USB_ReadFile(&s_stUsbParam.stFile, s_aucBinBuf, USB_OTA_PKT_LEN, &uiByteRead);
        Hv_Vos_InvalidAllDCache(); 

        // PM51也位于flash空间的0地址处
        Hv_Drv_Flash_OnlyRead(PM51_PARTATION_ADDR + ucChunkCnt * USB_OTA_PKT_LEN, s_aucReadFlashBuf, USB_OTA_PKT_LEN);

        if(0 != HV_MEMCMP(s_aucBinBuf, s_aucReadFlashBuf, USB_OTA_PKT_LEN))
        {
            bResult = HV_FALSE;
            break;
        }
    }
    return bResult;
}


static Status Hv_Mw_USB_UpdateSinglePartition(UINT32 uiReadBinAddr, UINT32 uiWriteFlashAddr, UINT32 uiTotalLen)
{
    UCHAR8 ucRetry = 0;
    UINT32 uiPktCur = 0;
    UINT32 uiReadPos = 0;
    UINT32 uiPktTotal = 0;
    UINT32 uiByteRead = 0;
    UCHAR8 ucPercent = 0;
    UCHAR8 ucPercentPre = 0xff;

    uiPktTotal = (uiTotalLen % USB_OTA_PKT_LEN == 0)
                      ? (uiTotalLen / USB_OTA_PKT_LEN)
                      : (uiTotalLen / USB_OTA_PKT_LEN + 1);

    Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, uiReadBinAddr);

    for(uiPktCur = 0; uiPktCur < uiPktTotal; uiPktCur++)
    {
        while(ucRetry < USB_OTA_MAX_RETRY)
        {
            /* Must do for usb dma to sync */
            Hv_Vos_InvalidAllDCache(); 
            if(ucRetry != 0)
            {
                /* ReadFile后，文件指针会自动累加到当前packet的末尾，所以出错后要重新配置文件指针到当前packet的开头 */
                uiReadPos = uiPktCur * USB_OTA_PKT_LEN + uiReadBinAddr;
                Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, uiReadPos);
            }

            /* 读一个PACKET */
            if(HV_SUCCESS != Hv_Drv_USB_ReadFile(&s_stUsbParam.stFile, s_aucBinBuf, USB_OTA_PKT_LEN, &uiByteRead))
            {
                Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                Hv_Drv_USB_UnmountDev();
                s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                return HV_FAILURE;
            }
            Hv_Vos_InvalidAllDCache();

            HV_LOG_DEBUG(DEFAULT, "write flash 0x%x", uiWriteFlashAddr + uiPktCur * USB_OTA_PKT_LEN);
            /* 写入并校验这个PACKET */
            if(Hv_Drv_Flash_OnlyWrite(uiWriteFlashAddr + uiPktCur * USB_OTA_PKT_LEN, s_aucBinBuf, uiByteRead) != HV_SUCCESS)
            {
                Hv_Drv_Flash_OnlyErase(uiWriteFlashAddr + uiPktCur * USB_OTA_PKT_LEN, USB_OTA_PKT_LEN);

                ucRetry++;
                if(ucRetry >= USB_OTA_MAX_RETRY)
                {
                    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                    Hv_Drv_USB_UnmountDev();
                    s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                    HV_ASSERT_PEEK_SUCCESS(Hv_Mw_USB_SendStateToOsd(s_stUsbParam.enUsbCurState, 0));
                    return HV_FAILURE;
                }
            }
            else
            {
                ucPercent = ((s_stUsbParam.uiOTAPktCompleted + uiPktCur + 1) * 100)/s_stUsbParam.uiOTABinPktTotal;
                HV_LOG_DEBUG(DEFAULT, "uiPktCur: %d, ucPercent: %d, uiOTAPktCompleted: %d", uiPktCur, ucPercent, s_stUsbParam.uiOTAPktCompleted);
                if(ucPercentPre != ucPercent)
                {
                    if(ucPercent % USB_OTA_PROGRESS_BAR_STEP == 0)
                    {
                        HV_ASSERT_PEEK_SUCCESS(Hv_Mw_USB_SendStateToOsd(s_stUsbParam.enUsbCurState, ucPercent));
                    }
                    ucPercentPre = ucPercent;
                }
                ucRetry = 0;
                break;
            }
        }
    }
    
    s_stUsbParam.uiOTAPktCompleted += uiPktTotal;
    return HV_SUCCESS;
}


static Status Hv_Mw_USB_DetectHubPort(UsbEvent *pstEvent)
{
    hub_port_check(usb_get_hub());
    return HV_SUCCESS;
}


VOID Hv_Mw_UsbHost_TaskStartInit(VOID)
{
    HV_LOG_INFO(DEFAULT, "host start");
    Hv_Mw_UsbSetWorkMode(USB_MODE_HOST);
    Hv_Drv_Usb_PlatformInit();

    Hv_Mw_USB_ClearUsbOtaStatus();
    return;
}


VOID Hv_Mw_UsbHost_TaskStop(VOID)
{
    HV_LOG_INFO(DEFAULT, "host stop");
    Hv_Mw_UsbSetWorkMode(USB_MODE_MAX);
    Hv_Drv_Usb_PlatformExit();

    Hv_Mw_USB_ClearUsbOtaStatus();
    
    HV_Drv_USB_GlobalFreeAll();
    return;
}


/**
 * @brief 对OSD发送的“确认升级”消息的处理函数
 * @param[in] pstEvent Pointer to UsbEvent
 * @return Status
 */
static Status Hv_Mw_USB_DoConfirm(UsbEvent *pstEvent)
{
    UINT32 uiByteRead = 0;
    UINT32 uiOtaTotalLen = 0;
    UCHAR8 aucCodeCRC[OTA_SBLK_CRC_LEN] = {0};
    PartitionSBLKInfo stPartInfo = {0};
    PartitionSBLKInfo stFlashPartInfo = {0};
    BOOL   bCodeUpdateFlag = HV_FALSE;
    BOOL   bPm51UpdateFlag = HV_FALSE;

    s_stUsbParam.enUsbCurState = USB_STATE_OTA_IN_PROCESSING;
    s_stUsbParam.uiOTAPktCompleted = 0;
    HV_MEMSET(aucCodeCRC, 0, OTA_SBLK_CRC_LEN);
    
    s_stUsbParam.enUsbOtaPart = Hv_Comm_OTA_GetUpgradePart();
    HV_LOG_INFO(DEFAULT, "OTA to %s", (OTA_PART_A == s_stUsbParam.enUsbOtaPart) ? "A" : "Bak");

    /* 检查待升级分区的分区表是否匹配，不匹配则不允许升级 */
    for(UCHAR8 ucIdx = 0; ucIdx < s_ucOtaPartitionCnt; ucIdx++)
    {
        if((HV_SUCCESS == Hv_Mw_USB_GetPartitionInfoByName(s_ucOtaPartitionName[ucIdx], SBLK_MAGIC_STRING_LENGTH, &stPartInfo))
            &&(HV_SUCCESS == Hv_Comm_OTA_GetPartitionInfoByName(s_ucOtaPartitionName[ucIdx], SBLK_MAGIC_STRING_LENGTH, &stFlashPartInfo)))
        {
            if((stPartInfo.uiStartAddr != stFlashPartInfo.uiStartAddr) || (stPartInfo.uiTotalLen != stFlashPartInfo.uiTotalLen))
            {
                HV_LOG_INFO(DEFAULT, "Error! Partition<%d> not match, Stop OTA!", ucIdx);
                Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                Hv_Drv_USB_UnmountDev();
                s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                return HV_FAILURE;
            }
        }
        else
        {
            HV_LOG_INFO(DEFAULT, "Warning! Partition<%d> Name Wrong, Skip it!", ucIdx);
        }
    }

    //计算得出待升级总长度
    for(UCHAR8 ucIdx = 0; ucIdx < s_ucOtaPartitionCnt; ucIdx++)
    {
        //传参中有"SBLKPMSB"
        if(0 == HV_MEMCMP(s_ucOtaPartitionName[ucIdx], STRING_SBLKPMSB, SBLK_MAGIC_STRING_LENGTH))
        {
            if(HV_FALSE == Hv_Mw_USB_ComparePm51())
            {
                bPm51UpdateFlag = HV_TRUE;
                uiOtaTotalLen += PM51_PARTATION_LEN;
            }
        }
        //传参中有"SBLKCODE"
        else if(0 == HV_MEMCMP(s_ucOtaPartitionName[ucIdx], STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH))
        {
            bCodeUpdateFlag = HV_TRUE;
            if(HV_SUCCESS == Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKBOOT, SBLK_MAGIC_STRING_LENGTH, &stPartInfo))
            {
                uiOtaTotalLen += stPartInfo.uiTotalLen;
                //HV_PRINTF("Got SBLK Name: ");
                //for (UINT32 k = 0; k < 8; k++)
                //{
                //    HV_PRINTF("%c", stPartInfo.ucSBLKName[k]);
                //}
                //HV_PRINTF("   StartAddr:0x%x, TotalLen:0x%x, Crc:0x%x, Valid:0x%x\n", stPartInfo.uiStartAddr, stPartInfo.uiTotalLen, stPartInfo.uiCRC, stPartInfo.uiValidLen);
            }
            if(HV_SUCCESS == Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH, &stPartInfo))
            {
                uiOtaTotalLen += stPartInfo.uiTotalLen;
                //HV_PRINTF("Got SBLK Name: ");
                //for (UINT32 k = 0; k < 8; k++)
                //{
                //    HV_PRINTF("%c", stPartInfo.ucSBLKName[k]);
                //}
                //HV_PRINTF("   StartAddr:0x%x, TotalLen:0x%x, Crc:0x%x, Valid:0x%x\n", stPartInfo.uiStartAddr, stPartInfo.uiTotalLen, stPartInfo.uiCRC, stPartInfo.uiValidLen);
            }

            //擦除
            if(OTA_PART_A == s_stUsbParam.enUsbOtaPart)
            {
                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKBOOT, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                Hv_Mw_USB_EraseFlash(stPartInfo.uiStartAddr, stPartInfo.uiTotalLen);

                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                Hv_Mw_USB_EraseFlash(stPartInfo.uiStartAddr, stPartInfo.uiTotalLen);
            }
            else
            {
                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKBTBK, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                Hv_Mw_USB_EraseFlash(stPartInfo.uiStartAddr, stPartInfo.uiTotalLen);

                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                Hv_Mw_USB_EraseFlash(stPartInfo.uiStartAddr + CODEBAK_PART_OFFSET, stPartInfo.uiTotalLen);
            }
        }
        else if(HV_SUCCESS == Hv_Mw_USB_GetPartitionInfoByName(s_ucOtaPartitionName[ucIdx], SBLK_MAGIC_STRING_LENGTH, &stPartInfo))
        {
            uiOtaTotalLen += stPartInfo.uiTotalLen;
            //HV_PRINTF("Got SBLK Name: ");
            //for (UINT32 k = 0; k < 8; k++)
            //{
            //    HV_PRINTF("%c", stPartInfo.ucSBLKName[k]);
            //}
            //HV_PRINTF("   StartAddr:0x%x, TotalLen:0x%x, Crc:0x%x, Valid:0x%x\n", stPartInfo.uiStartAddr, stPartInfo.uiTotalLen, stPartInfo.uiCRC, stPartInfo.uiValidLen);

            //如果待升级分区起始地址+有效数据长度超出bin的总大小，则返回错误，不允许升级
            if(stPartInfo.uiStartAddr + stPartInfo.uiValidLen > s_stUsbParam.uiOtaBinSize)
            {
                HV_LOG_INFO(DEFAULT, "Error！Partition exceeds the size of the bin file.");
                Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                Hv_Drv_USB_UnmountDev();
                s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                return HV_FAILURE;
            }
            
            Hv_Mw_USB_EraseFlash(stPartInfo.uiStartAddr, stPartInfo.uiTotalLen);
        }
    }
    s_stUsbParam.uiOTABinPktTotal = (uiOtaTotalLen % USB_OTA_PKT_LEN == 0)
                                      ? (uiOtaTotalLen / USB_OTA_PKT_LEN)
                                      : (uiOtaTotalLen / USB_OTA_PKT_LEN + 1);


    //逐个执行更新
    for(UCHAR8 ucIdx = 0; ucIdx < s_ucOtaPartitionCnt; ucIdx++)
    {
        if(0 == HV_MEMCMP(s_ucOtaPartitionName[ucIdx], STRING_SBLKPMSB, SBLK_MAGIC_STRING_LENGTH))
        {
            if(HV_TRUE == bPm51UpdateFlag)
            {
                Hv_Mw_USB_EraseFlash(PM51_PARTATION_ADDR, PM51_PARTATION_LEN);
                if(HV_SUCCESS != Hv_Mw_USB_UpdateSinglePartition(PM51_PARTATION_ADDR, PM51_PARTATION_ADDR, PM51_PARTATION_LEN))
                {
                    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                    Hv_Drv_USB_UnmountDev();
                    s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                    return HV_FAILURE;
                }
            }
        }
        //处理“SBLKCODE”，要拆成BOOT与CODE两部分进行
        else if(0 == HV_MEMCMP(s_ucOtaPartitionName[ucIdx], STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH))
        {
            if(OTA_PART_A == s_stUsbParam.enUsbOtaPart)
            {
                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKBOOT, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                if(HV_SUCCESS != Hv_Mw_USB_UpdateSinglePartition(stPartInfo.uiStartAddr, stPartInfo.uiStartAddr, stPartInfo.uiTotalLen))
                {
                    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                    Hv_Drv_USB_UnmountDev();
                    s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                    return HV_FAILURE;
                }

                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                if(HV_SUCCESS != Hv_Mw_USB_UpdateSinglePartition(stPartInfo.uiStartAddr, stPartInfo.uiStartAddr, stPartInfo.uiTotalLen))
                {
                    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                    Hv_Drv_USB_UnmountDev();
                    s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                    return HV_FAILURE;
                }
            }
            else
            {
                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKBTBK, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                if(HV_SUCCESS != Hv_Mw_USB_UpdateSinglePartition(stPartInfo.uiStartAddr, stPartInfo.uiStartAddr, stPartInfo.uiTotalLen))
                {
                    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                    Hv_Drv_USB_UnmountDev();
                    s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                    return HV_FAILURE;
                }

                Hv_Mw_USB_GetPartitionInfoByName(STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH, &stPartInfo);
                if(HV_SUCCESS != Hv_Mw_USB_UpdateSinglePartition(stPartInfo.uiStartAddr, stPartInfo.uiStartAddr + CODEBAK_PART_OFFSET, stPartInfo.uiTotalLen))
                {
                    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                    Hv_Drv_USB_UnmountDev();
                    s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                    return HV_FAILURE;
                }
            }
        }
        else
        {
            if(HV_SUCCESS == Hv_Mw_USB_GetPartitionInfoByName(s_ucOtaPartitionName[ucIdx], SBLK_MAGIC_STRING_LENGTH, &stPartInfo))
            {
                if(HV_SUCCESS != Hv_Mw_USB_UpdateSinglePartition(stPartInfo.uiStartAddr, stPartInfo.uiStartAddr, stPartInfo.uiTotalLen))
                {
                    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                    Hv_Drv_USB_UnmountDev();
                    s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                    return HV_FAILURE;
                }
            }
        }
    }

    /* 只有在Code分区有更新时，才需要更新Code CRC和启动分区标志；其他分区不需要改变也不需要重启 */
    if(HV_TRUE == bCodeUpdateFlag)
    {
        aucCodeCRC[0] = (s_stUsbParam.uiCodeCrc >> 24) & 0xFF;
        aucCodeCRC[1] = (s_stUsbParam.uiCodeCrc >> 16) & 0xFF;
        aucCodeCRC[2] = (s_stUsbParam.uiCodeCrc >> 8) & 0xFF;
        aucCodeCRC[3] = s_stUsbParam.uiCodeCrc & 0xFF;

        if(HV_SUCCESS == Hv_Comm_OTA_UpdateParams(aucCodeCRC, OTA_SBLK_CRC_LEN))
        {
            s_stUsbParam.enUsbCurState = USB_STATE_OTA_SUCCESS;
    
#if (HV_PROJECT_CONFIG_POWERON_AUTO_OTA == HV_CONFIG_ON)
            if(HV_TRUE == s_stUsbParam.bForceUpgradeFlag)
            {
                Hv_Mw_Led_SetLedMode(LED_OTA_OK);
            }
#else
            HV_LOG_INFO(DEFAULT, "OTA OK,Reset after 5s");
            Hv_Mw_USB_StartOTARstTimer(5000);
#endif
        }
        else
        {
            s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
        }
    }
    else
    {
        s_stUsbParam.enUsbCurState = USB_STATE_OTA_SUCCESS;
    }

    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
    Hv_Drv_USB_UnmountDev();

    return HV_SUCCESS;
}


/**
 * @brief 对OSD发送的“取消升级”消息的处理函数
 * @param[in] pstEvent Pointer to UsbEvent
 * @return Status
 */
static Status Hv_Mw_USB_DoCancel(UsbEvent *pstEvent)
{
    s_stUsbParam.enUsbCurState = USB_STATE_IDLE;

    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
    Hv_Drv_USB_UnmountDev();
    
    return HV_SUCCESS;
}


/**
 * @brief 寻找指定路径下的合法文件
          函数上报状态后，USB Task进入等待确认消息流程
 * @param[in] pstEvent USB事件.
 * @return Status
 */
static Status Hv_Mw_USB_DoFindFile(UsbEvent *pstEvent)
{
    Status    ret = HV_FAILURE;
    UsbState  enRetState = USB_STATE_NO_OTA_FILE;

    if(HV_TRUE == Hv_Drv_USB_GetConnect())
    {
        if(HV_FALSE == Hv_Drv_USB_GetMounted(&s_stUsbParam.stFs))
        {
            if(HV_SUCCESS != Hv_Drv_USB_MountDev(&s_stUsbParam.stFs))
            {
                HV_LOG_INFO(DEFAULT, "Mount Fail!");
                s_stUsbParam.enUsbCurState = enRetState;
                return ret;
            }
        }

        if(HV_SUCCESS == Hv_Drv_USB_FindFile(&s_stUsbParam.stFile, OTA_BIN_NAME))
        {
            s_stUsbParam.uiOtaBinSize = Hv_Drv_USB_GetFileSize(&s_stUsbParam.stFile);
            
            /* TODO: 什么条件下不允许升级？ */
            Hv_Mw_USB_FillPartitionTableFromBin(&s_stUsbParam);
            
            enRetState = USB_STATE_FOUND_OTA_FILE;
        }
        else
        {
            Hv_Drv_USB_UnmountDev();
            HV_LOG_INFO(DEFAULT, "No OTA Files");
        }

        if((s_stUsbParam.bForceUpgradeFlag) && (USB_STATE_FOUND_OTA_FILE == enRetState))
        {
            Hv_Drv_USB_SendEventToUsbQueue(USB_EVENT_UPGRADE_CONFIRM, 0);
#if (HV_PROJECT_CONFIG_POWERON_AUTO_OTA == HV_CONFIG_ON)
            Hv_Mw_Led_SetLedMode(LED_OTA_PROGRESSING);
#endif
        }
    }
    else
    {
        HV_LOG_INFO(DEFAULT, "No Plugin");
        enRetState = USB_STATE_NO_UDISK_IN;
    }

    if(HV_TRUE != Hv_Drv_USB_GetConnect())
    {
        enRetState = USB_STATE_NO_UDISK_IN;
    }
    s_stUsbParam.enUsbCurState = enRetState;

    return ret;
}

static Status Hv_Mw_USB_DoNormalOta(UsbEvent *pstEvent)
{
    /* 定义默认的升级分区，在无PartitionCfg.txt文件或者解析失败时仅更新默认分区 */
    UCHAR8*  ucDefaultPartList[] = {"SBLKPMSB", "SBLKCODE"};
    UCHAR8   ucDefaultPartCnt = sizeof(ucDefaultPartList) / sizeof(ucDefaultPartList[0]);
    /* 用于保存从PartitionCfg.txt解析出的待升级分区表 */
    UCHAR8   ucFilePartList[20][SBLK_MAGIC_STRING_LENGTH + 1];
    UCHAR8   ucFilePartCnt = 0;
    /* 用户文件读取的缓存，足够容纳8字符+换行符+终止符 */
    char     acBuffer[16];
    
    Hv_Mw_USB_ClearUsbOtaStatus();

    if(HV_TRUE != Hv_Drv_USB_GetConnect())
    {
        s_stUsbParam.enUsbCurState = USB_STATE_NO_UDISK_IN;
        return HV_FAILURE;
    }
    
    if(HV_FALSE == Hv_Drv_USB_GetMounted(&s_stUsbParam.stFs))
    {
        if(HV_SUCCESS != Hv_Drv_USB_MountDev(&s_stUsbParam.stFs))
        {
            s_stUsbParam.enUsbCurState = USB_STATE_NO_OTA_FILE;
            return HV_FAILURE;
        }
    }

    /* 检查U盘中是否有PargitionCfg.txt配置文件，
       如果有，则更新其中所指定的分区；如果没有，则默认仅更新PM51和Code分区 */
    if(HV_SUCCESS == Hv_Drv_USB_FindFile(&s_stUsbParam.stFile, OTA_PARTITION_CFG_FILE))
    {
        /* 读取首行数量 */
        if(f_gets(acBuffer, sizeof(acBuffer), &s_stUsbParam.stFile)) {
            ucFilePartCnt = (UCHAR8)atoi(acBuffer);
            HV_LOG_INFO(DEFAULT, "File declares %d partitions", ucFilePartCnt);
        }

        /* 逐行读取分区名 */
        if(ucFilePartCnt > 0)
        {
            UCHAR8 ucValidCount = 0;

            for(; ucValidCount < ucFilePartCnt; ucValidCount++)
            {
                if(f_gets(acBuffer, sizeof(acBuffer), &s_stUsbParam.stFile) == NULL)
                {
                    break;
                }
                /* 去除换行符(支持 \n 和 \r\n) */
                char* ptr = strchr(acBuffer, '\n');
                if (ptr)
                {
                    *ptr = '\0';
                }
                ptr = strchr(acBuffer, '\r');
                if (ptr)
                {
                    *ptr = '\0';
                }

                if ((strlen(acBuffer) != SBLK_MAGIC_STRING_LENGTH) || (strncmp(acBuffer, SBLK_HEADER, 4) != 0))
                {
                    HV_LOG_INFO(DEFAULT, "Invalid partition: %s", acBuffer);
                    break;
                }

                //ucFilePartList[ucValidCount] = strdup(acBuffer);
                strncpy((char*)ucFilePartList[ucValidCount], acBuffer, SBLK_MAGIC_STRING_LENGTH);
                ucFilePartList[ucValidCount][SBLK_MAGIC_STRING_LENGTH] = '\0';
                HV_LOG_INFO(DEFAULT, "Partitions Name: %s", ucFilePartList[ucValidCount]);
            }
        }
        
        Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
    }

    if(ucFilePartCnt > 0)
    {
        HV_LOG_INFO(DEFAULT, "Use PartitionCfg.txt");
        UCHAR8* ucFileArgV[20] = {0}; //创建指针数组
        for (UCHAR8 i = 0; i < ucFilePartCnt; i++) 
        {
            ucFileArgV[i] = ucFilePartList[i];
        }
        Hv_Mw_USB_StartOta(ucFilePartCnt, ucFileArgV, OTA_MODE_NORMAL);
    }
    else
    {
        HV_LOG_INFO(DEFAULT, "Use Default Partition List");
        Hv_Mw_USB_StartOta(ucDefaultPartCnt, ucDefaultPartList, OTA_MODE_NORMAL);
    }
    
    return HV_SUCCESS;
}

static Status Hv_Mw_USB_DoForceOta(UsbEvent *pstEvent)
{
    UCHAR8* ucDefaultPartList[] = {"SBLKPMSB", "SBLKCODE"};
    UCHAR8  ucDefaultPartCnt = sizeof(ucDefaultPartList) / sizeof(ucDefaultPartList[0]);

    Hv_Mw_USB_ClearUsbOtaStatus();

    Hv_Mw_USB_StartOta(ucDefaultPartCnt, ucDefaultPartList, OTA_MODE_FORCE);
    return HV_SUCCESS;
}


static Status Hv_Mw_USB_DoFullBinUpgrade(UsbEvent *pstEvent)
{
    Status    ret = HV_FAILURE;
    UsbState  enRetState = USB_STATE_NO_OTA_FILE;

    Hv_Mw_USB_ClearUsbOtaStatus();
    
    if(HV_TRUE == Hv_Drv_USB_GetConnect())
    {
        if(HV_FALSE == Hv_Drv_USB_GetMounted(&s_stUsbParam.stFs))
        {
            if(HV_SUCCESS != Hv_Drv_USB_MountDev(&s_stUsbParam.stFs))
            {
                HV_LOG_INFO(DEFAULT, "Mount Fail!");
                s_stUsbParam.enUsbCurState = enRetState;
                return ret;
            }
        }

        if(HV_SUCCESS == Hv_Drv_USB_FindFile(&s_stUsbParam.stFile, OTA_BIN_NAME))
        {
            s_stUsbParam.uiOtaBinSize = Hv_Drv_USB_GetFileSize(&s_stUsbParam.stFile);
            
            /* 如果需要检查bin文件是否匹配，可以在这里增加判断逻辑 */
            
            
            enRetState = USB_STATE_FOUND_OTA_FILE;
            Hv_Drv_USB_SendEventToUsbQueue(USB_EVENT_FULL_BIN_UPGRADE_CONFIRM, 0);
        }
        else
        {
            Hv_Drv_USB_UnmountDev();
            HV_LOG_INFO(DEFAULT, "No OTA Files");
        }

    }
    else
    {
        HV_LOG_INFO(DEFAULT, "No Plugin");
        enRetState = USB_STATE_NO_UDISK_IN;
    }

    s_stUsbParam.enUsbCurState = enRetState;

    return ret;
}

static Status Hv_Mw_USB_DoFullBinUpgradeConfirm(UsbEvent *pstEvent)
{
    UINT32 uiByteRead = 0;
    UINT32 uiPktCur = 0;
    UCHAR8 ucRetry = 0;
    UINT32 uiReadPos = 0;
    UCHAR8 ucPercent = 0;
    UCHAR8 ucPercentPre = 0xff;

    s_stUsbParam.enUsbCurState = USB_STATE_OTA_IN_PROCESSING;

    //chip erase flash
    Hv_Drv_Flash_EraseChip();
    
    s_stUsbParam.uiOTABinPktTotal = (s_stUsbParam.uiOtaBinSize % USB_OTA_PKT_LEN == 0)
                                      ? (s_stUsbParam.uiOtaBinSize / USB_OTA_PKT_LEN)
                                      : (s_stUsbParam.uiOtaBinSize / USB_OTA_PKT_LEN + 1);

    Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, 0);
    
   for(uiPktCur = 0; uiPktCur < s_stUsbParam.uiOTABinPktTotal; uiPktCur++)
   {
       while(ucRetry < USB_OTA_MAX_RETRY)
       {
           /* Must do for usb dma to sync */
           Hv_Vos_InvalidAllDCache(); 
           if(ucRetry != 0)
           {
               /* ReadFile后，文件指针会自动累加到当前packet的末尾，所以出错后要重新配置文件指针到当前packet的开头 */
               uiReadPos = uiPktCur * USB_OTA_PKT_LEN;
               Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, uiReadPos);
           }

           /* 读一个PACKET */
           if(HV_SUCCESS != Hv_Drv_USB_ReadFile(&s_stUsbParam.stFile, s_aucBinBuf, USB_OTA_PKT_LEN, &uiByteRead))
           {
               Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
               Hv_Drv_USB_UnmountDev();
               s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
               return HV_FAILURE;
           }
           Hv_Vos_InvalidAllDCache();

           HV_LOG_DEBUG(DEFAULT, "write flash 0x%x", uiPktCur * USB_OTA_PKT_LEN);
           /* 写入并校验这个PACKET */
           if(Hv_Drv_Flash_OnlyWrite(uiPktCur * USB_OTA_PKT_LEN, s_aucBinBuf, uiByteRead) != HV_SUCCESS)
           {
               Hv_Drv_Flash_OnlyErase(uiPktCur * USB_OTA_PKT_LEN, USB_OTA_PKT_LEN);

               ucRetry++;
               if(ucRetry >= USB_OTA_MAX_RETRY)
               {
                   Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                   Hv_Drv_USB_UnmountDev();
                   s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                   HV_ASSERT_PEEK_SUCCESS(Hv_Mw_USB_SendStateToOsd(s_stUsbParam.enUsbCurState, 0));
                   return HV_FAILURE;
               }
           }
           else
           {
               ucPercent = ((uiPktCur + 1) * 100)/s_stUsbParam.uiOTABinPktTotal;
               HV_LOG_DEBUG(DEFAULT, "uiPktCur: %d, ucPercent: %d", uiPktCur, ucPercent);
               if(ucPercentPre != ucPercent)
               {
                   if(ucPercent % USB_OTA_PROGRESS_BAR_STEP == 0)
                   {
                       HV_ASSERT_PEEK_SUCCESS(Hv_Mw_USB_SendStateToOsd(s_stUsbParam.enUsbCurState, ucPercent));
                   }
                   ucPercentPre = ucPercent;
               }
               ucRetry = 0;
               break;
           }
       }
   }

    s_stUsbParam.enUsbCurState = USB_STATE_OTA_SUCCESS;
    HV_LOG_INFO(DEFAULT, "OTA OK,Reset after 5s");
    Hv_Mw_USB_StartOTARstTimer(5000);

    Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
    Hv_Drv_USB_UnmountDev();

    return HV_SUCCESS;
}

/**
 * @brief USB OTA入口函数
 * @param[in] ucArgC  表示待升级分区的个数，该值要与后续的cArgV列表个数一致
 * @param[in] cArgV[] 包含待升级分区Name的列表.
 * @param[in] enMode  表示OTA方式：Normal交互式、Force强制式.
 * @return Status
 */
Status Hv_Mw_USB_StartOta(UCHAR8 ucArgC, UCHAR8* cArgV[], UsbOtaMode enMode)
{
    Status uiRet = HV_SUCCESS;
    
    if((ucArgC == 0) || (ucArgC > MAX_RESERVED_PARTITIONS) || (enMode > OTA_MODE_FORCE))
    {
        uiRet = HV_FAILURE;
    }
    else
    {
        if(USB_MODE_HOST != Hv_Mw_UsbGetWorkMode())
        {
#if defined(CONFIG_USER_USB_BILLBOARD_ON)
            if(USB_MODE_DEVICE == Hv_Mw_UsbGetWorkMode())
            {
                Hv_Mw_UsbBillboard_TaskStop();
            }
#endif
            Hv_Mw_UsbHost_TaskStartInit();
        }

        s_ucOtaPartitionCnt = ucArgC;
        for(UCHAR8 ucLoop = 0; ucLoop < s_ucOtaPartitionCnt; ucLoop++)
        {
            HV_LOG_INFO(DEFAULT, "OTA Partition::%s", cArgV[ucLoop]);
            HV_MEMCPY(s_ucOtaPartitionName[ucLoop], cArgV[ucLoop], SBLK_MAGIC_STRING_LENGTH);
        }

        if(OTA_MODE_FORCE == enMode)
        {
            s_stUsbParam.bForceUpgradeFlag = HV_TRUE;
        }
        else
        {
            s_stUsbParam.bForceUpgradeFlag = HV_FALSE;
        }
        Hv_Drv_USB_SendEventToUsbQueue(USB_EVENT_FIND_FILE, 0);
    }

    return uiRet;
}

#endif


#ifdef CONFIG_USER_USB_BILLBOARD_ON
extern void Hv_Drv_Usb_BillboardInit(void);
extern void Hv_Drv_Usb_BillboardExit(void);

VOID Hv_Mw_UsbBillboard_TaskStartInit(VOID)
{
    HV_LOG_INFO(DEFAULT, "billboard start");
    Hv_Mw_UsbSetWorkMode(USB_MODE_DEVICE);
    Hv_Drv_Usb_BillboardInit();
    return;
}

VOID Hv_Mw_UsbBillboard_TaskStop(VOID)
{
    HV_LOG_INFO(DEFAULT, "billboard stop");
    Hv_Mw_UsbSetWorkMode(USB_MODE_MAX);
    Hv_Drv_Usb_BillboardExit();

    HV_Drv_USB_GlobalFreeAll();
    return;
}

static Status Hv_Mw_USB_StartBillboard(UsbEvent *pstEvent)
{
    if(USB_MODE_DEVICE != Hv_Mw_UsbGetWorkMode())
    {
#ifdef CONFIG_USER_USB_OTA_ON
        Hv_Mw_UsbHost_TaskStop();
#endif
        Hv_Mw_UsbBillboard_TaskStartInit();
        Hv_Drv_USB_SetPriority(USB_NORMAL_TASK_PRIORITY);
    }
    return HV_SUCCESS;
}

#endif



UsbState Hv_Mw_USB_GetUsbState(VOID)
{
    return s_stUsbParam.enUsbCurState;
}

VOID Hv_Mw_SendEvtToUsb(UsbEventId enEvtID, USHORT16 usValue)
{
    Hv_Drv_USB_SendEventToUsbQueue(enEvtID, usValue);
    return;
}


static const UsbStateMachine s_astUsbStateMachine[] =
{
#ifdef CONFIG_USER_USB_OTA_ON
    {USB_STATE_ANY,                         USB_EVENT_DETECT_PORT,             Hv_Mw_USB_DetectHubPort},
    {USB_STATE_ANY,                         USB_EVENT_NORMAL_UPGRADE,          Hv_Mw_USB_DoNormalOta},
    {USB_STATE_ANY,                         USB_EVENT_FORCE_UPGRADE,           Hv_Mw_USB_DoForceOta},
    {USB_STATE_ANY,                         USB_EVENT_FIND_FILE,               Hv_Mw_USB_DoFindFile},
    /* 仅在找到OTA文件后才允许执行Confirm */
    {USB_STATE_FOUND_OTA_FILE,              USB_EVENT_UPGRADE_CONFIRM,         Hv_Mw_USB_DoConfirm},
    /* 仅在找到OTA文件后才允许执行Cancel */
    {USB_STATE_FOUND_OTA_FILE,              USB_EVENT_UPGRADE_CANCEL,          Hv_Mw_USB_DoCancel},
    {USB_STATE_ANY,                         USB_EVENT_FULL_BIN_UPGRADE,        Hv_Mw_USB_DoFullBinUpgrade},
    {USB_STATE_FOUND_OTA_FILE,              USB_EVENT_FULL_BIN_UPGRADE_CONFIRM,Hv_Mw_USB_DoFullBinUpgradeConfirm},
#endif
#ifdef CONFIG_USER_USB_BILLBOARD_ON
    {USB_STATE_ANY,                         USB_EVENT_START_BILLBOARD,         Hv_Mw_USB_StartBillboard},
#endif
};


static VOID Hv_Mw_USB_RunStateMachine(UsbEvent *pstEvent)
{
    HV_ASSERT_VALID_PTR_VOID(pstEvent);
    Status uiRet = HV_FAILURE;

    HV_LOG_INFO(DEFAULT, "usb state = %d, EventId = %d", s_stUsbParam.enUsbCurState, pstEvent->usEventId);

    for (USHORT16 usIndex = 0; usIndex < ARRAY_SIZE(s_astUsbStateMachine); ++usIndex)
    {
        if ((s_stUsbParam.enUsbCurState & s_astUsbStateMachine[usIndex].usAcceptStates)
           && (pstEvent->usEventId == s_astUsbStateMachine[usIndex].enEventId))
        {
            uiRet = s_astUsbStateMachine[usIndex].pfActionHandle(pstEvent);
            break;
        }
    }

    HV_LOG_INFO(DEFAULT, "end usb state = %d", s_stUsbParam.enUsbCurState);

#ifdef CONFIG_USER_USB_OTA_ON
    //强制升级时仅上报进度条、成功、失败消息，且需要按场景清除标志
    if(HV_TRUE == s_stUsbParam.bForceUpgradeFlag)
    {
#if (OTA_ALWAYS_SEND_FAIL == HV_CONFIG_ON)
        if((USB_STATE_NO_UDISK_IN == s_stUsbParam.enUsbCurState) || (USB_STATE_NO_OTA_FILE == s_stUsbParam.enUsbCurState))
        {
            s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
        }
#endif
        if(s_stUsbParam.enUsbCurState >= USB_STATE_OTA_IN_PROCESSING)
        {
            HV_ASSERT_PEEK_SUCCESS(Hv_Mw_USB_SendStateToOsd(s_stUsbParam.enUsbCurState, 0));
        }
        if((USB_STATE_NO_UDISK_IN == s_stUsbParam.enUsbCurState)
            ||(USB_STATE_NO_OTA_FILE == s_stUsbParam.enUsbCurState)
            ||(USB_STATE_OTA_SUCCESS == s_stUsbParam.enUsbCurState)
            ||(USB_STATE_OTA_FAIL == s_stUsbParam.enUsbCurState))
        {
            s_stUsbParam.bForceUpgradeFlag = HV_FALSE;
        }
    }
    else
    {
        //其他不需要上报给OSD的事件
        if((USB_EVENT_DETECT_PORT != pstEvent->usEventId) 
           && (USB_STATE_IDLE != s_stUsbParam.enUsbCurState)
          )
        {
            HV_ASSERT_PEEK_SUCCESS(Hv_Mw_USB_SendStateToOsd(s_stUsbParam.enUsbCurState, 0));
        }
    }
#endif
     
    return;
}


VOID Hv_Mw_UsbSetWorkMode(UsbWorkMode enMode)
{
    s_stUsbParam.enWorkMode = enMode;
    return;
}

UsbWorkMode Hv_Mw_UsbGetWorkMode(VOID)
{
    return s_stUsbParam.enWorkMode;
}


VOID Hv_Drv_USB_SetPriority(UCHAR8 ucPriority)
{
    vTaskPrioritySet(stUsbTaskHandle, ucPriority);
}

VOID Hv_Drv_USB_SetTaskHandler(TaskHandle_t stTaskHdl)
{
    stUsbTaskHandle = stTaskHdl;
}

VOID Hv_Mw_UsbTaskHandle(VOID* arg)
{
    UsbEvent stEventMsg = {0};

    HV_VOS_QUEUE_S* pUsbQueue = Hv_Mw_System_GetUsbQueue();
    HV_ASSERT_VALID_PTR_VOID(pUsbQueue);
    Hv_Drv_USB_RegisterGetQueueCb(Hv_Mw_System_GetUsbQueue);

    s_stUsbParam.enUsbCurState = USB_STATE_IDLE;
    Hv_Drv_USB_SetTaskHandler(xTaskGetCurrentTaskHandle());

#if defined(CONFIG_USER_USB_OTA_ON)
    Hv_Mw_UsbHost_TaskStartInit();
#endif

#if defined(CONFIG_USER_USB_OTA_ON) && HV_PROJECT_CONFIG_POWERON_AUTO_OTA == HV_CONFIG_ON
    Hv_Vos_MSleep(4000);
    Hv_Drv_USB_SendEventToUsbQueue(USB_EVENT_FORCE_UPGRADE, 0);
#endif

#if defined(CONFIG_USER_USB_OTA_ON) && HV_PROJECT_CONFIG_FULL_BIN_OTA == HV_CONFIG_ON
    Hv_Vos_MSleep(4000);
    Hv_Drv_USB_SendEventToUsbQueue(USB_EVENT_FULL_BIN_UPGRADE, 0);
#endif


    for (;;)
    {
#ifdef SW_DUMMY_DEBUG
        HV_WT32(SW_DUMMY_USB_TASK, (HV_RD32(SW_DUMMY_USB_TASK)+1));
#endif
        if (Hv_Vos_QueueRecv(pUsbQueue, (VOID*)&stEventMsg))
        {
            Hv_Mw_USB_RunStateMachine(&stEventMsg);
        }
        
        Hv_Vos_TaskYield();
    }
}
