/*
 * @Description: 
 * @Version: 2.0
 * @Author: Seven
 * @Date: 2023-08-29 11:44:39
 * @LastEditors: Seven
 * @LastEditTime: 2023-11-17 17:18:59
 */
#include "update.h"
#include "myflash.h"
#include "delay.h"
#include "type.h"
#include "bsp.h"
#include "mylib.h"

extern void IWDG_feed(void);

//擦除app
int erase_app(uint8_t app_num)
{
    uint32_t FlashAddress = 0;
    uint32_t Size = OTA_UPDATE_APP_FLASH_SIZE;
    switch (app_num)
    {
        case UPDATE_ENUM_APP1:
            FlashAddress = OTA_UPDATE_APP1_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_APP2:
            FlashAddress = OTA_UPDATE_APP2_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_APP3:
            FlashAddress = OTA_UPDATE_APP3_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_PT:
            FlashAddress = OTA_UPDATE_PT_FLASH_START_ADDR;
            Size = OTA_UPDATE_PT_FLASH_SIZE;
        break;
        case UPDATE_ENUM_FPGA:
            FlashAddress = OTA_UPDATE_FPGA_FLASH_START_ADDR;
            Size = OTA_UPDATE_FPGA_FLASH_SIZE;
        break;
    
        default:
            return -1;
        break;
    }
    Flash_RangeErase(FlashAddress, Size);
    return 0;
}


//复制
int copy_app(uint8_t from, uint8_t to)
{
    uint32_t FromFlashAddress = 0;
    uint32_t Size;
    uint32_t Size_p = OTA_UPDATE_APP_FLASH_SIZE;
    uint32_t ToFlashAddress = 0;
    uint32_t buffer[256];
    int size;
    switch(from)
    {
        case UPDATE_ENUM_APP1:
            FromFlashAddress = OTA_UPDATE_APP1_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_APP2:
            FromFlashAddress = OTA_UPDATE_APP2_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_APP3:
            FromFlashAddress = OTA_UPDATE_APP3_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_PT:
            FromFlashAddress = OTA_UPDATE_PT_FLASH_START_ADDR;
			Size_p = OTA_UPDATE_PT_FLASH_SIZE;
        break;
        case UPDATE_ENUM_FPGA:
            FromFlashAddress = OTA_UPDATE_FPGA_FLASH_START_ADDR;
            Size_p = OTA_UPDATE_FPGA_FLASH_SIZE;
        break;
        default:
        return -1;
    }

    switch (to)
    {
        case UPDATE_ENUM_APP1:
            ToFlashAddress = OTA_UPDATE_APP1_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_APP2:
            ToFlashAddress = OTA_UPDATE_APP2_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_APP3:
            ToFlashAddress = OTA_UPDATE_APP3_FLASH_START_ADDR;
        break;
        case UPDATE_ENUM_PT:
            ToFlashAddress = OTA_UPDATE_PT_FLASH_START_ADDR;
			// Size_p = OTA_UPDATE_PT_FLASH_SIZE;
        break;
        case UPDATE_ENUM_FPGA:
            ToFlashAddress = OTA_UPDATE_FPGA_FLASH_START_ADDR;
			// Size_p = OTA_UPDATE_FPGA_FLASH_SIZE;
        break;
        default:
        return -1;
    }
    Size = Flash_DatalenRead(FromFlashAddress,Size_p);
    size = Size;
    // printf("size = %u\n",size);

    while(size > 0)
    {
        Flash_BufferRead(FromFlashAddress, buffer, 1024);
		Flash_BufferWrite(ToFlashAddress, buffer, 1024);
		FromFlashAddress += 1024;
		ToFlashAddress += 1024;		
		size -= 1024;
    }
    return 0;
}

//拷贝app指定长度
int copy_app_specify_length(UPDATE_ENUM to, uint32_t addr, uint32_t len)
{
    uint32_t from_addr;
    uint32_t phy_addr;
    uint32_t buffer[256];
    int size; 
    uint32_t addr_len;
    printf("len=%d\n",len);
    if(len%4) return(FALSE);
    if(FALSE == flash_addr_get(to, 0, len, &phy_addr))return(FALSE);
    size = len;
    from_addr = addr;
    while(size > 0)
    {
        IWDG_feed();
        len = (size > 1024) ? 1024 : size;
        
        Flash_BufferRead(from_addr, buffer, len);
        // printf("len=%d\n",len);
		Flash_BufferWrite(phy_addr, buffer, len);
		phy_addr += len;
		from_addr += len;		
		size -= len;
    }
    return TRUE;
}

/**
 * @brief 获取FLASH数据地址
 * @details 将FALSH分区地址转换为物理地址
 *
 * @param  part 分区号
 * @param  addr 分区内数据相对地址
 * @param  len 要操作的数据长度
 * @param  *phy_addr 返回的物理地址
 * @return 操作的数据是否在分区内
 *   @retval TRUE 合法的操作
 *   @retval FALSE 非法的操作
 */
int flash_addr_get(UPDATE_ENUM part, uint32_t addr, uint32_t len, uint32_t *phy_addr)
{
    switch(part)                               //检查存储类型
    {
    case UPDATE_ENUM_BOOT:
        if((addr + len) > OTA_UPDATE_BOOTROM_SIZE) return(FALSE);
        *phy_addr = OTA_UPDATE_BOOTROM_FLASH_START_ADDR + addr;
        break;

    case UPDATE_ENUM_PT:
        if((addr + len) > OTA_UPDATE_PT_FLASH_SIZE)return(FALSE);
        *phy_addr = OTA_UPDATE_PT_FLASH_START_ADDR + addr;
        break;
    
    case UPDATE_ENUM_APP1:
        if((addr + len) > OTA_UPDATE_APP1_FLASH_SIZE)return(FALSE);
        *phy_addr = OTA_UPDATE_APP1_FLASH_START_ADDR + addr;
        break;    

    case UPDATE_ENUM_APP2:
        if((addr + len) > OTA_UPDATE_APP2_FLASH_SIZE)return(FALSE);
        *phy_addr = OTA_UPDATE_APP2_FLASH_START_ADDR + addr;
        break;
    
    case UPDATE_ENUM_APP3:
        if((addr + len) > OTA_UPDATE_APP3_FLASH_SIZE)return(FALSE);
        *phy_addr = OTA_UPDATE_APP3_FLASH_START_ADDR + addr;
        break;

    default:
        return(FALSE);
    }
    return(TRUE);
}

/**
 * @brief 分区数据写入
 * @details 当前分区数据写入,不支持非对齐写入
 *
 * @param  part 分区号
 * @param  addr 相对地址
 * @param  p 数据指针
 * @param  len 数据长度
 * @return 操作结果
 *   @retval 无 
 */
int flash_write_without(UPDATE_ENUM app_num, uint32_t addr, const void *p, uint32_t len)
{
    uint32_t phy_addr;
    U32_U8 dat;
    // uint8_t *datp = (uint8_t*)p;
    uint32_t *datp = (uint32_t *)p;
    int i;    
    
    if(FALSE == flash_addr_get(app_num, addr, len, &phy_addr))
    {
        printf("write addr err\n");
        return(FALSE);
    }
    
    IWDG_feed();
    // FLASH_Unlock();
    if((phy_addr % 4) != 0)
    {
        printf("write len err\n");
        return(FALSE);
    }

    Flash_BufferWrite(phy_addr,(uint32_t *)datp,len);
    
    // while(len)
    // {
    //     dat.d32 = 0xFFFFFFFF;
    //     for(i = 0; i < 4; i++)
    //     {
    //         if(len > 0)
    //         {
    //             dat.d8[i] = *(datp++);
    //             len--;
    //         }
    //     }
    //     // FLASH_ProgramWord(phy_addr, dat.d32); //按字写入
    //     // FLASH_FastProgram(phy_addr, dat.d32, 4);//按字写入
    //     // Flash_BufferWrite(phy_addr,(uint32_t *)&dat.d32,4);
    //     phy_addr += 4;
    //     //每写入1K数据,喂一次狗
    //     if(0 == (phy_addr & 0x3FF))
    //     {
    //         IWDG_feed();
    //     }
    // }
    // FLASH_Lock();
    
    return(TRUE);
}



/**
 * @brief 分区数据写入
 * @details 当前分区数据写入,支持非对齐写入,写之前不需要擦除
 *
 * @param  part 分区号
 * @param  addr 相对地址
 * @param  p 数据指针
 * @param  len 数据长度
 * @return 操作结果
 *   @retval 无 
 */
// int flash_write_1(UPDATE_ENUM part, uint32_t addr, const void *p, uint32_t len)
// {
//     uint32_t pg, pd, offset;
//     uint32_t page_addr, phy_addr;
//     uint8_t  *buff;
//     uint8_t *datp = (uint8_t*)p;

//     if(FALSE == flash_addr_get(part, addr, len, &phy_addr))return(FALSE);

//     IWDG_feed();
//     //申请内存
//     buff = (uint8_t *)malloc(FLASH_SECTOR_SIZE);
//     if(NULL == buff)
//     {
//         printk("FLASH:memory allocation failure...\r\n");
//         return(FALSE);
//     }

//     FLASH_Unlock();							    //解锁FLASH编写擦除控制器
//     pg = phy_addr / FLASH_SECTOR_SIZE;            //计算扇区号
//     offset = phy_addr % FLASH_SECTOR_SIZE;        //计算扇区内偏移
//     pd = FLASH_SECTOR_SIZE - offset;          	//计算当前地址所在的扇区还可以写多少字节
//     if(len <= pd)pd = len;                 		//判断数据是否在当前页内
//     page_addr = pg * FLASH_SECTOR_SIZE;	        //计算扇区物理地址
//     // flash_page_read(page_addr, buff);		    //读取数据
//     Flash_BufferRead(page_addr,buff,FLASH_SECTOR_SIZE);//读取数据

//     //判断要写入的区域是否为0xFF
//     if((FALSE == mylib_memcmp_b(buff + offset, 0xFF, pd)) || (offset % 4))
//     {
//         // FLASH_ErasePage(page_addr);		    //擦除一个扇区
//     }
//     memcpy(buff + offset, datp, pd);		    //修改数据
//     flash_page_write(page_addr, buff);		    //写入数据

//     len -= pd;                         		    //判断剩下的数据长度
//     datp += pd;                                 //移动数据指针
//     while(len)                            		//如果没有写完,写到下一页
//     {
//         pg++;                           		//扇区号指向下一扇区
//         page_addr = pg * FLASH_PAGE_SIZE;	    //计算物理地址
//         if(len >= FLASH_PAGE_SIZE)            	//如果剩下的数据大于扇区长度
//         {
//             flash_page_read(page_addr, buff);  //读取该扇区
//             //判断要写入的区域是否为0xFF
//             if(FALSE == mylib_memcmp_b(buff, 0xFF, FLASH_PAGE_SIZE))
//             {
//                 FLASH_ErasePage(page_addr);    //擦除一个扇区
//             }
//             flash_page_write(page_addr, datp); //写入数据
//             len -= FLASH_PAGE_SIZE;
//             datp += FLASH_PAGE_SIZE;
//         }
//         else
//         {
//             flash_page_read(page_addr, buff);  //读取该扇区
//             //判断要写入的区域是否为0xFF
//             if(FALSE == mylib_memcmp_b(buff, 0xFF, len))
//             {
//                 FLASH_ErasePage(page_addr);    //擦除一个扇区
//             }
//             memcpy(buff, datp, len);            //修改数据
//             flash_page_write(page_addr, buff); //写入数据
//             len = 0;
//         }
//     }
//     FLASH_Lock();
//     free(buff);
    
//     return(TRUE);
// }



/*
升级包校验判断
*/
int update_pkg_crc_check(UPDATE_ENUM part, uint32_t len, uint32_t check_crc)
{
    uint32_t get_crc;
    uint32_t phy_addr;
    if(FALSE == flash_addr_get(part, 0, len, &phy_addr))return(FALSE);

    //计算crc32
    SYS_EnableAHBClock(AHB_MASK_CRC0);
    CRC_Reset(CRC0);
    get_crc = crc_block_data_calculate((uint32_t *)phy_addr,len/4);
    printf("len:<0x%08x,%u>,read_crc:0x%08x,get_crc:0x%08x\n",len,len,check_crc,get_crc);

    if(get_crc == check_crc)
        return (TRUE);
    else
        return (FALSE);
}


//跳转
uint32_t run_app1(void)
{
    uint32_t appxaddr = OTA_UPDATE_APP1_FLASH_START_ADDR;
    printf("jump to 0x%08X\r\n",appxaddr);
    delay_us(1200);
    
    UTIL_JumpToAddress(appxaddr);
}
