#include "stm32f10x.h"

volatile uint32_t counter = 0;
volatile uint8_t blinkFlag = 0;
volatile uint8_t userButtonFlag = 0;
static char LED_on_msg[13] = "\rBlue LED ON\r";
static char LED_off_msg[14] = "\rBlue LED OFF\r";

void UserInit(void);
void usart1SendByte(uint8_t byte);
void SysTick_Handler(void);
void USART1_IRQHandler(void);

int main(void)
{
	UserInit();
	
	uint8_t ch = 'A';
	for(ch = 'A'; ch <= 'Z'; ch++)
	{
		usart1SendByte(ch);
	}
	usart1SendByte('\r');

	
	while(1)
	{
		if((GPIOA->IDR & GPIO_IDR_IDR0) && !userButtonFlag)
		{
			userButtonFlag = 1;
			
			if(blinkFlag)
				GPIOC->BSRR = GPIO_BSRR_BR9;
				
			blinkFlag = !blinkFlag;
		}
		if(!(GPIOA->IDR & GPIO_IDR_IDR0) && userButtonFlag)
			userButtonFlag = 0;
	}
	
}

void UserInit(void)
{
	// LED configuration
	RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;		// GPIOC clock enable
	
	GPIOC->CRH &= ~GPIO_CRH_CNF8;			// Reset CNF8 bits, General purpose output Push-pull
	GPIOC->CRH &= ~GPIO_CRH_MODE8;			// Reset MODE8 bits
	GPIOC->CRH |= GPIO_CRH_MODE8_0;			// Max out speed 10MHz
	GPIOC->BSRR = GPIO_BSRR_BR8;			// Clear PC8
 	
	GPIOC->CRH &= ~GPIO_CRH_CNF9;			// Reset CNF9 bits, General purpose output Push-pull
	GPIOC->CRH &= ~GPIO_CRH_MODE9;			// Reset MODE9 bits
	GPIOC->CRH |= GPIO_CRH_MODE9_0;			// Max out speed 10MHz
	GPIOC->BSRR = GPIO_BSRR_BR9;			// Clear PC9*/
	
	// Button configuration
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;		// GPIOA clock enable
	GPIOA->CRL &= ~GPIO_CRL_CNF0;			// Reset CNF0
	GPIOA->CRL |= GPIO_CRL_CNF0_0;			// Set CNF0 bit 0, Input floating
	GPIOA->CRL &= ~GPIO_CRL_MODE0;			// Reset MODE0 bits
	
	// USART1 TX pin
	GPIOA->CRH &= ~GPIO_CRH_CNF9;			// Reset CNF9 bits
	GPIOA->CRH |= GPIO_CRH_CNF9_1;			// Set CNF9 bit 1, Alternate function output Push-pull
	GPIOA->CRH &= ~GPIO_CRH_MODE9;			// Reset MODE9 bits
	GPIOA->CRH |= GPIO_CRH_MODE9_0;			// Max out speed 10MHz
	// USART1 RX pin
	GPIOA->CRH &= ~GPIO_CRH_CNF10;			// Reset CNF10
	GPIOA->CRH |= GPIO_CRH_CNF10_0;			// Set CNF10 bit 0, Input floating
	GPIOA->CRH &= ~GPIO_CRH_MODE10;			// Reset MODE10 bits
	
	// USART1 configuration
	RCC->APB2ENR |= RCC_APB2ENR_USART1EN;	// USART1 clock enable
	// USART1, RX, TX, RX complete interrupt enable
	USART1->CR1 |= (USART_CR1_UE | USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE);
	
	// calculate BRR
	float USARTDIV = SystemCoreClock / (9600 * 16);
	uint16_t DIV_Mantissa = (uint16_t)USARTDIV;
	uint16_t DIV_Fraction = (uint16_t)((USARTDIV - (uint16_t)USARTDIV) * 16 + 0.5);
	if(DIV_Fraction >= 16)
	{
		DIV_Mantissa++;
		DIV_Fraction -= 16; 
	}
	
	USART1->BRR = (DIV_Mantissa << 4) | DIV_Fraction;
	
	// Enable USART1_IRQn
	NVIC_EnableIRQ(USART1_IRQn);
	
	// Setup SysTick Timer for 1 msec interrupts
	if(SysTick_Config(SystemCoreClock / 1000))
	{ 
		// Capture error
		while(1);
	}
}

void usart1SendByte(uint8_t byte)
{
	while(!(USART1->SR & USART_SR_TC));
	USART1->DR = byte;
}

void SysTick_Handler(void)
{
	if(blinkFlag)
	{
		counter++;
		if(counter == 500)
		{
			counter = 0;
			GPIOC->ODR ^= GPIO_ODR_ODR9;
		}
	}
}

void USART1_IRQHandler(void)
{
	uint8_t c = USART1->DR;
	if(c == 'S')
	{
		for(uint8_t i = 0; i < 13; i++)
			usart1SendByte(LED_on_msg[i]);

		GPIOC->BSRR = GPIO_BSRR_BS8;
	}
	else if(c == 'C')
	{
		for(uint8_t i = 0; i < 14; i++)
			usart1SendByte(LED_off_msg[i]);
		
		GPIOC->BSRR = GPIO_BSRR_BR8;
	}
}