#include "BL210x_gpio.h"

/****************************************************************************************************************************************** 
* 函数名称: GPIO_Init()
* 功能说明:	引脚初始化，包含引脚方向、上拉、下拉、开漏  推挽输出 唤醒功能
* 输    入: GPIO_TypeDef * GPIOx	   
*			
* 输    出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void GPIO_Init(GPIO_TypeDef * GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
	switch((uint32_t)GPIOx)
	{
		case ((uint32_t)GPIOA):
		    
			SYS->CLKEN |= 0x01 << SYS_CLKEN_GPIOA_POS;                         //开启GPIOA的时钟

#ifdef IC_BL2101		
			PORT->PORTA_SEL &= ~(0x03 << ((GPIO_InitStruct->Pin)*2));          //将端口配置为GPIO功能
#endif
		
#ifdef IC_BL2102
			if(GPIO_InitStruct->Pin <= GPIO_PIN7)
			{
				PORT->PORTA_SEL0 &= ~(0x0F << ((GPIO_InitStruct->Pin)*4));       //将端口配置为GPIO功能
			}
			else if(GPIO_InitStruct->Pin <= GPIO_PIN15)
			{
				PORT->PORTA_SEL1 &= ~(0x0F << ((GPIO_InitStruct->Pin - GPIO_PIN8)*4)); 
			}
#endif
		
			PORT->PORTA_INEN |=  (0x01 << (GPIO_InitStruct->Pin));                //开启输入使能
		
			if(GPIO_InitStruct->Mode == MODE_FLOATING_IN)                      //浮空输入
			{
				PORT->PORTA_PU_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_PD_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_OD_OUT &= ~(0x01 << GPIO_InitStruct->Pin);
				
				GPIOA->DIR &= ~(1 << GPIO_InitStruct->Pin);                    //方向设置为输入
			}				
			else if(GPIO_InitStruct->Mode == MODE_PU_IN)	                   //上拉输入          
			{
				PORT->PORTA_PU_IN  |=  (0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_PD_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_OD_OUT &= ~(0x01 << GPIO_InitStruct->Pin);
				
				GPIOA->DIR &= ~(1 << GPIO_InitStruct->Pin);                    //方向设置为输入
			}
			else if(GPIO_InitStruct->Mode == MODE_PD_IN)	                   //下拉输入   
			{
				PORT->PORTA_PU_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_PD_IN  |=  (0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_OD_OUT &= ~(0x01 << GPIO_InitStruct->Pin);
				
				GPIOA->DIR &= ~(1 << GPIO_InitStruct->Pin);	                   //方向设置为输入
			}
			else if(GPIO_InitStruct->Mode == MODE_PP_OUT)                      //推挽输出
			{
				PORT->PORTA_PU_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_PD_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_OD_OUT &= ~(0x01 << GPIO_InitStruct->Pin);
				
				GPIOA->DIR |= (1 << GPIO_InitStruct->Pin);		               //方向设置为输出
			}	
			else if(GPIO_InitStruct->Mode == MODE_OD_OUT)                      //开漏输出       
			{
				PORT->PORTA_PU_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_PD_IN  &= ~(0x01 << GPIO_InitStruct->Pin);
				PORT->PORTA_OD_OUT |=  (0x01 << GPIO_InitStruct->Pin);
				
				GPIOA->DIR |= (1 << GPIO_InitStruct->Pin);                     //方向设置为输出
			}	 
			
			if(GPIO_InitStruct->WakeUp_En == WAKEUP_ENABLE)                    //唤醒功能使能
			{
				PORT->PORTA_WAKEUP |=  (0x01 << GPIO_InitStruct->Pin);
			}
			else
			{
				PORT->PORTA_WAKEUP &= ~(0x01 << GPIO_InitStruct->Pin);
			}
	
		break;

#ifdef IC_BL2101			
		case ((uint32_t)GPIOB):
			
			SYS->CLKEN |= 0x01 << SYS_CLKEN_GPIOB_POS;                         //开启GPIOB的时钟
		
			PORT->PORTB_SEL &= ~(0x03 << ((GPIO_InitStruct->Pin)*2));          //将端口配置为GPIO功能
			PORT->PORTB_INEN |=  (1 << (GPIO_InitStruct->Pin));                //开启输入使能
		
			if(GPIO_InitStruct->Mode == MODE_FLOATING_IN)                      //浮空输入
			{
				PORT->PORTB_PU_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_PD_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_OD_OUT &= ~(1 << GPIO_InitStruct->Pin);
				
				GPIOB->DIR &= ~(1 << GPIO_InitStruct->Pin);                    //方向设置为输入
			}				
			else if(GPIO_InitStruct->Mode == MODE_PU_IN)	                   //上拉输入  
			{
				PORT->PORTB_PU_IN  |=  (1 << GPIO_InitStruct->Pin);
				PORT->PORTB_PD_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_OD_OUT &= ~(1 << GPIO_InitStruct->Pin);
				
				GPIOB->DIR &= ~(1 << GPIO_InitStruct->Pin);                    //方向设置为输入
			}
			else if(GPIO_InitStruct->Mode == MODE_PD_IN)	                   //下拉输入 
			{
				PORT->PORTB_PU_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_PD_IN  |=  (1 << GPIO_InitStruct->Pin);
				PORT->PORTB_OD_OUT &= ~(1 << GPIO_InitStruct->Pin);
				
				GPIOB->DIR &= ~(1 << GPIO_InitStruct->Pin);                    //方向设置为输入
			}
			else if(GPIO_InitStruct->Mode == MODE_PP_OUT)                      //推挽输出
			{
				PORT->PORTB_PU_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_PD_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_OD_OUT &= ~(1 << GPIO_InitStruct->Pin);
				
				GPIOB->DIR |= (1 << GPIO_InitStruct->Pin);	                   //方向设置为输出
			}	
			else if(GPIO_InitStruct->Mode == MODE_OD_OUT)                      //开漏输出  
			{
				PORT->PORTB_PU_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_PD_IN  &= ~(1 << GPIO_InitStruct->Pin);
				PORT->PORTB_OD_OUT |=  (1 << GPIO_InitStruct->Pin);
				
				GPIOB->DIR |= (1 << GPIO_InitStruct->Pin);                     //方向设置为输出
			}	
			
			if(GPIO_InitStruct->WakeUp_En == WAKEUP_ENABLE)                    //唤醒功能使能
			{
				PORT->PORTB_WAKEUP |=  (1 << GPIO_InitStruct->Pin);
			}
			else
			{
				PORT->PORTB_WAKEUP &= ~(1 << GPIO_InitStruct->Pin);
			}
			
		break;
#endif

		default:
		break;
	}		
}

/****************************************************************************************************************************************** 
* 函数名称: GPIO_SetBit()
* 功能说明:	将参数指定的引脚电平置高
* 输    入: GPIO_TypeDef * GPIOx	    指定GPIO端口，有效值包括GPIOA、GPIOB
*			uint32_t GPIO_Pin		    指定GPIO引脚，有效值包括PIN0、PIN1、PIN2、... ... PIN14、PIN15
* 输    出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void GPIO_SetBit(GPIO_TypeDef * GPIOx, uint32_t GPIO_Pin)
{
	GPIOx->DATA |= (0x01 << GPIO_Pin);
}

/****************************************************************************************************************************************** 
* 函数名称:	GPIO_ClrBit()
* 功能说明:	将参数指定的引脚电平置低
* 输    入: GPIO_TypeDef * GPIOx	    指定GPIO端口，有效值包括GPIOA、GPIOB
*			uint32_t GPIO_Pin		    指定GPIO引脚，有效值包括PIN0、PIN1、PIN2、... ... PIN14、PIN15
* 输    出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void GPIO_ClrBit(GPIO_TypeDef * GPIOx, uint32_t GPIO_Pin)
{
	GPIOx->DATA &= ~(0x01 << GPIO_Pin);
}

/****************************************************************************************************************************************** 
* 函数名称: GPIO_InvBit()
* 功能说明:	将参数指定的引脚电平反转
* 输    入: GPIO_TypeDef * GPIOx	    指定GPIO端口，有效值包括GPIOA、GPIOB
*			uint32_t n		       指定GPIO引脚，有效值包括PIN0、PIN1、PIN2、... ... PIN14、PIN15
* 输    出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void GPIO_InvBit(GPIO_TypeDef * GPIOx, uint32_t GPIO_Pin)
{
	GPIOx->DATA ^= (0x01 << GPIO_Pin);
}

/****************************************************************************************************************************************** 
* 函数名称:	GPIO_GetBit()
* 功能说明:	读取参数指定的引脚的电平状态
* 输    入: GPIO_TypeDef * GPIOx	    指定GPIO端口，有效值包括GPIOA、GPIOB
*			uint32_t n		       指定GPIO引脚，有效值包括PIN0、PIN1、PIN2、... ... PIN14、PIN15
* 输    出: 参数指定的引脚的电平状态	0 低电平	1 高电平
* 注意事项: 无
******************************************************************************************************************************************/
uint32_t GPIO_GetBit(GPIO_TypeDef * GPIOx, uint32_t GPIO_Pin)
{	
	return ((GPIOx->DATA >> GPIO_Pin) & 0x01);
}
