/*
 * @Description: 
 * @Version: 2.0
 * @Author: Seven
 * @Date: 2023-11-09 14:38:52
 * @LastEditors: Seven
 * @LastEditTime: 2023-12-05 15:33:02
 */
#include "ota.h"
#include "update.h"
#include "myflash.h"
#include "delay.h"
#include "type.h"
#include "uart.h"
#include "bsp.h"
#include "lzma_decompress.h"
#include "crc32.h"
#include "bspatch.h"
#include "ota_flash.h"

ota_info_t ota_info;
DFOTA_pkg_header_t dfota_pkg_header;
DFOTA_blk_header_t dfota_blk_header;




// uint8_t test_buf[128] = {0};
// uint32_t test_buf1[128] = {0};

// void my_copy(uint32_t *da,uint32_t len)
// {
//     uint8_t i;
//     for(i = 0; i < len/4; i++)
//     {
//         da[i] = test_buf1[i];
//     }
// }

//升级过程
uint8_t ota_process(void)
{
    uint8_t temp;
    uint32_t i;
    uint8_t blk_ret;
    uint32_t get_crc3;
    U32_U8 header_buff[24] = {0};
    uint32_t blk_addr = 0;
    uint32_t blk_len = 0;
    uint8_t blk_res;
    
    // image_header_t ih;
    uint32_t uimage_addr;
    uint32_t size, dcrc, crc, ocrc;
    uint32_t app_addr, image_len, unpk_len;
    uint8_t *image_p, *patch_p;
    uint8_t *buff;
    vFile* vfp;
    uint32_t old_size;
    uint32_t new_file;

    uint8_t bk_buf[4];
    uint32_t bk_len=0,len1=0;
    
    // DFOTA_pkg_header_t *pkg_header = (DFOTA_pkg_header_t *)header_buff;

    if(app_check(OTA_UPDATE_APP3_FLASH_START_ADDR,OTA_UPDATE_APP3_FLASH_SIZE,&get_crc3))//校验错误
    {
        printf("app3校验错误\n");
        return OTA_RET_APP3_CRC_ERR;
    }
        

    memset(&dfota_pkg_header,0,PKG_HEADER_LEN);
    Flash_BufferRead(OTA_UPDATE_APP3_FLASH_START_ADDR,(uint32_t *)header_buff,PKG_HEADER_LEN);//读升级包开头24字节
    memcpy(&dfota_pkg_header,header_buff,PKG_HEADER_LEN);

    
    if(strstr(dfota_pkg_header.pkg_magic,"DFOTA"))//合成包
    {
        printf("合成包\n");
        blk_addr = 24;//头 24字节
        while((dfota_pkg_header.pkg_size-8) >= blk_addr)
        {
            blk_ret = blk_check(OTA_UPDATE_APP3_FLASH_START_ADDR+blk_addr,&blk_len);
            printf("blk_ret:%d\n",blk_ret);
            if(blk_ret == 0)//是当前块
            {
                blk_res = 1;
                break;
            }
            if((blk_len > 256*1024) || (blk_len <= BLK_HEADER_LEN))//块错误，退出
            {
                blk_res = 0;
                break;
            }
            blk_addr += blk_len;
        }
        if(blk_res)//找到对应的块
        {
            if((dfota_blk_header.z_flag==0) && (dfota_blk_header.d_flag==0))//未压缩，未差分
            {
                printf("未压缩未差分\n");
                //直接拷贝
                erase_app(ota_info.update_enum);//擦除APP1
                ota_info.erase_app1 = 1;
                app_addr = (OTA_UPDATE_APP3_FLASH_START_ADDR+blk_addr+BLK_HEADER_LEN);//升级包的首地址
                size = blk_len - BLK_HEADER_LEN - dfota_blk_header.pad_size - 4;//升级文件大小
                copy_app_specify_length(ota_info.update_enum,app_addr,size);

                if(!update_pkg_crc_check(ota_info.update_enum,size,dfota_blk_header.new_crc32))//升级后的crc校验错误
                {
                    printf("升级后的crc校验错误\n");
                    return OTA_RET_NEWCRC_ERR;
                }
                printf("升级完成\n");
                return OTA_RET_SUCCESS;
            }
            else if((dfota_blk_header.z_flag==1) && (dfota_blk_header.d_flag==0))//LZMA压缩，未差分
            {
                printf("压缩未差分\n");
                //分配内存
                buff = (uint8_t *)malloc(FLASH_PAGE_SIZE*8+4);
                if(NULL == buff) 
                    return OTA_RET_NEWSIZE_ERR;
                
                erase_app(ota_info.update_enum);//擦除APP1
                ota_info.erase_app1 = 1;
                //解压uzimage的数据段
                // image_p = flash_read_fp(flash_bak, IAP_BAK_ADDR + UIMAGE_HEADER_LEN);
                image_p = (uint8_t *)(OTA_UPDATE_APP3_FLASH_START_ADDR+blk_addr+BLK_HEADER_LEN);//压缩包的首地址
                size = blk_len - BLK_HEADER_LEN - dfota_blk_header.pad_size - 4;//压缩文件大小
                vfp = vfopen(image_p, size);
                app_addr = 0;
                image_len = 0;
                bk_len = 0;
                while(1)
                {
                    unpk_len = lzma_decompress_read(vfp, buff+bk_len, FLASH_PAGE_SIZE*8);
                    if(bk_len)
                    {
                        memcpy(buff,bk_buf,bk_len);
                    }
                    len1 = unpk_len+bk_len;
                    if(len1%4)//len长度不是4的整数倍
                    {
                        bk_len = len1%4;
                        memcpy(bk_buf,buff+len1-bk_len,bk_len);//剩余的字节备份
                    }
                    else
                    {
                        bk_len = 0;
                    }
                    len1 -= bk_len;

                    printf("i=%u,unpk_len:%u,write_len:%u\n",i++,unpk_len,len1);
                    if(unpk_len == 0)break;
                    
                    if((app_addr > 256*1024) || (app_addr > dfota_blk_header.new_size)) break;
                    if((app_addr < dfota_blk_header.new_size) && ((app_addr+len1) > dfota_blk_header.new_size))
                    {
                        len1 = dfota_blk_header.new_size-app_addr;
                    }
                    flash_write_without(ota_info.update_enum, app_addr, buff, len1);
                    app_addr += len1;
                    image_len += unpk_len;
                }
                free(buff);
                printf("new_size:<0x%08x,%u>,image_len:<0x%08x,%u>\n",dfota_blk_header.new_size,dfota_blk_header.new_size,app_addr,app_addr);
                if(dfota_blk_header.new_size != app_addr)//解压后的字节数错误
                {
                    printf("解压后的字节数错误\n");
                    return OTA_RET_NEWSIZE_ERR;
                }
                if(!update_pkg_crc_check(ota_info.update_enum,app_addr,dfota_blk_header.new_crc32))//解压后的crc校验错误
                {
                    printf("解压后的crc校验错误\n");
                    return OTA_RET_NEWCRC_ERR;
                }
                printf("升级完成\n");
                return OTA_RET_SUCCESS;
            }
            else if((dfota_blk_header.z_flag==1) && (dfota_blk_header.d_flag==1))//LZMA压缩，diff差分
            {
                printf("压缩并差分\n");
                if(ota_info.old_size != dfota_blk_header.old_size)
                {
                    printf("旧固件长度错误\n");
                    return OTA_RET_OLDSIZE_ERR;
                }
                printf("old_crc_get:0x%08x,old_crc_read:0x%08x\n",ota_info.old_crc32,dfota_blk_header.old_crc32);
                if(ota_info.old_crc32 != dfota_blk_header.old_crc32)
                {
                    printf("旧固件crc校验错误\n");
                    return OTA_RET_OLDCRC_ERR;
                }

                erase_app(ota_info.update_enum);//擦除APP1
                ota_info.erase_app1 = 1;
                //将差分包和APP合并,数据保存到备份区
                // image_p = flash_read_fp(flash_bak, IAP_BAK_ADDR + UIMAGE_HEADER_LEN);
                flash_addr_get(ota_info.update_enum,0,0,&new_file);//new_file 差分后写入的flash地址
                size = blk_len - BLK_HEADER_LEN - dfota_blk_header.pad_size - 4;//压缩文件大小
                patch_p = (uint8_t *)(OTA_UPDATE_APP3_FLASH_START_ADDR+blk_addr+BLK_HEADER_LEN);//压缩包的首地址
                image_p = (uint8_t *)(OTA_UPDATE_APP2_FLASH_START_ADDR);//旧固件的首地址
                old_size = ota_info.old_size;//旧固件的大小
                image_len = iap_patch(image_p, old_size, patch_p, size, new_file);

                printf("new_size:<0x%08x,%u>,image_len:<0x%08x,%u>\n",dfota_blk_header.new_size,dfota_blk_header.new_size,image_len,image_len);
                if(dfota_blk_header.new_size != image_len)//解压后的字节数错误
                {
                    printf("解压后的字节数错误\n");
                    return OTA_RET_NEWSIZE_ERR;
                }
                if(!update_pkg_crc_check(ota_info.update_enum,image_len,dfota_blk_header.new_crc32))//解压后的crc校验错误
                {
                    printf("解压后的crc校验错误\n");
                    return OTA_RET_NEWCRC_ERR;
                }
                printf("升级完成\n");
                return OTA_RET_SUCCESS;
            }
        }
        else
        {
            return OTA_RET_NO_BLK_ERR;
        }
        
    }
    else//原始bin文件
    {
        printf("原始包\n");
        //直接拷贝
        erase_app(ota_info.update_enum);//擦除APP1
        ota_info.erase_app1 = 1;
        temp = firmware_tail_check(UPDATE_ENUM_APP3,&size);
        printf("size=%d\n",size);
        if(temp)//包含尾部20字节
        {
            size -= 20;
        }
        // app_addr = (OTA_UPDATE_APP3_FLASH_START_ADDR);//升级包的首地址
        // size = ota_info.old_size;//升级文件大小
        copy_app_specify_length(ota_info.update_enum,OTA_UPDATE_APP3_FLASH_START_ADDR,size);

        return OTA_RET_SUCCESS;
    }

    // for(i = 0; i < 128; i++)
    // {
    //     test_buf[i] = rand()%0x100;
    //     test_buf1[i] = rand()%0xffffffff;
    //     printf("%08x ",test_buf1[i]);
    // }
    // printf("\n");
    // // data_dump("u",test_buf,128);
    // // memcpy(header_buff,test_buf,24);
    // my_copy((uint32_t *)header_buff,32);
    // memcpy(&dfota_pkg_header,header_buff,24);
    // data_dump("magic",pkg_header->pkg_magic,16);
    // printf("pkg_time=0x%08x\n",pkg_header->pkg_time);
    // data_dump("magic1",dfota_pkg_header.pkg_magic,16);
    // printf("pkg_time1=0x%08x\n",dfota_pkg_header.pkg_time);
}


//块校验
uint8_t blk_check(uint32_t addr, uint32_t *len)
{
    uint32_t get_blk;
    U32_U8 buff[44] = {0};
    // DFOTA_blk_header_t *blk_header = (DFOTA_blk_header_t *)buff;
    memset(&dfota_blk_header,0,BLK_HEADER_LEN);
    Flash_BufferRead(addr,(uint32_t *)buff,BLK_HEADER_LEN);//读块开头40字节
    memcpy(&dfota_blk_header,buff,BLK_HEADER_LEN);
    *len = dfota_blk_header.blk_size;
    printf("new_ver:0x%08x,new_size:0x%08x,new_crc:0x%08x,new_ep:0x%08x\n",dfota_blk_header.new_ver,dfota_blk_header.new_size,\
    dfota_blk_header.new_crc32,dfota_blk_header.new_ep);
    if(!strstr(dfota_blk_header.blk_magic,"BLOK"))//魔数，块标记错误
    {
        return 1; 
    }
    if(app_check(addr,dfota_blk_header.blk_size,&get_blk))//校验错误
    {
        return 2;
    }
    if((dfota_blk_header.d_flag) && (dfota_blk_header.old_ver != ota_info.old_ver))//差分且旧版本号不一致
    {
        return 3;
    }
    return 0;
}

//判断固件中是否包含尾部20字节
//返回值    1 包含；0 不包含
uint8_t firmware_tail_check(uint32_t part, uint32_t *firm_len)
{
    uint32_t addr,addr_len;
    uint32_t read_len;

    uint32_t crcVl,fixChar,fileVer,filelen,fileaddr;
	uint32_t getcrc;
    switch(part)
    {
        case UPDATE_ENUM_BOOT:
            addr = OTA_UPDATE_BOOTROM_FLASH_START_ADDR;
            addr_len = OTA_UPDATE_BOOTROM_SIZE;
        break;
        case UPDATE_ENUM_PT:
            addr = OTA_UPDATE_PT_FLASH_START_ADDR;
            addr_len = OTA_UPDATE_PT_FLASH_SIZE;
        break;
        case UPDATE_ENUM_APP1:
            addr = OTA_UPDATE_APP1_FLASH_START_ADDR;
            addr_len = OTA_UPDATE_APP1_FLASH_SIZE;
        break;
        case UPDATE_ENUM_APP2:
            addr = OTA_UPDATE_APP2_FLASH_START_ADDR;
            addr_len = OTA_UPDATE_APP2_FLASH_SIZE;
        break;
        case UPDATE_ENUM_APP3:
            addr = OTA_UPDATE_APP3_FLASH_START_ADDR;
            addr_len = OTA_UPDATE_APP3_FLASH_SIZE;
        break;
        default:
            return 0;
        break;
    }

    read_len = Flash_DatalenRead(addr,addr_len);
    *firm_len = read_len;

    crcVl = *(uint32_t*)(addr+read_len-4); //CRC校验
    fixChar = *(uint32_t*)(addr+read_len-8); // 固定字符 WBJW
    fileVer = *(uint32_t*)(addr+read_len-12); // 固件版本信息
	fileaddr = *(uint32_t*)(addr+read_len-16); // 存储地址
    filelen = *(uint32_t*)(addr+read_len-20); // 文件总长度

    printf("read_crc:%x, get_crc:%x\n",crcVl,getcrc);
    printf("read_filelen:%08x, total_bytes:%08x\n",filelen,(read_len-20));
    printf("read_fixchar:%08x, fixchar:%08x\n",fixChar,WBJW);
    if(WBJW != fixChar)//固定字符错误
        return 0;
    printf("read_filelen:%08x, total_bytes:%08x\n",filelen,(read_len-20));
    if(read_len != (filelen+20))//长度错误
        return 0;

    //计算crc32
    SYS_EnableAHBClock(AHB_MASK_CRC0);
    CRC_Reset(CRC0);
    getcrc = crc_block_data_calculate((uint32_t *)addr,(read_len -4)/4);
    printf("read_crc:%x, get_crc:%x\n",crcVl,getcrc);
    if(getcrc!=crcVl)  //校验错误
        return 0;

    return 1;
}

//备份
uint8_t app_backup(void)
{
    uint8_t ret = 0;
    erase_app(UPDATE_ENUM_APP2);
    printf("firm:%d\n",ota_info.firmware_type);
    switch(ota_info.firmware_type)
    {
        case FIRMTYPE_PT:
            copy_app(UPDATE_ENUM_PT, UPDATE_ENUM_APP2);
            device_mcu_info.app2_ver = device_mcu_info.pt_ver;
            device_mcu_info.pt_ver = device_mcu_info.app3_ver;
        break;
        case FIRMTYPE_APP:
            copy_app(UPDATE_ENUM_APP1, UPDATE_ENUM_APP2);
            device_mcu_info.app2_ver = device_mcu_info.app1_ver;
            device_mcu_info.app1_ver = device_mcu_info.app3_ver;
        break;
        default:
            ret = 1;
        break;
    }
    return ret;
}

//计算老版本信息
void old_firm_info_cal(void)
{
    uint32_t temp;
    
    switch(ota_info.firmware_type)
    {
        case FIRMTYPE_PT:
            ota_info.old_ver = device_mcu_info.pt_ver;
            ota_info.old_size = Flash_DatalenRead(OTA_UPDATE_PT_FLASH_START_ADDR,OTA_UPDATE_PT_FLASH_SIZE);
            SYS_EnableAHBClock(AHB_MASK_CRC0);
            CRC_Reset(CRC0);
            ota_info.old_crc32 = crc_block_data_calculate((uint32_t *)OTA_UPDATE_PT_FLASH_START_ADDR,ota_info.old_size/4);
            ota_info.update_enum = UPDATE_ENUM_PT;
            ota_info.tail_flag = firmware_tail_check(UPDATE_ENUM_PT,&temp);
        break;
        case FIRMTYPE_APP:
            ota_info.old_ver = device_mcu_info.app1_ver;
            ota_info.old_size = Flash_DatalenRead(OTA_UPDATE_APP1_FLASH_START_ADDR,OTA_UPDATE_APP1_FLASH_SIZE);
            SYS_EnableAHBClock(AHB_MASK_CRC0);
            CRC_Reset(CRC0);
            ota_info.old_crc32 = crc_block_data_calculate((uint32_t *)OTA_UPDATE_APP1_FLASH_START_ADDR,ota_info.old_size/4);
            ota_info.update_enum = UPDATE_ENUM_APP1;
            ota_info.tail_flag = firmware_tail_check(UPDATE_ENUM_APP1,&temp);
            printf("old_size:<0x%08x,%u>,old_crc:0x%08x\n",ota_info.old_size,ota_info.old_size,ota_info.old_crc32);
        break;
        default:
            
        break;
    }
}

//回退
void ota_backoff(uint8_t update_type)
{
    uint16_t write_data_dr2;
    uint8_t part;
    if(update_type == 2)//产测
    {
        part = UPDATE_ENUM_PT;
    }
    else if(update_type == 3)//app
    {
        part = UPDATE_ENUM_APP1;
    }
    else
    {
        return;
    }
    erase_app(part);
    copy_app(UPDATE_ENUM_APP2,part);
    write_data_dr2 = set_flag_not(BACKOFF_OVER);
    RTC_WriteBackupRegister(BKP_UPDATE_FLAG,write_data_dr2);

    if(update_type == 2)//产测
    {
        device_mcu_info.pt_ver = device_mcu_info.app2_ver;
        updata_flag = 1;
    }
    else if(update_type == 3)//app
    {
        device_mcu_info.app1_ver = device_mcu_info.app2_ver;
        updata_flag = 1;
    }
    else if(update_type == 4)//fpga
    {
        device_mcu_info.fpga_ver = device_mcu_info.app2_ver;
        updata_flag = 1;
    }
}

//IAP主程序
void myiap_task(void)
{
    uint8_t p_ret;
    uint16_t write_data_dr2;
    uint16_t data_dr1,data_dr2,data_dr3;
    data_dr1 = RTC_ReadBackupRegister(BKP_UPDATE_FLAG);//升级标志
    printf("BKP_UPDATE_FLAG=%04x\n",data_dr1);
    if(flag_not_cmp(data_dr1))
    {
        data_dr2 = RTC_ReadBackupRegister(BKP_UPDATE_FIRM_TYPE);//升级固件类型
        printf("BKP_UPDATE_FIRM=%04x\n",data_dr2);
              
        if((data_dr1&0x00ff) == UPDATA_FLAG)//升级
		{  
            if(!flag_not_cmp(data_dr2))//升级固件类型错误
            {
                printf("升级固件类型错误\n");
                write_data_dr2 = set_flag_not(UPDATE_ERR);
                RTC_WriteBackupRegister(BKP_UPDATE_FLAG,write_data_dr2);

                write_data_dr2 = set_flag_not(OTA_RET_FIRMWARE_ERR);
                RTC_WriteBackupRegister(BKP_UPDATE_STATE,write_data_dr2);
                return;
            }
            memset(&ota_info,0,sizeof(ota_info_t));
            ota_info.firmware_type = data_dr2&0x00ff;
            old_firm_info_cal();//计算旧固件信息
            if(app_backup()==0)//备份成功
            {
                printf("updata begin\n");
			    p_ret = ota_process();
                if(p_ret == OTA_RET_SUCCESS)//升级成功
                {
                    updata_flag = 1;
                    write_data_dr2 = set_flag_not(BACKOFF_FLAG);
                    RTC_WriteBackupRegister(BKP_UPDATE_FLAG,write_data_dr2);

                    // printf("read update flag:%04x\n",RTC_ReadBackupRegister(BKP_UPDATE_FLAG));
                }
                else//升级失败
                {
                    if(ota_info.erase_app1)//app1已经擦除，需要回退
                    {
                        ota_info.erase_app1 = 0;
                        ota_backoff(ota_info.firmware_type);//回退
                    }

                    write_data_dr2 = set_flag_not(UPDATE_ERR);
                    RTC_WriteBackupRegister(BKP_UPDATE_FLAG,write_data_dr2);

                    write_data_dr2 = set_flag_not(p_ret);
                    RTC_WriteBackupRegister(BKP_UPDATE_STATE,write_data_dr2);
                }
            }
            else
            {
                printf("升级固件类型错误1\n");
                write_data_dr2 = set_flag_not(UPDATE_ERR);
                RTC_WriteBackupRegister(BKP_UPDATE_FLAG,write_data_dr2);

                write_data_dr2 = set_flag_not(OTA_RET_FIRMWARE_ERR);
                RTC_WriteBackupRegister(BKP_UPDATE_STATE,write_data_dr2);
            }
		}
        else if((data_dr1&0x00ff) == BACKOFF_FLAG)//回退
        {
            if(!flag_not_cmp(data_dr2))//升级固件类型错误
            {
                printf("升级固件类型错误\n");
                write_data_dr2 = set_flag_not(UPDATE_ERR);
                RTC_WriteBackupRegister(BKP_UPDATE_FLAG,write_data_dr2);

                write_data_dr2 = set_flag_not(OTA_RET_FIRMWARE_ERR);
                RTC_WriteBackupRegister(BKP_UPDATE_STATE,write_data_dr2);
                return;
            }
            ota_info.firmware_type = data_dr2&0x00ff;

            printf("back off begin\n");
            ota_backoff(ota_info.firmware_type);
        }
        else if((data_dr1&0x00ff) == BACKOFF_OVER)//回退失败
		{
			RTC_WriteBackupRegister(BKP_UPDATE_FLAG,0x0000);
		}
        else
        {
            RTC_WriteBackupRegister(BKP_UPDATE_FLAG,0x0000);
        }
    }
}

