#include <stdio.h>
#include <stdint.h>
#include "driver.h"
#include "hal_interface_api.h"
#include <fcntl.h>




typedef struct 
{
	char 			pinstr[5];
	GPIO_TypeDef  	*gpioport;
	uint16_t 		gpiopin;
} GPIO_TABLE_T;

const GPIO_TABLE_T gpio_map[] = {
	/**** GPIOA ****/
	{"PA0",	GPIOA, GPIO_PIN_0},
	{"PA1",	GPIOA, GPIO_PIN_1},
	{"PA2",	GPIOA, GPIO_PIN_2},
	{"PA3",	GPIOA, GPIO_PIN_3},
	{"PA4",	GPIOA, GPIO_PIN_4},
	{"PA5",	GPIOA, GPIO_PIN_5},
	{"PA6",	GPIOA, GPIO_PIN_6},
	{"PA7",	GPIOA, GPIO_PIN_7},
	{"PA8",	GPIOA, GPIO_PIN_8},
	{"PA9",	GPIOA, GPIO_PIN_9},
	{"PA10",	GPIOA, GPIO_PIN_10},
	{"PA11",	GPIOA, GPIO_PIN_11},
	{"PA12",	GPIOA, GPIO_PIN_12},
	{"PA13",	GPIOA, GPIO_PIN_13},
	{"PA14",	GPIOA, GPIO_PIN_14},
	{"PA15",	GPIOA, GPIO_PIN_15},
	/**** GPIOB ****/
	{"PB0",	GPIOB, GPIO_PIN_0},
	{"PB1",	GPIOB, GPIO_PIN_1},
	{"PB2",	GPIOB, GPIO_PIN_2},
	{"PB3",	GPIOB, GPIO_PIN_3},
	{"PB4",	GPIOB, GPIO_PIN_4},
	{"PB5",	GPIOB, GPIO_PIN_5},
	{"PB6",	GPIOB, GPIO_PIN_6},
	{"PB7",	GPIOB, GPIO_PIN_7},
	{"PB8",	GPIOB, GPIO_PIN_8},
	{"PB9",	GPIOB, GPIO_PIN_9},
	{"PB10",	GPIOB, GPIO_PIN_10},
	{"PB11",	GPIOB, GPIO_PIN_11},
	{"PB12",	GPIOB, GPIO_PIN_12},
	{"PB13",	GPIOB, GPIO_PIN_13},
	{"PB14",	GPIOB, GPIO_PIN_14},
	{"PB15",	GPIOB, GPIO_PIN_15},
	/**** GPIOC ****/
	{"PC0",	GPIOC, GPIO_PIN_0},
	{"PC1",	GPIOC, GPIO_PIN_1},
	{"PC2",	GPIOC, GPIO_PIN_2},
	{"PC3",	GPIOC, GPIO_PIN_3},
	{"PC4",	GPIOC, GPIO_PIN_4},
	{"PC5",	GPIOC, GPIO_PIN_5},
	{"PC6",	GPIOC, GPIO_PIN_6},
	{"PC7",	GPIOC, GPIO_PIN_7},
	{"PC8",	GPIOC, GPIO_PIN_8},
	{"PC9",	GPIOC, GPIO_PIN_9},
	{"PC10",	GPIOC, GPIO_PIN_10},
	{"PC11",	GPIOC, GPIO_PIN_11},
	{"PC12",	GPIOC, GPIO_PIN_12},
	{"PC13",	GPIOC, GPIO_PIN_13},
	{"PC14",	GPIOC, GPIO_PIN_14},
	{"PC15",	GPIOC, GPIO_PIN_15},
	/**** GPIOD ****/
	{"PD0",	GPIOD, GPIO_PIN_0},
	{"PD1",	GPIOD, GPIO_PIN_1},
	{"PD2",	GPIOD, GPIO_PIN_2},
	{"PD3",	GPIOD, GPIO_PIN_3},
	{"PD4",	GPIOD, GPIO_PIN_4},
	{"PD5",	GPIOD, GPIO_PIN_5},
	{"PD6",	GPIOD, GPIO_PIN_6},
	{"PD7",	GPIOD, GPIO_PIN_7},
	{"PD8",	GPIOD, GPIO_PIN_8},
	{"PD9",	GPIOD, GPIO_PIN_9},
	{"PD10",	GPIOD, GPIO_PIN_10},
	{"PD11",	GPIOD, GPIO_PIN_11},
	{"PD12",	GPIOD, GPIO_PIN_12},
	{"PD13",	GPIOD, GPIO_PIN_13},
	{"PD14",	GPIOD, GPIO_PIN_14},
	{"PD15",	GPIOD, GPIO_PIN_15},
	/**** GPIOE ****/
	{"PE0",	GPIOE, GPIO_PIN_0},
	{"PE1",	GPIOE, GPIO_PIN_1},
	{"PE2",	GPIOE, GPIO_PIN_2},
	{"PE3",	GPIOE, GPIO_PIN_3},
	{"PE4",	GPIOE, GPIO_PIN_4},
	{"PE5",	GPIOE, GPIO_PIN_5},
	{"PE6",	GPIOE, GPIO_PIN_6},
	{"PE7",	GPIOE, GPIO_PIN_7},
	{"PE8",	GPIOE, GPIO_PIN_8},
	{"PE9",	GPIOE, GPIO_PIN_9},
	{"PE10",	GPIOE, GPIO_PIN_10},
	{"PE11",	GPIOE, GPIO_PIN_11},
	{"PE12",	GPIOE, GPIO_PIN_12},
	{"PE13",	GPIOE, GPIO_PIN_13},
	{"PE14",	GPIOE, GPIO_PIN_14},
	{"PE15",	GPIOE, GPIO_PIN_15},
	/**** GPIOF ****/
	{"PF0",	GPIOF, GPIO_PIN_0},
	{"PF1",	GPIOF, GPIO_PIN_1},
	{"PF2",	GPIOF, GPIO_PIN_2},
	{"PF3",	GPIOF, GPIO_PIN_3},
	{"PF4",	GPIOF, GPIO_PIN_4},
	{"PF5",	GPIOF, GPIO_PIN_5},
	{"PF6",	GPIOF, GPIO_PIN_6},
	{"PF7",	GPIOF, GPIO_PIN_7},
	{"PF8",	GPIOF, GPIO_PIN_8},
	{"PF9",	GPIOF, GPIO_PIN_9},
	{"PF10",	GPIOF, GPIO_PIN_10},
	{"PF11",	GPIOF, GPIO_PIN_11},
	{"PF12",	GPIOF, GPIO_PIN_12},
	{"PF13",	GPIOF, GPIO_PIN_13},
	{"PF14",	GPIOF, GPIO_PIN_14},
	{"PF15",	GPIOF, GPIO_PIN_15},
	/**** GPIOG ****/
	{"PG0",	GPIOG, GPIO_PIN_0},
	{"PG1",	GPIOG, GPIO_PIN_1},
	{"PG2",	GPIOG, GPIO_PIN_2},
	{"PG3",	GPIOG, GPIO_PIN_3},
	{"PG4",	GPIOG, GPIO_PIN_4},
	{"PG5",	GPIOG, GPIO_PIN_5},
	{"PG6",	GPIOG, GPIO_PIN_6},
	{"PG7",	GPIOG, GPIO_PIN_7},
	{"PG8",	GPIOG, GPIO_PIN_8},
	{"PG9",	GPIOG, GPIO_PIN_9},
	{"PG10",	GPIOG, GPIO_PIN_10},
	{"PG11",	GPIOG, GPIO_PIN_11},
	{"PG12",	GPIOG, GPIO_PIN_12},
	{"PG13",	GPIOG, GPIO_PIN_13},
	{"PG14",	GPIOG, GPIO_PIN_14},
	{"PG15",	GPIOG, GPIO_PIN_15},
	/**** GPIOH ****/
	{"PH0",	GPIOH, GPIO_PIN_0},
	{"PH1",	GPIOH, GPIO_PIN_1},
	{"PH2",	GPIOH, GPIO_PIN_2},
	{"PH3",	GPIOH, GPIO_PIN_3},
	{"PH4",	GPIOH, GPIO_PIN_4},
	{"PH5",	GPIOH, GPIO_PIN_5},
	{"PH6",	GPIOH, GPIO_PIN_6},
	{"PH7",	GPIOH, GPIO_PIN_7},
	{"PH8",	GPIOH, GPIO_PIN_8},
	{"PH9",	GPIOH, GPIO_PIN_9},
	{"PH10",	GPIOH, GPIO_PIN_10},
	{"PH11",	GPIOH, GPIO_PIN_11},
	{"PH12",	GPIOH, GPIO_PIN_12},
	{"PH13",	GPIOH, GPIO_PIN_13},
	{"PH14",	GPIOH, GPIO_PIN_14},
	{"PH15",	GPIOH, GPIO_PIN_15},
	/**** GPIOI ****/
	{"PI0",	GPIOI, GPIO_PIN_0},
	{"PI1",	GPIOI, GPIO_PIN_1},
	{"PI2",	GPIOI, GPIO_PIN_2},
	{"PI3",	GPIOI, GPIO_PIN_3},
	{"PI4",	GPIOI, GPIO_PIN_4},
	{"PI5",	GPIOI, GPIO_PIN_5},
	{"PI6",	GPIOI, GPIO_PIN_6},
	{"PI7",	GPIOI, GPIO_PIN_7},
	{"PI8",	GPIOI, GPIO_PIN_8},
	{"PI9",	GPIOI, GPIO_PIN_9},
	{"PI10",	GPIOI, GPIO_PIN_10},
	{"PI11",	GPIOI, GPIO_PIN_11},
	{"PI12",	GPIOI, GPIO_PIN_12},
	{"PI13",	GPIOI, GPIO_PIN_13},
	{"PI14",	GPIOI, GPIO_PIN_14},
	{"PI15",	GPIOI, GPIO_PIN_15},
};

void help()
{
	printf("gpiotool set <PA0~PI15> <outputpp/outputod/input> <pullup/pulldown/nopull>\n");
	printf("gpiotool write <PA0~PI15> <high/low>\n");
	printf("gpiotool read <PA0~PI15>\n");
}

int main(int argc, char* argv[])
{
	int i;
	uint16_t buf;
	GPIO_TABLE_T *gpioinfo;
	GPIO_TypeDef  	*GPIO_PORT;
	uint16_t		GPIO_PIN;
	GPIO_InitTypeDef GPIO_InitStruct;
	uint8_t 		pin_state;


	if(argc < 3)
	{
		help();
		return -1;
	}

	for(i=0;i<sizeof(gpio_map)/sizeof(GPIO_TABLE_T);i++)
	{
		if(strcmp(argv[2], gpio_map[i].pinstr) == 0)
		{
			GPIO_PORT = gpio_map[i].gpioport;
			GPIO_PIN = gpio_map[i].gpiopin;
			break;
		}
	}

	if(i == sizeof(gpio_map)/sizeof(GPIO_TABLE_T))
	{
		printf("Invalid gpio pin %s \n", argv[2]);
		help();
		return -1;
	}

	if((strcmp(argv[1], "set") == 0) && (argc == 5))
	{
		GPIO_InitStruct.Pin = GPIO_PIN;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;

		if(strcmp(argv[3], "outputpp") == 0)
			GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
		else if(strcmp(argv[3], "outputod") == 0)
			GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
		else if(strcmp(argv[3], "input") == 0)
			GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
		else
		{
			printf("Invalid dir %s\n", argv[3]);
			help();
			return -1;
		}

		if(strcmp(argv[4], "pullup") == 0)
			GPIO_InitStruct.Pull = GPIO_PULLUP;
		else if(strcmp(argv[4], "pulldown") == 0)
			GPIO_InitStruct.Pull = GPIO_PULLDOWN;
		else if(strcmp(argv[4], "nopull") == 0)
			GPIO_InitStruct.Pull = GPIO_NOPULL;
		else
		{
			printf("Invalid pull %s\n", argv[4]);
			help();
			return -1;
		}

		stm32_gpio_init(GPIO_PORT, &GPIO_InitStruct);
		printf("Set %s %s %s\n", argv[2], argv[3], argv[4]);
	}
	else if((strcmp(argv[1], "write") == 0) && (argc == 4))
	{
		if(strcmp(argv[3], "high") == 0)
		{
			stm32_gpio_write(GPIO_PORT, GPIO_PIN, 1);
			printf("Set %s high\n", argv[2]);
		}
		else if(strcmp(argv[3], "low") == 0)
		{
			stm32_gpio_write(GPIO_PORT, GPIO_PIN, 0);
			printf("Set %s low\n", argv[2]);
		}
		else
		{
			printf("Invalid pin state %s\n", argv[3]);
			help();
			return -1;
		}
	}
	else if((strcmp(argv[1], "read") == 0) && (argc == 3))
	{
		pin_state = stm32_gpio_read(GPIO_PORT, GPIO_PIN);
		if(pin_state)
			printf("Read %s high\n", argv[2]);
		else
			printf("Read %s low\n", argv[2]);
	}	
	else
	{
		help();
		return -1;
	}
}