/*
 * @Description: OTA模块-svc层
 * @Author: yangsw
 * @Date: 2021-06-21 10:39:07
 * @LastEditTime: 2023-03-06 12:40:20
 * @LastEditors: Lida
 * @Reference:
 */
#include "svc_ota.h"
#include "../../flash/svc/svc_flash.h"
#include "../../log/svc/svc_log.h"
#include "../../util/util_crc.h"
#include "../../util/util_data.h"

// 前64个Block是bootloader程序存放位置，不能擦除，96*128=12288=0x3000=0xB000-0x8000
#define FLASH_BLOCKS_NUM 96 //(0xB000-0x8000)/128=96
#define BLOCK_BYTES 128
// #define  FLASH_START          0x008000ul
// #define  FLASH_END            0x01FFFFul

/** page缓存 */
static gw_u8 FLASH_PAGE_BUF[FLASH_PAGE_SIZE];

static S_Ota s_ota;

/**
 * @brief Flash编程, 内部支持函数
 * @param
 *			SrcAdd ：要写入的数据的起始地址
 *      DstAddr：要写入数据的Falsh地址
 *			Len		 ：操作的数据长度
 *
 * @return
 *			FLASH_ERR_PG：操作失败
 *			FLASH_COMPL ：操作成功
 */
static FLASH_STS FLASH_ProgramPage(uint32_t *SrcAddr, uint32_t DstAddr, uint16_t Len)
{
    uint32_t i;

    for (i = 0; i < Len; i += 4)
    {
        FLASH_ProgramWord(DstAddr + i, *(uint32_t *)((uint32_t)SrcAddr + i));
        if (*(uint32_t *)(DstAddr + i) != *(uint32_t *)((uint32_t)SrcAddr + i))
        {
            return FLASH_ERR_PG; // 读出校验
        }
    }

    return FLASH_COMPL;
}

/**
 * @brief 任意地址写入任意长度数据
 * @param
 *			addr：起始地址
 *      src ：写入的数据指针
 *			len ：写入数据长度(byte)
 *
 * @return
 *			FLASH_ERR_WRP：操作失败
 *			FLASH_COMPL  ：操作成功
 */
FLASH_STS MID_FLASH_E2P_Write(u32 addr, const u8 *src, u32 len)
{
    gw_u32 i;
    gw_u32 pageAddr;  // 按页对齐的地址
    gw_u32 pageCount; // 写Falsh的页数
    gw_u32 tmpAddr;   // 按页对齐的余地址
    gw_u32 tmpLen;    // 首页需要写入Flash的长度
    gw_u32 startAddr; // 起始地址是否页对齐
    gw_u32 endAddr;   // 结束地址是否页对齐
    gw_u32 flag = 0;  // 页不对齐时,是否跨页

    if (FLASH_HSICLOCK_DISABLE == FLASH_ClockInit())
    {
        printf("HSI oscillator not yet ready\r\n");
        while (1)
            ;
    }

    FLASH_Unlock();
    startAddr = (addr % FLASH_PAGE_SIZE);       // 获取起始页偏移地址
    endAddr = ((addr + len) % FLASH_PAGE_SIZE); // 获取结束页偏移地址

    /** 起始地址页对齐 */
    if (startAddr == 0)
    {
        pageAddr = addr;
        pageCount = (len / FLASH_PAGE_SIZE);
        for (i = 0; i < pageCount; i++)
        {
            /** 写Flash前先擦除, 不需要备份 */
            if (FLASH_COMPL != FLASH_EraseOnePage(pageAddr))
            {
                FLASH_Lock();
                return FLASH_ERR_WRP;
            }

            /** 按页写Flash */
            if (FLASH_COMPL != FLASH_ProgramPage((uint32_t *)(src + (i * FLASH_PAGE_SIZE)), pageAddr, FLASH_PAGE_SIZE))
            {
                FLASH_Lock();
                return FLASH_ERR_WRP;
            }
            pageAddr += FLASH_PAGE_SIZE;
        }

        /** 结束地址页不对齐 */
        if (endAddr != 0)
        {
            /** 备份一页数据 */
            for (i = 0; i < FLASH_PAGE_SIZE; i++)
            {
                FLASH_PAGE_BUF[i] = ((uint8_t *)pageAddr)[i];
            }

            /** 计算按页对齐的余地址 */
            tmpAddr = (len % FLASH_PAGE_SIZE);

            /** 把需要写入Flash的数据保存到备份buf中 */
            for (i = 0; i < tmpAddr; i++)
            {
                FLASH_PAGE_BUF[i] = ((uint8_t *)(src + (pageCount * FLASH_PAGE_SIZE)))[i];
            }

            /** 写Flash前先擦除 */
            if (FLASH_COMPL != FLASH_EraseOnePage(pageAddr))
            {
                FLASH_Lock();
                return FLASH_ERR_WRP;
            }

            /** 写最后一页 */
            if (FLASH_COMPL != FLASH_ProgramPage((uint32_t *)FLASH_PAGE_BUF, pageAddr, FLASH_PAGE_SIZE))
            {
                FLASH_Lock();
                return FLASH_ERR_WRP;
            }
        }
    }
    else /** 起始地址页不对齐 */
    {
        pageAddr = ((addr / FLASH_PAGE_SIZE) * FLASH_PAGE_SIZE); // 计算首页的页对齐地址
        tmpAddr = (addr % FLASH_PAGE_SIZE);                      // 计算首页的余地址
        tmpLen = (FLASH_PAGE_SIZE - tmpAddr);                    // 计算首页需要写入Flash的长度

        if (tmpLen > len)
        {
            tmpLen = len;
            flag = 0; // 不跨页
        }
        else
        {
            flag = 1; // 跨页
        }

        /** 备份一页数据 */
        for (i = 0; i < FLASH_PAGE_SIZE; i++)
        {
            FLASH_PAGE_BUF[i] = ((uint8_t *)pageAddr)[i];
        }

        /** 把需要写入Flash的数据保存到备份buf中 */
        for (i = 0; i < tmpLen; i++)
        {
            FLASH_PAGE_BUF[tmpAddr + i] = ((uint8_t *)src)[i];
        }

        /** 写Flash前先擦除 */
        if (FLASH_COMPL != FLASH_EraseOnePage(pageAddr))
        {
            FLASH_Lock();
            return FLASH_ERR_WRP;
        }

        /** 写首页Flash */
        if (FLASH_COMPL != FLASH_ProgramPage((uint32_t *)FLASH_PAGE_BUF, pageAddr, FLASH_PAGE_SIZE))
        {
            FLASH_Lock();
            return FLASH_ERR_WRP;
        }

        /** 计算剩余写Flash的页数 */
        pageCount = ((len - tmpLen) / FLASH_PAGE_SIZE);
        pageAddr += FLASH_PAGE_SIZE;
        for (i = 0; i < pageCount; i++)
        {
            /** 写Flash前先擦除 */
            if (FLASH_COMPL != FLASH_EraseOnePage(pageAddr))
            {
                FLASH_Lock();

                return FLASH_ERR_WRP;
            }

            /** 按页写Flash */
            if (FLASH_COMPL != FLASH_ProgramPage((uint32_t *)(src + tmpLen + (i * FLASH_PAGE_SIZE)), pageAddr, FLASH_PAGE_SIZE))
            {
                FLASH_Lock();

                return FLASH_ERR_WRP;
            }
            pageAddr += FLASH_PAGE_SIZE;
        }

        /** 结束地址跨页 */
        if ((endAddr != 0) && (flag == 1))
        {
            /** 结束地址页不对齐，需要备份最后一页数据 */
            for (i = 0; i < FLASH_PAGE_SIZE; i++)
            {
                FLASH_PAGE_BUF[i] = ((uint8_t *)pageAddr)[i];
            }

            /** 计算按页对齐的余地址 */
            tmpAddr = (len - tmpLen) % FLASH_PAGE_SIZE;

            /** 把需要写入Flash的数据保存到buf中 */
            for (i = 0; i < tmpAddr; i++)
            {
                FLASH_PAGE_BUF[i] = ((uint8_t *)(src + tmpLen + (pageCount * FLASH_PAGE_SIZE)))[i];
            }

            /** 写Flash前先擦除 */
            if (FLASH_COMPL != FLASH_EraseOnePage(pageAddr))
            {
                FLASH_Lock();
                return FLASH_ERR_WRP;
            }

            /** 写最后一页 */
            if (FLASH_COMPL != FLASH_ProgramPage((uint32_t *)FLASH_PAGE_BUF, pageAddr, FLASH_PAGE_SIZE))
            {
                FLASH_Lock();
                return FLASH_ERR_WRP;
            }
        }
    }

    FLASH_Lock();
    return FLASH_COMPL;
}
/**
 * @brief: 固件信息参数保存
 * @param  {void}
 * @return {E_Result_State} 执行结果
 * @note:
 * @see:
 */
E_Result_State Svc_Ota_Save_Para(void)
{
    S_Ota_Para s_ota_para;
    gw_u8 *ptr = (gw_u8 *)&s_ota_para;
    gw_u8 *ptr1 = (gw_u8 *)&s_ota.s_para;
    s_ota.s_para.u8IsNewFirmware = 0;
    s_ota.s_para.u8Sum = Util_Data_Check_Sum(ptr1, (gw_u32)&s_ota.s_para.u8Sum - (gw_u32)&s_ota.s_para);
    if (Svc_Flash_Write(ptr1, OTA_FIRMWARE_PARA_ADDR, sizeof(S_Ota_Para)) == E_STATE_ERROR)
    { // flash写入异常
//        Svc_Log_Printf(LOG_ERROR, "%s->write fail\r\n", __FUNCTION__);
        return E_STATE_ERROR;
    }
    Svc_Flash_Read(ptr, OTA_FIRMWARE_PARA_ADDR, sizeof(S_Ota_Para));
    if (memcmp(&s_ota.s_para, ptr, sizeof(S_Ota_Para)))
    {
//        Svc_Log_Printf(LOG_ERROR, "%s->write fail\r\n", __FUNCTION__);
        return E_STATE_ERROR;
    }
    return E_STATE_SUCCESS;
}

/**
 * @brief: 读取固件信息参数
 * @return {E_Result_State} 执行结果
 * @note:
 * @see:
 * @param {S_Ota_Para} *ps_ota_para
 */
E_Result_State Svc_Ota_Read_Para(S_Ota_Para *ps_ota_para)
{
    gw_u8 *ptr = (gw_u8 *)ps_ota_para;
    gw_u8 u8Sum;
    Svc_Flash_Read(ptr, OTA_FIRMWARE_PARA_ADDR, sizeof(S_Ota_Para));
    if (s_ota.s_para.u8Sig != 0xF5)
    {
//        Svc_Log_Printf(LOG_ERROR, "%s->sig err\r\n", __FUNCTION__);
        return E_STATE_ERROR;
    }
    u8Sum = Util_Data_Check_Sum(ptr, (gw_u32)&ps_ota_para->u8Sum - (gw_u32)ps_ota_para);
    if (u8Sum != ps_ota_para->u8Sum)
    {
//        Svc_Log_Printf(LOG_ERROR, "%s->sum err\r\n", __FUNCTION__);
        return E_STATE_ERROR;
    }
    return E_STATE_SUCCESS;
}

/**
 * @brief: 校验固件
 * @param  {void}
 * @return {E_Result_State} 校验结果
 * @note: 固件信息(8字节)+固件长度(2字节)+固件crc16(2字节)+保留(20字节)+固件数据(X字节)
 * @see:
 */
E_Result_State Svc_Ota_Check(void)
{
    gw_u32 u32FirmwareBinLen;
    gw_u16 u16Index = 0;
    gw_u16 u16Crc;
    gw_u16 u16CalCrc = 0xFFFF;
    gw_u32 u32RemainLen;
    gw_u16 i;
    if (Svc_Ota_Read_Para(&s_ota.s_para) == E_STATE_ERROR)
    { // 读取ota参数
        return E_STATE_ERROR;
    }
    if (s_ota.s_para.u8IsNewFirmware == 0)
    { // 没有新固件，不需要更新app程序
//        Svc_Log_Printf(LOG_ERROR, "%s->no new\r\n", __FUNCTION__);
        return E_STATE_ERROR;
    }
    if (s_ota.s_para.u32FirmwareLen < 100)
    { // 固件太小，有异常
//        Svc_Log_Printf(LOG_ERROR, "%s->len err\r\n", __FUNCTION__);
        return E_STATE_ERROR;
    }
    Svc_Flash_Read(s_ota.pu8Buf, OTA_FIRMWARE_ADDR, OTA_BUF_SIZE);
    u16Index = u16Index + 8;
    u32FirmwareBinLen = (gw_u32)(((s_ota.pu8Buf[u16Index] << 24) & 0xFF000000) | ((s_ota.pu8Buf[u16Index + 1] << 16) & 0x00FF0000) | ((s_ota.pu8Buf[u16Index + 2] << 8) & 0x0000FF00) | (s_ota.pu8Buf[u16Index + 3] & 0x000000FF)); // 获取真实bin文件长度
//    Svc_Log_Printf(LOG_INFO, "totalLen=%u,curLen=%u\r\n", u32FirmwareBinLen, s_ota.s_para.u32FirmwareLen);
    if ((s_ota.s_para.u32FirmwareLen - OTA_FIRMWARE_BIN_INDEX) != u32FirmwareBinLen)
    { // 校验固件真实bin文件长度
//        Svc_Log_Printf(LOG_ERROR, "firmware len err\r\n");
        return E_STATE_ERROR;
    }
    u16Index = u16Index + 4;
    u16Crc = (((gw_u16)s_ota.pu8Buf[u16Index] << 8) & 0xFF00) | (s_ota.pu8Buf[u16Index + 1] & 0x00FF); // 获取真实bin文件的crc16
    u16Index = u16Index + 2;
    u16Index = u16Index + 18;

    if (u32FirmwareBinLen <= (OTA_BUF_SIZE - OTA_FIRMWARE_BIN_INDEX))
    { // 只有一包数据
        u16CalCrc = Util_Crc16_Cut(u16CalCrc, &s_ota.pu8Buf[u16Index], u32FirmwareBinLen);
        u32RemainLen = 0;
    }
    else
    { // 还有数据
        u16CalCrc = Util_Crc16_Cut(u16CalCrc, &s_ota.pu8Buf[u16Index], OTA_BUF_SIZE - OTA_FIRMWARE_BIN_INDEX);
        u32RemainLen = u32FirmwareBinLen - (OTA_BUF_SIZE - OTA_FIRMWARE_BIN_INDEX);
    }
    i = 1;
    while (u32RemainLen > 0)
    {                                                                                     // 还有剩余固件数据
        Svc_Flash_Read(s_ota.pu8Buf, OTA_FIRMWARE_ADDR + i * OTA_BUF_SIZE, OTA_BUF_SIZE); // 读取剩余固件
        i++;
        if (u32RemainLen <= OTA_BUF_SIZE)
        { // 最后一包数据了
            u16CalCrc = Util_Crc16_Cut(u16CalCrc, &s_ota.pu8Buf[0], u32RemainLen);
            u32RemainLen = 0;
        }
        else
        { // 还有数据
            u16CalCrc = Util_Crc16_Cut(u16CalCrc, &s_ota.pu8Buf[0], OTA_BUF_SIZE);
            u32RemainLen = u32RemainLen - OTA_BUF_SIZE;
        }
    }
    if (u16Crc != u16CalCrc)
    { // 固件数据校验失败
        Svc_Ota_Save_Para();
//        Svc_Log_Printf(LOG_ERROR, "%s->check err\r\n", __FUNCTION__);
        return E_STATE_ERROR;
    }
    Svc_Ota_Save_Para();
    return E_STATE_SUCCESS;
}

/**
 * @brief: 载入固件
 * @param  {void}
 * @return {void}
 * @note:
 * @see:
 */
void Svc_Ota_Load(void)
{
    gw_u16 j;
    gw_u32 u32FirmwareBinLen;
    gw_u32 u32RemainLen = 0;
    gw_u32 u32CurLen = 0;
    gw_u16 u16Index = 0;
//    Svc_Log_Printf(LOG_INFO, "ota start...\r\n");

    Svc_Flash_Read(s_ota.pu8Buf, OTA_FIRMWARE_ADDR, OTA_BUF_SIZE); // 读第一包数据
    u32FirmwareBinLen = s_ota.s_para.u32FirmwareLen - OTA_FIRMWARE_BIN_INDEX;
    u16Index = OTA_FIRMWARE_BIN_INDEX; // 头部32个字节去掉，不是真正的固件

    if (u32FirmwareBinLen <= (OTA_BUF_SIZE - OTA_FIRMWARE_BIN_INDEX))
    { // 只有一包数据

        // for(i=0;i<u16FirmwareBinLen;i++){
        //     FLASH_ProgramByte(APPLICATION_ADDRESS+i,s_ota.pu8Buf[u16Index+i]);
        // }
        MID_FLASH_E2P_Write(APPLICATION_ADDRESS, &s_ota.pu8Buf[u16Index], u32FirmwareBinLen);
        // FLASH_Lock(FLASH_MemType_Program);
        // FLASH_Lock(FLASH_MemType_Data);
        u32CurLen = u32FirmwareBinLen; // 更新当前已写长度
        u32RemainLen = 0;              // 更新剩余未写长度
    }
    else
    { // 还有数据，写2016(2048-32)个字节
        // FLASH_Unlock(FLASH_MemType_Program);
        // FLASH_Unlock(FLASH_MemType_Data);
        // for(i=0;i<(OTA_BUF_SIZE-OTA_FIRMWARE_BIN_INDEX);i++){
        //     FLASH_ProgramByte(APPLICATION_ADDRESS+i,s_ota.pu8Buf[u16Index+i]);
        // }
        MID_FLASH_E2P_Write(APPLICATION_ADDRESS, &s_ota.pu8Buf[u16Index], (OTA_BUF_SIZE - OTA_FIRMWARE_BIN_INDEX));
        // FLASH_Lock(FLASH_MemType_Program);
        // FLASH_Lock(FLASH_MemType_Data);
        u32CurLen = (OTA_BUF_SIZE - OTA_FIRMWARE_BIN_INDEX); // 更新当前已写长度
        u32RemainLen = u32FirmwareBinLen - u32CurLen;        // 更新剩余未写长度
    }
    j = 1;
    // Svc_Log_Printf(LOG_INFO,"totalLen=%u,curLen=%u,remainLen=%u\r\n",u16FirmwareBinLen,u16CurLen,u16RemainLen);
    while (u32RemainLen > 0)
    { // 还有剩余固件数据
//        Svc_Log_Printf(LOG_INFO, "totalLen=%u,curLen=%u,remainLen=%u\r\n", u32FirmwareBinLen, u32CurLen, u32RemainLen);
        Svc_Flash_Read(s_ota.pu8Buf, OTA_FIRMWARE_ADDR + j * OTA_BUF_SIZE, OTA_BUF_SIZE); // 读下一包数据
        j++;
        if (u32RemainLen <= OTA_BUF_SIZE)
        { // 最后一包数据了,直接全写
            // FLASH_Unlock(FLASH_MemType_Program);
            // FLASH_Unlock(FLASH_MemType_Data);
            // for(i=0;i<(u16RemainLen);i++){
            //     FLASH_ProgramByte(APPLICATION_ADDRESS+u16CurLen+i,s_ota.pu8Buf[i]);
            // }
            MID_FLASH_E2P_Write(APPLICATION_ADDRESS + u32CurLen, &s_ota.pu8Buf[0], u32RemainLen);
            // FLASH_Lock(FLASH_MemType_Program);
            // FLASH_Lock(FLASH_MemType_Data);
            u32CurLen = u32CurLen + u32RemainLen; // 更新当前已写长度
            u32RemainLen = 0;                     // 更新剩余未写长度
        }
        else
        { // 还有数据，一次写2048个字节
            // FLASH_Unlock(FLASH_MemType_Program);
            // FLASH_Unlock(FLASH_MemType_Data);
            // for(i=0;i<OTA_BUF_SIZE;i++){
            //     FLASH_ProgramByte(APPLICATION_ADDRESS+u16CurLen+i,s_ota.pu8Buf[i]);
            // }
            MID_FLASH_E2P_Write(APPLICATION_ADDRESS + u32CurLen, &s_ota.pu8Buf[0], OTA_BUF_SIZE);
            u32CurLen = u32CurLen + OTA_BUF_SIZE;       // 更新当前已写长度
            u32RemainLen = u32RemainLen - OTA_BUF_SIZE; // 更新剩余未写长度
        }
    }
    Svc_Ota_Save_Para();
//    Svc_Log_Printf(LOG_INFO, "OTA finish...\r\n");
}
