#include "stm32f10x_lib.h"

#define MAXBUFFER	512
#define IAPSTART	0x8002000
#define PAGESIZE	1024

#define TIMER_ONESHOT		0
#define TIMER_PERIOD		1

typedef struct __TIMER
{
	u32 Timeoutcnt;
	u32 Timeout;
	void (*Timeoutfuc)(void* parameter);
	void* Parameter;
	u8 Timerflag;
}Timer_typedef;

static Timer_typedef TimerList[10];

static u8 UsartBuffer[MAXBUFFER];
static volatile u16 UsartWptr = 0;
static u16 UsartRptr = 0;
static u8 Timeout = 0;
typedef  void (*pFunction)(void);
pFunction Jump_To_Application;

static void RCC_Configuration(void);
static void UsartInit (void);
static void KeyInit (void);
static void NvicInit (void);
static u8 GetKey (void);
static u8 BufferRead (u8* data);
static void FLASH_DisableWriteProtectionPages (void);
static void FlashProgram (void);
static void FlashProgramedata (u16 data);
static void FlashAllErase (void);
static void TIMER_TimerInitialisation(void);


int main(void)
{
	RCC_Configuration ();
	KeyInit ();

	if(!GetKey ())
	{
		GPIO_SetBits(GPIOA, GPIO_Pin_4);	
		UsartInit ();
		TIMER_TimerInitialisation();
		NvicInit ();
		FlashAllErase ();
		FlashProgram ();
	}
	else
	{
		Jump_To_Application  = (pFunction)(*(vu32*) (IAPSTART + 4));
		__MSR_MSP(*(vu32*) IAPSTART);
		Jump_To_Application();
	}
	
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
	while(1);
}

void RCC_Configuration(void)
{
	ErrorStatus HSEStartUpStatus;
  	RCC_DeInit();
  	RCC_HSEConfig(RCC_HSE_ON);
  	HSEStartUpStatus = RCC_WaitForHSEStartUp();
  	if(HSEStartUpStatus == SUCCESS)
  	{
    	RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    	RCC_PCLK2Config(RCC_HCLK_Div1); 
    	RCC_PCLK1Config(RCC_HCLK_Div2);
    	FLASH_SetLatency(FLASH_Latency_2);
    	FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    	RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    	RCC_PLLCmd(ENABLE);
    	while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    	RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    	while(RCC_GetSYSCLKSource() != 0x08);
  	} 
}


void KeyInit (void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA , &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA , &GPIO_InitStructure);
}


void UsartInit (void)
{
	USART_InitTypeDef USART_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
	
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA , &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA , &GPIO_InitStructure);
	
	USART_InitStructure.USART_BaudRate = 4800;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART1, &USART_InitStructure);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	USART_Cmd(USART1, ENABLE);
}


void NvicInit (void)
{
	NVIC_InitTypeDef NVIC_InitStructure;

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}


u8 GetKey (void)
{
	return (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0));
}


void BufferWrite (void)
{
	if(UsartWptr == (UsartRptr - 1))
	{
		return;
	}
	
	UsartBuffer[UsartWptr] = USART_ReceiveData(USART1);
	UsartWptr++;
	UsartWptr = UsartWptr % MAXBUFFER;
}


u8 BufferRead (u8* data)
{
	u8 s = 0;
	
	if(UsartRptr == UsartWptr)
	{
		s = 0;
	}
	else
	{
		s = 1;	
		*data = UsartBuffer[UsartRptr];
		UsartRptr++;
		UsartRptr = UsartRptr % MAXBUFFER;
	}
	
	return s;
}

void FlashProgramedata (u16 data)
{
	static u32 flashwptr = IAPSTART;
	
	FLASH_Unlock();
	
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
	FLASH_ProgramHalfWord(flashwptr, data);
	flashwptr = flashwptr + 2;
	
	FLASH_Lock();
}


void FlashAllErase (void)
{
	u8 n = 0;

	FLASH_Unlock();
	
	FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
	for(n = 8; n < 64; n++)
	{
		FLASH_ErasePage(0x8000000 + (n * PAGESIZE));
	}
	
	FLASH_Lock();

}
void FlashProgram (void)
{
	u8 Blocknum = 0;	// 块，一块4页，1页1k字节
	u8 n = 0;
	u8 data = 0;
	u8 datalow = 0;
	u8 datahigh = 0;
	u32 UserMemoryMask = 0;
	Blocknum = (IAPSTART - 0x8000000) >> 12;
	UserMemoryMask = ((u32)(~((1 << Blocknum) - 1))); 
	if((FLASH_GetWriteProtectionOptionByte() & UserMemoryMask) != UserMemoryMask)
	{
		FLASH_DisableWriteProtectionPages ();
	}
	
	while(1)
	{
		switch(n)
		{
		case 0:
			{
				if(BufferRead (&data))
				{
					datalow = data;
					n = 1;
				}
				else
				{
					break;
				}
			}
		case 1:
			{
				if(BufferRead (&data))
				{
					datahigh = data;
					n = 0;
					FlashProgramedata (((u16)(datalow)) | ((u16)(datahigh << 8)));
				}
				else if(Timeout)
				{
					datahigh = 0xff;
					n = 0;
					FlashProgramedata (((u16)(datalow)) | ((u16)(datahigh << 8)));
				}
				break;
			}
		default:
			{
				break;
			}
		}
		
		if(Timeout)
		{
			break;
		}
	}
	
}


void FLASH_DisableWriteProtectionPages (void)
{
	FLASH_EraseOptionBytes();
}


void TimerOutFlagSet (void* para)
{
	Timeout = 1;
}


void USART_UsartprintString (u8* string)
{
	while((*string) != '\0')
	{
		USART_SendData(USART1, *string);
		string++;
	}
}


static Timer_typedef TimerList[10];

void TIMER_TimerInitialisation(void)
{
	u8 i = 0;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    
    TIM_DeInit(TIM2);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
    TIM_TimeBaseStructure.TIM_Period = 2;                        	// 最大计数值,根据设定的分频，time=1即为0.5ms      
    TIM_TimeBaseStructure.TIM_Prescaler = 36000-1;                  // 分频36000
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         // 时钟分割  
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     // 计数方向向上计数
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

	TIM_SetAutoreload(TIM2, 2); 
	TIM_ARRPreloadConfig(TIM2, ENABLE); 

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);  
    TIM_Cmd(TIM2, ENABLE);	
	
	for(i = 0; i < 10; i++)
	{
		TimerList[i].Timeoutcnt = 1000001;
		TimerList[i].Timeout = 1000001;
		TimerList[i].Timeoutfuc = (void*)0;
		TimerList[i].Parameter = (void*)0;
	} 
}


void TIMER_TimerStart(u8 TimerIdent, u32 TimeOut, void (*Timeoutfuc)(void* parameter), void* parameter, u8 flag)
{
	if(TimerIdent > 9)
	{
		return;
	}
	
	__disable_irq();
	
	TimerList[TimerIdent].Timeoutcnt = TimeOut;
	TimerList[TimerIdent].Timeout = TimeOut;
	TimerList[TimerIdent].Timeoutfuc = Timeoutfuc;
	TimerList[TimerIdent].Parameter = parameter;
	TimerList[TimerIdent].Timerflag = flag;
	
	__enable_irq();
}


void TIMER_Execute(void)
{
	u8 i = 0;															
	for(i = 0; i < 10; i++)												
	{
		if((TimerList[i].Timeoutcnt != 0) && (TimerList[i].Timeoutcnt <= 1000000))
		{
			TimerList[i].Timeoutcnt--;										
			if(TimerList[i].Timeoutcnt == 0)								
			{
				if(TimerList[i].Timerflag != TIMER_PERIOD)				
				{
					TimerList[i].Timeoutcnt = 1000001;						
				}
				else
				{
					TimerList[i].Timeoutcnt = TimerList[i].Timeout;			
				}
				TimerList[i].Timeoutfuc(TimerList[i].Parameter);				
			}
		}
	}
}
