/***********************************************************************
 * Copyright (c)  2017 - 2020, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : gpio.c
 * Description : gpio source file
 * Author(s)   : Chloe\Troy
 * version     : V1.0
 * Modify date : 2019-02-27
 ***********************************************************************/
#include "gpio.h"

void (*GPIO_callback[5])(uint8_t val_ris) = { 0 };

/************************************************************************
 * Function   	: GPIO_PA_IRQHandler
 * Description	: GPIO_PA_IRQHandler GPIOA中断处理函数
 * Input 		: none
 * Output 		: none
 * Return		: none
 ************************************************************************/
void GPIO_PA_IRQHandler(void)
{
	uint8_t regdata;	
	regdata = REG_GPIO_MIS(GPIOA);

	if(regdata & 0xFF)
	{
		if(GPIO_callback[0] != NULL)
		{
			(*GPIO_callback[0])((regdata));   		//调用GPIOA中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOA) = regdata;				//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOA) = 0xFF;					//清除所有中断标志
	}
}

/************************************************************************
 * Function   	: GPIO_PB_IRQHandler
 * Description	: GPIO_PB_IRQHandler GPIOB中断处理函数
 * Input 		: none
 * Output 		: none
 * Return		: none
 ************************************************************************/
void GPIO_PB_IRQHandler(void)
{
	uint8_t regdata;
	regdata = REG_GPIO_MIS(GPIOB);

	if(regdata & 0xFF)
	{
		if(GPIO_callback[1] != NULL)
		{
			(*GPIO_callback[1])((regdata));   		//调用GPIOA中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOB) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOB) = 0xFF;						//清除所有中断标志
	}
}

/************************************************************************
 * Function   	: GPIO_PC_IRQHandler
 * Description	: GPIO_PC_IRQHandler GPIOC中断处理函数
 * Input 		: none
 * Output 		: none
 * Return		: none
 ************************************************************************/
void GPIO_PC_IRQHandler(void)
{
	uint8_t regdata;
	regdata = REG_GPIO_MIS(GPIOC);

	if(regdata & 0xFF)
	{
		if(GPIO_callback[2] != NULL)
		{
			(*GPIO_callback[2])((regdata));   		//调用GPIOA中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOC) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOC) = 0xFF;						//清除所有中断标志
	}	
}

/************************************************************************
 * Function   	: GPIO_PD_IRQHandler
 * Description	: GPIO_PD_IRQHandler GPIOD中断处理函数
 * Input 		: none
 * Output 		: none
 * Return		: none
 ************************************************************************/
void GPIO_PD_IRQHandler(void)
{	
	uint8_t regdata;
	regdata = REG_GPIO_MIS(GPIOD);

	if(regdata & 0xFF)
	{
		if(GPIO_callback[3] != NULL)
		{
			(*GPIO_callback[3])((regdata));   //调用GPIOA中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOD) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOD) = 0xFF;						//清除所有中断标志
	}	
}

/************************************************************************
 * Function   	: GPIO_PE_IRQHandler
 * Description	: GPIO_PE_IRQHandler GPIOE中断处理函数
 * Input 		: none
 * Output 		: none
 * Return		: none
 ************************************************************************/
void GPIO_PE_IRQHandler(void)
{	
	uint8_t regdata;
	regdata = REG_GPIO_MIS(GPIOE);

	if(regdata & 0xFF)
	{
		if(GPIO_callback[4] != NULL)
		{
			(*GPIO_callback[4])((regdata));   		//调用GPIOA中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOE) = regdata;				//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOE) = 0xFF;					//清除所有中断标志
	}	
}

/************************************************************************
 * Function   	: gpio_init
 * Description	: gpio_init GPIO初始化函数
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_init(uint8_t port, uint8_t pin)
{
	//开启GPIO时钟，GPIO模块正常工作,端口为GPIO
	
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护
	
	if(port == GPIOA)
	{
		REG_SCU_PERICLKEN |= GPIOA_CLKEN;
		REG_SCU_PERIRESET |= GPIOA_RESET;	
		
		REG_SCU_PASEL &= ~(0x7<<(4*pin));
		REG_SCU_PASEL |= (0<<(4*pin));
		
	}
	else if(port == GPIOB)
	{
		REG_SCU_PERICLKEN |= GPIOB_CLKEN;
		REG_SCU_PERIRESET |= GPIOB_CLKEN;	
		
		REG_SCU_PBSEL &= ~(0x7<<(4*pin));
		REG_SCU_PBSEL |= (0<<(4*pin));
		
	}
	else if(port == GPIOC)
	{
		REG_SCU_PERICLKEN |= GPIOC_CLKEN;
		REG_SCU_PERIRESET |= GPIOC_RESET;	
		
		REG_SCU_PCSEL &= ~(0x7<<(4*pin));
		REG_SCU_PCSEL |= (0<<(4*pin));
	
	}
	else if(port == GPIOD)
	{
		REG_SCU_PERICLKEN |= GPIOD_CLKEN;
		REG_SCU_PERIRESET |= GPIOD_RESET;	
		
		REG_SCU_PDSEL &= ~(0x7<<(4*pin));
		REG_SCU_PDSEL |= (0<<(4*pin));

	}
    else if(port == GPIOE)
	{
		REG_SCU_PERICLKEN |= GPIOE_CLKEN;
		REG_SCU_PERIRESET |= GPIOE_RESET;	
		
		REG_SCU_PESEL &= ~(0x7<<(4*pin));
		REG_SCU_PESEL |= (0<<(4*pin));

	}
		
	REG_SCU_IOCTRLPROTECT = 0xffffffff; 	//开启IO写保护
	
}

/************************************************************************
 * Function   	: gpio_dir
 * Description	: gpio_dir GPIO方向设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   GPIO_DIR_OUT：输出  GPIO_DIR_IN：输入
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_dir(uint8_t port, uint8_t pin, uint8_t newstate)
{	

	if(newstate)     //GPIO_DIR_OUT
	{
		REG_GPIO_DIR(port) |= (1 << pin);
	}
    else		     //GPIO_DIR_IN
    {
        REG_GPIO_DIR(port) &= (~(1 << pin));	
    }

}

/************************************************************************
 * Function   	: gpio_in_enable
 * Description	: gpio_in_enable GPIO输入使能设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：使能  0：禁止
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_in_enable(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护 
	
	if(port==GPIOE)
	{
		if(newstate)
		{	//输入使能
			REG_SCU_PADIE1 |= (1<<(pin));			//输入使能
		}
		else
		{	//输入禁止
			REG_SCU_PADIE1 &= ~(1<<(pin));			//输入禁止
		}
	}	
	else
	{
		if(newstate)
		{
			REG_SCU_PADIE0 |= (1<<(port*8+pin));	//输入使能
		}
		else
		{
			REG_SCU_PADIE0 &= ~(1<<(port*8+pin));
		}
	}
	
	REG_SCU_IOCTRLPROTECT = 0xffffffff; 			//开启IO写保护
}

/************************************************************************
 * Function   	: gpio_config_pu
 * Description	: gpio_config_pu GPIO上拉使能设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：使能  0：禁止
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_config_pu(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护
	if(port==GPIOE)
	{
		if(newstate)
		{
			REG_SCU_PADPU1 |= (1<<(pin));			//上拉使能
		}
		else
		{
			REG_SCU_PADPU1 &= ~(1<<(pin));			//上拉禁止
		}
	}	
	else
	{
		if(newstate)
		{
			REG_SCU_PADPU0 |= (1<<(port*8+pin));	//上拉使能
		}
		else
		{
			REG_SCU_PADPU0 &= ~(1<<(port*8+pin));	//上拉禁止
		}
	}		
	REG_SCU_IOCTRLPROTECT = 0xffffffff; 			//开启IO写保护
}

/************************************************************************
 * Function   	: gpio_config_pd
 * Description	: gpio_config_pd GPIO下拉使能设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：使能  0：禁止
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_config_pd(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护
	
	if(port==GPIOE)
	{
		if(newstate)
		{
			REG_SCU_PADPD1 |= (1<<(pin));			//下拉使能
		}
		else
		{
			REG_SCU_PADPD1 &= ~(1<<(pin));			//下拉禁止
		}
	}	
	else
	{
		if(newstate)
		{
			REG_SCU_PADPD0 |= (1<<(port*8+pin));	//下拉使能
		}
		else
		{			
			REG_SCU_PADPD0 &= ~(1<<(port*8+pin));	//下拉禁止
		}
	}
	
	REG_SCU_IOCTRLPROTECT = 0xffffffff; 			//开启IO写保护
}

/************************************************************************
 * Function   	: gpio_config_od
 * Description	: gpio_config_od GPIO开漏使能设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：使能  0：禁止
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_config_od(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护
	
	if(port==GPIOE)
	{
		if(newstate)
		{
			REG_SCU_PADOD1 |= (1<<(pin));			//开漏输出使能
		}
		else
		{		
			REG_SCU_PADOD1 &= ~(1<<(pin));			//开漏输出禁止
		}
	}	
	else
	{
		if(newstate)
		{
			REG_SCU_PADOD0 |= (1<<(port*8+pin));	//开漏输出使能
		}
		else
		{
			REG_SCU_PADOD0 &= ~(1<<(port*8+pin));	//开漏输出禁止
		}
	}	
	
	REG_SCU_IOCTRLPROTECT = 0xffffffff; 			//开启IO写保护
}


/************************************************************************
 * Function   	: gpio_read_io
 * Description	: gpio_read_io GPIO输入电平获取
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 * Output 		: none
 * Return		: 管脚电平状态
 ************************************************************************/
uint8_t gpio_read_io(uint8_t port, uint8_t pin)
{
    return (REG_GPIO_IDATA(port) >> pin) & 0x01;	
}

/************************************************************************
 * Function   	: gpio_write_io
 * Description	: gpio_write_io   GPIO输出电平
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 * Output 		: none
 * Return		: 管脚电平状态
 ************************************************************************/

void gpio_write_io(uint8_t port, uint8_t pin, uint8_t newstate)
{
	if(newstate)
	{
	    REG_GPIO_ODATA(port) |= (1<<pin);
	}
	else
	{
	    REG_GPIO_ODATA(port) &= ~(1<<pin);
	}
		
}

/************************************************************************
 * Function   	: gpio_setio
 * Description	: gpio_setio GPIO电平设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：高电平  0：低电平
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_setio(uint8_t port, uint8_t pin, uint8_t newstate)
{
	if(newstate)
	{
	    REG_GPIO_SET(port) |= 1 << pin;
	}
	else
	{
	    REG_GPIO_CLR(port) |= 1 << pin;
	}
}

/************************************************************************
 * Function   	: gpio_set_irq
 * Description	: gpio_set_irq GPIO中断初始化
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：使能中断  0：禁止中断
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_irq_init(uint8_t port, uint8_t pin, uint8_t irq_enable, void (*pfunc)(uint8_t val_ris))  
{
	if(irq_enable)
	{
		REG_GPIO_IEN(port) |= (1 << pin);
	}
	else
	{
	    REG_GPIO_IEN(port) &= (~(1 << pin));
	}	
	switch(port)
    {
        case GPIOA:  
			NVIC_ClearPendingIRQ(GPIO_PA_IRQn);
			NVIC_EnableIRQ(GPIO_PA_IRQn);
			
			GPIO_callback[0] = pfunc;
       	break;
		
        case GPIOB:  
			NVIC_ClearPendingIRQ(GPIO_PB_IRQn);
			NVIC_EnableIRQ(GPIO_PB_IRQn);
		
			GPIO_callback[1] = pfunc;
       	break;	
		
		case GPIOC:  
			NVIC_ClearPendingIRQ(GPIO_PC_IRQn);
			NVIC_EnableIRQ(GPIO_PC_IRQn);
		
			GPIO_callback[2] = pfunc;
		break;
		
		case GPIOD:  
			NVIC_ClearPendingIRQ(GPIO_PD_IRQn);
			NVIC_EnableIRQ(GPIO_PD_IRQn);
		
			GPIO_callback[3] = pfunc;
		break;
		
		case GPIOE:  
			NVIC_ClearPendingIRQ(GPIO_PE_IRQn);
			NVIC_EnableIRQ(GPIO_PE_IRQn);
		
			GPIO_callback[4] = pfunc;
		break;
		
        default :
            
        break;
	}
}

/************************************************************************
 * Function   	: gpio_set_is
 * Description	: gpio_set_is GPIO中断触发类型设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：电平触发 0：边沿触发
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_set_is(uint8_t port, uint8_t pin, uint8_t newstate)
{
    if (newstate == GPIO_IS_EDGE)
    {
        REG_GPIO_IS(port) &= (~(1 << pin));		//边沿触发
    }
    else
    {
        REG_GPIO_IS(port) |= (1 << pin);		//电平触发
    }
}

/************************************************************************
 * Function   	: gpio_set_iev
 * Description	: gpio_set_iev GPIO中断触发极性设置
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：上升沿/高电平触发 0：下降沿/低电平触发
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_set_iev(uint8_t port, uint8_t pin, uint8_t newstate)
{
    if (newstate == GPIO_IEV_FALLEDGEORLOWLEVEL)
    {
        REG_GPIO_IEV(port) &= (~(1 << pin));				//下降沿/低电平
    }
    else
    {
        REG_GPIO_IEV(port) |= (1 << pin);					//上升沿/高电平
    }
}

/************************************************************************
 * Function   	: gpio_set_ibe
 * Description	: gpio_set_ibe GPIO单双边沿触发
 * Input 		: uint8_t port    GPIO端口类型
 *				  uint8_t pin	  GPIO管脚
 *                uint8_t newstate   1：双边沿触发 0：单边沿触发
 * Output 		: none
 * Return		: none
 ************************************************************************/
void gpio_set_ibe(uint8_t port, uint8_t pin, uint8_t newstate)
{
    if (newstate == GPIO_IBE_SINGLE)
    {
        REG_GPIO_IBE(port) &= (~(1 << pin));		//单边
    }
    else
    {
        REG_GPIO_IBE(port) |= (1 << pin);			//双边
    }
}

