#ifndef __GPIO_REGISTERS_H__
#define __GPIO_REGISTERS_H__

// MS Didn't even supply stdint.h! Ugh...
#include "stdint.h"  
#include "register_bitops.h"

#define GPIO1BaseAddress 0x53FCC000
#define GPIO2BaseAddress 0x53FD0000
#define GPIO3BaseAddress 0x53FA4000

PVOID MapPhysicalAddr(PVOID dwPhysicalAddress, DWORD dwSize);

namespace gpio1
{
	static volatile uint32_t virtualAddress = (uint32_t) MapPhysicalAddr((PVOID) GPIO1BaseAddress, 0x001F); 
	
	enum Registers
	{
		DR		= 0x0000,		//Data Register
		GDIR	= 0x0004,		//Direction Register
		PSR		= 0x0008,		//Pad Status Register
		ICR1	= 0x000C,		//Interrupt Configuration 1 
		ICR2	= 0x0010,		//Interrupt Configuration 2
		IMR		= 0x0014,		//Interrupt Mask
		ISR		= 0x0018		//Interrupt Status
	};

	// Bits 25 and 24 of the control register
	enum REGISTER_BIT_FIELDS
	{
		// Look in LogicPD AN375 for available GPIO pins
		GPIO0		= REGISTER_BIT_DEFINITION(0, 0),	
		GPIO1		= REGISTER_BIT_DEFINITION(1, 1),	
		upGPIO0		= REGISTER_BIT_DEFINITION(8, 8),
		upGPIO3		= REGISTER_BIT_DEFINITION(31, 31),
	};

	inline volatile uint32_t *regAddress(Registers reg)
	{
		return reinterpret_cast<volatile uint32_t*>(virtualAddress + reg);
	}
	
	inline uint32_t regRead(Registers reg)
	{
		return *regAddress(reg);
	}
	
	inline void regWrite(Registers reg, uint32_t value)
	{
		*regAddress(reg) = value;
	}

}

namespace gpio2
{
	static volatile uint32_t virtualAddress = (uint32_t) MapPhysicalAddr((PVOID) GPIO2BaseAddress, 0x001F); 
	
	enum Registers
	{
		DR		= 0x0000,		//Data Register
		GDIR	= 0x0004,		//Direction Register
		PSR		= 0x0008,		//Pad Status Register
		ICR1	= 0x000C,		//Interrupt Configuration 1 
		ICR2	= 0x0010,		//Interrupt Configuration 2
		IMR		= 0x0014,		//Interrupt Mask
		ISR		= 0x0018		//Interrupt Status
	};

	// Bits 25 and 24 of the control register
	enum REGISTER_BIT_FIELDS
	{
		// Look in LogicPD AN375 for available GPIO pins
		GPIO0		= REGISTER_BIT_DEFINITION(18, 18),	
		GPIO1		= REGISTER_BIT_DEFINITION(19, 19),	
	};

	inline volatile uint32_t *regAddress(Registers reg)
	{
		return reinterpret_cast<volatile uint32_t*>(virtualAddress + reg);
	}
	
	inline uint32_t regRead(Registers reg)
	{
		return *regAddress(reg);
	}
	
	inline void regWrite(Registers reg, uint32_t value)
	{
		*regAddress(reg) = value;
	}

}

namespace gpio3
{
	static volatile uint32_t virtualAddress = (uint32_t) MapPhysicalAddr((PVOID) GPIO3BaseAddress, 0x001F); 
	
	enum Registers
	{
		DR		= 0x0000,		//Data Register
		GDIR	= 0x0004,		//Direction Register
		PSR		= 0x0008,		//Pad Status Register
		ICR1	= 0x000C,		//Interrupt Configuration 1 
		ICR2	= 0x0010,		//Interrupt Configuration 2
		IMR		= 0x0014,		//Interrupt Mask
		ISR		= 0x0018		//Interrupt Status
	};

	// Bits 25 and 24 of the control register
	enum REGISTER_BIT_FIELDS
	{
		// Look in LogicPD AN375 for available GPIO pins
		GPIO0		= REGISTER_BIT_DEFINITION(26, 26),	
		GPIO1		= REGISTER_BIT_DEFINITION(27, 27),	
	};

	inline volatile uint32_t *regAddress(Registers reg)
	{
		return reinterpret_cast<volatile uint32_t*>(virtualAddress + reg);
	}
	
	inline uint32_t regRead(Registers reg)
	{
		return *regAddress(reg);
	}
	
	inline void regWrite(Registers reg, uint32_t value)
	{
		*regAddress(reg) = value;
	}

}

#endif // __GPIO_REGISTERS_H__
