/*
 * @Description: OTA模块-svc层
 * @Author: yangsw
 * @Date: 2021-06-21 10:39:07
 * @LastEditTime: 2023-05-19 16:37:44
 * @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)
{
    uint32_t i;
    uint32_t pageAddr;  //按页对齐的地址
    uint32_t pageCount; //写Falsh的页数
    uint32_t tmpAddr;   //按页对齐的余地址
    uint32_t tmpLen;    //首页需要写入Flash的长度
    uint32_t startAddr; //起始地址是否页对齐
    uint32_t endAddr;   //结束地址是否页对齐
    uint32_t 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;
    }
    gw_u8 a;
    a = s_ota.s_para.u32FirmwareLen;
    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 i,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;//更新剩余未写长度
        }    
    }
    s_ota.s_para.u8otasuccFlag = 0;
    Svc_Ota_Save_Para();
    Svc_Log_Printf(LOG_INFO,"OTA finish...\r\n");
}


