/***********************************************************************
 * Copyright (c)  2017 - 2022, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : low_power_test.c
 * Description : low_power_test source file
 * Author(s)   : Mason
 * version     : V1.0
 * Modify date : 2022-08-04
 ***********************************************************************/
#include "low_power_test.h"
#include  "system_um321xF.h"
#include  "app.h"
#include  "config.h"
#include  "common.h"
#include  "gpio.h"
#include  "lptimer.h"
#include  "rtc.h"
#include  "lpuart.h"
#include  "wdt.h"

uint32_t g_PERICLKEN_STATUES;

uint32_t g_PASEL_STATUES;
uint32_t g_PBSEL_STATUES;
uint32_t g_PDSEL_STATUES;

uint32_t g_PADPU0_STATUES;                                              //上拉信息
uint32_t g_PADPU1_STATUES;

uint32_t g_PADPD0_STATUES;                                              //下拉信息
uint32_t g_PADPD1_STATUES;

/************************************************************************
 * Function     : low_power_before
 * Description  : setting before enter low power 
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void low_power_before(void)
{
	/**************进入低功耗前**************/
	/*1、获得当前整个系统使用到模块的时钟信息*/
	
	g_PERICLKEN_STATUES = REG_SCU_PERICLKEN;
	
	/*2、获得获得整个系统使用到io的状态信息*/
	
	g_PASEL_STATUES = REG_SCU_PASEL;
	g_PBSEL_STATUES = REG_SCU_PBSEL;
	g_PDSEL_STATUES = REG_SCU_PDSEL;
	
	g_PADPU0_STATUES = REG_SCU_PADPU0;
	g_PADPD0_STATUES = REG_SCU_PADPD0;
	
	/*****************关闭所有ip**********************/
	uint32_t reg_scu_periclken = 0;
	uint32_t reg_scu_perireset = 0;
	
	reg_scu_periclken |= ((1 << 20)|(1 << 13));                         //efc和rtc保留
	reg_scu_perireset |= ((1 << 20)|(1 << 13)); 
	
	REG_SCU_PERICLKEN = reg_scu_periclken;	  
	REG_SCU_PERIRESET = reg_scu_perireset;	  
	
    /*3、将所有的io配置为有利于最低功耗状态（根据外设情况，灵活调整）*/

        /*--将所有io禁用输入使能，且全部配置为下拉--*/
	
    REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; //清除IO写保护
    
    REG_SCU_PADPU0 = 0x0;                                               //A、B、C、D、E、F、G端口上拉禁止
    REG_SCU_PADPU1 = 0x0;                                               //A、B、C、D、E、F、G端口上拉禁止
                                                  
    REG_SCU_PADPD0 = 0;                                                 //A、B、C、D、E、F、G端口下拉开启
    REG_SCU_PADPD1 = 0;                                                 //A、B、C、D、E、F、G端口下拉开启
    
    REG_SCU_PADIE0 = 0 ;   
    REG_SCU_PADIE1 = 0 ; 
    
    REG_SCU_IOCTRLPROTECT = 0xffffffff;                                 //开启IO写保护
	
	/*4、关闭LVR、LVD等对功耗有影响的模块*/
		
    REG_SCU_LVRCFG &= ~(1<<0);
    
    REG_SCU_LVDCFG &= ~((1<<0)|(1<<24));
        
    REG_SCU_BUZZERCR &= ~(1<<17);                                       //蜂鸣器关闭
		
		
	/*5、清除SYSCTRL0,SYSCTRL1的写保护*/
	/*连接ULINK或者JLINK后，在SLEEP、DEEPSLEEP或者STOP模式下*/
	/*不唤醒系统，便于首次通过JLINK，能够正常唤醒*/
    REG_SCU_CTRLPROTECT = 0xA5A55A5A; 		
    REG_SCU_CTRL0 &= ~(1<<16);
	
}

/************************************************************************
 * Function     : set_wakeup_condition
 * Description  : configure wakeup conditions
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void set_wakeup_condition(void)
{
#ifdef IO_WAKE_UP	//通过IO进行中断唤醒	
    gpio_init(GPIOD, PIN4, 0);                                          //时钟初始化，模块正常工作
    gpio_irq_init(GPIOD, PIN4, ENABLE , NULL);                          //使能GPIO模块中断
    gpio_dir(GPIOD, PIN4,GPIO_DIR_IN);                                  //配置为输入
    gpio_in_enable(GPIOD, PIN4,ENABLE);                                 //输入使能
    gpio_config_pu(GPIOD, PIN4, ENABLE);                                //上拉使能 
    gpio_set_is(GPIOD, PIN4, GPIO_IS_EDGE);                             //EDGE触发中断
    gpio_set_ibe(GPIOD, PIN4, GPIO_IBE_SINGLE);                         //单边触发
    gpio_set_iev(GPIOD, PIN4, GPIO_IEV_FALLEDGEORLOWLEVEL);             //下降沿触发
#endif
    
    
#ifdef LPUART_WAKE_UP    //通过LPUART接收中断唤醒
    gpio_config_pu(GPIOF, PIN3, 1);                                     //PF3设置上拉
    gpio_in_enable(GPIOF, PIN3, 1);                                     //PF3配置输入使能
	lpuart_init(LPUART_BAUD_RATE);                                      //使能LPUART
    lpuart_irq_init(LPUART_IRQ_ENABLE, NULL, NULL);                     //开启LPUART接收中断
#endif
	
    
#ifdef LPTIMER_WAKE_UP   //通过LPtime进行中断唤醒
	lptim0_count_init(VAL_LPTIM_CR2_CLKSEL_LSRC32K, VAL_LPTIM_CR2_DIVSEL_DIV1, 32000*5);	//时钟源为32k,不分频，定时5s
	lptim0_irq_init(VAL_LPTIM_IRQ_ENABLE, VAL_LPTIM0_IER_UIE, NULL);				        //LPTimer0溢出中断初始化
	lptim0_start();	                                                                        
#endif


#ifdef WDT_WAKE_UP
    wdt_init(0);
    wdt_irq_init(WDT_IRQ_ENABLE,NULL);
    wdt_load_set(32000*5);					                            //5S中断
#endif


#ifdef RTC_WAKE_UP
    rtc_enable();                                                       //使能RTC
    rtc_irq_init(RTC_IRQ_ENABLE, NULL);                                 //开启RTC中断
#endif

}

#define SLEEP_MODE 		 	0
#define DEEPSLEEP_MODE  	1
#define STOP_MODE  			2

/************************************************************************
 * Function     : low_power_set
 * Description  : low power set
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void low_power_set(uint8_t lpmode)
{
	switch (lpmode)
	{
		case 0 : sys_entersleep();		break ;
		case 1 : sys_enterdeepsleep();	break ;
		case 2 : sys_enterstop();		break ;
	}
}

/************************************************************************
 * Function     : low_power_after
 * Description  : configure after low power 
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void low_power_after()
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;                                 //清除IO写保护
	/*所有io输入使能*/
	REG_SCU_PADIE0 = 0xFFFFFFFF;
	REG_SCU_PADIE1 = 0xFFFFFFFF;
    REG_SCU_IOCTRLPROTECT = 0xffffffff;                                 //开启IO写保护
  
    uart_init();
    printfS(" ***I am wake up***!\r\n");	
	
	/**************唤醒后**************/
	/*1、根据记录的模块时钟信息进行还原*/
	
	/*2、根据记录的IO信息进行还原*/
		
}

/************************************************************************
 * Function     : lowpower_test
 * Description  : lowpower test
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void lowpower_test(void)
{
	low_power_before();                                                 //根据实际应用，配置休眠前的操作
	set_wakeup_condition();			                                    //配置【唤醒条件】
	low_power_set(DEEPSLEEP_MODE);                                      //根据参数进入到休眠模式
	low_power_after();                                                  //被【唤醒条件】唤醒之后的操作
	
}

/************************************************************************
 * Function     : dynamic_low_power_before
 * Description  : dynamic low power before
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void dynamic_low_power_before()
{
	uint32_t reg_scu_periclken = 0;
	uint32_t reg_scu_perireset = 0;
	
	reg_scu_periclken |= (1 << 20);                                     //efc保留
	reg_scu_perireset |= (1 << 20); 
	
	REG_SCU_PERICLKEN = reg_scu_periclken;	  
	REG_SCU_PERIRESET = reg_scu_perireset;	  
    
    REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;                                 //清除IO写保护
    
    REG_SCU_PADPU0 = 0x0;                                               //A、B、C、D、E、F、G端口上拉禁止
    REG_SCU_PADPU1 = 0x0;                                               //A、B、C、D、E、F、G端口上拉禁止
    
    REG_SCU_PADPD0 = 0xffffffff;                                        //A、B、C、D、E、F、G端口下拉开启
    REG_SCU_PADPD1 = 0xffffffff;                                        //A、B、C、D、E、F、G端口下拉开启
    
    REG_SCU_PADIE0 = 0 ;   
    REG_SCU_PADIE1 = 0 ; 
    
    REG_SCU_IOCTRLPROTECT = 0xffffffff;                                 //开启IO写保护

/*4、关闭LVR、LVD等对功耗有影响的模块*/
    
    REG_SCU_LVRCFG &= ~(1<<0);
    
    REG_SCU_LVDCFG &= ~((1<<0)|(1<<24));
    
    
    REG_SCU_PERICLKEN &= ~(1<<13);	                                    //关闭rtc时钟	
    REG_SCU_PERIRESET &= ~(1<<13);	                                    //rtc保持复位
    
    REG_SCU_BUZZERCR &= ~(1<<17);
		
	
}

/************************************************************************
 * Function     : dynamic_lowpower_test
 * Description  : dynamic lowpower test
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void dynamic_lowpower_test(void)
{
	dynamic_low_power_before();
	while(1);                                                           //ip全部关闭，在rch48M的情况下，运行while（1）；测量其功耗
}
