#include <uart.h>
#include <stm32f411.h>

/* Wait for data to be transferred into the shift register.  */
static void
busywait_txe (void)
{
  /* TXE: Transmit data register empty  */
  while (!(*USART1_SR & (1u << 7))); /* 0: Data is not transferred to the shift
                                        register  */
}

/* Wait for transmission of the last frame.  */
static void
busywait_tc (void)
{
  /* TC: Transmission complete  */
  while (!(*USART1_SR & (1u << 6))); /* 0: Transmission is not complete  */
}

static void
tx (char c)
{
  /* DR[8:0]: Data value  */
  *USART1_DR = c;
}

void
uart_init (void)
{
  /* GPIOAEN: IO port A clock enable  */
  *RCC_AHB1ENR |= (1u); /* 1: IO port A clock enabled  */

  /* MODERy[1:0]: Port x configuration bits (y = 0..15)  */
  *GPIOA_MODER &= ~(0b1111u << 18); /* Clear PA9 and PA10 bits  */
  *GPIOA_MODER |= (0b1010u << 18); /* 10: Alternate function mode  */

  /* AFRHy: Alternate function selection for port x bit y (y = 8..15)  */
  *GPIOA_AFRH &= ~(0b11111111u << 4); /* Clear PA9 and PA10 bits  */
  *GPIOA_AFRH |= (0b01110111u << 4); /* 0111: AF7  */

  /* PA9: USART1_TX
   * PA10: USART1_RX  */

  /* USART1EN: USART1 clock enable  */
  *RCC_APB2ENR |= (1u << 4); /* 1: USART1 clock enabled  */

  /* UE: USART enable  */
  *USART1_CR1 |= (1u << 13); /* 1: USART enable  */

  /* M: Word length  */
  *USART1_CR1 &= ~(1u << 12); /* 0: 1 Start bit, 8 Data bits, n Stop bit  */

  /* PCE: Parity control enable  */
  *USART1_CR1 &= ~(1u << 10); /* 0: Parity control disabled  */

  /* STOP: STOP bits  */
  *USART1_CR2 &= ~(0b11u << 12); /* 00: 1 Stop bit  */

  /* Clock frequency: 25MHz
   * Desired baud rate: 1.2 KBps */

  /* Mantissa and fraction (/16)  */
  *USART1_BRR = (1302u << 4) | 1u; /* USARTDIV = 1302.0625  */

  /* TE: Transmitter enable  */
  *USART1_CR1 |= (1u << 3); /* 1: Transmitter is enabled  */
}

void
kputs_busytc (const char *str)
{
  while (*str)
  {
    busywait_txe ();
    tx (*(str++));
  }

  busywait_tc ();
}
