#include "leaf_ota.h"
#include "usart.h"
#include "stdio.h"
#include "string.h"
#include "TerminalSlave485.h"
#include "md5c.h"
#include "main.h"
/**
  * @brief  根据输入的地址给出它所在的sector
  *					例如：
						uwStartSector = GetSector(FLASH_USER_START_ADDR);
						uwEndSector = GetSector(FLASH_USER_END_ADDR);	
  * @param  Address：地址
  * @retval 地址所在的sector
  */
static uint32_t GetSector(uint32_t Address)
{
  uint32_t sector = 0;
  
  if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
  {
    sector = FLASH_SECTOR_0;  
  }
  else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
  {
    sector = FLASH_SECTOR_1;  
  }
  else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
  {
    sector = FLASH_SECTOR_2;  
  }
  else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
  {
    sector = FLASH_SECTOR_3;  
  }
  else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
  {
    sector = FLASH_SECTOR_4;  
  }
  else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
  {
    sector = FLASH_SECTOR_5;  
  }
  else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
  {
    sector = FLASH_SECTOR_6;  
  }
  else/*(Address < FLASH_END_ADDR) && (Address >= ADDR_FLASH_SECTOR_23))*/
  {
    sector = FLASH_SECTOR_7;  
  }
  return sector;
}


//uint8_t Erase_page(uint32_t pageaddr, uint32_t num)
//{
//  /*要擦除的起始扇区(包含)及结束扇区(不包含)，如8-12，表示擦除8、9、10、11扇区*/
//	uint32_t FirstSector = 0;
//	uint32_t NbOfSectors = 0;
//	uint32_t SECTORError = 0;
//	static FLASH_EraseInitTypeDef EraseInitStruct;
//	__disable_irq();
//	HAL_FLASH_Unlock();
//	
//	FirstSector = GetSector(pageaddr);
//	NbOfSectors = GetSector(num)- FirstSector + 1;
//	/* 擦除用户区域 (用户区域指程序本身没有使用的空间，可以自定义)**/
//	/* Fill EraseInit structure*/
//	EraseInitStruct.TypeErase     = FLASH_TYPEERASE_SECTORS;
//	EraseInitStruct.VoltageRange  = FLASH_VOLTAGE_RANGE_3;/* 以“字”的大小进行操作 */ 
//	EraseInitStruct.Sector        = FirstSector;
//	EraseInitStruct.NbSectors     = 1;
//	/* 开始擦除操作 */
//	if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
//	{
//		/*擦除出错，返回，实际应用中可加入处理 */
//		return -1;
//	}
//	
//	
//	HAL_FLASH_Lock();
//	__enable_irq();
//	return 1;
//}


int App2_MD5_Check(uint32_t addr,unsigned int all_len)
{
	unsigned char digest[16];
//	unsigned char *md5_ptr=(unsigned char *)(StartMode_Addr+72);
	unsigned int i,update_len;
	MD5_CTX md5c;
	all_len -= 16;
	MD5Init(&md5c);
	for(i=0;i<all_len;)
	{
		if(all_len>(i+512))
			update_len = 512;
		else
			update_len = all_len-i;
		memcpy(USART1_TX_BUF,(const void *)(addr+i),update_len);
		MD5Update (&md5c, USART1_TX_BUF, update_len);
		i += update_len;
		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	}
	MD5Final(digest,&md5c);
	memcpy(USART1_TX_BUF,(const void *)(addr+all_len),16);
	for(i=0;i<16;++i)
	{
		if(digest[i]!=USART1_TX_BUF[i])
			break;
	}
	if(i>=16)
		return 1;
	else
		return 0;
}



/**
 * @bieaf 擦除页
 *
 * @param pageaddr  起始地址	
 * @param num       擦除的页数
 * @return 1
 */
uint8_t Erase_page(uint32_t pageaddr, uint32_t num)
{
	__disable_irq();
	HAL_FLASH_Unlock();
	
	/* 擦除FLASH*/
	FLASH_EraseInitTypeDef FlashSet;
	FlashSet.TypeErase = FLASH_TYPEERASE_SECTORS;
	FlashSet.VoltageRange  = FLASH_VOLTAGE_RANGE_3;
	FlashSet.Sector = GetSector(pageaddr);
	//FlashSet.NbSectors =(pageaddr+num-1);
	FlashSet.NbSectors=1;
	/*设置PageError，调用擦除函数*/
	uint32_t PageError = 0;
	HAL_FLASHEx_Erase(&FlashSet, &PageError);
	
	HAL_FLASH_Lock();
	__enable_irq();
	return 1;
}


/**
 * @bieaf 写若干个数据
 *
 * @param addr       写入的地址
 * @param buff       写入数据的起始地址
 * @param word_size  长度
 * @return 
 */
static void WriteFlash(uint32_t addr, uint32_t * buff, int word_size)
{	
	/* 1/4解锁FLASH*/
	HAL_FLASH_Unlock();
	
	for(int i = 0; i < word_size; i++)	
	{
		/* 3/4对FLASH烧写*/
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + 4 * i, buff[i]);	
	}

	/* 4/4锁住FLASH*/
	HAL_FLASH_Lock();
}



/**
 * @bieaf 读若干个数据
 *
 * @param addr       读数据的地址
 * @param buff       读出数据的数组指针
 * @param word_size  长度
 * @return 
 */
static void ReadFlash(uint32_t addr, uint32_t * buff, uint16_t word_size)
{
	//uint32_t get=0;
	for(int i =0; i < word_size; i++)
	{
		buff[i] = *(__IO uint32_t*)(addr + 4 * i);
		//buff[i] =((get&0x000000ff)<< 24)| ((get&0x0000ff00 ) << 8 )| (( get&0x00ff0000 ) >> 8 ) | ((get&0xff000000 )>> 24 );
	}
	return;
}


/* 读取启动模式 */
unsigned int Read_Start_Mode(void)
{
	unsigned int mode = 0;
	//ReadFlash((Application_2_Addr + Application_Size - 4), &mode, 1);
	ReadFlash(StartMode_Addr, &mode, 1);
	
	return mode;
}


/**
 * @bieaf 写若干个数据
 *
 * @param addr       写入的地址
 * @param buff       写入数据的起始地址
 * @param word_size  长度
 * @return 
 */
void WriteFlash2(uint32_t addr, uint32_t *buff, int word_size)
{
	/* 1/4解锁FLASH*/
	HAL_FLASH_Unlock();

	for(int i = 0; i < word_size; i++)
	{
		/* 3/4对FLASH烧写*/
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + 4 * i, buff[i]);
	}

	/* 4/4锁住FLASH*/
	HAL_FLASH_Lock();
}


/* 标记升级完成 */
void Set_Update_Down(void)
{
	unsigned int update_flag = Startup_Update; ///< 对应bootloader的启动步骤
	memcpy(USART1_TX_BUF,(void *)StartMode_Addr,256);
	memcpy(USART1_TX_BUF,&update_flag,4);
	Erase_page(StartMode_Addr, Appear_si);
	WriteFlash2(StartMode_Addr, (uint32_t *)USART1_TX_BUF, 64);
}




/**
 * @bieaf 进行程序的覆盖
 * @detail 1.擦除目的地址
 *         2.源地址的代码拷贝到目的地址
 *         3.擦除源地址
 *
 * @param  搬运的源地址
 * @param  搬运的目的地址
 * @return 搬运的程序大小
 */
void MoveCode(unsigned int src_addr, unsigned int des_addr, unsigned int byte_size)
{
	/*1.擦除目的地址*/
	//printf("> Start erase des flash......\r\n");
	//Erase_page(des_addr, (byte_size/PageSize));
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	Erase_page(des_addr, Appear_si);
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	//printf("> Erase des flash down......\r\n");
	
	/*2.开始拷贝*/	
	unsigned int temp[128]={0};
	
	//printf("> Start copy......\r\n");
	for(int i = 0; i < (byte_size+511)/512; i++)
	{
		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
		ReadFlash((src_addr + i*512), temp, 128);
		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
		WriteFlash((des_addr + i*512), temp, 128);
		HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	}
	//printf("> Copy down......\r\n");
	
	/*3.擦除源地址*/
	//printf("> Start erase src flash......\r\n");
	//Erase_page(src_addr, (byte_size/PageSize));
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	;//Erase_page(src_addr, Appear_si);
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	
	//HAL_NVIC_SystemReset();
	//printf("> Erase src flash down......\r\n");
  

}



///* 采用汇编设置栈的值 */
//__asm void MSR_MSP (uint32_t ulAddr) 
//{
//    MSR MSP, r0 			                   //set Main Stack value
//    BX r14
//}



///* 程序跳转函数 */
//typedef void (*Jump_Fun)(void);
//void IAP_ExecuteApp (uint32_t App_Addr)
//{
//	Jump_Fun JumpToApp; 
//    
////	if ( ( ( * ( __IO uint32_t * ) App_Addr ) & 0x2FE00000 ) == 0x20000000 )	//检查栈顶地址是否合法.
////	{ 
//		JumpToApp = (Jump_Fun) * ( __IO uint32_t *)(App_Addr + 4);				//用户代码区第二个字为程序开始地址(复位地址)		
//		MSR_MSP( * ( __IO uint32_t * ) App_Addr );								//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)
//		__disable_irq();
//		JumpToApp();															//跳转到APP.
////	}
//}



/*
*********************************************************************************************************
*	函 数 名: JumpToBootloader
*	功能说明: 跳转到系统BootLoader
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void JumpToBootloader(void)
{
	uint32_t i=0;
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	void (*SysMemBootJump)(void);        /* 声明一个函数指针 */
	__IO uint32_t BootAddr = Application_1_Addr; /* STM32F4的系统BootLoader地址 */
	
	
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706

	/* 关闭全局中断 */
	DISABLE_INT(); 

	/* 关闭滴答定时器，复位到默认值 */
	SysTick->CTRL = 0;
  SysTick->LOAD = 0;
  SysTick->VAL = 0;
	
	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706

	/* 设置所有时钟到默认状态，使用HSI时钟 */
	HAL_RCC_DeInit();
	
	 __HAL_RCC_GPIOC_CLK_ENABLE();
	
	
	//看门狗配置  初始化
  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
	
	if(0)//看门狗sp706
	//if(1)//打开看门狗sp706
	{
		//
		GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	
	}
	else
	{
		GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
	
	}
  
	
	
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
	
	
	
//	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706

	/* 关闭所有中断，清除所有中断挂起标志 */
	for (i = 0; i < 8; i++)
	{
		NVIC->ICER[i]=0xFFFFFFFF;
		NVIC->ICPR[i]=0xFFFFFFFF;
	}	
	
//	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706

	/* 使能全局中断 */
	ENABLE_INT();

	/* 跳转到系统BootLoader，首地址是MSP，地址+4是复位中断服务程序地址 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4)));

	/* 设置主堆栈指针 */
	__set_MSP(*(uint32_t *)BootAddr);
	
//	/* 在RTOS工程，这条语句很重要，设置为特权级模式，使用MSP指针 */
	__set_CONTROL(0);

	/* 跳转到系统BootLoader */
//	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	SysMemBootJump(); 

	/* 跳转成功的话，不会执行到这里，用户可以在这里添加代码 */
	while (1)
	{

	}
}


/**
 * @bieaf 进行BootLoader的启动
 *
 * @param none
 * @return none
 */
void Start_BootLoader(void)
{
  	unsigned int update_flag = 0xAAAAAAAA; ///< 对应bootloader的启动步骤
	unsigned int ModeStart;
	unsigned int i,all_len;
//	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
	
	ModeStart=Read_Start_Mode();
	switch(ModeStart)									///< 读取是否启动应用程序 */
	{
		case Startup_Normal:										///< 正常启动 */   //在APP2中可以设定此标志位   使得下次重启之后进入APP1
		{
			;//printf("> Normal start......\r\n");
			break;
		}
		case Startup_Update: ///< 升级再启动 */
		{

			
			HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2); //看门狗sp706

			for (i = 0, all_len = 0; i < 4; ++i)
			{
				all_len = all_len << 8;
				all_len |= *(unsigned char *)(StartMode_Addr + 68 + i);
			}
			if ((*(unsigned int*)(Application_Buffer_Addr+6144)==Application_2_Addr) && App2_MD5_Check(Application_Buffer_Addr,all_len))
			{
				MoveCode(Application_Buffer_Addr, Application_2_Addr, all_len);//假定程序大小为100k
				HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
//			printf("> Update down......\r\n");
			
				update_flag = Startup_APP2;
				memcpy(USART1_TX_BUF,(void *)StartMode_Addr,256);
				Erase_page(StartMode_Addr, Appear_si);
				memcpy(USART1_TX_BUF,&update_flag,4);
				memcpy(USART1_TX_BUF+132,USART1_TX_BUF+68,4);
				WriteFlash2(StartMode_Addr, (uint32_t *)USART1_TX_BUF, 64);
				HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
				/*for (i = 0, all_len = 0; i < 4; ++i)
				{
					all_len = all_len << 8;
					all_len |= *(unsigned char *)(StartMode_Addr + 68 + i);
				}
				if(App2_MD5_Check(Application_2_Addr,all_len))
					JumpToAPP2();//
				*/
			}
		//	break;
		}

		case Startup_APP2:										///跳转到APP2
		{
			for (i = 0, all_len = 0; i < 4; ++i)
			{
				all_len = all_len << 8;
				all_len |= *(unsigned char *)(StartMode_Addr + 132 + i);
			}
			if((*(unsigned int*)(Application_2_Addr+6144)==Application_2_Addr) && App2_MD5_Check(Application_2_Addr,all_len))
				JumpToAPP2();//
			break;
		}	
		
		
		case Startup_Reset:										///< 恢复出厂设置 目前没使用 */
		{
//			printf("> Restore to factory program......\r\n");
			break;			
		}
		default:														///< 启动失败
		{
//			printf("> Error:%X!!!......\r\n", Read_Start_Mode());
			return;			
		}
	}
	
//	/* 跳转到应用程序 */
////	HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);//看门狗sp706
//  printf("> Start up......\r\n\r\n");
//	//IAP_ExecuteApp(Application_1_Addr);
//	JumpToBootloader();
}




