/**
 * @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"

#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


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


#ifdef CONFIG_USER_USB_OTA_ON

/**
 * @brief Define the variables for the USB upgrade process.
 */
typedef struct _HvMwUsbParams
{
    UsbState       enUsbCurState;
    OtaPartDef     enUsbOtaPart;        /*!< 此次更新要烧写到哪个分区，与当前程序的运行分区相反 */
    BOOL           bForceUpgradeFlag;   /*!< 强制升级的标志，用于强制升级流程中的条件判断 */
    UINT32         uiOTABinPktTotal;    /*!< 表示OTA bin中BOOT+CODE分区的packet总个数, 用于计算升级进度百分比 */
    HV_TIMER_S     *pstOTARstTimer;
    FATFS          stFs;
    FIL            stFile;
    PartitionInfo  stPartitionInfo;
    USHORT16       usOtaPartitionMask;  /*!< 表征需要升级的分区，bitmask，@ref OtaPartitionFlagDef*/
}HvMwUsbParams;


/**
 * @brief The max length of data that is read from the version.txt. Cannot be smaller than the length of the real version.
 *        The actual read length is returned by the f_read function.
 */
#define USB_OTA_VER_LEN             (50)

/**
 * @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 Local USB-related variables. 
 */
static HvMwUsbParams s_stUsbParam = {0};

/**
 * @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 清除U盘升级的一些状态变量
 * @return none
 */
static VOID Hv_Mw_USB_ClearUsbOtaStatus(VOID)
{
    s_stUsbParam.enUsbCurState      = USB_STATE_IDLE;
    s_stUsbParam.enUsbOtaPart       = OTA_PART_MAX;

    HV_MEMSET(&s_stUsbParam.stPartitionInfo, 0, sizeof(PartitionInfo));
}

/**
 * @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 Status Hv_Mw_USB_ParsePartitionInfoFromBin(HvMwUsbParams *       pstUsbParam)
{
    Status  uiRet = HV_SUCCESS;
    UINT32 uiByteRead = 0;

    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, SBLK_READ_LEN, &uiByteRead);
    Hv_Vos_InvalidAllDCache(); 

    if(HV_SUCCESS != Hv_Comm_OTA_ParsePartitionInfo(s_aucBinBuf, SBLK_READ_LEN, &(pstUsbParam->stPartitionInfo)))
    {
        uiRet = HV_FAILURE;
    }
    return uiRet;
}


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 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 Status Hv_Mw_USB_Write51(VOID)
{
    UCHAR8 ucRetry = 0;
    UINT32 uiPktCur = 0;
    UINT32 uiReadPos = 0;
    UINT32 uiByteRead = 0;
    UINT32 uiPktCnt = PM51_PARTATION_LEN / USB_OTA_PKT_LEN;

    Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, uiReadPos);

    for(uiPktCur = 0; uiPktCur < uiPktCnt; uiPktCur++)
    {
        while(ucRetry < USB_OTA_MAX_RETRY)
        {
            /* Must do for usb dma to sync */
            Hv_Vos_InvalidAllDCache(); 
            /* ReadFile后，文件指针会自动累加到当前packet的末尾，所以出错后要重新配置文件指针到当前packet的开头 */
            if(ucRetry != 0)
            {
                uiReadPos = uiPktCur * USB_OTA_PKT_LEN + PM51_PARTATION_ADDR;
                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();
            
            /* 写入并校验这个PACKET */
            if(Hv_Drv_Flash_OnlyWrite(PM51_PARTATION_ADDR + uiPktCur * USB_OTA_PKT_LEN, s_aucBinBuf, USB_OTA_PKT_LEN) != HV_SUCCESS)
            {
                Hv_Drv_Flash_OnlyErase(PM51_PARTATION_ADDR + 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
            {
                ucRetry = 0;
                break;
            }
        }
    }
    
    return HV_SUCCESS;
}


static Status Hv_Mw_USB_WriteBoot(UINT32 uiBootWriteAddr)
{
    UCHAR8 ucRetry = 0;
    UINT32 uiPktCur = 0;
    UINT32 uiReadPos = 0;
    UINT32 uiPktTotal = 0;
    UINT32 uiByteRead = 0;
    UCHAR8 ucPercent = 0;
    UCHAR8 ucPercentPre = 0xff;

    uiPktTotal = (s_stUsbParam.stPartitionInfo.uiBootTotalLen % USB_OTA_PKT_LEN == 0)
                  ? (s_stUsbParam.stPartitionInfo.uiBootTotalLen / USB_OTA_PKT_LEN)
                  : (s_stUsbParam.stPartitionInfo.uiBootTotalLen / USB_OTA_PKT_LEN + 1);

    /* 文件定位到Boot */
    if(OTA_PART_A == s_stUsbParam.enUsbOtaPart)
    {
        Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, s_stUsbParam.stPartitionInfo.uiBootStartAddr);
    }
    else
    {
        Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, s_stUsbParam.stPartitionInfo.uiBootBakStartAddr);
    }

    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 + uiBootWriteAddr;
                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();

            /* 写入并校验这个PACKET */
            if(Hv_Drv_Flash_OnlyWrite(uiBootWriteAddr + uiPktCur * USB_OTA_PKT_LEN, s_aucBinBuf, USB_OTA_PKT_LEN) != HV_SUCCESS)
            {
                Hv_Drv_Flash_OnlyErase(uiBootWriteAddr + 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;
                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;
            }
        }
    }
    
    return HV_SUCCESS;
}


static Status Hv_Mw_USB_WriteCode(UINT32 uiCodeWriteAddr)
{
    UCHAR8 ucRetry = 0;
    UINT32 uiPktCur = 0;
    UINT32 uiReadPos = 0;
    UINT32 uiBootPktTotal = 0;
    UINT32 uiPktTotal = 0;
    UINT32 uiByteRead = 0;
    UCHAR8 ucPercent = 0;
    UCHAR8 ucPercentPre = 0xff;

    uiBootPktTotal = (s_stUsbParam.stPartitionInfo.uiBootTotalLen % USB_OTA_PKT_LEN == 0)
                      ? (s_stUsbParam.stPartitionInfo.uiBootTotalLen / USB_OTA_PKT_LEN)
                      : (s_stUsbParam.stPartitionInfo.uiBootTotalLen / USB_OTA_PKT_LEN + 1);
    uiPktTotal = (s_stUsbParam.stPartitionInfo.uiCodeTotalLen % USB_OTA_PKT_LEN == 0)
                      ? (s_stUsbParam.stPartitionInfo.uiCodeTotalLen / USB_OTA_PKT_LEN)
                      : (s_stUsbParam.stPartitionInfo.uiCodeTotalLen / USB_OTA_PKT_LEN + 1);

    /* 文件定位到Code */
    Hv_Drv_USB_SetFileSeek(&s_stUsbParam.stFile, s_stUsbParam.stPartitionInfo.uiCodeStartAddr);

    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 + s_stUsbParam.stPartitionInfo.uiCodeStartAddr;
                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();

            /* 写入并校验这个PACKET */
            if(Hv_Drv_Flash_OnlyWrite(uiCodeWriteAddr + uiPktCur * USB_OTA_PKT_LEN, s_aucBinBuf, USB_OTA_PKT_LEN) != HV_SUCCESS)
            {
                Hv_Drv_Flash_OnlyErase(uiCodeWriteAddr + 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 = ((uiBootPktTotal + uiPktCur + 1) * 100)/s_stUsbParam.uiOTABinPktTotal;
                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;
            }
        }
    }
    
    return HV_SUCCESS;
}


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

    s_stUsbParam.usOtaPartitionMask = pstEvent->usValue;
    if(HV_SUCCESS != Hv_Drv_USB_FindFile(&s_stUsbParam.stFile, OTA_BIN_NAME))
    {
        s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
        return HV_FAILURE;
    }

    s_stUsbParam.enUsbCurState = USB_STATE_OTA_IN_PROCESSING;
    HV_MEMSET(aucCodeCRC, 0, OTA_SBLK_CRC_LEN);

    /* 默认无参升级方式，会更新PM51、BOOT、CODE */
    if(OTA_PART_NORMAL == s_stUsbParam.usOtaPartitionMask)
    {
        /* 先比对PM51的bin是否与flash中一致，如果一致则跳过PM51更新，否则要执行更新PM51 */
        if(HV_FALSE == Hv_Mw_USB_ComparePm51())
        {
            bUpdatePm51 = HV_TRUE;
        }
        else
        {
            bUpdatePm51 = HV_FALSE;
        }
    
        /* 如果判定要升级PM51，则优先更新PM51，再执行Code分区的擦除和更新操作，以降低51更新过程中变砖风险 */
        /* 为简化程序逻辑，且PM51并非每次更新，进度条只统计Code分区 */
        if(HV_TRUE == bUpdatePm51)
        {
            HV_LOG_INFO(DEFAULT, "Notice: OTA PM51!!!");
            Hv_Mw_USB_EraseFlash(PM51_PARTATION_ADDR, PM51_PARTATION_LEN);
    
            if(HV_SUCCESS != Hv_Mw_USB_Write51())
            {
                Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
                Hv_Drv_USB_UnmountDev();
                s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
                //如果51更新失败则变砖，此时重启已经无效
                //Hv_Mw_USB_StartOTARstTimer(1000);
                HV_LOG_ERROR(DEFAULT, "OOPS, PM51 Update Fail! Halt!");
                return HV_FAILURE;
            }
        }
    
        s_stUsbParam.enUsbOtaPart = Hv_Comm_OTA_GetUpgradePart();
        HV_LOG_INFO(DEFAULT, "OTA to %s", (OTA_PART_A == s_stUsbParam.enUsbOtaPart) ?"A":"Bak");
        if(OTA_PART_A == s_stUsbParam.enUsbOtaPart)
        {
            uiBootFlashAddr = s_stUsbParam.stPartitionInfo.uiBootStartAddr;
            uiCodeFlashAddr = s_stUsbParam.stPartitionInfo.uiCodeStartAddr;
        }
        else
        {
            uiBootFlashAddr = s_stUsbParam.stPartitionInfo.uiBootBakStartAddr;
            uiCodeFlashAddr = s_stUsbParam.stPartitionInfo.uiCodeStartAddr + USB_OTA_CODEBAK_OFFSET;
        }
        Hv_Mw_USB_EraseFlash(uiBootFlashAddr, s_stUsbParam.stPartitionInfo.uiBootTotalLen);
        Hv_Mw_USB_EraseFlash(uiCodeFlashAddr, s_stUsbParam.stPartitionInfo.uiCodeTotalLen);
    
        uiOtaTotalLen = s_stUsbParam.stPartitionInfo.uiBootTotalLen + s_stUsbParam.stPartitionInfo.uiCodeTotalLen;
        

        s_stUsbParam.uiOTABinPktTotal = (uiOtaTotalLen % USB_OTA_PKT_LEN == 0)
                                          ? (uiOtaTotalLen / USB_OTA_PKT_LEN)
                                          : (uiOtaTotalLen / USB_OTA_PKT_LEN + 1);

        if(HV_SUCCESS != Hv_Mw_USB_WriteBoot(uiBootFlashAddr))
        {
            Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
            Hv_Drv_USB_UnmountDev();
            s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
            HV_LOG_ERROR(DEFAULT, "OOPS, Boot Update Fail!");
            return HV_FAILURE;
        }
        
        if(HV_SUCCESS != Hv_Mw_USB_WriteCode(uiCodeFlashAddr))
        {
            Hv_Drv_USB_CloseFile(&s_stUsbParam.stFile);
            Hv_Drv_USB_UnmountDev();
            s_stUsbParam.enUsbCurState = USB_STATE_OTA_FAIL;
            HV_LOG_ERROR(DEFAULT, "OOPS, Code Update Fail!");
            return HV_FAILURE;
        }
    }
    else
    {
        
    }

    
    /* 更新Code分区时也需要更新Code CRC */
    if((OTA_PART_NORMAL == s_stUsbParam.usOtaPartitionMask) || (OTA_PART_APP & s_stUsbParam.usOtaPartitionMask))
    {
        aucCodeCRC[0] = (s_stUsbParam.stPartitionInfo.uiCodeCrc >> 24) & 0xFF;
        aucCodeCRC[1] = (s_stUsbParam.stPartitionInfo.uiCodeCrc >> 16) & 0xFF;
        aucCodeCRC[2] = (s_stUsbParam.stPartitionInfo.uiCodeCrc >> 8) & 0xFF;
        aucCodeCRC[3] = s_stUsbParam.stPartitionInfo.uiCodeCrc & 0xFF;
    }

    /* 双分区下需更新启动分区标志; 更新Code分区时需同步Code-Crc */
    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;
    }

    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;
}


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


/**
 * @brief 查找U盘中是否有指定的OTA文件
 * @param[in] pstEvent enum of UsbEvent, unused.
 * @return Status HV_TRUE:got file, HV_FALSE:no file
 */
static Status Hv_Mw_USB_FindOtaFile(UsbEvent *pstEvent)
{
    Status           ret = HV_FAILURE;
    UsbState         enRetState = USB_STATE_NO_OTA_FILE;
    PartitionInfo stOtaPartInfo = {0};

    Hv_Mw_USB_ClearUsbOtaStatus();
    
    if(HV_TRUE == Hv_Drv_USB_GetConnect())
    {
        if(HV_SUCCESS == Hv_Drv_USB_MountDev(&s_stUsbParam.stFs))
        {
            /* 检查U盘中指定的bin文件是否存在 */
            if(HV_SUCCESS == Hv_Drv_USB_FindFile(&s_stUsbParam.stFile, OTA_BIN_NAME))
            {
                /* 找到同名文件后，解析super block分区表，如果无法解析，仍返回未找到文件 */
                /* 并与flash中的分区表做对比，如果分区不一致，则不允许升级，返回未找到匹配文件 */
                if((HV_SUCCESS == Hv_Mw_USB_ParsePartitionInfoFromBin(&s_stUsbParam)) && (HV_SUCCESS == Hv_Comm_OTA_ParsePartitionInfoFromFlash(&stOtaPartInfo)))
                {
                    if((s_stUsbParam.stPartitionInfo.uiBootStartAddr == stOtaPartInfo.uiBootStartAddr)
                        && (s_stUsbParam.stPartitionInfo.uiBootBakStartAddr == stOtaPartInfo.uiBootBakStartAddr)
                        && (s_stUsbParam.stPartitionInfo.uiCodeStartAddr == stOtaPartInfo.uiCodeStartAddr)
                        && (s_stUsbParam.stPartitionInfo.uiCodeTotalLen == stOtaPartInfo.uiCodeTotalLen))
                    {
                        enRetState = USB_STATE_FOUND_OTA_FILE;
                        ret = HV_SUCCESS;
                    }
                    else
                    {
                        HV_LOG_INFO(DEFAULT, "ERROR: Different Partition, Exit OTA!");
                    }
                }
            }
            else
            {
                Hv_Drv_USB_UnmountDev();
                HV_LOG_INFO(DEFAULT, "No OTA Files");
            }
        }
        else
        {
            HV_LOG_INFO(DEFAULT, "Mount Fail!");
        }

        /* 强制升级模式，自动进入DoConfirm状态 */
        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;
    }

    //任意时刻都可能拔出U盘，如果是已拔出，则只上报弹出U盘消息
    //只可能返回3个状态：设备弹出、无升级文件、找到升级文件
    if(HV_TRUE != Hv_Drv_USB_GetConnect())
    {
        enRetState = USB_STATE_NO_UDISK_IN;
    }
    s_stUsbParam.enUsbCurState = enRetState;

    return ret;
}


/**
 * @brief “强制升级”消息的处理函数, 与正常交互升级流程基本一致，只是不需要用户二次确认
 * @param[in] pstEvent Pointer to UsbEvent
 * @return Status
 */
static Status Hv_Mw_USB_DoForceOTA(UsbEvent *pstEvent)
{
    Hv_Mw_USB_ClearUsbOtaStatus();
    s_stUsbParam.bForceUpgradeFlag = HV_TRUE;

    Hv_Drv_USB_SendEventToUsbQueue(USB_EVENT_NORMAL_UPGRADE, 0);
    
    return HV_SUCCESS;
}


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;
}

VOID Hv_Mw_UsbHost_TaskStartInit(VOID)
{
    Hv_Drv_USB_RegisterGetQueueCb(Hv_Mw_System_GetUsbQueue);
    Hv_Drv_Usb_PlatformInit();

    Hv_Mw_USB_ClearUsbOtaStatus();
    return;
}


VOID Hv_Mw_UsbHost_TaskStop(VOID)
{
    Hv_Drv_Usb_PlatformExit();

    Hv_Mw_USB_ClearUsbOtaStatus();
    return;
}


static const UsbStateMachine s_astUsbStateMachine[] =
{
    /* 任意态都可以启动OTA流程，返回状态：无设备接入、找到OTA文件、找到更新的版本、找到更旧的版本、未找到OTA文件 */
    {USB_STATE_ANY,                         USB_EVENT_DETECT_PORT,             Hv_Mw_USB_DetectHubPort},
    {USB_STATE_ANY,                         USB_EVENT_NORMAL_UPGRADE,          Hv_Mw_USB_FindOtaFile},
    {USB_STATE_ANY,                         USB_EVENT_FORCE_UPGRADE,           Hv_Mw_USB_DoForceOTA},
    /* 仅在找到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},
};


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);
    
    //强制升级时仅上报进度条、成功、失败消息，且需要按场景清除标志
    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
    {
        //仅在disconnect中断里触发USB_EVENT_DETECT_PORT事件，不需要上报给OSD
        if(USB_EVENT_DETECT_PORT != pstEvent->usEventId)
        {
            HV_ASSERT_PEEK_SUCCESS(Hv_Mw_USB_SendStateToOsd(s_stUsbParam.enUsbCurState, 0));
        }
    }
     
    return;
}


#endif

#ifdef CONFIG_USER_USB_BILLBOARD_ON
VOID Hv_Mw_UsbBillboard_TaskStartInit(VOID)
{
    Hv_Drv_Usb_BillboardInit();
    return;
}
#endif


VOID Hv_Mw_UsbTaskHandle(VOID* arg)
{

#ifdef CONFIG_USER_USB_OTA_ON
    UsbEvent stEventMsg = {0};

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

    Hv_Mw_UsbHost_TaskStartInit();
#if (HV_PROJECT_CONFIG_POWERON_AUTO_OTA == HV_CONFIG_ON)
    Hv_Drv_USB_SendEventToUsbQueue(USB_EVENT_FORCE_UPGRADE, 0);
#endif
#endif
#ifdef CONFIG_USER_USB_BILLBOARD_ON
    Hv_Mw_UsbBillboard_TaskStartInit();
#endif

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