/**
 * @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_ProtectDisable();
    Hv_Drv_Flash_OnlyErase(PM51_DATA_ADDR, PM51_DATA_LEN);

    Hv_Drv_Flash_ProtectDisable();
    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_ProtectDisable();
                Hv_Drv_Flash_OnlyErase(SBLK_PARTATION_ADDR, SBLK_PARTATION_LEN);
                Hv_Drv_Flash_ProtectDisable();
                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_UpdatePartitionCrcByAddr(UCHAR8 *pucCrc, UCHAR8 ucCrcLen, UINT32 uiPartitionAddr)
{
    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));

    /* 检索Super Block分区，找到匹配的分区起始地址后，更新CRC */
    if((NULL != pucCrc) && (OTA_SBLK_CRC_LEN == ucCrcLen) && (0 != HV_MEMCMP(pucCrc, aucNullCrc, OTA_SBLK_CRC_LEN)))
    {
        Hv_Drv_Flash_OnlyRead(SBLK_PARTATION_ADDR, aucBuf, SBLK_PARTATION_LEN);

        for (UINT32 i = 0; i < MAX_SBLK_SIZE; i += SBLK_PER_SIZE)
        {
            if(Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET) == uiPartitionAddr)
            {
                HV_MEMCPY(aucBuf + i + CRC_OFFSET, pucCrc, OTA_SBLK_CRC_LEN);
                
                Hv_Drv_Flash_ProtectDisable();
                Hv_Drv_Flash_OnlyErase(SBLK_PARTATION_ADDR, SBLK_PARTATION_LEN);
                Hv_Drv_Flash_ProtectDisable();
                uiRet = Hv_Drv_Flash_OnlyWrite(SBLK_PARTATION_ADDR, aucBuf, SBLK_PARTATION_LEN);
                break;
            }
        }
    }

    return uiRet;
}


Status Hv_Comm_OTA_GetPartitionInfoByName(UCHAR8* pucName, UCHAR8 ucLen, PartitionSBLKInfo *pstPartInfo)
{
    Status uiRet = HV_FAILURE;
    UCHAR8  aucBuf[MAX_SBLK_SIZE];

    HV_MEMSET(pstPartInfo, 0, sizeof(PartitionSBLKInfo));
    Hv_Drv_Flash_OnlyRead(SBLK_PARTATION_ADDR, aucBuf, MAX_SBLK_SIZE);

    for (UINT32 i = 0; i < MAX_SBLK_SIZE; i += SBLK_PER_SIZE)
    {
        if (0 == HV_MEMCMP(&aucBuf[i], pucName, SBLK_MAGIC_STRING_LENGTH))
        {
            HV_MEMCPY(pstPartInfo->ucSBLKName, aucBuf + i, SBLK_MAGIC_STRING_LENGTH);
            pstPartInfo->uiValidLen    = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + VALID_LEN_OFFSET);
            pstPartInfo->uiStartAddr   = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET);
            pstPartInfo->uiCRC         = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + CRC_OFFSET);
            /* ！！！
            因为分区表中没有分区大小项，故TotalLen需要计算得出
            规则：如果其下一个分区的起始地址非0xFFFFFFFF，则用 (下一个分区起始地址 - 当前分区起始地址)
                  如果其下一个分区的起始地址是0xFFFFFFFF，则用 (当前分区的有效长度)
            ！！！*/
            if(Hv_Comm_OTA_ConvertToUint32(aucBuf, i + SBLK_PER_SIZE + START_ADDR_OFFSET) != 0xFFFFFFFF)
            {
                pstPartInfo->uiTotalLen    = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + SBLK_PER_SIZE + START_ADDR_OFFSET) 
                                             - Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET);
            }
            else
            {
                pstPartInfo->uiTotalLen    = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + VALID_LEN_OFFSET);
            }
            uiRet = HV_SUCCESS;
            break;
        }
    }
    return uiRet;
}


Status Hv_Comm_OTA_GetPartitionInfoByStartAddr(UINT32 uiPartStartAddr, PartitionSBLKInfo *pstPartInfo)
{
    Status uiRet = HV_FAILURE;
    UCHAR8  aucBuf[MAX_SBLK_SIZE];

    HV_MEMSET(pstPartInfo, 0, sizeof(PartitionSBLKInfo));
    Hv_Drv_Flash_OnlyRead(SBLK_PARTATION_ADDR, aucBuf, MAX_SBLK_SIZE);

    for (UINT32 i = 0; i < MAX_SBLK_SIZE; i += SBLK_PER_SIZE)
    {
        if(Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET) == uiPartStartAddr)
        {
            HV_MEMCPY(pstPartInfo->ucSBLKName, aucBuf + i, SBLK_MAGIC_STRING_LENGTH);
            pstPartInfo->uiValidLen    = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + VALID_LEN_OFFSET);
            pstPartInfo->uiStartAddr   = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET);
            pstPartInfo->uiCRC         = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + CRC_OFFSET);
            /* ！！！
            因为分区表中没有分区大小项，故TotalLen需要计算得出
            规则：如果其下一个分区的起始地址非0xFFFFFFFF，则用 (下一个分区起始地址 - 当前分区起始地址)
                  如果其下一个分区的起始地址是0xFFFFFFFF，则用 (当前分区的有效长度)
            ！！！*/
            if(Hv_Comm_OTA_ConvertToUint32(aucBuf, i + SBLK_PER_SIZE + START_ADDR_OFFSET) != 0xFFFFFFFF)
            {
                pstPartInfo->uiTotalLen    = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + SBLK_PER_SIZE + START_ADDR_OFFSET) 
                                             - Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET);
            }
            else
            {
                pstPartInfo->uiTotalLen    = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + VALID_LEN_OFFSET);
            }
            uiRet = HV_SUCCESS;
            break;
        }
    }
    return uiRet;
}

Status Hv_Comm_OTA_GetFlashWriteAddr(OtaPartDef enToWhich, UINT32 *uiBootWriteAddr, UINT32 *uiCodeWriteAddr)
{
    Status uiRet = HV_SUCCESS;
    UCHAR8 aucBuf[MAX_SBLK_SIZE];
    UINT32 uiBootAddr = 0;
    UINT32 uiBootBakAddr = 0;
    UINT32 uiCodeAddr = 0;

    Hv_Drv_Flash_OnlyRead(SBLK_PARTATION_ADDR, aucBuf, MAX_SBLK_SIZE);

    for (UINT32 i = 0; i < MAX_SBLK_SIZE; i += SBLK_PER_SIZE)
    {
        if (0 == HV_MEMCMP(&aucBuf[i], STRING_SBLKBOOT, SBLK_MAGIC_STRING_LENGTH))
        {
            uiBootAddr   = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET);
        }
        else if (0 == HV_MEMCMP(&aucBuf[i], STRING_SBLKBTBK, SBLK_MAGIC_STRING_LENGTH))
        {
            uiBootBakAddr   = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET);
        }
        else if (0 == HV_MEMCMP(&aucBuf[i], STRING_SBLKCODE, SBLK_MAGIC_STRING_LENGTH))
        {
            uiCodeAddr   = Hv_Comm_OTA_ConvertToUint32(aucBuf, i + START_ADDR_OFFSET);
        }
        else
        {

        }
    }

    if((0 != uiBootAddr) && (0 != uiBootBakAddr) && (0 != uiCodeAddr))
    {
        if(OTA_PART_A == enToWhich)
        {
            *uiBootWriteAddr = uiBootAddr;
            *uiCodeWriteAddr = uiCodeAddr;
        }
        else
        {
            *uiBootWriteAddr = uiBootBakAddr;
            *uiCodeWriteAddr = uiCodeAddr + CODEBAK_PART_OFFSET;
        }
    }
    else
    {
        uiRet = HV_FAILURE;
    }

    return uiRet;
}

