/**
******************************************************************************************************************************************************************************************
*@file                       cpu_gpio.c
*@author         
*@data                       
*@version                    v1.0
*@par Copyright(c):
*
*@par History:
*     version:author,date,desc
*     v1.0   :create this file
*
*******************************************************************************************************************************************************************************************
*/
#include	"cpu_gpio.h"
#include 	"app_trace.h"

gpio_type_def gpio_a = {GPIOA_INOUT_CTRL,GPIOA_MAP_CTRL};
gpio_type_def gpio_b = {GPIOB_INOUT_CTRL,GPIOB_MAP_CTRL};
gpio_type_def gpio_c = {GPIOC_INOUT_CTRL,GPIOC_MAP_CTRL};
gpio_type_def gpio_d = {GPIOD_INOUT_CTRL,GPIOD_MAP_CTRL};

gpio_type_def *GPIOA = &gpio_a;
gpio_type_def *GPIOB = &gpio_b;
gpio_type_def *GPIOC = &gpio_c;
gpio_type_def *GPIOD = &gpio_d;

gpio_type_def *gpio_bank_reg[4]={&gpio_a,&gpio_b,&gpio_c,&gpio_d};
/*******************************************************************************
* 函数名   : gpio_remap_config.
* 说明     : GPIO 的映射配置
* 参数     : -gpio_pinx,    pin脚编号: GPIOA_Pin0--GPIOD_Pin7
             -gpio_remap,   映射类型,参考 gpio_remap_type 定义
* 返回值   : None.
* 示例     : gpio_remap_config(GPIOB_Pin2,GPIO_Remap_UART0_RX); 设置PB2 串口0 RX 
*******************************************************************************/
void gpio_remap_config(gpio_pin gpio_pinx, gpio_remap_type gpio_remap)
{
	if(gpio_pinx > GPIO_MAXS )
		return;

	gpio_type_def 		*gpiox 		= gpio_bank_reg[gpio_pinx>>3];
	unsigned char 		gpio_pin_x 	= gpio_pinx & 0x07;
	
	// 每个IO占用8位，低6位为配置，高2位位状态读取 
	// 8个一组，占用64bit 0-3 占用0-31 bit 4-7占用32-63 bit
	
	uint32_t pos 	= gpio_pin_x >> 2;
	uint32_t mask 	= 0x3f			<< ((gpio_pin_x & 0x03) << 3);
	uint32_t val 	= gpio_remap	<< ((gpio_pin_x & 0x03) << 3);
	
	gpiox->map_ctrl->map_mode[pos] &= ~mask;
	gpiox->map_ctrl->map_mode[pos] |= val;
}

/*******************************************************************************
* 函数名   : gpio_init.
* 说明     : GPIO 的初始化,配置GPIO的模式,输入、输出、下拉
* 参数     : -gpio_pinx,  pin脚编号: GPIOA_Pin0--GPIOD_Pin7
             -gpio_mode, GPIO的模式,参考 gpio_mode_type 定义
* 返回值   : None.
* 示例     : gpio_init(GPIOB_Pin2,GPIO_Mode_Output); 设置PB2 为输出模式
*******************************************************************************/
void gpio_init(gpio_pin gpio_pinx,gpio_mode_type gpio_mode)
{
	uint32_t set_pin_bit 			= 0;
	if(gpio_pinx > GPIO_MAXS )
		return;
	
	gpio_type_def 		*gpiox 			= gpio_bank_reg[gpio_pinx>>3];
	unsigned char 		 gpio_pin_x 	= gpio_pinx&7;
	// 0-15 
	// 每个IO占用2位，00 输入  10 下拉输入 11 输出	adc无效
	set_pin_bit = (gpio_pin_x << 1);
	gpiox->inout_ctrl->CON &= ~(3         << set_pin_bit);
	gpiox->inout_ctrl->CON |= (gpio_mode << set_pin_bit);
}

/*******************************************************************************
* 函数名   : gpio_group_init.
* 说明     : GPIO 按照组来初始化,配置GPIO的模式,输入、输出、下拉
* 参数     : -bank,  	 组编号: GPIO_BANK_A -- GPIO_BANK_D
             -gpio_mode, GPIO的模式,参考 gpio_mode_type 定义
* 返回值   : None.
* 示例     : gpio_group_init(GPIO_BANK_B,GPIO_Mode_Output); 设置B组所有IO 为输出模式
*******************************************************************************/
void gpio_group_init(group_bank bank,gpio_mode_type gpio_mode)
{
	uint32_t gpio_pin_x 			= 0;
	uint32_t set_pin_bit 			= 0;
	if(bank > GPIO_BANK_MAX )
		return;
	
	gpio_type_def *gpiox 		= gpio_bank_reg[bank];
	// 每个IO占用2位，00 输入  10 下拉输入 11 输出	adc无效
	for(gpio_pin_x = 0; gpio_pin_x < 8; gpio_pin_x++)
	{
		set_pin_bit = (gpio_pin_x<<1);
		gpiox->inout_ctrl->CON &= ~(3         << set_pin_bit);
		gpiox->inout_ctrl->CON |= (gpio_mode << set_pin_bit);
	}
}

/*******************************************************************************
* 函数名   : gpio_group_sel_init.
* 说明     : 初始化某组中部分GPIO
* 参数     : -gpio_pinx, 	pin脚编号: GPIOA_Pin0--GPIOD_Pin7       
			 -gpio_pins_map,0x00~0xFF
* 返回值   : None.
* 示例     : gpio_group_sel_init(GPIO_BANK_B,0x04,GPIO_Mode_Input);  设置B组中IO 2 为输出模式
*****************************************************************************/
void gpio_group_sel_init(group_bank bank,uint32_t gpio_pins_map,gpio_mode_type gpio_mode)
{
	uint32_t gpio_pinx 				= 0;
	uint32_t set_pin_bit 			= 0;
	if(bank > GPIO_BANK_MAX )
		return;
	gpio_type_def *gpiox 		= gpio_bank_reg[bank];
	for(gpio_pinx = 0; gpio_pinx < 8; gpio_pinx++)
	{
		if(gpio_pins_map &0x01)
		{
			set_pin_bit = (gpio_pinx<<1);
			gpiox->inout_ctrl->CON &= ~(3         << set_pin_bit);
			gpiox->inout_ctrl->CON |= (gpio_mode << set_pin_bit);
		}
		gpio_pins_map >>= 1;
	}
}

/*******************************************************************************
* 函数名   : gpio_set.
* 说明     : 设置某组GPIO为高电平
* 参数     : -gpio_pinx, 	 pin脚编号: GPIOA_Pin0--GPIOD_Pin7       
			 -gpio_pins_map, 0x00~0xFF
* 返回值   : None.
* 示例     : gpio_set(GPIO_BANK_B,0x04);  设置B组中IO 2 为高电平
*****************************************************************************/
void gpio_group_set(group_bank bank,uint32_t gpio_pins_map)
{
	if(bank > GPIO_BANK_MAX )
		return;

	gpio_type_def *gpiox 			= gpio_bank_reg[bank];
	gpiox->inout_ctrl->BSR 			= gpio_pins_map;
}

/*******************************************************************************
* 函数名   : gpio_set.
* 说明     : 设置某组GPIO为低电平
* 参数     : -gpio_pinx, 	 pin脚编号: GPIOA_Pin0--GPIOD_Pin7       
			 -gpio_pins_map, 0x00~0xFF
* 返回值   : None.
* 示例     : gpio_set(GPIO_BANK_B,0x04); 设置B组中IO 2 为低电平
*****************************************************************************/
void gpio_group_reset(group_bank bank,int gpio_pins_map)
{
	if(bank > GPIO_BANK_MAX )
		return;

	gpio_type_def *gpiox 			= gpio_bank_reg[bank];
	gpiox->inout_ctrl->BSR 			|= (gpio_pins_map<<8);
}

/*******************************************************************************
* 函数名   : gpio_set.
* 说明     : 设置某个GPIO为高电平
* 参数     : -gpio_pinx, pin脚编号: GPIOA_Pin0--GPIOD_Pin7             
* 返回值   : None.
* 示例     : gpio_set(GPIOB,GPIO_Pin_2);	//设置PB2为高电平
*****************************************************************************/
void gpio_set(gpio_pin gpio_pinx)
{
	if(gpio_pinx > GPIO_MAXS )
		return;

	gpio_type_def 		*gpiox 		 = gpio_bank_reg[gpio_pinx>>3];
	unsigned char 		GPIO_Pinx 	 = gpio_pinx & 0x07;
	gpiox->inout_ctrl->BSR 			|= (1 << GPIO_Pinx);
}


/*******************************************************************************
* 函数名   : gpio_reset.
* 说明     : 设置某个GPIO为低电平
* 参数     : -gpio_pinx, pin脚编号: GPIOA_Pin0--GPIOD_Pin7             
* 返回值   : None.
* 示例     : gpio_reset(GPIOB_Pin2);		//设置PB2为低电平
*******************************************************************************/
void gpio_reset(gpio_pin gpio_pinx)
{
	if(gpio_pinx > GPIO_MAXS )
		return;

	gpio_type_def 		*gpiox 		= gpio_bank_reg[gpio_pinx>>3];
	unsigned char 		GPIO_Pinx 	= gpio_pinx & 0x07;
	gpiox->inout_ctrl->BSR 			|= ((1 << GPIO_Pinx) << 8);
}

/*******************************************************************************
* 函数名   : gpio_toggle.
* 说明     : 翻转某个GPIO
* 参数     : -gpio_pinx, pin脚编号: GPIOA_Pin0--GPIOD_Pin7                 
* 返回值   : None.
* 示例     : gpio_toggle(GPIOB_Pin2); 			//翻转PB2
*****************************************************************************/
void gpio_toggle(gpio_pin gpio_pinx)
{
	if(gpio_pinx > GPIO_MAXS )
		return;

	gpio_type_def 		*gpiox 		= gpio_bank_reg[gpio_pinx>>3];
	unsigned char 		GPIO_Pinx 	= gpio_pinx & 0x07;
	
	if(gpiox->inout_ctrl->IOD & (1 << GPIO_Pinx))
	{
		gpio_reset(gpio_pinx);
	}
	else
	{
		gpio_set(gpio_pinx);
	}
}


/*******************************************************************************
* 函数名   : gpio_set_output_level.
* 说明     : 设置某个GPIO为高电平或者低电平
* 参数     : -gpio_pinx, pin脚编号: GPIOA_Pin0--GPIOD_Pin7                 
             -level,    level=1,设置高电平, level=0,设置低电平
* 返回值   : None.
* 示例     : gpio_set_output_level(GPIOB_Pin2,1);	//设置PB2为低电平
*******************************************************************************/
void gpio_set_output_level(gpio_pin gpio_pinx,uint32_t level)
{
	if(gpio_pinx > GPIO_MAXS )
		return;

	if(level)
	{		
		gpio_set(gpio_pinx);
	}
	else
	{
		gpio_reset(gpio_pinx);
	}
}

/*******************************************************************************
* 函数名   : gpio_group_get_input.
* 说明     : 获取某组GPIO电平状态
* 参数     : -bank,    GPIO分组,GPIO_BANK_A ~ GPIO_BANK_D
* 返回值   : 某组GPIO的电平状态.低8bit有效，每个bit对于1个IO，1表示该IO为高电平，
             0表示该IO为低电平
* 示例     : gpio_group_get_input(GPIOB_Pin2);		//获取B组IO电平状态
*******************************************************************************/
uint32_t gpio_group_get_input(group_bank bank)
{
	uint32_t tmp = 0;
	
	if(bank > GPIO_BANK_MAX )
		return 0;
	
	gpio_type_def *gpiox 		= gpio_bank_reg[bank];
	tmp = gpiox->inout_ctrl->IOD;
	return ((tmp>>8)&0xff);
}

/*******************************************************************************
* 函数名   : gpio_get_input.
* 说明     : 获取某个GPIO电平状态
* 参数     : -gpio_pin, pin脚编号: GPIOA_Pin0--GPIOD_Pin7 
* 返回值   : HIGHT 表示该IO为高电平
             LOW   表示该IO为低电平
* 示例     : gpio_get_input(GPIOB_Pin2);		//获取PB2IO电平状态
*******************************************************************************/
uint32_t gpio_get_input(gpio_pin gpio_pinx)
{
	uint32_t pin_Level = 0;
	
	if(gpio_pinx > GPIO_MAXS )
		return 0;
	
	group_bank 			group 		= (group_bank)(gpio_pinx>>3);
	unsigned char 		GPIO_Pinx 	= gpio_pinx & 0x07;

	pin_Level = gpio_group_get_input(group);
	if(pin_Level & (1 << GPIO_Pinx))
		return HIGHT;
	else
		return LOW;
}

/*******************************************************************************
* 函数名   : gpio_get_input.
* 说明     : 获取某个GPIO电平状态
* 参数     : -gpio_intx 		GPIO外部中断组编号 参考定义 irq_bank
			 -gpio_pinx, 		pin脚编号: GPIOA_Pin0--GPIOD_Pin7 
			 -gpio_int_type		GPIO中断触发条件，参考定义 gpio_irq_type
* 返回值   : HIGHT 表示该IO为高电平
             LOW   表示该IO为低电平
* 示例     : gpio_get_input(GPIOB_Pin2);		//获取PB2IO电平状态
*******************************************************************************/
void gpio_set_irq_src_type(irq_bank gpio_intx,gpio_pin gpiox_pinx,gpio_irq_type gpio_int_type)
{
	uint32_t idx = gpio_intx - GPIO_Int0;
	uint32_t mask = (0x03U)<<(idx*8);
	GPIO_MODULE->INTP_TYPE &= ~mask;
	GPIO_MODULE->INTP_TYPE |= (gpio_int_type<<(idx*8));
	
	mask = (0x1fU)<<(idx*8);
	GPIO_MODULE->INTP_SRC  &= ~mask;
	GPIO_MODULE->INTP_SRC  |= (gpiox_pinx<<(idx*8));
}

/*******************************************************************************
* 函数名   : gpio_clear_it_pending.
* 说明     : 清除GPIO中断状态
* 参数     : -gpio_intx, 中断源选择GPIO_Int0--GPIO_Int3,参考cpu_gpio.h中的定义 
* 返回值   : None.
* 示例     : gpio_clear_it_pending(GPIO_Int0);
*******************************************************************************/
void gpio_clear_it_pending(irq_bank gpio_intx)
{
	uint32_t idx = gpio_intx - GPIO_Int0;
	uint32_t mask = (0x01U)<<(idx*8);
	GPIO_MODULE->INTP_STAT = mask;
}

