/**
 * @file hv_comm_Ota.h
 * @brief Header file of OTA Utilities module.
 *
 * @verbatim
 * ==============================================================================
 *                        ##### How to use #####
 * ==============================================================================
 *
 * @endverbatim
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-22
 */

#ifndef __SDK_COMMON_UTIL_UTILITIES_INC_OTA_H__
#define __SDK_COMMON_UTIL_UTILITIES_INC_OTA_H__


#include "hv_comm_DataType.h"

#define ALIGN_4K(x)     (((x) + 0xFFF) & ~0xFFF)


#define STRING_SBLKPMSB                 "SBLKPMSB"
#define STRING_SBLKBOOT                 "SBLKBOOT"  //第一启动分区的Boot
#define STRING_SBLKBTBK                 "SBLKBTBK"  //第二启动分区的Boot
#define STRING_SBLKCODE                 "SBLKCODE"
#define SBLK_HEADER                     "SBLK"
#define SBLK_MAGIC_STRING_LENGTH        (8)

#define VALID_LEN_OFFSET                (0x08)
#define START_ADDR_OFFSET               (0x0C)
#define CRC_OFFSET                      (0x1C)

#define SBLK_PER_SIZE                   (32)
#define MAX_RESERVED_PARTITIONS         (32)
#define MAX_SBLK_SIZE                   (MAX_RESERVED_PARTITIONS * SBLK_PER_SIZE)


/* PM51和SBLK分区的地址和长度是固定的，所以在这里用宏定义；
   其余的Boot、Code分区的起始地址和长度则通过解析SBLK的信息来得到
            |    PM51     |    51Data    |     SB      |    Boot1    |    Boot2    |    Code      | ------
Start(0x)   0            7000           8000          9000           x             x
Len         |     7000    |     1000     |     1000    |      x      |      x      |    
*/
#define PM51_PARTATION_ADDR             (0x00000000)
#define PM51_DATA_ADDR                  (0x00007000)
#define SBLK_PARTATION_ADDR             (0x00008000)

#define PM51_PARTATION_LEN              (0x00007000)
#define PM51_DATA_LEN                   (0x00001000)
#define SBLK_PARTATION_LEN              (0x00001000)


/**
 * @brief 双分区中CodeBak分区起始地址 = Code分区起始地址 + 2M
 */
#define CODEBAK_PART_OFFSET             (0x200000)

/**
 * @brief 定义SBLK分区中Code段的CRC长度
 */
#define OTA_SBLK_CRC_LEN                (4)

/**
 * @brief Enumeration definition of the boot partition 
 */
typedef enum _OtaPart
{
    OTA_PART_A = 0,
    OTA_PART_B,
    OTA_PART_MAX,
    OTA_PART_SHORT_PATCH,
} OtaPartDef;

/**
 * @brief 描述Flash分区表结构
 */
typedef struct _PartitionSBLKInfo
{
    UCHAR8             ucSBLKName[8];
    UINT32             uiValidLen;
    UINT32             uiStartAddr;
    UINT32             uiCRC;
    UINT32             uiTotalLen;
} PartitionSBLKInfo;


/**
 * @brief OTA后更新OTA_Flag，和Code_CRC
 * @param[in] pucCodeCrc 指向Code CRC值的指针, 必须传递4个字节! 且值全为0时不写入!
 * @param[in] ucCrcLen 表示Code CRC的长度, 必须设为4
 * @return Status
 */
Status Hv_Comm_OTA_UpdateParams(UCHAR8 *pucCodeCrc, UCHAR8 ucCrcLen);


/**
 * @brief 把4个字节按照Big Endian顺序组成UINT32数据
 * @param[in] pucData 指向UCHAR8数据块的指针
 * @param[in] uiOffset 偏移值，表示取UCHAR8数据块中指定偏移位置后的4个字节
 * @return UINT32
 */
UINT32 Hv_Comm_OTA_ConvertToUint32(const UCHAR8 *pucData, UINT32 uiOffset);


/**
 * @brief 获取本次OTA要升级到哪个分区，返回与当前正运行分区相反的分区号
 * @return OtaPartDef 指示待更新的分区号
 */
OtaPartDef Hv_Comm_OTA_GetUpgradePart(VOID);

/**
 * @brief 根据分区地址更新该分区对应的CRC
 * @return Status
 */
Status Hv_Comm_OTA_UpdatePartitionCrcByAddr(UCHAR8 *pucCrc, UCHAR8 ucCrcLen, UINT32 uiPartitionAddr);

/**
 * @brief 根据分区名字查找Flash上对应分区的信息
 * @return Status
 */
Status Hv_Comm_OTA_GetPartitionInfoByName(UCHAR8* pucName, UCHAR8 ucLen, PartitionSBLKInfo *pstPartInfo);

/**
 * @brief 根据分区起始地址查找Flash上对应分区的信息
 * @return Status
 */
Status Hv_Comm_OTA_GetPartitionInfoByStartAddr(UINT32 uiPartStartAddr, PartitionSBLKInfo *pstPartInfo);

/**
 * @brief 根据要升级到哪个分区来获取Boot和Code的写入地址
 * @return Status
 */
Status Hv_Comm_OTA_GetFlashWriteAddr(OtaPartDef enToWhich, UINT32 *uiBootWriteAddr, UINT32 *uiCodeWriteAddr);

#endif
