/***********************************************************************
 * Copyright (c)  2017 - 2022, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : gpio.c
 * Description : gpio source file
 * Author(s)   : zhilan
 * version     : V1.0
 * Modify date : 2022-08-04
 ***********************************************************************/
#include "gpio.h"
#include <stdio.h>

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

/************************************************************************
 * function   	: GPIO_PA_IRQHandler
 * description	: GPIO_PA_IRQHandler GPIOA中断处理函数
 * input 		: none
 * return		: none
 ************************************************************************/
void GPIO_PA_IRQHandler(void)
{
	uint8_t regdata;	
	regdata = REG_GPIO_RIS(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
 * return		: none
 ************************************************************************/
void GPIO_PB_IRQHandler(void)
{
	uint8_t regdata;
	regdata = REG_GPIO_RIS(GPIOB);
	
	if(regdata & 0xFF)
	{
		if(GPIO_callback[1] != NULL)
		{
			(*GPIO_callback[1])((regdata));   				//调用GPIOB中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOB) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOB) = 0xFF;							//清除所有中断标志
	}
}

/************************************************************************
 * function   	: GPIO_PC_IRQHandler
 * description	: GPIO_PC_IRQHandler GPIOC中断处理函数
 * input 		: none
 * return		: none
 ************************************************************************/
void GPIO_PC_IRQHandler(void)
{
	uint8_t regdata;
	regdata = REG_GPIO_RIS(GPIOC);
	
	if(regdata & 0xFF)
	{
		if(GPIO_callback[2] != NULL)
		{
			(*GPIO_callback[2])((regdata));   				//调用GPIOC中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOC) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOC) = 0xFF;							//清除所有中断标志
	}	
}

/************************************************************************
 * function   	: GPIO_PD_IRQHandler
 * description	: GPIO_PD_IRQHandler GPIOD中断处理函数
 * input 		: none
 * return		: none
 ************************************************************************/
void GPIO_PD_IRQHandler(void)
{	
	uint8_t regdata;
	regdata = REG_GPIO_RIS(GPIOD);

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

/************************************************************************
 * function   	: GPIO_PE_IRQHandler
 * description	: GPIO_PE_IRQHandler GPIOE中断处理函数
 * input 		: none
 * return		: none
 ************************************************************************/
void GPIO_PE_IRQHandler(void)
{	
	uint8_t regdata;
	regdata = REG_GPIO_RIS(GPIOE);
	
	if(regdata & 0xFF)
	{
		if(GPIO_callback[4] != NULL)
		{
			(*GPIO_callback[4])((regdata));   				//调用GPIOE中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOE) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOE) = 0xFF;							//清除所有中断标志
	}	
}

/************************************************************************
 * function   	: GPIO_PF_IRQHandler
 * description	: GPIO_PF_IRQHandler GPIOF中断处理函数
 * input 		: none
 * return		: none
 ************************************************************************/
void GPIO_PF_IRQHandler(void)
{	
	uint8_t regdata;
	regdata = REG_GPIO_RIS(GPIOF);
	
	if(regdata & 0xFF)
	{
		if(GPIO_callback[5] != NULL)
		{
			(*GPIO_callback[5])((regdata));   				//调用GPIOF中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOF) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOF) = 0xFF;							//清除所有中断标志
	}	
}

/************************************************************************
 * function   	: GPIO_PG_IRQHandler
 * description	: GPIO_PG_IRQHandler GPIOF中断处理函数
 * input 		: none
 * return		: none
 ************************************************************************/
void GPIO_PG_IRQHandler(void)
{	
	uint8_t regdata;
	regdata = REG_GPIO_RIS(GPIOG);
	
	if(regdata & 0xFF)
	{
		if(GPIO_callback[6] != NULL)
		{
			(*GPIO_callback[6])((regdata));   				//调用GPIOG中断回调,并传入引脚位	
		}
		REG_GPIO_IC(GPIOG) = regdata;						//中断清除
	}
	else
	{
		REG_GPIO_IC(GPIOG) = 0xFF;							//清除所有中断标志
	}	
}

/************************************************************************
 * function   	: gpio_init
 * description	: gpio_init GPIO初始化函数
 * input 		: uint8_t port    GPIO端口类型 GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚   PIN0,PIN1,PIN2,PIN3,PIN4.....
				  uint8_t mulfunc GPIO引脚复用功能选择 0,1,2,3,4,5,6.....
 * return		: none
 ************************************************************************/
void gpio_init(uint8_t port, uint8_t pin,uint8_t mulfunc)
{

	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;											//清除IO写保护
	if(port == GPIOA)
	{
		if(mulfunc==0)
		{
			REG_SCU_PERICLKEN |= GPIOA_CLKEN;                                  //用作普通gpio时开启gpioA模块时钟
			REG_SCU_PERIRESET |= GPIOA_RESET;	
		}
		REG_SCU_PASEL &= ~(0xf<<(4*pin));                                      //设置为除gpio之外的其他复用功能，具体查看用户手册
		REG_SCU_PASEL |= (mulfunc<<(4*pin));
		
	}
	else if(port == GPIOB)
	{
		if(mulfunc==0)
		{
			REG_SCU_PERICLKEN |= GPIOB_CLKEN;                                 //用作普通gpio时开启gpioB模块时钟
			REG_SCU_PERIRESET |= GPIOB_CLKEN;	                              
		}                                                                     
		REG_SCU_PBSEL &= ~(0xf<<(pin*4));                                     //设置为除gpio之外的其他复用功能，具体查看用户手册
		REG_SCU_PBSEL |= (mulfunc<<(pin*4));
	}
	else if(port == GPIOC)
	{
		if(mulfunc==0)
		{
			REG_SCU_PERICLKEN |= GPIOC_CLKEN;                                //用作普通gpio时开启gpioC模块时钟
			REG_SCU_PERIRESET |= GPIOC_RESET;	                             
		}                                                                    
		REG_SCU_PCSEL &= ~(0xf<<(pin*4));                                    //设置为除gpio之外的其他复用功能，具体查看用户手册
		REG_SCU_PCSEL |= (mulfunc<<(pin*4));
	}
	else if(port == GPIOD)
	{
		if(mulfunc==0)
		{
			REG_SCU_PERICLKEN |= GPIOD_CLKEN;                                //用作普通gpio时开启gpioD模块时钟
			REG_SCU_PERIRESET |= GPIOD_RESET;	                             
		}                                                                    
		REG_SCU_PDSEL &= ~(0xf<<(pin*4));                                    //设置为除gpio之外的其他复用功能，具体查看用户手册
		REG_SCU_PDSEL |= (mulfunc<<(pin*4));

	}
    else if(port == GPIOE)
	{
		if(mulfunc==0)
		{
			REG_SCU_PERICLKEN |= GPIOE_CLKEN;                               //用作普通gpio时开启gpioE模块时钟
			REG_SCU_PERIRESET |= GPIOE_RESET;	                            
		}                                                                   
		REG_SCU_PESEL &= ~(0xf<<(4*pin));                                   //设置为除gpio之外的其他复用功能，具体查看用户手册
		REG_SCU_PESEL |= (mulfunc<<(4*pin));

	}
	else if(port == GPIOF)
	{
		if(mulfunc==0)
		{
			REG_SCU_PERICLKEN |= GPIOF_CLKEN;                                //用作普通gpio时开启gpioF模块时钟
			REG_SCU_PERIRESET |= GPIOF_RESET;	                             
		}                                                                    
		REG_SCU_PFSEL &= ~(0xf<<(pin*4));                                    //设置为除gpio之外的其他复用功能，具体查看用户手册
		REG_SCU_PFSEL |= (mulfunc<<(pin*4));

	}
	else if(port == GPIOG)
	{
		if(mulfunc==0)
		{
			REG_SCU_PERICLKEN |= GPIOG_CLKEN;                                 //用作普通gpio时开启gpioG模块时钟
			REG_SCU_PERIRESET |= GPIOG_RESET;	                              
		}                                                                     
		REG_SCU_PGSEL &= ~(0xf<<(pin*4));                                     //设置为除gpio之外的其他复用功能，具体查看用户手册
		REG_SCU_PGSEL |= (mulfunc<<(pin*4));

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

/************************************************************************
 * function   	: gpio_dir
 * description	: gpio_dir GPIO方向设置
 * input 		: uint8_t port    GPIO端口类型  GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚  PIN0,PIN1,PIN2,PIN3,PIN4.....
 *                uint8_t newstate   GPIO_DIR_OUT：输出  GPIO_DIR_IN：输入
 * 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端口类型  GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚  PIN0,PIN1,PIN2,PIN3,PIN4.....
 *                uint8_t newstate   1：使能  0：禁止
 * return		: none
 ************************************************************************/
void gpio_in_enable(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;											//清除IO写保护 
	
	if((port == GPIOE) || (port == GPIOF) || (port == GPIOG))
	{
		if(newstate)
		{																		//输入使能
			REG_SCU_PADIE1 |= (1<<(((port&0x8)<<(port & 0x1))+pin));			//输入使能
		}
		else
		{																		//输入禁止
			REG_SCU_PADIE1 &= ~(1<<(((port&0x8)<<(port & 0x1))+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端口类型 GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚  PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：使能 0：禁止
 * return		: none
 ************************************************************************/
void gpio_config_pu(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护
	if((port == GPIOE) || (port == GPIOF) || (port == GPIOG))
	{
		if(newstate)
		{
			REG_SCU_PADPU1 |= (1<<(((port&0x8)<<(port & 0x1))+pin));			//上拉使能
		}
		else
		{
			REG_SCU_PADPU1 &= ~(1<<(((port&0x8)<<(port & 0x1))+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端口类型 GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚   PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：使能  0：禁止
 * return		: none
 ************************************************************************/
void gpio_config_pd(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护
	
	if((port == GPIOE) || (port == GPIOF) || (port == GPIOG))
	{
		if(newstate)
		{
			REG_SCU_PADPD1 |= (1<<(((port&0x8)<<(port & 0x1))+pin));			//下拉使能
		}
		else
		{
			REG_SCU_PADPD1 &= ~(1<<(((port&0x8)<<(port & 0x1))+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端口类型 GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚    PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：使能  0：禁止
 * return		: none
 ************************************************************************/
void gpio_config_od(uint8_t port, uint8_t pin, uint8_t newstate)
{
	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A;				//清除IO写保护
	
	if((port == GPIOE) || (port == GPIOF) || (port == GPIOG))
	{
		if(newstate)
		{
			REG_SCU_PADOD1 |= (1<<(((port&0x8)<<(port & 0x1))+pin));			//开漏输出使能
		}
		else
		{		
			REG_SCU_PADOD1 &= ~(1<<(((port&0x8)<<(port & 0x1))+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端口类型 GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚 PIN0,PIN1,PIN2,PIN3......
 * 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端口类型  GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚 PIN0,PIN1,PIN2,PIN3......
 *				  uint8_t newstate  1：高电平  0：低电平
 * return		: none
 ************************************************************************/
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端口类型 GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚 PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：高电平  0：低电平
 * 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_irq_init
 * description	: gpio_irq_init GPIO中断初始化
 * input 		: uint8_t port    GPIO端口类型  GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚 PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：使能中断  0：禁止中断
 * 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 == 1)                                          //中断使能
	{
		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;			
			case GPIOF:  
				NVIC_ClearPendingIRQ(GPIO_PF_IRQn);
				NVIC_EnableIRQ(GPIO_PF_IRQn);			
				GPIO_callback[5] = pfunc;
				break;
			case GPIOG:  
				NVIC_ClearPendingIRQ(GPIO_PG_IRQn);
				NVIC_EnableIRQ(GPIO_PG_IRQn);		
				GPIO_callback[6] = pfunc;
				break;
			default :
				break;
	}
	}
	else                                                       //中断禁止
	{
	    REG_GPIO_IEN(port) &= (~(1 << pin));
		for(uint8_t i=0;i<7;i++)
		{
			GPIO_callback[i] = NULL;
		}
	}	
	
}

/************************************************************************
 * function   	: gpio_set_is
 * description	: gpio_set_is GPIO中断触发类型设置
 * input 		: uint8_t port    GPIO端口类型  GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚  PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：电平触发 0：边沿触发
 * 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端口类型  GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚  PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：上升沿/高电平触发 
                                     0：下降沿/低电平触发
 * 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端口类型  GPIOA,GPIOB,GPIOC....
 *				  uint8_t pin	  GPIO管脚  PIN0,PIN1,PIN2,PIN3......
 *                uint8_t newstate   1：双边沿触发 0：单边沿触发
 * 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);					//双边
    }
}

