/*
 * @Description: 
 * @Version: 2.0
 * @Author: Seven
 * @Date: 2023-08-29 14:35:07
 * @LastEditors: Seven
 * @LastEditTime: 2023-12-05 10:25:49
 */
#include "bsp.h"
#include "hamming.h"
#include "at24cXX.h"
#include "update.h"
#include "myflash.h"
#include "ota.h"

uint32_t apb_clken;
uint32_t misc_ctrl;

uint8_t run_led_state = 0;
uint32_t count = 0;
uint16_t read_data_dr2 = 0, write_data_dr2 = 0;
uint8_t updata_flag = 0;
uint32_t read_crc1,read_crc2,read_crc3;
uint32_t get_crc1,get_crc2,get_crc3;
uint32_t datalen1,datalen2,datalen3;
uint8_t app1_check_result,app2_check_result,app3_check_result;
uint8_t app1_check_num=0,app2_check_num=0,app3_check_num=0;
uint8_t jump_flag = 0;
uint32_t update_addr=0,update_len=0;
uint16_t read_data_dr=0;
uint8_t copy_addr=0,update_type;

device_public_info_t device_public_info;
device_mcu_info_t device_mcu_info;
// MqttIdPort mqttidport;

uint32_t Reset_cnt = 0;
uint8_t updata_flag;
__attribute__((weak)) uint32_t FCB_GetPLLFreq(uint32_t clkin_freq);
__attribute__((weak)) void board_init(void)
{
    SYS_DisableJTDI();
    SYS_DisableJTDO();
    SYS_DisableNJTRST();

    INT_Init();
    INT_EnableIntGlobal();
    INT_EnableIntExternal();

  if (FCB_GetPLLFreq) {
    uint32_t freq = BOARD_PLL_FREQUENCY;
    SYS_EnableAPBClock(APB_MASK_FCB0);
    if (FCB_IsActive()) {
      freq = FCB_GetPLLFreq(board_pll_clkin_freq());
    } else {
      FCB_Activate();
    }
    SYS_SetPLLFreq(freq);
  }
  SYS_SwitchPLLClock(board_hse_source());

//   INT_Init(); // This will disabe all interrupts. INT_EnableIRQ should be called after this to enable any external interrupt.
//   INT_EnableIntGlobal();
//   INT_EnableIntExternal();

  SYS_EnableAPBClock(SIM_TXEN_GPIO_MASK);
  //GPIO_SetOutput(SIM_TXEN_GPIO, SIM_12_TXEN_BIT|SIM_13_TXEN_BIT|SIM_14_TXEN_BIT);
  GPIO_SetInput(SIM_TXEN_GPIO, SIM_15_TXEN_BIT);  // IO口状态。Input:MCU'u0 日志输出，Output:SIM15.默认日志口。
  GPIO_SetLow(SIM_TXEN_GPIO, SIM_15_TXEN_BIT);      // 低电平=接收，高电平=发送.默认输入。

}
void bsp_init(void)
{
    SYS_SetHSIConfig(0xf);
    SYS_SwitchHSIClock();

    // Provide a minimal working FPGA configuration to avoid problems if the default configuration is corrupted.
 #ifdef DFU_FPGA_CONFIG
    SYS->APB_CLKENABLE = APB_MASK_FCB0; // Disable all peripherial clocks execpt for FCB to avoid any noise from FPGA
    __attribute__ ((aligned(4))) uint8_t fpga_config[] = {
 #include DFU_FPGA_CONFIG
    };
    FCB_AutoDecompress((uint32_t)fpga_config);
#endif
    SYS_SwitchPLLClock(SYS_HSE_BYPASS_OFF); //use hse
}


//函数功能:设置看门狗复位周期为4秒
void IWDG_Config(void)
{
    uint32_t sleep_ms = (1 << 12) * (1 << (4 + 1)) * RTC_PERIOD / 1000000;
    // printf("Iwdg with pr %d will trigger every %d ms. Will%s freeeze in stop. Will%s freeeze in standby.\n",
    //           4, sleep_ms,
    //           IWDG_FREEZE_STOP & IWDG_STOP_FREEZE    ? "" : " not",
    //           IWDG_FREEZE_STOP & IWDG_STANDBY_FREEZE ? "" : " not");
    RTC_Init(board_rtc_source());
    RTC_SetPrescaler(32768);
    IWDG_SetPrescaler(0x04);
    IWDG_SetFreezeMode(IWDG_FREEZE_STOP);
    IWDG_SetClkSource(IWDG_CLK_SOURCE_LSE);
    IWDG_Enable();
}

//喂狗
void IWDG_feed(void)
{
    IWDG_ReloadCounter();
}


//eeprom上电初始化处理
void eeprom_init_handle(void)
{
	AT24CXX_Read(DEVICE_PUBLIC_INFO_ADDR,(uint8_t *)&device_public_info,sizeof(device_public_info_t));

	AT24CXX_Read(DEVICE_VERSION_INFO_ADDR,(uint8_t *)&device_mcu_info,sizeof(device_mcu_info_t));
	
	AT24CXX_Read(DEVICE_RESET_ADDR,(uint8_t *)&Reset_cnt,4);

    if(device_public_info.eeprom_first_flag != EEPROM_FIRST_FLAG)//第一次读eeprom
    {
        printf("eeprom first init\n");
        Reset_cnt = 0;
        device_public_info.eeprom_first_flag = EEPROM_FIRST_FLAG;
        AT24CXX_Write(DEVICE_PUBLIC_INFO_ADDR,(uint8_t *)&device_public_info.eeprom_first_flag,2);
    }
}

//更新eeprom信息
void eeprom_info_update(void)
{
	Reset_cnt++;
	AT24CXX_Write(DEVICE_RESET_ADDR,(uint8_t *)&Reset_cnt,4);
	
	//如果bt版本不对，写bt版本
	if(device_mcu_info.bootloader_ver != SOFTWARE_VERSION_BOOT)
	{
		device_mcu_info.bootloader_ver = SOFTWARE_VERSION_BOOT;
		AT24CXX_Write(DEVICE_VERSION_INFO_ADDR,(uint8_t *)&device_mcu_info.bootloader_ver,4);
	}
		
	//如果执行过升级或回退，写pt、app1、2、3版本
	if(updata_flag)
	{
		updata_flag = 0;
//		HM_encode((uint8_t *)&device_mcu_info.app1_ver,code_buf,12);
		AT24CXX_Write(DEVICE_VERSION_INFO_ADDR+4,(uint8_t *)&device_mcu_info.pt_ver,16);
	}
}



//设置标记高位取反
//将一个数设置为高八位是低八位的取反
uint16_t set_flag_not(uint16_t data)
{
	uint16_t temp_data,ret_data = 0;
	uint16_t temp_h,temp_l;
	temp_data = data;
	temp_h = ((~temp_data)<<8)&0xff00;
	temp_l = temp_data&0x00ff;
	ret_data = temp_h | temp_l;
	return ret_data;
}

//标记高位取反判断
//0 错误，1 正确
uint8_t flag_not_cmp(uint16_t data)
{
	uint8_t ret = 0;
	uint16_t temp_data;
	uint8_t temp_h,temp_l;
	temp_data = data;
	temp_h = (uint8_t)((temp_data&0xff00)>>8);
	temp_l = (uint8_t)(temp_data&0x00ff);
	if((temp_h^temp_l) == 0xff)
	{
		ret = 1;
	}
	return ret;
}

//crc32校验
uint32_t crc_block_data_calculate(uint32_t *buf, uint32_t len)
{
    uint32_t i,data;
    for(i = 0; i < len; i++)
    {
        CRC_FeedData32(CRC0, buf[i]);
    }
    data = CRC_ReadData32(CRC0);
    return data;
}

/*
对app进行校验
参数：addr：app首地址
	 len: app长度
	 checkdata：计算的crc值
返回：0：校验正确，1：校验失败
*/
uint8_t app_check(uint32_t addr, uint32_t len, uint32_t *checkdata)
{
	uint8_t ret = 0;
	uint32_t datalen,read_crc,get_crc;
	datalen = Flash_DatalenRead(addr,len);
	read_crc = *(uint32_t*)(addr + datalen-4); //CRC校验

    //计算crc32
    SYS_EnableAHBClock(AHB_MASK_CRC0);
    CRC_Reset(CRC0);
    get_crc = crc_block_data_calculate((uint32_t *)addr,(datalen -4)/4);
    SYS_DisableAHBClock(AHB_MASK_CRC0);

    printf("len:<0x%08x,%u>,read_crc:0x%08x,get_crc:0x%08x\n",datalen,datalen,read_crc,get_crc);
	
	*checkdata = get_crc;
	if(read_crc != get_crc)
	{
		ret = 1;
	}
	return ret;
}


/////////////////////////////////////////////////////////////////////////////////
//升级流程
void updatee_process(void)
{
    read_data_dr2 = RTC_ReadBackupRegister(BKP_DR2);
    printf("BKP_DR2=%04x\n",read_data_dr2);
    if(flag_not_cmp(read_data_dr2))
    {
        // read_data_dr=RTC_ReadBackupRegister(2);//升级的固件类型
        // if(read_data_dr == 0x02)//升级产测
		// {
		// 	update_addr = OTA_UPDATE_PT_FLASH_START_ADDR;
		// 	update_len = OTA_UPDATE_PT_FLASH_SIZE;
		// 	copy_addr = UPDATE_ENUM_PT;
		// 	update_type = 2;
		// 	printf("升级产测\n");
		// }
		// else if(read_data_dr == 0x03)//升级app
		// {
		// 	update_addr = OTA_UPDATE_APP1_FLASH_START_ADDR;
		// 	update_len = OTA_UPDATE_APP1_FLASH_SIZE;
		// 	copy_addr = UPDATE_ENUM_APP1;
		// 	update_type = 3;
		// 	printf("升级app\n");
		// }
        // else if(read_data_dr == 0x03)//升级fpga
        // {
        //     update_addr = OTA_UPDATE_FPGA_FLASH_START_ADDR;
		// 	update_len = OTA_UPDATE_FPGA_FLASH_SIZE;
		// 	copy_addr = UPDATE_ENUM_FPGA;
		// 	update_type = 4;
		// 	printf("升级fpga\n");
        // }

        update_addr = OTA_UPDATE_APP1_FLASH_START_ADDR;
        update_len = OTA_UPDATE_APP1_FLASH_SIZE;
        copy_addr = UPDATE_ENUM_APP1;
        update_type = 3;
        printf("升级app\n");

        if((read_data_dr2&0x00ff) == UPDATA_FLAG)//升级
		{
			printf("updata begin\n");
			update_handle();
			
		}
        else if((read_data_dr2&0x00ff) == BACKOFF_FLAG)//回退
        {
            printf("back off begin\n");
            backoff_handle();
        }
        else if((read_data_dr2&0x00ff) == BACKOFF_OVER)//回退失败
		{
			RTC_WriteBackupRegister(BKP_DR2,0x0000);
		}
    }
}

//升级部分
void update_handle(void)
{
    uint8_t i;
    //校验app1
    app1_check_result = app_check(update_addr,update_len,&get_crc1);
    app3_check_result = app_check(OTA_UPDATE_APP3_FLASH_START_ADDR,OTA_UPDATE_APP3_FLASH_SIZE,&get_crc3);

    for(i = 0; i < 2; i++)
    {
        erase_app(UPDATE_ENUM_APP2);
        IWDG_feed(); 
    //			printf("erase app2 end\n");
        copy_app(copy_addr, UPDATE_ENUM_APP2);
        IWDG_feed(); 
    //			printf("copy app1 end\n");
        //校验app2
        app2_check_result = app_check(OTA_UPDATE_APP2_FLASH_START_ADDR,OTA_UPDATE_APP2_FLASH_SIZE,&get_crc2);
        if(get_crc1 != get_crc2)//校验错误，拷贝过程出错
        {
            printf("copy app1 to app2 error\n");
        }
        else{//校验正确
            break;
        }
    }
    
    for(i = 0; i < 2; i++)
    {
        erase_app(copy_addr);
        IWDG_feed();
    //			printf("erase app1 end\n");
        copy_app(UPDATE_ENUM_APP3, copy_addr);
        IWDG_feed(); 
    //			printf("copy app3 end\n");
        app1_check_result = app_check(update_addr,update_len,&get_crc1);
        if(get_crc1 != get_crc3)//校验错误，拷贝过程出错
        {
            printf("copy app3 to app1 error\n");
        }
        else//校验正确
        {
            break;
        }
    }
    
    write_data_dr2 = set_flag_not(BACKOFF_FLAG);
    RTC_WriteBackupRegister(BKP_DR2,write_data_dr2);
    
    if(update_type == 2)//产测
    {
        device_mcu_info.app2_ver = device_mcu_info.pt_ver;
        device_mcu_info.pt_ver = device_mcu_info.app3_ver;
        updata_flag = 1;
    }
    else if(update_type == 3)//app
    {
        device_mcu_info.app2_ver = device_mcu_info.app1_ver;
        device_mcu_info.app1_ver = device_mcu_info.app3_ver;
        updata_flag = 1;
    }
    else if(update_type == 4)//fpga
    {
        device_mcu_info.app2_ver = device_mcu_info.fpga_ver;
        device_mcu_info.fpga_ver = device_mcu_info.app3_ver;
        updata_flag = 1;
    }
}

//回退部分
void backoff_handle(void)
{
    uint8_t i;
    app2_check_result = app_check(OTA_UPDATE_APP2_FLASH_START_ADDR,OTA_UPDATE_APP2_FLASH_SIZE,&get_crc2);

    for(i = 0; i < 2; i++)
    {
        erase_app(copy_addr);
        IWDG_feed();
        copy_app(UPDATE_ENUM_APP2, copy_addr);
        IWDG_feed();
        app1_check_result = app_check(update_addr,update_len,&get_crc1);
        if(get_crc1 != get_crc2)//校验错误，拷贝过程出错
        {
            printf("copy app2 to app1 error\n");
        }
        else//校验正确
        {
            break;
        }
    }
    
    write_data_dr2 = set_flag_not(BACKOFF_OVER);
    RTC_WriteBackupRegister(BKP_DR2,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;
    }
}

void int_disable(void)
{
    uint32_t i;
    for(i = 7; i < 45; i++)
    {
        INT_DisableIRQ(i);
    }
}

void deinit_all(void)
{
    UART_DeInit(UARTx(0));
    SYS_DisableAPBClock(APB_MASK_UARTx(0));
    UART_DeInit(UARTx(1));
    SYS_DisableAPBClock(APB_MASK_UARTx(1));
    UART_DeInit(UARTx(2));
    SYS_DisableAPBClock(APB_MASK_UARTx(2));
    UART_DeInit(UARTx(3));
    SYS_DisableAPBClock(APB_MASK_UARTx(3));
    UART_DeInit(UARTx(4));
    SYS_DisableAPBClock(APB_MASK_UARTx(4));

    GPIO_DisableInt(GPIO6,0b01010101);
    GPIO_DisableInt(GPIO7,0b11101);
    GPIO_DisableInt(GPIO8,0b10101010);
    SYS_DisableAPBClock(APB_MASK_GPIO6);
    SYS_DisableAPBClock(APB_MASK_GPIO7);
    SYS_DisableAPBClock(APB_MASK_GPIO8);


    TIM_DisableInt1(TIMER1);
    TIM_DisableInt1(TIMER0);
    SYS_DisableAPBClock(APB_MASK_TIMER1);
    SYS_DisableAPBClock(APB_MASK_TIMER0);

    INT_DisableIntTimer();

}
//跳转
void run_app(void)
{
    // int_disable();
    // deinit_all();

    UART_DeInit(UARTx(0));
    SYS_DisableAPBClock(APB_MASK_UARTx(0));
    
    // SYS->APB_CLKENABLE = apb_clken;
    // SYS->MISC_CNTL = misc_ctrl;
    // SYS_SwitchHSIClock();
    INT_Init(); 
    SYS_DisableAPBClock(APB_MASK_FCB0 | SIM_TXEN_GPIO_MASK | APB_MASK_GPIO2);
    INT_DisableIntGlobal();

    // SYS_EnableAPBClock(APB_MASK_FCB0);
    // FCB_AutoConfig(DFU_APP_LOGIC_ADDRESS); //restore APP logic
    // //FCB_AutoDecompress(DFU_APP_LOGIC_ADDRESS);
    // SYS_DisableAPBClock(APB_MASK_FCB0);

    run_app1();
}



//升级测试
void update_test(void)
{
    uint16_t temp;
    //置升级标志
    temp = set_flag_not(UPDATA_FLAG);
    RTC_WriteBackupRegister(BKP_UPDATE_FLAG, temp);
    //置升级类型
    temp = set_flag_not(FIRMTYPE_APP);
    RTC_WriteBackupRegister(BKP_UPDATE_FIRM_TYPE, temp);

    SYS_SoftwareReset();
}

//清除升级状态
void clear_update_status(void)
{
    RTC_WriteBackupRegister(BKP_UPDATE_FLAG, 0);
    RTC_WriteBackupRegister(BKP_UPDATE_STATE, 0);
}
