/**
 * @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_SBLKBOOTBAK              "SBLKBTBK"  //第二启动分区的Boot
#define STRING_SBLKCODE                 "SBLKCODE"
#define STRING_SBLKLOGO                 "SBLKLOGO"
#define STRING_SBLKPQDA                 "SBLKPQDA"
#define STRING_SBLKCFIG                 "SBLKCFIG"
#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)

/* 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 USB_OTA_CODEBAK_OFFSET          (0x200000)

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

/**
 * @brief 定义读取super block的字节数
          每32个字节为一个分区的描述信息，这里读取512字节共预留16个分区
 */
#define SBLK_READ_LEN                   (512)

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


/**
 * @brief 分区定义, bit mask，用以表征哪些分区需要升级;
          0值：总是表示默认更新PM51, BOOT与CODE，
          非0值：需要对应解析bit位，置1的分区需要被更新，且OTA_PART_CODE表示会更新BOOT与CODE.
 */
typedef enum _OtaPartitionFlagDef
{
    OTA_PART_NORMAL     = 0,         /*!< 默认只更新PM51, BOOT与CODE */
    OTA_PART_PM51       = 1 << 0,
    OTA_PART_APP        = 1 << 1,    /*!< BOOT与CODE总是同时更新，这里仅用1个bit来表示，统称为APP */
    OTA_PART_LOGO       = 1 << 2,
    OTA_PART_PQ         = 1 << 3,
    OTA_PART_CFG        = 1 << 4,
} OtaPartitionFlagDef;


/**
 * @brief 描述Flash分区表信息
 */
typedef struct _OtaPartInfo
{
    UINT32             uiPMSBStartAddr;
    UINT32             uiPMSBTotalLen;
    UINT32             uiBootStartAddr;
    UINT32             uiBootBakStartAddr;
    UINT32             uiBootTotalLen;
    UINT32             uiCodeStartAddr;
    UINT32             uiCodeBakStartAddr;
    UINT32             uiCodeTotalLen;
    UINT32             uiCodeCrc;
    UINT32             uiLogoStartAddr;
    UINT32             uiLogoTotalLen;
    UINT32             uiPQStartAddr;
    UINT32             uiPQTotalLen;
    UINT32             uiConfigStartAddr;
    UINT32             uiConfigTotalLen;
}PartitionInfo;


/**
 * @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 解析分区表信息
 * @param[in] pucData 分区表数据块
 * @param[in] uiLen 待解析的分区表数据长度，建议设置成pucData的实际长度
 * @param[in] pstPartInfo 指向 PartitionInfo 结构体的指针，这里会返回解析后的数据
 * @return Status
 */
Status Hv_Comm_OTA_ParsePartitionInfo(const UCHAR8 *pucData, UINT32 uiLen, PartitionInfo *pstPartInfo);

/**
 * @brief 解析Flash中的分区表信息
 * @param[in] pstPartInfo 指向 PartitionInfo 结构体的指针
 * @return Status
 */
Status Hv_Comm_OTA_ParsePartitionInfoFromFlash(PartitionInfo *pstPartInfo);


#endif
