/**
  ******************************************************************************
  * @file    main.c
  * @author  MCU Application Team
  * @brief   Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 Puya Semiconductor Co.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by Puya under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "ms32c0xx.h"

/* Private define ------------------------------------------------------------*/
#define HSI_TIMEOUT_VALUE          ((uint32_t)100)  /* 100 ms */
#define CLOCKSWITCH_TIMEOUT_VALUE  ((uint32_t)5000) /* 5 s    */

#define ERROR_HSI_TIMEOUT          0x01
#define ERROR_CLKSWITCH_TIMEOUT    0x02

#define UART_DIV_SAMPLING16_100(__PERIPHCLK__, __BAUDRATE__)     (((__PERIPHCLK__)*25)/(4*(__BAUDRATE__)))
#define UART_DIVMANT_SAMPLING16(__PERIPHCLK__, __BAUDRATE__)     (UART_DIV_SAMPLING16_100((__PERIPHCLK__), (__BAUDRATE__))/100)
#define UART_DIVFRAQ_SAMPLING16(__PERIPHCLK__, __BAUDRATE__)     (((UART_DIV_SAMPLING16_100((__PERIPHCLK__), (__BAUDRATE__)) - (UART_DIVMANT_SAMPLING16((__PERIPHCLK__), (__BAUDRATE__)) * 100)) * 16 + 50) / 100)
/* UART BRR = mantissa + overflow + fraction
            = (UART DIVMANT << 4) + (UART DIVFRAQ & 0xF0) + (UART DIVFRAQ & 0x0F) */
#define UART_DIV_SAMPLING16(__PERIPHCLK__, __BAUDRATE__)         (((UART_DIVMANT_SAMPLING16((__PERIPHCLK__), (__BAUDRATE__)) << 4)    + \
                                                                   (UART_DIVFRAQ_SAMPLING16((__PERIPHCLK__), (__BAUDRATE__)) & 0xF0)) + \
                                                                   (UART_DIVFRAQ_SAMPLING16((__PERIPHCLK__), (__BAUDRATE__)) & 0x0F))

#define RX_MAX_LEN 128     /* Single frame data, maximum received data length */

/* Private variables ---------------------------------------------------------*/
static __IO uint32_t Tick;
volatile uint16_t error = 0;

uint8_t  aRxBuffer[RX_MAX_LEN] = {0};
uint32_t __IO cRxIndex = 0;
/* Private user code ---------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static __INLINE void APP_SystemClockConfig(void);
static __INLINE void APP_GPIOConfig(void);
static __INLINE void APP_ConfigUart1Gpio(void);
static __INLINE void APP_ConfigUart1(void);

/**
  * @brief  Main program.
  * @param  None
  * @retval int
  */
int main(void)
{
  SysTick_Config(8000); /* 1ms config */
  APP_SystemClockConfig();

  RCC->APBENR1 |= (RCC_APBENR1_PWREN);
  RCC->APBENR2 |= (RCC_APBENR2_SYSCFGEN);

  APP_GPIOConfig();
  if (error != 0)
  {
    while(1) /* endless loop */
    {
    }
  }

  APP_ConfigUart1Gpio();  /* Configure UART GPIO */

  APP_ConfigUart1();  /* Configure UART */

  UART1->CR2 |= UART_CR2_RXNEIE; /* Enable RX Not Empty Interrupt */

  while (1) /* Infinite loop */
  {
  }
}

/**
  * @brief  This function configures the system clock @8MHz 
  *         assuming the registers have their reset value before the call.
  *         SYSTEM CLOCK  = HSI DIV1
  *         FLASH LATENCY = 0
  * @param  None
  * @retval None
  */
static __INLINE void APP_SystemClockConfig(void)
{
  uint32_t tickstart = 0;
  /* (1) HSI DIV1 and Enable HSI */
  /* (2) Set HSI 8M and Triming Data */
  /* (3) Wait for HSI ready flag */
  /* (4) Set AHB divider:HCLK = SYSCLK */
  /* (5) Select HSISYS as system clock */
  /* (6) Wait for clock switched on HSI */
  /* (7) Set APB divider:PCLK = HCLK */

  RCC->CR = (RCC->CR &~(RCC_CR_HSIDIV)) | RCC_CR_HSION;                        /* (1) */

  RCC->ICSCR = (RCC->ICSCR & 0xFFFE0000) | (0 << RCC_ICSCR_HSI_FS_CR_Pos) | \
               ((*(uint32_t *)(0x1FFF0080)) & 0xFFFF);                         /* (2) */

  tickstart = Tick;
  while ((RCC->CR & (RCC_CR_HSIRDY)) != (RCC_CR_HSIRDY ))                      /* (3) */
  {
    if ((Tick - tickstart ) > HSI_TIMEOUT_VALUE)
    {
      error = ERROR_HSI_TIMEOUT; /* Report an error */
      return;
    }
  }

  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_HPRE));                                  /* (4) */

  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_SW)) | RCC_CFGR_SW_HSISYS;               /* (5) */
  tickstart = Tick;
  while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSISYS)                    /* (6) */
  {
    if ((Tick - tickstart ) > CLOCKSWITCH_TIMEOUT_VALUE)
    {
      error = ERROR_CLKSWITCH_TIMEOUT; /* Report an error */
      return;
    }
  }
 
  RCC->CFGR = (RCC->CFGR & ~(RCC_CFGR_PPRE));                                  /* (7) */
}

/**
  * @brief  This function enables the peripheral clocks on GPIO port A,
  *         configures GPIO PA1 in output mode for the Green LED pin.
  * @param  None
  * @retval None
  */
static __INLINE void APP_GPIOConfig(void)
{
  /* (1) Enable the peripheral clock of GPIOA */
  /* (2) Select output mode (01) on GPIOA pin 1 */
  /* (3) Turn off green led on PA1 */
  RCC->IOPENR  |= RCC_IOPENR_GPIOAEN ;                /* (1) */
  GPIOA->MODER = (GPIOA->MODER & ~(GPIO_MODER_MODE1))
               | (GPIO_MODER_MODE1_0);                /* (2) */
  GPIOA->BSRR  = (1<<1);                              /* (3) */
}

/**
  * Brief   This function :
             - Enables GPIO clock
             - Configures the UART1 pins on GPIO PB4 PB5
  * Param   None
  * Retval  None
  */
static __INLINE void APP_ConfigUart1Gpio(void)
{
  /* Enable the peripheral clock of GPIOB */
  RCC->IOPENR |= RCC_IOPENR_GPIOBEN;

  /* GPIO configuration for UART1 signals */
  /* (1) Select AF mode (10) on PB4 and PB5 */
  /* (2) AF1 for UART1 signals */
  GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODE4|GPIO_MODER_MODE5)) \
                 | (GPIO_MODER_MODE4_1 | GPIO_MODER_MODE5_1); /* (1) */
  GPIOB->AFR   = (GPIOB->AFR &~ (0x00770000)) \
                 | (1 << (4 * 4)) | (1 << (5 * 4));           /* (2) */
}

/**
  * Brief   This function configures UART1.
  * Param   None
  * Retval  None
  */
static __INLINE void APP_ConfigUart1(void)
{
  /* Enable the peripheral clock UART1 */
  RCC->APBENR1 |= RCC_APBENR1_UART1EN;

  /* Set UART1 interrupt priority  */
  NVIC_SetPriority(UART1_IRQn,0);
  /* Enable UART1 interrupt request */
  NVIC_EnableIRQ(UART1_IRQn);

  /* Configure UART1 */
  /* (1) 8 data bit, 1 start bit, 1 stop bit, no parity */
  /* (2) oversampling by 16, 115200 baud */
  UART1->CR1  = UART_CR1_M;                                             /* (1) */
  UART1->BRR  = ((UART_DIV_SAMPLING16(8000000, 115200) >> 4) & 0xFFFF); /* (2) */
  UART1->BRRF = (UART_DIV_SAMPLING16(8000000, 115200) & 0xF);

}

/******************************************************************************/
/*            Cortex-M0 Plus Processor Exceptions Handlers                    */
/******************************************************************************/

/**
  * @brief   This function handles NMI exception.
  * @param   None
  * @retval  None
  */
void NMI_Handler(void)
{
}

/**
  * @brief   This function handles Hard Fault exception.
  * @param   None
  * @retval  None
  */
void HardFault_Handler(void)
{
  /* Go to infinite loop when Hard Fault exception occurs */
  while (1)
  {
  }
}

/**
  * @brief   This function handles SVCall exception.
  * @param   None
  * @retval  None
  */
void SVC_Handler(void)
{
}

/**
  * @brief   This function handles PendSVC exception.
  * @param   None
  * @retval  None
  */
void PendSV_Handler(void)
{
}

/**
  * @brief   This function handles SysTick Handler.
  * @param   None
  * @retval  None
  */
void SysTick_Handler(void)
{
  Tick++;
}

/******************************************************************************/
/*                 MS32C001B Peripherals Interrupt Handlers                   */
/*  Add here the Interrupt Handler for the used peripheral(s) (PPP), for the  */
/*  available peripheral interrupt handler's name please refer to the startup */
/*  file (startup_ms32c001bxx.s).                                             */
/******************************************************************************/
/**
  * @brief This function handles UART1 interrupt.
  */
void UART1_IRQHandler(void)
{
  __IO uint32_t tmpreg;

  /* receive data register not empty */
  if (((UART1->SR & UART_SR_RXNE) != RESET) && ((UART1->CR2 & UART_CR2_RXNEIE) != RESET))
  {
    /* Receive data */
    aRxBuffer[cRxIndex] = (uint8_t)(UART1->DR & (uint8_t)0x00FF);

    /* Wait SR_TXE bit set 1 */
    while((UART1->SR & UART_SR_TXE) == RESET)
    {
    }
    /* Send received data */
    UART1->DR = aRxBuffer[cRxIndex];
    
    cRxIndex++;
    if(cRxIndex > (RX_MAX_LEN - 1))
    {
      cRxIndex = (RX_MAX_LEN - 1);
    }
  }
  if((UART1->SR & UART_SR_ORE) != RESET)
  {
    /* Clearing the ORE bit */
    tmpreg = UART1->SR;
    (void) tmpreg;
    tmpreg = UART1->DR;
    (void) tmpreg;
    
    GPIOA->BRR = (1<<1); /* Turn on green led on PA1 */
  }
}
/************************ (C) COPYRIGHT Puya *****END OF FILE******************/
