#include <stdint.h>
#include "uart.h"

#define GPIOAEN        (1U<<0)
#define UART2EN        (1U<<17)

#define DBG_UART_BAUDRATE     115200
#define SYS_FREQ              16000000
#define APB1_CLK              SYS_FREQ
#define CR1_TE                (1U<<3)
#define CR1_UE                (1U<<13)
#define SR_TXE                (1U<<7)

static void uart_set_baudrate(uint32_t periph_clk,uint32_t baudrate);
static void uart_write(int ch);

int __io_putchar(int ch)
{
    uart_write(ch);
    return ch;
}

void uart_init(void)
{
    /*Włączanie dostępu do zegara dla GPIOA*/
    RCC->AHB1ENR |= GPIOAEN;

    /*Ustawianie trybu PA2 na tryb funkcji alternatywnej*/
    GPIOA->MODER &=~(1U<<4);
    GPIOA->MODER |=(1U<<5);

    /*Ustawianie typu funkcji alternatywnej na AF7(UART2_TX)*/
    GPIOA->AFR[0] |=(1U<<8);
    GPIOA->AFR[0] |=(1U<<9);
    GPIOA->AFR[0] |=(1U<<10);
    GPIOA->AFR[0] &=~(1U<<11);

    /*Włączanie dostęp do zegara dla UART2*/
    RCC->APB1ENR |= UART2EN;

    /*Konfigurowanie prędkości transmisji UART*/
    uart_set_baudrate(APB1_CLK,DBG_UART_BAUDRATE);

    /*Konfigurowanie kierunku transmisji*/
    USART2->CR1 = CR1_TE;

    /*Włączanie modułu UART*/
    USART2->CR1 |= CR1_UE;
}

static void uart_write(int ch)
{
    /*Upewniamy się, że rejestr transmisji jest pusty*/
    while(!(USART2->SR & SR_TXE)){}

    /*Zapisujemy dane do rejestru transmisji */
    USART2->DR =(ch & 0xFF);
}

static uint16_t compute_uart_bd(uint32_t periph_clk,uint32_t baudrate)
{
    return((periph_clk + (baudrate/2U))/baudrate);
}

static void uart_set_baudrate(uint32_t periph_clk,uint32_t baudrate)
{
    USART2->BRR = compute_uart_bd(periph_clk,baudrate);
}
