#include "gpio.h"

void MyGPIO_Init(MyGPIO_Struct_TypeDef * GPIOStructPtr)
{
	RCC->APB2ENR |= GPIO2Int(GPIOStructPtr->GPIO);
	//We get the pointer of the CRH/CRL depending on the IO_Pin number
	volatile uint32_t * CRAny = GPIOStructPtr->GPIO_Pin >= 0x08 ? &(GPIOStructPtr->GPIO->CRH):&(GPIOStructPtr->GPIO->CRL);
	//setup high or low
	*CRAny &= ~(0xF << (GPIOStructPtr->GPIO_Pin%8)*4);											//reset
	//for input pull or push
	switch(GPIOStructPtr->GPIO_Conf)
	{
		case In_PullUp:
			GPIOStructPtr->GPIO->ODR |= (0x01 << GPIOStructPtr->GPIO_Pin);	//if pullup -> ODR = 1
			*CRAny |= (In_PullDown << (GPIOStructPtr->GPIO_Pin%8)*4);	//set pin mode -> force to In_PullDown because PullDown is modified
			break;
		case In_PullDown:
			GPIOStructPtr->GPIO->ODR &= ~(0x01 << GPIOStructPtr->GPIO_Pin);	//if pullup -> ODR = 0
		default:
			*CRAny |= (GPIOStructPtr->GPIO_Conf << (GPIOStructPtr->GPIO_Pin%8)*4);	//set pin mode for any input/output
			break;	
	}
}

int MyGPIO_Read(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin)
{
	return (GPIO->IDR & (0x1 << GPIO_Pin)) > 0; 
}

void MyGPIO_Set(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin)
{
	GPIO->BSRR = (1 << GPIO_Pin);				//BSX set register
}

void MyGPIO_Reset(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin)
{
	GPIO->BRR = (1 << GPIO_Pin);	//BRX = BSX+16 reset register
}

void MyGPIO_Toggle(GPIO_TypeDef * GPIO, uint8_t GPIO_Pin)
{
	if((GPIO->ODR = GPIO->ODR & (1 << GPIO_Pin)) > 0)
	{
		GPIO->BRR = (1 << GPIO_Pin);	//reset
	} else {
		GPIO->BSRR = (1 << GPIO_Pin);				//set
	}
}

int GPIO2Int(GPIO_TypeDef * GPIOX)
{
	if(GPIOX == GPIOA)
	{
		return (0x01 << 2);
	} else if (GPIOX == GPIOB){
		return (0x01 << 3);
	} else if (GPIOX == GPIOC){
		return (0x01 << 4);
	} else if (GPIOX == GPIOD){
		return (0x01 << 5);
	} else if (GPIOX == GPIOE){
		return (0x01 << 6);
	} else if (GPIOX == GPIOF){
		return (0x01 << 7);
	} else if (GPIOX == GPIOE){
		return (0x01 << 8);
	} else {
		return -1;
	};
}
