
#include <stdint.h>
#include "Pipe.h"
#include "stm32f030x6.h"
#include "stm32f0xx_hal.h"

Pipe<32, uint8_t> ReceiverQueue;
Pipe<32, uint8_t> SendQueue;

extern UART_HandleTypeDef huart1;

bool s_IsSending_bt = false;
uint8_t s_EchoCnt_u8 = 0U;

const uint32_t TRANSMIT_ENABLE = USART_CR1_UE | USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE | USART_CR1_TXEIE;
const uint32_t RECEIVER_ENABLE = USART_CR1_UE | USART_CR1_RE | USART_CR1_RXNEIE;
const uint32_t RECEIVER_WAIT = USART_CR1_UE | USART_CR1_RE | USART_CR1_PEIE | USART_CR1_RXNEIE;
const uint32_t ENABLE_MASK = USART_CR1_UE | USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE | USART_CR1_TXEIE | USART_CR1_PEIE;

int uart_getc() 
{
  uint8_t Byte;
  if (ReceiverQueue.Read(Byte)) {
    return static_cast<int>(Byte);
  }
  return 0x100;
}

void uart_putc(char c)
{
  SendQueue.Write(c);
  if (!s_IsSending_bt) {
    s_IsSending_bt = true;
    MODIFY_REG(USART1->CR1, ENABLE_MASK, TRANSMIT_ENABLE);
    uint8_t val;
    SendQueue.Read(val);
    USART1->TDR = val;  
  }
}

void uart_sleep()
{
    MODIFY_REG(USART1->CR1, ENABLE_MASK, RECEIVER_WAIT);
}

void uart_puts(const char* pStr)
{
#if 0
  HAL_UART_Transmit_IT(&huart1,(uint8_t *)pStr,strlen(pStr));
#else
  const char* p=pStr;
  while (*p) {
    uart_putc(*p++);
  }
#endif
}

#if 1
HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef * huart)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
  /* USER CODE END USART1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
  
    /**USART1 GPIO Configuration    
    PA2     ------> USART1_TX
    PA3     ------> USART1_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF1_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


    USART1->BRR = 2500U;        // 48MHz --> 19200
    USART1->CR2 = 0U;
    USART1->CR3 = 0U; 
    uint32_t tmpreg = (uint32_t)huart->Init.WordLength | huart->Init.Parity | huart->Init.Mode | huart->Init.OverSampling ;
    tmpreg |=  RECEIVER_ENABLE;
    USART1->CR1 = tmpreg;
        
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
    
    return HAL_OK;
}


void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
  static volatile uint8_t LastRec;
    uint32_t isr = USART1->ISR;
    if (isr & UART_FLAG_RXNE) {      
      uint8_t val=USART1->RDR;
      LastRec = val;
      if (0U==s_EchoCnt_u8) {
        ReceiverQueue.Write(val);
      }
      else {
        s_EchoCnt_u8--;
      }
    }    
    if (isr & (UART_FLAG_PE)) {
      USART1->ICR =  UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_FEF;
      uint8_t val=USART1->RDR;
      LastRec = val;
      if (LastRec == 0xAA) {
        MODIFY_REG(huart->Instance->CR1, ENABLE_MASK, RECEIVER_ENABLE);
      }
    }
    if (isr & (UART_FLAG_ORE | UART_FLAG_FE)) {
      USART1->ICR =  UART_CLEAR_OREF | UART_CLEAR_FEF;
    }
    if ( 0!= (isr & (UART_FLAG_TXE | UART_FLAG_TC)) && s_IsSending_bt){
      uint8_t val;
      if (SendQueue.Read(val)) {
        USART1->TDR = val;
        s_EchoCnt_u8++;
      }      
      else {        // nothing left to send
          MODIFY_REG(huart->Instance->CR1, ENABLE_MASK, RECEIVER_WAIT);
          USART1->ICR =  UART_CLEAR_TCF;
          s_IsSending_bt = false;
      }
    }
}

/**
  * @brief Configure the UART peripheral.
  * @param huart: UART handle.
  * @retval HAL status
  */
#define UART_CR1_FIELDS  ((uint32_t)(USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | \
                                     USART_CR1_TE | USART_CR1_RE | USART_CR1_OVER8)) /*!< UART or USART CR1 fields of parameters set by UART_SetConfig API */


HAL_StatusTypeDef UART_SetConfig(UART_HandleTypeDef *huart)
{
  uint32_t tmpreg                     = 0x00000000;
  UART_ClockSourceTypeDef clocksource = UART_CLOCKSOURCE_UNDEFINED;
  uint16_t brrtemp                    = 0x0000;
  uint16_t usartdiv                   = 0x0000;
  HAL_StatusTypeDef ret               = HAL_OK;

  /* Check the parameters */
  assert_param(IS_UART_BAUDRATE(huart->Init.BaudRate));
  assert_param(IS_UART_WORD_LENGTH(huart->Init.WordLength));
  assert_param(IS_UART_STOPBITS(huart->Init.StopBits));
  assert_param(IS_UART_PARITY(huart->Init.Parity));
  assert_param(IS_UART_MODE(huart->Init.Mode));
  assert_param(IS_UART_HARDWARE_FLOW_CONTROL(huart->Init.HwFlowCtl));
  assert_param(IS_UART_ONE_BIT_SAMPLE(huart->Init.OneBitSampling));
  assert_param(IS_UART_OVERSAMPLING(huart->Init.OverSampling));


  /*-------------------------- USART CR1 Configuration -----------------------*/
  /* Clear M, PCE, PS, TE, RE and OVER8 bits and configure
   *  the UART Word Length, Parity, Mode and oversampling:
   *  set the M bits according to huart->Init.WordLength value
   *  set PCE and PS bits according to huart->Init.Parity value
   *  set TE and RE bits according to huart->Init.Mode value
   *  set OVER8 bit according to huart->Init.OverSampling value */
  tmpreg = (uint32_t)huart->Init.WordLength | huart->Init.Parity | huart->Init.Mode | huart->Init.OverSampling ;
  MODIFY_REG(huart->Instance->CR1, UART_CR1_FIELDS, tmpreg);

  /*-------------------------- USART CR2 Configuration -----------------------*/
  /* Configure the UART Stop Bits: Set STOP[13:12] bits according
   * to huart->Init.StopBits value */
  MODIFY_REG(huart->Instance->CR2, USART_CR2_STOP, huart->Init.StopBits);

  /*-------------------------- USART CR3 Configuration -----------------------*/
  /* Configure
   * - UART HardWare Flow Control: set CTSE and RTSE bits according
   *   to huart->Init.HwFlowCtl value
   * - one-bit sampling method versus three samples' majority rule according
   *   to huart->Init.OneBitSampling */
  tmpreg = (uint32_t)huart->Init.HwFlowCtl | huart->Init.OneBitSampling ;
  MODIFY_REG(huart->Instance->CR3, (USART_CR3_RTSE | USART_CR3_CTSE | USART_CR3_ONEBIT), tmpreg);

  /*-------------------------- USART BRR Configuration -----------------------*/
  UART_GETCLOCKSOURCE(huart, clocksource);
  
  /* Check UART Over Sampling to set Baud Rate Register */
  if (huart->Init.OverSampling == UART_OVERSAMPLING_8)
  {
    switch (clocksource)
    {
      case UART_CLOCKSOURCE_PCLK1:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(HAL_RCC_GetPCLK1Freq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_HSI:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(HSI_VALUE, huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_SYSCLK:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(HAL_RCC_GetSysClockFreq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_LSE:
        usartdiv = (uint16_t)(UART_DIV_SAMPLING8(LSE_VALUE, huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_UNDEFINED:
      default:
        ret = HAL_ERROR;
        break;
    }

    brrtemp = usartdiv & 0xFFF0;
    brrtemp |= (uint16_t)((usartdiv & (uint16_t)0x000F) >> 1U);
    huart->Instance->BRR = brrtemp;
  }
  else
  {
    switch (clocksource)
    {
      case UART_CLOCKSOURCE_PCLK1:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(HAL_RCC_GetPCLK1Freq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_HSI:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(HSI_VALUE, huart->Init.BaudRate)); 
        break;
      case UART_CLOCKSOURCE_SYSCLK:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(HAL_RCC_GetSysClockFreq(), huart->Init.BaudRate));
        break;
      case UART_CLOCKSOURCE_LSE:
        huart->Instance->BRR = (uint16_t)(UART_DIV_SAMPLING16(LSE_VALUE, huart->Init.BaudRate)); 
        break;
      case UART_CLOCKSOURCE_UNDEFINED:
      default:
        ret = HAL_ERROR;
        break;
    }
  }

  return ret;

}

#endif
