/*!
 * @file        user_config.c
 *
 * @brief       Used for user config
 *
 * @version     V1.0.0
 *
 * @date        2026-02-25
 *
 * @attention
 *
 *  Copyright (C) 2026 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */

/* Includes */
#include "Board.h"
#include "stdio.h"
#include "inttypes.h"
#include "g32a10xx_gpio.h"
#include "g32a10xx_misc.h"
#include "g32a10xx_eint.h"
#include "g32a10xx_rcm.h"
#include "user_config.h"

/** @addtogroup Examples
  @{
  */

/** @addtogroup RCM_Examples
  @{
  */

/** @addtogroup RCM_ClockDetection
  @{
  */

/** @defgroup RCM_ClockDetection_Variables Variables
  @{
*/
Rcm_SysClkSwitchType g_clkSwitchFlg = RCM_SYSCLK_NO_SWITCH;

/* Clock Select */
const char *g_rcmSysclkSelTab[3] =
{
    "RCM_SYSCLK_SEL_HSI",
    "RCM_SYSCLK_SEL_HSE",
    "RCM_SYSCLK_SEL_PLL",
};

/**@} end of group RCM_ClockDetection_Variables */

/** @defgroup RCM_ClockDetection_Functions
  @{
  */

/*!
 * @brief       HSE as System Clock
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Rcm_SystemClock_HSE_Init(void)
{
    uint32_t timeout = 0xFFFF;
    
    /* Open HSE */
    Rcm_ConfigHSE(RCM_HSE_OPEN);

    /* Wait until HSE is ready */
    while ((Rcm_WaitHseReady() == (uint8_t)ERROR) && (timeout > 0U))
    {
        timeout = timeout - 1U;
    }
    if(Rcm_WaitHseReady() == (uint8_t)ERROR)
    {
        printf("\r\n HSE config timeout \r\n");
    }
    else
    {
        /* select HSE as SYSCLK */
        Rcm_ConfigSysClk(RCM_SYSCLK_SEL_HSE);

        /* Initiatate the usart */
        Board_ComInit(COM1);
        
        printf("\r\n RCM clock switch to HSE(16MHz)\r\n");
        printf("  sysSource = %s ", g_rcmSysclkSelTab[Rcm_ReadSysClkSource()]);
        printf("  sysClock = %" PRId32 "\r\n", Rcm_ReadSysClkFreq());
    }
}

/*!
 * @brief       HSI as System Clock
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Rcm_SystemClock_HSI_Init(void)
{
    uint32_t timeout = 0xFFFF;
    
    /* set HSI trimming value */
    Rcm_SetHsiTrim(16);

    /* Enable HSI */
    Rcm_EnableHsi();

    while ((Rcm_WaitHsiReady() == (uint8_t)ERROR) && (timeout > 0U))
    {
        timeout = timeout - 1U;
    }
    
    if((Rcm_WaitHsiReady() == (uint8_t)ERROR))
    {
        printf("\r\n HSI config timeout \r\n");
    }
    else
    {
        /* select HSI as SYSCLK */
        Rcm_ConfigSysClk(RCM_SYSCLK_SEL_HSI);

        /* Initiatate the usart */
        Board_ComInit(COM1);
        printf("\r\n RCM clock switch to HSI(8MHz)\r\n");
        printf("  sysSource = %s ", g_rcmSysclkSelTab[Rcm_ReadSysClkSource()]);
        printf("  sysClock = %" PRId32 "\r\n", Rcm_ReadSysClkFreq());
    }
}

/*!
 * @brief       PLL as System Clock
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Rcm_SystemClock_PLL_Init(void)
{
    uint32_t timeout = 0xFFFF;
    
    /* Select HSI as System Clock at first */
    Rcm_ConfigSysClk(RCM_SYSCLK_SEL_HSI);

    /* Disable PLL */
    Rcm_DisablePll();

    /* Wait until Pll is disable */
    while ((Rcm_WaitPllReady() == (uint8_t)SUCCESS) && (timeout > 0U))
    {
        timeout = timeout - 1U;
    }
    
    if(Rcm_WaitPllReady() == (uint8_t)SUCCESS)
    {
        printf("\r\n Rcm_DisablePll timeout \r\n");
    }
    else
    {
        /* Config PLL source and multiplication factor
            SYSCLKFreq = (HSE * 4) / 1 */
        Rcm_ConfigPll(RCM_PLL_SEL_HSE, RCM_PLLMF_4);
        Rcm_ConfigClkDiv(RCM_CLK_DIV_1);

        /* Enable PLL */
        Rcm_EnablePll();
        
        timeout = 0xFFFF;
        /* Wait until Pll is ready */
        while ((Rcm_WaitPllReady() == (uint8_t)ERROR) && (timeout > 0U))
        {
            timeout = timeout - 1U;
        }
        if(Rcm_WaitPllReady() == (uint8_t)ERROR)
        {
            printf("\r\n Rcm_EnablePll timeout \r\n");
        }
        else
        {
            /* Selct PLL as Sysclk */
            Rcm_ConfigSysClk(RCM_SYSCLK_SEL_PLL);

            /* Initiatate the usart */
            Board_ComInit(COM1);
            printf("\r\n RCM clock switch to PLL(64MHz)\r\n");
            printf("  sysSource = %s ", g_rcmSysclkSelTab[Rcm_ReadSysClkSource()]);
            printf("  sysClock = %" PRId32 "\r\n", Rcm_ReadSysClkFreq());
        }
    }
}

/*!
 * @brief       Clock output init
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Rcm_ClockOutputInit(void)
{
    Gpio_ConfigType gpioconfig = {0};

    /* Connect RCM Clock output */
    Gpio_ConfigPinAF(GPIOA, GPIO_PIN_SOURCE_8, GPIO_AF_PIN0);
    gpioconfig.mode    =  GPIO_MODE_AF;
    gpioconfig.outtype =  GPIO_OUT_TYPE_PP;
    gpioconfig.pin     =  (uint16_t)GPIO_PIN_8;
    gpioconfig.pupd    =  GPIO_PUPD_NO;
    gpioconfig.speed   =  GPIO_SPEED_50MHz;
    Gpio_Config(GPIOA, &gpioconfig);

    /* set SYSCLK as COC source */
    Rcm_ConfigCoc(RCM_COC_SYSCLK);
}

/*!
 * @brief       Switch sysclk with Key press
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Rcm_KeySwitchSysclkIsr(void)
{
    if (Eint_ReadStatusFlag((uint32_t)EINT_LINE2) == (uint8_t)SET)
    {
        /* The interrupt flag bit must be cleared first. */
        Eint_ClearStatusFlag((uint32_t)EINT_LINE2);
        g_clkSwitchFlg = RCM_SYSCLK_SWITCH_PLL;
    }
    else
    {
        /* nothing */
    }
    if (Eint_ReadStatusFlag((uint32_t)EINT_LINE1) == (uint8_t)SET)
    {
        /* The interrupt flag bit must be cleared first. */
        Eint_ClearStatusFlag((uint32_t)EINT_LINE1);
        g_clkSwitchFlg = RCM_SYSCLK_SWITCH_HSE;
    }
    else
    {
        /* nothing */
    }
    if (Eint_ReadStatusFlag((uint32_t)EINT_LINE0) == (uint8_t)SET)
    {
        /* The interrupt flag bit must be cleared first. */
        Eint_ClearStatusFlag((uint32_t)EINT_LINE0);
        g_clkSwitchFlg = RCM_SYSCLK_SWITCH_HSI;
    }
    else
    {
        /* nothing */
    }
}

/*!
 * @brief       Rcm_Delay
 *
 * @param       None
 *
 * @retval      None
 *
 * @note
 */
void Rcm_Delay(void)
{
    volatile uint32_t delay = 0x7ffff;

    while (delay != 0U)
    {
        delay = delay - 1U;
    }
}


/**@} end of group RCM_ClockDetection_Functions */
/**@} end of group RCM_ClockDetection*/
/**@} end of group RCM_Examples */
/**@} end of group Examples */
