#include "gd32f10x.h"
#include "boot.h"
#include "main.h"
#include "delay.h"
#include "fmc.h"
#include "w25q32.h"
#include <stdio.h>
#include "ota_message.h"
#define APP_PROGRAMMER_BLOCK 2   //程序在W25Q32中存放的位置

load_a load_A;       

//进入bootloader更新
void BootLoader_Brance(uint32_t app_byte)
{
	GD32_EraseFlash(GD32_A_START_PAGE,GD32_A_PAGE_NUM);//擦除A区原有程序
	for(uint8_t i=0;i<app_byte/1024;i++)
	{
		uint8_t app_programmer[1024];
		memset(app_programmer,0,1024);
		uint32_t addr=APP_PROGRAMMER_BLOCK*64*1024+i*1024;   //其在w25q32中的地址
		W25Q32_Read(app_programmer,addr,1024);               
		GD32_WriteFlash(GD32_A_SADDR+i*1024,(uint32_t *)&app_programmer,1024); //将读出的数据按页写入数据
	}
	//将不满1024数据单独写入
	if(app_byte%1024!=0)
	{
		uint32_t startAddress=(app_byte/1024)*1024;
		uint8_t app_programmer[1024];
		uint32_t addr=APP_PROGRAMMER_BLOCK*64*1024+(app_byte/1024)*1024;   														//其在w25q32中的地址
		memset(app_programmer,0,1024);
		W25Q32_Read(app_programmer,addr,app_byte%1024);																					
		GD32_WriteFlash(GD32_A_SADDR+(app_byte/1024)*1024,(uint32_t *)&app_programmer,app_byte%1024);
	}
	clear_ota_message_config_block();  
	LOAD_A(GD32_A_SADDR);
}


/*-------------------------------------------------*/
/*函数名：设置SP                                   */
/*参  数：addr：栈顶指针初始值                     */
/*返回值：无                                       */
/*-------------------------------------------------*/
__asm void MSR_SP(uint32_t addr)
{
	MSR MSP, r0      
	BX r14             
}
/*-------------------------------------------------*/
/*函数名：跳转到A区                                */
/*参  数：addr：A区的起始地址                      */
/*返回值：无                                       */
/*-------------------------------------------------*/
void LOAD_A(uint32_t addr)
{
	if((*(uint32_t *)addr>=0x20000000)&&(*(uint32_t *)addr<=0x20017FFF)){     
		MSR_SP(*(uint32_t *)addr);                                            
		load_A = (load_a)*(uint32_t *)(addr+4);                               
		BootLoader_Clear();                                                
		load_A();                                       
	}else ; 
}
/*-------------------------------------------------*/
/*函数名：清除B区使用的外设                        */
/*参  数：无                                       */
/*返回值：无                                       */
/*-------------------------------------------------*/
void BootLoader_Clear(void)
{
	gpio_deinit(GPIOA);    
	gpio_deinit(GPIOB);    
}













