/******************************************************************************

                  版权所有 (C), 2019-2039, 深圳前海维晟智能技术有限公司

 ******************************************************************************
  文 件 名   : deep_sleep_awk.c
  版 本 号   : 初始版本
  生成日期   : 2019年12月3日
  最近修改   :
  功能描述   : 休眠中断唤醒
  函数列表   :
              Awake_NVIC_Configuration
              deep_sleep_awkup
              GPIO_INT0_IRQHandler
******************************************************************************/

#include <stdio.h>
#include "sdk_include.h"

uint8_t cur_power_mode_type 	= 0xFF;
uint8_t sys_power_mode 		= 0xFF;

typedef struct _irq_awk_sav{
	int32_t irq_bank;
	gpio_pin irq_gpio;
}irq_awk_sav;

static irq_awk_sav irq_gpio[4]={
	{GPIO_Int0,GPIO_INVAILD},
	{GPIO_Int1,GPIO_INVAILD},
	{GPIO_Int2,GPIO_INVAILD},
	{GPIO_Int3,GPIO_INVAILD},
};

static irq_awk_sav awk_gpio[4]={
	{GPIO_Int0,GPIO_INVAILD},
	{GPIO_Int1,GPIO_INVAILD},
	{GPIO_Int2,GPIO_INVAILD},
	{GPIO_Int3,GPIO_INVAILD},
};

void cpu_prevent_sleep_clear(uint32_t prv_slp_bit);
void cpu_prevent_sleep_set(uint32_t prv_slp_bit);
uint32_t cpu_prevent_sleep_get(void);
void deepsleep_prepare(void);
void deepsleep_exit(void);



/*****************************************************************************
 函 数 名  : low_power_type_config_ex
 功能描述  : 低功耗切换函数
 输入参数  : deep_sleep_retain retention_sram  
             uint8_t type                      
 输出参数  : 无
 返 回 值  : static
 调用函数  : 
 被调函数  : 
*****************************************************************************/
static void low_power_type_config_ex(deep_sleep_retain retention_sram,uint8_t type)
{
	if (type > sys_power_mode)
		return;

	if(retention_sram == SYSCFG_noRetention_Sram)		// 低功耗不允许不配置内存
	{
		return;
	}
	
    syscfg_deepsleep_set_ram_retention(retention_sram);
	syscfg_deepsleep_cmd_wakeup_source(src_deep_sleep_ctrl_gpio_wk_en,DISABLE);	//禁用IO唤醒源
	
	cur_power_mode_type = type;
	
//	set_low_power_mode(sys_power_mode != NONE_SLEEP);

	if (cur_power_mode_type == DEEP_SLEEP)									//深度睡眠
	{
		syscfg_deepsleep_set_mode(SYSCFG_DeepSleepMode_DEEPSLEEP);
	}	
	else if (cur_power_mode_type == NORMAL_SLEEP)							//浅度睡眠
	{
		syscfg_deepsleep_set_mode(SYSCFG_DeepSleepMode_SLEEP); 
	}
}



/*****************************************************************************
 函 数 名  : deep_sleep_not_available
 功能描述  : 低功耗自适应调整函数
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
static  uint8_t deep_sleep_not_available(void)
{
//【1】 检测低功耗系统开关
//    if(get_low_power_mode() == 0){								// 	不允许低功耗休眠
//		return 1;
//    }
	
//【2】 系统只允许浅睡眠低功耗
	if(sys_power_mode == NORMAL_SLEEP){
		*((__IO uint32_t *)(0xE000ED10)) = 0x0; //浅睡眠
		__wfi();
		return 1;
	}


//【3】 任务处理完 切换到深睡眠模式
	if((cur_power_mode_type == NORMAL_SLEEP) && (cpu_prevent_sleep_get() == 0)){
//		dbg_block_printf("will goto deep sleep\n");
		low_power_type_config_ex(SYSCFG_Retention_Sram_24k,DEEP_SLEEP);
		*((__IO uint32_t *)(0xE000ED10)) = 0x4; //深睡眠
        return 1;
	}
	
//【4】 深睡眠模式 有任务要处理，需要切换到浅睡眠模式
	if ((cur_power_mode_type == DEEP_SLEEP) && cpu_prevent_sleep_get()){
//		dbg_block_printf("will goto normal sleep\n");
		low_power_type_config_ex(SYSCFG_Retention_Sram_24k,NORMAL_SLEEP);
		*((__IO uint32_t *)(0xE000ED10)) = 0x0; //浅睡眠
        return 1;
	}
	
//【5】 当前处于无低功耗状态
	if(cur_power_mode_type == NONE_SLEEP){
		return 1;
	}
	

//【6】 当前处于浅睡眠低功耗状态
	if(cur_power_mode_type == NORMAL_SLEEP){
		*((__IO uint32_t *)(0xE000ED10)) = 0x0; //浅睡眠
		__wfi();
		return 1;
	}
	
//	dbg_block_printf("m %x s %x ",cur_power_mode_type,cpu_prevent_sleep_get());
// 系统允许深睡眠模式

//【7】 SDK 底层校准中 不允许深度睡眠
//    if(get_calibrate_ing()){
//        return 1;
//    }

//【8】	允许DEEP_SLEEP的情况
	return 0;
}

/*****************************************************************************
 函 数 名  : low_power_sleep
 功能描述  : 低功耗处理函数
 输入参数  : ptr_sleep lib_sleep  
 输出参数  : 无
 返 回 值  : 

*****************************************************************************/
void low_power_sleep(void)
{
//【0】低功耗之前，应该把串口FIFO数据刷掉，保证数据完整性及实时性
	flush_uartx_2_usr_fifo(cur_power_mode_type);

//【1】低功耗自适应函数
	if(deep_sleep_not_available())
		return;

//【2】重设低功耗寄存器
	low_power_sleep_config_ex(SYSCFG_Retention_Sram_24k,SDK_ENABLE_SLEEP);
    
		
//【3】进入低功耗，非常开电源域外设会掉电，需要进行数据或者省电处理
//     外设寄存器少或关键外设部分，放入retainram区域中
    deepsleep_prepare();       /* prepare for into sleep. */

//【4】ws8100进入低功耗状态，高频部分停止工作，32k监测唤醒事件
    deep_sleep_enter();		/* into sleep. */

//【5】ws8100检测到唤醒事件，高频部分停开始工作，恢复外设，恢复运行
//	   外设寄存器少或关键外设部分，从retainram区域中恢复
    deepsleep_exit();			/* exit sleep */
}


/*****************************************************************************
 函 数 名  : enter_standbye_deepsleep
 功能描述  : 待机配置函数
 输入参数  : deep_sleep_retain type  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 
*****************************************************************************/
void enter_standbye_deepsleep(deep_sleep_retain type)
{
	syscfg_deepsleep_cmd_wakeup_source(src_deep_sleep_ctrl_gpio_wk_en,ENABLE); 		// ++				
	syscfg_deepsleep_set_mode(SYSCFG_DeepSleepMode_DEEPSLEEP_PLUS);	
	*((__IO uint32_t *)(0xE000ED10)) = 0x4;  				//使能arm核休眠                    
		dbg_block_printf("sleep noRetention_Sram.\n");			//此处需要用pringf，阻塞方式输出
	deepsleep_prepare();
	__wfi();
}



/*****************************************************************************
 函 数 名  : low_power_sleep_config
 功能描述  : 低功耗配置函数
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 
*****************************************************************************/
void low_power_sleep_config( void )
{
	sys_power_mode = SDK_ENABLE_SLEEP;
	
     /* set retention ram size 8k/16k/32k */
    syscfg_deepsleep_set_ram_retention(SYSCFG_Retention_Sram_24k);
	syscfg_deepsleep_cmd_wakeup_source(src_deep_sleep_ctrl_jtag,ENABLE);								//禁用JTAG休眠唤醒
	syscfg_deepsleep_cmd_wakeup_source(src_deep_sleep_ctrl_gpio_wk_en,DISABLE);	//禁用IO唤醒源

/* open low power mode. */
#if (SDK_ENABLE_SLEEP)
   // set_low_power_mode(TRUE);
    /* sleep mode : Deepsleep */
    syscfg_deepsleep_set_mode(SYSCFG_DeepSleepMode_DEEPSLEEP ); 
	cur_power_mode_type 	=   DEEP_SLEEP;
#else
   // set_low_power_mode(FALSE);
#endif

}


/*****************************************************************************
 函 数 名  : low_power_sleep_config_ex
 功能描述  : 低功耗配置函数
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void low_power_sleep_config_ex(deep_sleep_retain retain,uint8_t type)
{
//【1】 配置系统低功耗模式
	sys_power_mode = type;

//【2】 配置低功耗保留RAM 大小
    syscfg_deepsleep_set_ram_retention(SYSCFG_Retention_Sram_24k);

//【3】 开启蓝牙设备中，蓝牙唤醒会激活GPIO唤醒源，此处禁用GPIO 唤醒
	syscfg_deepsleep_cmd_wakeup_source(src_deep_sleep_ctrl_gpio_wk_en,ENABLE);		//IO唤醒源

//【4】 开启蓝牙设备中，蓝牙唤醒会激活GPIO唤醒源，此处禁用GPIO 唤醒
	syscfg_deepsleep_cmd_wakeup_source(src_deep_sleep_ctrl_ble_extwkupdsb,DISABLE);	//禁用BT唤醒源

//【5】禁用JTAG唤醒
	syscfg_deepsleep_cmd_wakeup_source(src_deep_sleep_ctrl_jtag,ENABLE);				//使能JTAG休眠唤醒

//【6】设置低功耗开关
	//set_low_power_mode(sys_power_mode != NONE_SLEEP);

//【7】设置当前低功耗状态
	cur_power_mode_type 	=	sys_power_mode;

//【8】将当前低功耗模式写入寄存器
	if (cur_power_mode_type == DEEP_SLEEP)								//深度睡眠
	{
		*((__IO uint32_t *)(0xE000ED10)) = 0x4; 							//深度睡眠
	    syscfg_deepsleep_set_mode(SYSCFG_DeepSleepMode_DEEPSLEEP);
	}
	else if (cur_power_mode_type == NORMAL_SLEEP)							//浅度睡眠
	{
		*((__IO uint32_t *)(0xE000ED10)) = 0x0; 							//浅睡眠
		syscfg_deepsleep_set_mode(SYSCFG_DeepSleepMode_SLEEP); 
	}
}

/*****************************************************************************
 函 数 名  : set_gpio_wake_deepsleep
 功能描述  : 选择中断组的方式配置待机唤醒
 输入参数  : irq_bank start     
             uint32_t pins_map  
 输出参数  : 无
 调用注意  : 过时接口，兼容早期版本，使用 setup_gpio_wake_irq 代替
*****************************************************************************/
void set_gpio_wake_deepsleep(irq_bank start,uint32_t pins_map)
{
    int i=0,k=start;
    for(i=0; i<32; i++)
    {
        if((pins_map & ((0x00000001)<< i)) && (k<4))
        {
            syscfg_deepsleep_set_gpiopin_wakeup_src((irq_bank)(GPIO_Int0+k),WakeUpType_32K_AntiShake,(gpio_pin)i);
			gpio_set_irq_src_type((irq_bank)(GPIO_Int0+k),(gpio_pin)i,GPIO_Int_Type_RisingEdge);
			k++;
        }
    }
}

/*****************************************************************************
 函 数 名  : setup_gpio_wake_irq
 功能描述  : 唤醒配置
 输入参数  : irq_bank start 可选参数:
							             	GPIO_Int0
							             	GPIO_Int1
											GPIO_Int2
											GPIO_Int3
		uint32_t pins_map   可选参数:
							             	gpio_to_value(GPIOA_Pin1)
							             	gpio_to_value(GPIOA_Pin2)
							             	...
							             	gpio_to_value(GPIOD_Pin7)
         gpio_irq_type type  可选参数:
							             	GPIO_Int_Type_Disable,
											GPIO_Int_Type_RisingEdge,
											GPIO_Int_Type_FallingEdge,
											GPIO_Int_Type_BothEdge 
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void setup_gpio_wake_irq(irq_bank start,uint32_t pins_map,gpio_irq_type type)
{
    int i=0,k=start;
	
	gpio_wk_type wk_type = WakeUpType_32K_AntiShake;
	
	if(type == GPIO_Int_Type_Disable)
		wk_type = WakeUpType_Disable;
		
    for(i=0; i<32; i++)
    {
        if((pins_map & ((0x00000001)<< i)) && (k<4))
        {
            deepsleep_set_wakeup_gpio((irq_bank)(GPIO_Int0+k),wk_type,type,(gpio_pin)i);
			gpio_set_irq_src_type((irq_bank)(GPIO_Int0+k),(gpio_pin)i,type);
			if(wk_type == GPIO_Int_Type_Disable){
				awk_gpio[k].irq_gpio = GPIO_INVAILD;
			}else{
				awk_gpio[k].irq_gpio = (gpio_pin)i;
			}
			k++;
        }
    }
}


/*****************************************************************************
 函 数 名  : setup_gpio_irq
 功能描述  : 低功耗模式下的中断配置
 输入参数  : irq_bank start 可选参数:
							             	GPIO_Int0
							             	GPIO_Int1
											GPIO_Int2
											GPIO_Int3
		uint32_t pins_map   可选参数:
							             	gpio_to_value(GPIOA_Pin1)
							             	gpio_to_value(GPIOA_Pin2)
							             	...
							             	gpio_to_value(GPIOD_Pin7)
         gpio_irq_type type  可选参数:
							             	GPIO_Int_Type_Disable,
											GPIO_Int_Type_RisingEdge,
											GPIO_Int_Type_FallingEdge,
											GPIO_Int_Type_BothEdge 
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void setup_gpio_irq(irq_bank start,uint32_t pins_map,gpio_irq_type type)
{
    int i=0,k=start;
	
	gpio_wk_type wk_type = WakeUpType_32K_AntiShake;
	
	if(type == GPIO_Int_Type_Disable)
		wk_type = WakeUpType_Disable;
		
    for(i=0; i<32; i++)
    {
        if((pins_map & ((0x00000001)<< i)) && (k<4))
        {
            deepsleep_set_wakeup_gpio((irq_bank)(GPIO_Int0+k),wk_type,type,(gpio_pin)i);
			gpio_set_irq_src_type((irq_bank)(GPIO_Int0+k),(gpio_pin)i,type);
			if(wk_type == GPIO_Int_Type_Disable){
				irq_gpio[k].irq_gpio = GPIO_INVAILD;
			}else{
				irq_gpio[k].irq_gpio = (gpio_pin)i;
			}
			k++;
        }
    }
}


/*****************************************************************************
 函 数 名  : cmd_goto_standbye_prepare
 功能描述  : 进入待机准备，禁用可中断唤醒源,检测唤醒IO为低电平，才能进入待机
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void cmd_goto_standbye_prepare(void)
{
	int i,j;
	for(i=0;i<4;i++){
		if(irq_gpio[i].irq_gpio != GPIO_INVAILD){
			setup_gpio_irq((irq_bank)irq_gpio[i].irq_bank,gpio_to_value(irq_gpio[i].irq_gpio),GPIO_Int_Type_Disable);
		}
	}
	
	for(i=0;i<4;i++){
		if(awk_gpio[i].irq_gpio != GPIO_INVAILD){
			while(gpio_get_input(awk_gpio[i].irq_gpio));
			for(j=0;j<10000;j++);	
			while(gpio_get_input(awk_gpio[i].irq_gpio));
			for(j=0;j<10000;j++);
			while(gpio_get_input(awk_gpio[i].irq_gpio));
			for(j=0;j<10000;j++);
		}
	}
}


 
