#include <stdlib.h>
#include "cpu_gpio.h"
#include "user_gpio.h"
#include <string.h>
#include "app_trace.h"
#include "app_config.h"
typedef struct 
{
    gpio_interrupt_handler gpio_handler;
}gpio_env_t;

gpio_env_t gpio_env;

void user_gpio_init(void)
{
    memset(&gpio_env, 0, sizeof(gpio_env_t));
}

void user_gpio_config(user_gpio_cfg_parameter_t *p_parameter)
{
    gpio_env.gpio_handler = p_parameter->gpio_handler;
}

/*****************************************************************************
 函 数 名  : gpio_config_default
 功能描述  : 设置所有IO默认下拉
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void gpio_config_default(void)
{
	gpio_pin pin;
	for(pin = GPIOA_Pin0;pin <= GPIOD_Pin7;pin ++){
		gpio_remap_config(pin,GPIO_Remap_GPIO);
		gpio_init(pin,GPIO_Mode_Input_Pull_Down_Resistor);
	}
}


/*****************************************************************************
 函 数 名  : all_gpio_config
 功能描述  : 设置所有IO并初始化
 输入参数  : gpio_mode_type mode  
 输出参数  : 无
*****************************************************************************/
void all_gpio_config(gpio_mode_type mode)
{
	gpio_pin pin;
	for(pin = GPIOA_Pin0;pin <= GPIOD_Pin7;pin ++){
		gpio_remap_config(pin,GPIO_Remap_GPIO);
		gpio_init(pin,mode);
	}
}



/*****************************************************************************
 函 数 名  : user_gpio_dir_out_hig
 功能描述  : 共阴极LED驱动 GPIO 输出
 输入参数  : uint32_t gpio_pins_map  
             uint32_t pins_value     
 输出参数  : 无
 调用说明  : 共阴极驱动
 函数说明  : 为低功耗设计的函数，高电平有驱动能力，低电平无驱动能力，低电平是配置输入下拉
 返 回 值  : 
*****************************************************************************/
void user_gpio_dir_out_hig(uint32_t gpio_pins_map, uint32_t pins_value)
{
	uint32_t input_pins;
	input_pins = (gpio_pins_map & (~pins_value));

    gpio_group_sel_init(GPIO_BANK_A,input_pins      ,GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_B,input_pins >> 8 ,GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_C,input_pins >> 16,GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_D,input_pins >> 24,GPIO_Mode_Input_Pull_Down_Resistor);

    gpio_group_sel_init(GPIO_BANK_A,pins_value    ,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_B,pins_value>>8 ,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_C,pins_value>>16,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_D,pins_value>>24,GPIO_Mode_Output);
    
    gpio_group_set(GPIO_BANK_A, pins_value      & 0xff);
    gpio_group_set(GPIO_BANK_B,(pins_value>>8)  & 0xff);
    gpio_group_set(GPIO_BANK_C,(pins_value>>16) & 0xff);
    gpio_group_set(GPIO_BANK_D,(pins_value>>24) & 0xff);
}

/*****************************************************************************
 函 数 名  : user_gpio_dir_out_hig
 功能描述  : 共阳极LED驱动 GPIO 输出
 输入参数  : uint32_t gpio_pins_map  
             uint32_t pins_value     
 输出参数  : 无
 调用说明  : 共阳极驱动
 函数说明  : 为低功耗设计的函数，低电平有驱动能力，高电平无驱动能力，高电平是配置输入
 返 回 值  : 
*****************************************************************************/
void user_gpio_dir_out_low(uint32_t gpio_pins_map, uint32_t pins_value)
{
	uint32_t input_pins;
	input_pins = (gpio_pins_map & (~pins_value));

    gpio_group_sel_init(GPIO_BANK_A,input_pins      ,GPIO_Mode_Input);
    gpio_group_sel_init(GPIO_BANK_B,input_pins >> 8 ,GPIO_Mode_Input);
    gpio_group_sel_init(GPIO_BANK_C,input_pins >> 16,GPIO_Mode_Input);
    gpio_group_sel_init(GPIO_BANK_D,input_pins >> 24,GPIO_Mode_Input);

    gpio_group_sel_init(GPIO_BANK_A,pins_value    ,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_B,pins_value>>8 ,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_C,pins_value>>16,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_D,pins_value>>24,GPIO_Mode_Output);
    
    gpio_group_reset(GPIO_BANK_A, pins_value      & 0xff);
    gpio_group_reset(GPIO_BANK_B,(pins_value>>8)  & 0xff);
    gpio_group_reset(GPIO_BANK_C,(pins_value>>16) & 0xff);
    gpio_group_reset(GPIO_BANK_D,(pins_value>>24) & 0xff);
}


/*****************************************************************************
 函 数 名  : user_gpio_dir_set
 功能描述  : 共阳极LED驱动
 输入参数  : uint32_t group_gpio_pins  
             uint32_t set_pins_value   
 输出参数  : 无
 函数说明  : 高电平低电平均有有驱动能力
 返 回 值  : 
*****************************************************************************/
void user_gpio_dir_set(uint32_t group_gpio_pins, uint32_t set_pins_value)
{
	uint32_t reset_gpio_pins;
	reset_gpio_pins = (group_gpio_pins & (~set_pins_value));

    gpio_group_sel_init(GPIO_BANK_A,group_gpio_pins    ,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_B,group_gpio_pins>>8 ,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_C,group_gpio_pins>>16,GPIO_Mode_Output);
    gpio_group_sel_init(GPIO_BANK_D,group_gpio_pins>>24,GPIO_Mode_Output);

    gpio_group_reset(GPIO_BANK_A, reset_gpio_pins      & 0xff);
    gpio_group_reset(GPIO_BANK_B,(reset_gpio_pins>>8)  & 0xff);
    gpio_group_reset(GPIO_BANK_C,(reset_gpio_pins>>16) & 0xff);
    gpio_group_reset(GPIO_BANK_D,(reset_gpio_pins>>24) & 0xff);
	
    gpio_group_set(GPIO_BANK_A, set_pins_value      & 0xff);
    gpio_group_set(GPIO_BANK_B,(set_pins_value>>8)  & 0xff);
    gpio_group_set(GPIO_BANK_C,(set_pins_value>>16) & 0xff);
    gpio_group_set(GPIO_BANK_D,(set_pins_value>>24) & 0xff);
}



/*****************************************************************************
 函 数 名  : user_gpio_out
 功能描述  : 低功耗方式下的输出配置，低电平为输入下拉配置，不具备驱动能力
 输入参数  : gpio_pin GPIO_Pin          
             functional_state_t enable  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void user_gpio_out(gpio_pin GPIO_Pin, functional_state_t enable)
{
	if(enable){
		gpio_remap_config(GPIO_Pin,GPIO_Remap_GPIO);
		gpio_init(GPIO_Pin,GPIO_Mode_Output); 
		gpio_set(GPIO_Pin);
	}else{
		gpio_remap_config(GPIO_Pin,GPIO_Remap_GPIO);
		gpio_init(GPIO_Pin,GPIO_Mode_Input_Pull_Down_Resistor);
	}
}

/*****************************************************************************
 函 数 名  : user_pwm_config
 功能描述  : pwm io口配置
 输入参数  : gpio_pin GPIO_Pin          
             functional_state_t enable  
 输出参数  : 无
*****************************************************************************/
void user_pwm_config(gpio_pin GPIO_Pin, functional_state_t enable)
{
	if(enable){
		gpio_init(GPIO_Pin,GPIO_Mode_Output);
		gpio_remap_config(GPIO_Pin,GPIO_Remap_PWM0);
	}else{
		gpio_remap_config(GPIO_Pin,GPIO_Remap_GPIO);
		gpio_init(GPIO_Pin,GPIO_Mode_Input_Pull_Down_Resistor);
	}
}


/*****************************************************************************
 函 数 名  : user_gpio_dir_in
 功能描述  : 配置gpio输入
 输入参数  : uint32_t gpio_pins_map     
             gpio_irq_type interr_type  
 输出参数  : 无
 返 回 值  : 
*****************************************************************************/
void user_gpio_dir_in(uint32_t gpio_pins_map,gpio_irq_type interr_type)
{
    uint8_t i=0;
    uint8_t interrupt_num = 0;
    gpio_group_sel_init(GPIO_BANK_A,gpio_pins_map    ,GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_B,gpio_pins_map>>8 ,GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_C,gpio_pins_map>>16,GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_D,gpio_pins_map>>24,GPIO_Mode_Input_Pull_Down_Resistor);

    for(i=0; i<32; i++)
    {
        if((gpio_pins_map>>i) & 0x00000001)
        {
            gpio_set_irq_src_type((irq_bank)interrupt_num,(gpio_pin)i,interr_type);
            interrupt_num++;
            if(interrupt_num >= 4)
                break;
        }
    }
}

/*****************************************************************************
 函 数 名  : user_gpio_get_pins_value
 功能描述  : 获取gpio组电平值
 输入参数  : uint32_t pins_map  
 输出参数  : 无
*****************************************************************************/
uint32_t user_gpio_get_pins_value(uint32_t pins_map)
{
    uint32_t pins_value = 0;
    pins_value = (GPIOD->inout_ctrl->IOD>>8<<24) | (GPIOC->inout_ctrl->IOD>>8<<16) |\
                 (GPIOB->inout_ctrl->IOD>>8<<8)| (GPIOA->inout_ctrl->IOD>>8);
                 
    return (pins_map & pins_value);
}

void GPIO_INT0_IRQHandler()
{
    gpio_clear_it_pending(GPIO_Int0);
    if(gpio_env.gpio_handler != NULL)
        gpio_env.gpio_handler(GPIO_Int0);
}

void GPIO_INT1_IRQHandler()
{
    gpio_clear_it_pending(GPIO_Int1);
    if(gpio_env.gpio_handler != NULL)
        gpio_env.gpio_handler(GPIO_Int1);
}

void GPIO_INT2_IRQHandler()
{
    gpio_clear_it_pending(GPIO_Int2);
    if(gpio_env.gpio_handler != NULL)
        gpio_env.gpio_handler(GPIO_Int2);
}

void GPIO_INT3_IRQHandler()
{
    gpio_clear_it_pending(GPIO_Int3);
    if(gpio_env.gpio_handler != NULL)
        gpio_env.gpio_handler(GPIO_Int3);
}


void set_gpio_irq(uint32_t gpio_pins_map,gpio_irq_type interr_type)
{
    uint8_t i=0;
    uint8_t interrupt_num = 0;
    gpio_group_sel_init(GPIO_BANK_A,	gpio_pins_map    ,	GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_B,	gpio_pins_map>>8 ,	GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_C,	gpio_pins_map>>16,	GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_D,	gpio_pins_map>>24,	GPIO_Mode_Input_Pull_Down_Resistor);

    for(i=0; i<32; i++)
    {
        if((gpio_pins_map>>i) & 0x00000001)
        {
            gpio_set_irq_src_type((irq_bank)interrupt_num,(gpio_pin)i,interr_type);
            interrupt_num++;
            if(interrupt_num >= 4)
                break;
        }
    }
}


void set_gpio_irq_sel_int(irq_bank start,uint32_t gpio_pins_map,gpio_irq_type interr_type)
{
    uint8_t i=0;
    uint8_t interrupt_num = start;
    gpio_group_sel_init(GPIO_BANK_A,	gpio_pins_map    ,	GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_B,	gpio_pins_map>>8 ,	GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_C,	gpio_pins_map>>16,	GPIO_Mode_Input_Pull_Down_Resistor);
    gpio_group_sel_init(GPIO_BANK_D,	gpio_pins_map>>24,	GPIO_Mode_Input_Pull_Down_Resistor);

    for(i=0; i<32; i++)
    {
        if((gpio_pins_map>>i) & 0x00000001)
        {
            gpio_set_irq_src_type((irq_bank)interrupt_num,(gpio_pin)i,interr_type);
            interrupt_num++;
            if(interrupt_num >= 4)
                break;
        }
    }
}


//=========================================================================
//****	GPIO 应用举例
//****  中断中，用阻塞打印
//****
//=========================================================================
void example_user_gpio_isr(uint8_t intter_num)
{
	switch(intter_num)
	{
		case GPIO_Int0:
			dbg_block_printf("int 0\n");
			if(gpio_get_input(GPIOA_Pin1)){
				dbg_block_printf("PA1 HIG \n");
				cpu_prevent_sleep_set(USER_INT0_ONGOING);			//
			}else{
				dbg_block_printf("PA1 LOW \n");
				cpu_prevent_sleep_clear(USER_INT0_ONGOING);			//
			}
			break;
		case GPIO_Int1:
			dbg_block_printf("int 1\n");
			if(gpio_get_input(GPIOA_Pin2)){
				dbg_block_printf("PA2 HIG \n");
				cpu_prevent_sleep_set(USER_INT1_ONGOING);			//
			}else{
				dbg_block_printf("PA2 LOW \n");
				cpu_prevent_sleep_clear(USER_INT1_ONGOING);			//
			}
			break;
		case GPIO_Int2:
			dbg_block_printf("int 2 ");
			if(gpio_get_input(GPIOA_Pin3)){
				dbg_block_printf("PA3 HIG \n");
				cpu_prevent_sleep_set(USER_INT2_ONGOING);			//
			}else{
				dbg_block_printf("PA3 LOW \n");
				cpu_prevent_sleep_clear(USER_INT2_ONGOING);			//
			}
			break;
		case GPIO_Int3:
			dbg_block_printf("int 3 ");
			if(gpio_get_input(GPIOA_Pin4)){
				dbg_block_printf("PA4 HIG \n");
				cpu_prevent_sleep_set(USER_INT3_ONGOING);			//
			}else{
				dbg_block_printf("PA4 LOW \n");
				cpu_prevent_sleep_clear(USER_INT3_ONGOING);			//
			}
			break;
	}
}


void user_gpio_example(void)
{
//	uint32_t i;
//【1】 开启GPIO 时钟	
	system_clock_config(ws_gpio,ENABLE);
	
//【2】 开启GPIO 中断	
	nvic_init_type_def nvic_init_structure;
	NVIC_SetPriorityGrouping(NVIC_PriorityGroup_2);
	nvic_init_structure.nvic_irq_channel_preemption_priority	= 1;
	nvic_init_structure.nvic_irq_channel_subpriority			= 0;
	nvic_init_structure.nvic_irq_channel_cmd					= ENABLE; 
	
	nvic_init_structure.nvic_irq_channel						= GPIO_INT0_IRQn;
	nvic_init(&nvic_init_structure);

	nvic_init_structure.nvic_irq_channel						= GPIO_INT1_IRQn;
	nvic_init(&nvic_init_structure);

	nvic_init_structure.nvic_irq_channel						= GPIO_INT2_IRQn;
	nvic_init(&nvic_init_structure);

	nvic_init_structure.nvic_irq_channel						= GPIO_INT3_IRQn;
	nvic_init(&nvic_init_structure);
	
//【3】 映射pin为GPIO	
	gpio_remap_config(GPIOA_Pin1,GPIO_Remap_GPIO);
	gpio_remap_config(GPIOA_Pin2,GPIO_Remap_GPIO);
	gpio_remap_config(GPIOA_Pin3,GPIO_Remap_GPIO);
	gpio_remap_config(GPIOA_Pin4,GPIO_Remap_GPIO);
	
//【4】 注册回掉函数
    user_gpio_cfg_parameter_t p_parameter;
	p_parameter.gpio_handler = example_user_gpio_isr;
	user_gpio_config(&p_parameter);

//【5】 配置GPIO下拉输入	内置70K下拉，目前输入模式支持 下拉 悬浮两种
	gpio_init(GPIOA_Pin1,GPIO_Mode_Input_Pull_Down_Resistor);
	gpio_init(GPIOA_Pin2,GPIO_Mode_Input_Pull_Down_Resistor);


//【6】 注册低功耗唤醒中断	高电平无法进入休眠，进入待机，必须保证配置了唤醒中断的GPIO 处于低电平
	setup_gpio_irq(GPIO_Int0,gpio_to_value(GPIOA_Pin1),GPIO_Int_Type_BothEdge); 	// PA1
	setup_gpio_irq(GPIO_Int1,gpio_to_value(GPIOA_Pin2),GPIO_Int_Type_BothEdge); 	// PA2


//【7】 注册普通中断	普通中断 在非低功耗状态下才能响应,
//						测试普通PA3 PA4两个中断，需要关闭低功耗，或者按下PA1不动测试PA3 PA4
	gpio_set_irq_src_type(GPIO_Int2,GPIOA_Pin3,GPIO_Int_Type_BothEdge);
	gpio_set_irq_src_type(GPIO_Int3,GPIOA_Pin4,GPIO_Int_Type_BothEdge);

}

/*****************************************************************************
 函 数 名  : user_gpio_standbye_example
 功能描述  : 注册了3个中断gpio PA1 PA2 PB4其中PB4唤醒，进入待机之前PA1 PA2为
             高电平
             
初始化条件如下 
#if SDK_ENABLE_STANDBYE
//【6】 注册待机唤醒gpio
    dbg_printf("Register standbye ... \n");
	setup_gpio_irq(GPIO_Int0,gpio_to_value(GPIOB_Pin4),GPIO_Int_Type_RisingEdge);		// PA0 每一比特对应一个gpio，PA0~PD7 共32位
#endif

//【7】 注册gpio中断回调函数
    p_parameter.gpio_handler = user_gpio_cbk;
    user_gpio_config(&p_parameter);

//【8】注册可唤醒类型的中断
	setup_gpio_irq(GPIO_Int1,gpio_to_value(GPIOA_Pin1),GPIO_Int_Type_BothEdge);		// PA1
	setup_gpio_irq(GPIO_Int2,gpio_to_value(GPIOA_Pin2),GPIO_Int_Type_BothEdge);		// PA2


             
 输入参数  : void  
*****************************************************************************/
void user_gpio_standbye_example(void)
{
	setup_gpio_irq(GPIO_Int1,gpio_to_value(GPIOA_Pin1),GPIO_Int_Type_Disable);		// PA1
	setup_gpio_irq(GPIO_Int2,gpio_to_value(GPIOA_Pin2),GPIO_Int_Type_Disable);		// PA2
	enter_standbye(SYSCFG_noRetention_Sram);
}

