/**
  ******************************************************************************
  * @file    PMU/LOW_POWER/main.c
  * @author  IOT Development Team
  * @version V1.0.0
  * @date    10-January-2020
  * @brief   Main program body.
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "apm32f10x.h"
#include "platform_config.h"

/** @addtogroup APM32F10x_StdPeriph_Examples
  * @{
  */

/** @addtogroup PMU_LOW_POWER
  * @{
  */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define PMU_SLEEPEntry_WFI  ((uint8_t)0x01)
#define PMU_SLEEPEntry_WFE  ((uint8_t)0x02)
#define SysCtrl_SLEEPONEXIT_Set  ((uint16_t)0x0002)
#define SysCtrl_SLEEPDEEP_Set  ((uint16_t)0x0004)

#define STANDBY_Mode
#define STOP_Mode
#define SLEEP_Mode
#define LIRC_ON
#define IWDT_ON

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
GPIO_ConfigStruct_T  GPIO_configStruct;
/* Private function prototypes -----------------------------------------------*/
void PMU_EnterSLEEPMode(u32 SysCtrl_Set,u8 PMU_SLEEPEntry);

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */

int main(void)
{
    /*!< At this stage the microcontroller clock setting is already configured,
         this is done through SystemInit() function which is called from startup
         file (startup_apm32f10x_xx.s) before to branch to application main.
         To reconfigure the default setting of SystemInit() function, refer to
         system_apm32f10x.c file
       */
    
    RCM_Reset();

    GPIO_ConfigPinRemap(GPIO_REMAP_SWJ_Disable);
    GPIO_ConfigPinRemap(GPIO_REMAP_PD01);

    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOE|RCM_APB2_PERIPH_GPIOB|
                              RCM_APB2_PERIPH_GPIOD|RCM_APB2_PERIPH_GPIOA|
                              RCM_APB2_PERIPH_GPIOC|RCM_APB2_PERIPH_AFIO);

    GPIO_configStruct.pin=GPIO_PIN_All;
    GPIO_configStruct.mode=GPIO_MODE_IN_PD;
    GPIO_configStruct.speed= GPIO_SPEED_50MHz;
    GPIO_Config(GPIOA,&GPIO_configStruct);
    GPIO_Config(GPIOB,&GPIO_configStruct);
    GPIO_Config(GPIOC,&GPIO_configStruct);
    GPIO_Config(GPIOD,&GPIO_configStruct);
    GPIO_Config(GPIOE,&GPIO_configStruct);
    
    /* Initialize LEDs and Key Button mounted on APM32-MINI board */
#if defined(APM32_MINI)
    APM_MINI_LEDInit(LED2);
    APM_MINI_LEDInit(LED3);
#elif defined (APM32_DISCOVERY)
    APM_DISCOVERY_LEDInit(LED2);
    APM_DISCOVERY_LEDInit(LED3);
#elif defined(APM32F103V_EVAL)
    APM_EVAL_LEDInit(LED2);
    APM_EVAL_LEDInit(LED3);
#endif

    /* Configure PA.3 (USART2_RX) and PA.10 (USART1_RX)*/
    GPIO_configStruct.pin=GPIO_PIN_3|GPIO_PIN_10;
    GPIO_configStruct.mode=GPIO_MODE_IN_FLOATING;
    GPIO_Config(GPIOA,&GPIO_configStruct);

    /* Configure PA.13 (JTMS/SWDAT), PA.14 (JTCK/SWCLK) and PA.15 (JTDI)*/
    GPIO_configStruct.pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    GPIO_configStruct.speed = GPIO_SPEED_50MHz;
    GPIO_configStruct.mode = GPIO_MODE_IN_FLOATING;
    GPIO_Config(GPIOA, &GPIO_configStruct);

    /* Configure PB.03 (JTDO) and PB.04 (JTRST) */
    GPIO_configStruct.pin = GPIO_PIN_3 | GPIO_PIN_4;
    GPIO_configStruct.speed = GPIO_SPEED_50MHz;
    GPIO_configStruct.mode = GPIO_MODE_IN_FLOATING;
    GPIO_Config(GPIOB, &GPIO_configStruct);

    /* Disable the LIRC¡¢HIRC¡¢HXT¡¢LXT*/
    RCM_DisableLIRC();
    RCM_DisableHIRC();
    RCM_ConfigHXT(RCM_HXT_CLOSE);
    RCM_ConfigLXT(RCM_LXT_CLOSE);

    while (RCM_ReadFlag(RCM_FLAG_LIRCRDY) == SET)
    {
    }

    /* Disable the RTC */
    RCM_DisableRTCCLK();

    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_PMU);
    
#if defined(STANDBY_Mode)

#if defined(LIRC_ON)
    
    /* Enables the Internal Low Speed oscillator (LIRC) */
    RCM_EnableLIRC();;

    while (RCM_ReadFlag(RCM_FLAG_LIRCRDY) == RESET)
    {
    }

    
#endif

#if defined(IWDT_ON)
    
    /* Enable the IWDT write access */
    IWDT_WriteAccess_Enable();
    
    /* Set IWDT frequency divider values */
    IWDT_SetDivider(IWDT_DIVIDER_256);   
    
    /* Set IWDT count reload values */
    IWDT_SetCountReload(0x0FFF);   
    
    /* Reload the IWDT counter with value */
    IWDT_ReloadCounter();   
    
    /* Enable the IWDT */
    IWDT_Enable();   
    
#endif

    /* Enters STANDBY mode */
    PMU_EnterStandbyMode();
    
#elif defined (STOP_Mode)

    /* Enters STOP mode */
    PMU_EnterSTOPMode(PMU_Regulator_ON, PMU_STOPEntry_WFI);
    
#elif defined (SLEEP_Mode)

    /* Configures the APB1 clock (PCLK1) */
    RCM_ConfigAPB1(RCM_HCLK_DIV_2);
    
    /* Configures the APB2 clock (PCLK2) */
    RCM_ConfigAPB2(RCM_HCLK_DIV_1);
    
    /* Enables the PLL */
    RCM_EnablePLL();

    while (RCM_ReadFlag(RCM_FLAG_PLLRDY) == RESET)
    {
    }

    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOF|RCM_APB2_PERIPH_GPIOG|RCM_APB2_PERIPH_ADC1|RCM_APB2_PERIPH_ADC2|RCM_APB2_PERIPH_TMR1|RCM_APB2_PERIPH_SPI1|RCM_APB2_PERIPH_TMR8
                           |RCM_APB2_PERIPH_USART1|RCM_APB2_PERIPH_ADC3|RCM_APB2_PERIPH_TMR15|RCM_APB2_PERIPH_TMR16|RCM_APB2_PERIPH_TMR17|RCM_APB2_PERIPH_TMR9|RCM_APB2_TPERIPH_TMR10
                           |RCM_APB2_PERIPH_TMR11);
    
    RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR2|RCM_APB1_PERIPH_TMR3|RCM_APB1_PERIPH_TMR4|RCM_APB1_PERIPH_TMR5|RCM_APB1_PERIPH_TMR6|RCM_APB1_PERIPH_TMR7|RCM_APB1_PERIPH_TMR12
                           |RCM_APB1_PERIPH_TMR13|RCM_APB1_PERIPH_TMR14|RCM_APB1_PERIPH_WWDT|RCM_APB1_PERIPH_SPI2|RCM_APB1_PERIPH_SPI3|RCM_APB1_PERIPH_USART2|RCM_APB1_PERIPH_USART3
                           |RCM_APB1_PERIPH_UART4|RCM_APB1_PERIPH_UART5|RCM_APB1_PERIPH_I2C1|RCM_APB1_PERIPH_I2C2|RCM_APB1_PERIPH_USB|RCM_APB1_PERIPH_CAN1|RCM_APB1_PERIPH_CAN2
                           |RCM_APB1_PERIPH_BAKR|RCM_APB1_PERIPH_PMU|RCM_APB1_PERIPH_DAC);

    /*  */
    PMU_EnterSLEEPMode(SysCtrl_SLEEPONEXIT_Set,PMU_SLEEPEntry_WFI);
    
#endif

    while (1);
}

/**
  * @brief  Configures EINT Lines.
  * @param  SysCtrl_Set
  * @param  PMU_SLEEPEntry
  * @retval None
  */
void PMU_EnterSLEEPMode(u32 SysCtrl_Set,u8 PMU_SLEEPEntry)
{
    if (SysCtrl_Set)
    {
        SCB->SCR |= SysCtrl_SLEEPONEXIT_Set;
    }
    else
    {
        SCB->SCR &= ~SysCtrl_SLEEPONEXIT_Set;
    }

    SCB->SCR &= ~SysCtrl_SLEEPDEEP_Set;

    if (PMU_SLEEPEntry == PMU_SLEEPEntry_WFI)
    {
        __WFI();
    }
    else
    {
        __WFE();
    }
}
