/**
 * @file hv_comm_Ota.c
 * @brief OTA Utilities source doe.
 *
 * @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_Ota.h"
#include "hv_comm_DataType.h"
#include "hv_vos_Comm.h"
#include "hv_comm_Define.h"
#include "hv_comm_Assert.h"
#include "hv_drv_Flash.h"
#include "OtaConfig.h"


/**
 * @brief 启动分区标志
          如果为0xAA，则表示将要从第二分区启动; 其余值都从第一分区启动.
 */
#define BOOT_PARTATION_MAGIC         (0xAA)

/**
 * @brief 定义启动分区标志的偏移字节数
          位于 PM51_DATA_ADDR(0x7009) 处
 */
#define BOOT_PARTATION_OFFSET        (9)

Status Hv_Comm_OTA_UpdateParams(UCHAR8 *pucCodeCrc, UCHAR8 ucCrcLen)
{
    UCHAR8  aucBuf[4096];  //PM51 Data分区和SBLK分区的长度都是0x1000
    UINT32  uiSuperBlockSize = 32;
    Status  uiRet = HV_SUCCESS;
    UCHAR8  aucNullCrc[OTA_SBLK_CRC_LEN] = {0, 0, 0, 0};

    HV_MEMSET(aucBuf, 0xFF, sizeof(aucBuf));

    /* 如果是双分区则更新启动分区标志 */
#if (HV_PROJECT_CONFIG_DUAL_PARTITION == HV_CONFIG_ON)
    Hv_Drv_Flash_OnlyRead(PM51_DATA_ADDR, aucBuf, PM51_DATA_LEN);

    if(OTA_PART_B == Hv_Comm_OTA_GetUpgradePart())
    {
        aucBuf[BOOT_PARTATION_OFFSET] = BOOT_PARTATION_MAGIC;
    }
    else
    {
        aucBuf[BOOT_PARTATION_OFFSET] = 0xFF;
    }
    
    Hv_Drv_Flash_OnlyErase(PM51_DATA_ADDR, PM51_DATA_LEN);

    uiRet = Hv_Drv_Flash_OnlyWrite(PM51_DATA_ADDR, aucBuf, PM51_DATA_LEN);
#endif

    /* 检索Super Block分区并更新Code CRC */
    if((NULL != pucCodeCrc) && (OTA_SBLK_CRC_LEN == ucCrcLen) && (0 != HV_MEMCMP(pucCodeCrc, aucNullCrc, OTA_SBLK_CRC_LEN)))
    {
        Hv_Drv_Flash_OnlyRead(SBLK_PARTATION_ADDR, aucBuf, SBLK_PARTATION_LEN);

        for (UINT32 i = 0; i < SBLK_PARTATION_LEN; i += uiSuperBlockSize)
        {
            // 找到"SBLKCODE"
            if (0 == HV_MEMCMP(&aucBuf[i], STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH))
            {
                HV_MEMCPY(aucBuf + i + CRC_OFFSET, pucCodeCrc, OTA_SBLK_CRC_LEN);
                
                Hv_Drv_Flash_OnlyErase(SBLK_PARTATION_ADDR, SBLK_PARTATION_LEN);
                uiRet = Hv_Drv_Flash_OnlyWrite(SBLK_PARTATION_ADDR, aucBuf, SBLK_PARTATION_LEN);
                break;
            }
        }
    }

    /* Notice:这里未对CRC写入做校验，即便失败也不影响OTA的最终状态 */
    return uiRet;
}


OtaPartDef Hv_Comm_OTA_GetUpgradePart(VOID)
{
#if (HV_PROJECT_CONFIG_DUAL_PARTITION == HV_CONFIG_ON)
    UCHAR8 aucBuf[BOOT_PARTATION_OFFSET + 1] = {0};
    Hv_Drv_Flash_OnlyRead(PM51_DATA_ADDR, aucBuf, BOOT_PARTATION_OFFSET + 1);

    if(aucBuf[BOOT_PARTATION_OFFSET] == BOOT_PARTATION_MAGIC)
    {
        return OTA_PART_A;
    }
    else
    {
        return OTA_PART_B;
    }
#else
    return OTA_PART_A;
#endif
}



UINT32 Hv_Comm_OTA_ConvertToUint32(const UCHAR8 *pucData, UINT32 uiOffset)
{
    // 以Big Endian顺序组合4个字节
    UINT32 uiValue = (pucData[uiOffset] << 24) |
                     (pucData[uiOffset + 1] << 16) |
                     (pucData[uiOffset + 2] << 8) |
                     pucData[uiOffset + 3];

    return uiValue;
}


Status Hv_Comm_OTA_ParsePartitionInfo(const UCHAR8 *pucData, UINT32 uiLen, PartitionInfo *pstPartInfo)
{

    // 每32字节块遍历Super Block分区
    for (UINT32 i = 0; i < uiLen; i += SBLK_PER_SIZE)
    {
        if (0 == HV_MEMCMP(&pucData[i], STRING_SBLKPMSB, SBLK_MAGIC_STRING_LENGTH))
        {
            pstPartInfo->uiPMSBStartAddr = Hv_Comm_OTA_ConvertToUint32(pucData, i + START_ADDR_OFFSET);
        }
        else if (0 == HV_MEMCMP(&pucData[i], STRING_SBLKBOOT, SBLK_MAGIC_STRING_LENGTH))
        {
            pstPartInfo->uiBootStartAddr = Hv_Comm_OTA_ConvertToUint32(pucData, i + START_ADDR_OFFSET);
            pstPartInfo->uiPMSBTotalLen = pstPartInfo->uiBootStartAddr - pstPartInfo->uiPMSBStartAddr;
        }
        else if (0 == HV_MEMCMP(&pucData[i], STRING_SBLKBOOTBAK, SBLK_MAGIC_STRING_LENGTH))
        {
            pstPartInfo->uiBootBakStartAddr = Hv_Comm_OTA_ConvertToUint32(pucData, i + START_ADDR_OFFSET);
            pstPartInfo->uiBootTotalLen = pstPartInfo->uiBootBakStartAddr - pstPartInfo->uiBootStartAddr;
        }
        else if (0 == HV_MEMCMP(&pucData[i], STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH))
        {
            pstPartInfo->uiCodeStartAddr = Hv_Comm_OTA_ConvertToUint32(pucData, i + START_ADDR_OFFSET);
            pstPartInfo->uiCodeCrc = Hv_Comm_OTA_ConvertToUint32(pucData, i + CRC_OFFSET);
        }
        else if (0 == HV_MEMCMP(&pucData[i], STRING_SBLKLOGO, SBLK_MAGIC_STRING_LENGTH))
        {
            pstPartInfo->uiLogoStartAddr = Hv_Comm_OTA_ConvertToUint32(pucData, i + START_ADDR_OFFSET);
            pstPartInfo->uiCodeTotalLen = pstPartInfo->uiLogoStartAddr - pstPartInfo->uiCodeStartAddr;
        }
        else if (0 == HV_MEMCMP(&pucData[i], STRING_SBLKPQDA, SBLK_MAGIC_STRING_LENGTH))
        {
            pstPartInfo->uiPQStartAddr = Hv_Comm_OTA_ConvertToUint32(pucData, i + START_ADDR_OFFSET);
            pstPartInfo->uiLogoTotalLen = pstPartInfo->uiPQStartAddr - pstPartInfo->uiLogoStartAddr;
        }
        else if (0 == HV_MEMCMP(&pucData[i], STRING_SBLKCFIG, SBLK_MAGIC_STRING_LENGTH))
        {
            pstPartInfo->uiConfigStartAddr = Hv_Comm_OTA_ConvertToUint32(pucData, i + START_ADDR_OFFSET);
            pstPartInfo->uiPQTotalLen = pstPartInfo->uiConfigStartAddr - pstPartInfo->uiPQStartAddr;
            pstPartInfo->uiConfigTotalLen = Hv_Comm_OTA_ConvertToUint32(pucData, i + SBLK_PER_SIZE + START_ADDR_OFFSET) - pstPartInfo->uiPQStartAddr;
        }
        else
        {
            // 有更新其他分区的需求时，再在此处增加
        }
    }

    HV_LOG_INFO(DEFAULT, "PMSB: Addr: 0x%08x, Len: 0x%08x", pstPartInfo->uiPMSBStartAddr, pstPartInfo->uiPMSBTotalLen);
    HV_LOG_INFO(DEFAULT, "Boot: Addr: 0x%08x, Bak: 0x%08x, Len: 0x%08x", pstPartInfo->uiBootStartAddr, pstPartInfo->uiBootBakStartAddr, pstPartInfo->uiBootTotalLen);
    HV_LOG_INFO(DEFAULT, "Code: Addr: 0x%08x, Len: 0x%08x, CRC: 0x%08x", pstPartInfo->uiCodeStartAddr, pstPartInfo->uiCodeTotalLen, pstPartInfo->uiCodeCrc);
    HV_LOG_INFO(DEFAULT, "Logo: Addr: 0x%08x, Len: 0x%08x", pstPartInfo->uiLogoStartAddr, pstPartInfo->uiLogoTotalLen);
    HV_LOG_INFO(DEFAULT, "PQ: Addr: 0x%08x, Len: 0x%08x", pstPartInfo->uiPQStartAddr, pstPartInfo->uiPQTotalLen);
    HV_LOG_INFO(DEFAULT, "Config: Addr: 0x%08x, Len: 0x%08x", pstPartInfo->uiConfigStartAddr, pstPartInfo->uiConfigTotalLen);

    // 判断bin中是否有SBLK信息，这里以起始地址来判断
    if((0 == pstPartInfo->uiBootStartAddr) 
        || (0 == pstPartInfo->uiBootBakStartAddr)
        || (0 == pstPartInfo->uiCodeStartAddr)
        || (0 == pstPartInfo->uiLogoStartAddr)
        || (0 == pstPartInfo->uiPQStartAddr)
        || (0 == pstPartInfo->uiConfigStartAddr))
    {
        return HV_FAILURE;
    }
    return HV_SUCCESS;
}



//分区表必须不能发生变化
//如果是第一分区，则直接使用SBLK中的信息
//如果是第二分区，Code2地址是Code1地址+0x200000
Status Hv_Comm_OTA_ParsePartitionInfoFromFlash(PartitionInfo *pstPartInfo)
{
    Status  uiRet = HV_SUCCESS;
    UCHAR8  aucBuf[SBLK_READ_LEN];
    UINT32  uiSuperBlockSize = 32;
    UINT32  uiCodeAddr = 0;

    HV_LOG_INFO(DEFAULT, "-Parse flash sblk");
    HV_MEMSET(pstPartInfo, 0, sizeof(PartitionInfo));
    
    Hv_Drv_Flash_OnlyRead(SBLK_PARTATION_ADDR, aucBuf, SBLK_READ_LEN);

    if(HV_SUCCESS != Hv_Comm_OTA_ParsePartitionInfo(aucBuf, SBLK_READ_LEN, pstPartInfo))
    {
        uiRet = HV_FAILURE;
    }
    return uiRet;
}

