///////////////////////////////////////////////////
// BitsyXGPIO.cpp
// 720020-1180x
//
// Applied Data Systems
//
// See BitsyXGPIO.h for a description and history
// 
///////////////////////////////////////////////////
#include "BitsyXGPIO.h"

/////////////////////////////////////////////////////////////////////////////
// VirtualCopy definition
//
extern "C" BOOL VirtualCopy(LPVOID lpvDestMem, LPVOID lpvSrcMem, 
							DWORD dwSizeInBytes, DWORD dwProtectFlag);


/////////////////////////////////////////////////////////////////////////////
// Forward declarations for internal functions
//
LPVOID MapAddress(DWORD baseAddress);
void UnmapAddress(LPVOID address);

/////////////////////////////////////////////////////////////////////////////
// Internal defines
//
#define GPIO_BASE		0x40E00000
#define GPLR0_OFFSET	0x00		// level register 0
#define GPLR1_OFFSET	0x04		// level register 1
#define GPLR2_OFFSET	0x08		// level register 2
#define GPLR3_OFFSET	0x0100		// level register 2
#define GPDR0_OFFSET	0x0C		// direction register 0
#define GPDR1_OFFSET	0x10		// direction register 1
#define GPDR2_OFFSET	0x14		// direction register 2
#define GPDR3_OFFSET	0x010C		// direction register 2
#define GPSR0_OFFSET	0x18		// set register 0
#define GPSR1_OFFSET	0x1C		// set register 1
#define GPSR2_OFFSET	0x20		// set register 2
#define GPSR3_OFFSET	0x0118		// set register 2
#define GPCR0_OFFSET	0x24		// clear register 0
#define GPCR1_OFFSET	0x28		// clear register 1
#define GPCR2_OFFSET	0x2C		// clear register 2
#define GPCR3_OFFSET	0x0124		// clear register 2
#define GAFR0_L_OFFSET	0x54		// alt. fxn register 1
#define GAFR0_U_OFFSET	0x58		// alt. fxn register 2
#define GAFR1_L_OFFSET	0x5C		// alt. fxn register 1
#define GAFR1_U_OFFSET	0x60		// alt. fxn register 2
#define GAFR2_L_OFFSET	0x64		// alt. fxn register 1
#define GAFR2_U_OFFSET	0x68		// alt. fxn register 2
#define GAFR3_L_OFFSET	0x6C		// alt. fxn register 1
#define GAFR3_U_OFFSET	0x70		// alt. fxn register 2

#define GP33_AF_BITS	0x0C
#define GP80_AF_BITS	0x03
#define GP33_BIT		0x00000002
#define GP80_BIT		0x00010000
#define GP106_AF_BITS	0x0300000
#define GP107_AF_BITS	0x0C00000
#define GP106_BIT		0x0400
#define GP107_BIT		0x0800

BitsyXGPIO::BitsyXGPIO(BYTE direction)
{
	DEBUGMSG(TRUE, (_T("+BitsyXGPIO(%i)\r\n"), direction));
	m_direction = direction;

	m_hGPIO = MapAddress(GPIO_BASE);

	// make sure alternate functions are *off*
	SetDirection(0x00);
	DWORD *p;

	p = (DWORD*)m_hGPIO;
	p += (GAFR1_L_OFFSET / sizeof(DWORD));
	DEBUGMSG(TRUE, (_T("    GAFR1_L changed from 0x%08x "), *p));
	*p &= ~GP33_AF_BITS;
	DEBUGMSG(TRUE, (_T("to 0x%08x "), *p));

	p = (DWORD*)m_hGPIO;
	p += (GAFR2_U_OFFSET / sizeof(DWORD));
	DEBUGMSG(TRUE, (_T("    GAFR2_U changed from 0x%08x "), *p));
	*p &= ~GP80_AF_BITS;
	DEBUGMSG(TRUE, (_T("to 0x%08x "), *p));

	p = (DWORD*)m_hGPIO;
	p += (GAFR3_L_OFFSET / sizeof(DWORD));
	DEBUGMSG(TRUE, (_T("    GAFR3_U changed from 0x%08x "), *p));
	*p &= ~GP106_AF_BITS;
	DEBUGMSG(TRUE, (_T("to 0x%08x "), *p));
	DEBUGMSG(TRUE, (_T("    GAFR3_U changed from 0x%08x "), *p));
	*p &= ~GP107_AF_BITS;
	DEBUGMSG(TRUE, (_T("to 0x%08x "), *p));

	SetDirection(direction);
	DEBUGMSG(TRUE, (_T("-BitsyXGPIO()\r\n")));
}

BitsyXGPIO::~BitsyXGPIO()
{
	DEBUGMSG(TRUE, (_T("+~BitsyXGPIO()\r\n")));
	UnmapAddress(m_hGPIO);
	DEBUGMSG(TRUE, (_T("-~BitsyXGPIO()\r\n")));
}

BYTE BitsyXGPIO::Read()
{
	BYTE state = 0;
	
	DWORD *p;

	if((m_direction & GPIO33) == 0)
	{
		p = (DWORD*)m_hGPIO;
		p += (GPLR1_OFFSET / sizeof(DWORD));

		if(*p & GP33_BIT)
		{
			// high
			state |= GPIO33;
		}
	}

	if((m_direction & GPIO80) == 0)
	{
		p = (DWORD*)m_hGPIO;
		p += (GPLR2_OFFSET / sizeof(DWORD));

		if(*p & GP80_BIT)
		{
			// low
			state |= GPIO80;
		}
	}

	return state;
}

void BitsyXGPIO::Write(BYTE state)
{
	int i;
	
	// mask to 2 bits
	state &= 0x00000003;

	DWORD *ps, *pc,
			set, clear;

	pc = ps = (DWORD*)m_hGPIO;
	ps += (GPSR3_OFFSET / sizeof(DWORD));
	pc += (GPCR3_OFFSET / sizeof(DWORD));

	for(i=0; i<10; i++)
	{
		*ps = 0x0C00;
		*pc = 0x0C00;
	}


/*	if(m_direction & GPIO33)
	{
		pc = ps = (DWORD*)m_hGPIO;
		ps += (GPSR1_OFFSET / sizeof(DWORD));
		pc += (GPCR1_OFFSET / sizeof(DWORD));

		if(state & GPIO33)
		{
			// set
			*ps |= GP33_BIT;
		}
		else
		{
			// clear
			*pc |= GP33_BIT;
		}
	}

	if(m_direction & GPIO80)
	{
		pc = ps = (DWORD*)m_hGPIO;
		ps += (GPSR2_OFFSET / sizeof(DWORD));
		pc += (GPCR2_OFFSET / sizeof(DWORD));

		if(state & GPIO80)
		{
			// set
			*ps |= GP80_BIT;
		}
		else
		{
			// clear
			*pc |= GP80_BIT;
		}
	}
*/
}

void BitsyXGPIO::SetDirection(BYTE direction)
{
	DEBUGMSG(TRUE, (_T("+SetDirection()\r\n")));
	// mask to 2 bits
	direction &= 0x00000003;
	
	DWORD *p;

	p = (DWORD*)m_hGPIO;
	p += (GPDR3_OFFSET / sizeof(DWORD));
	*p |= GP106_BIT;
	*p |= GP107_BIT;
	
/*	p = (DWORD*)m_hGPIO;
	p += (GPDR1_OFFSET / sizeof(DWORD));

	DEBUGMSG(TRUE, (_T("    GPDR1 changed from 0x%08x "), *p));

	if(direction & GPIO33)
	{
		// output
		*p |= GP33_BIT;
	}
	else
	{
		// input
		*p &= ~GP33_BIT;
	}

	DEBUGMSG(TRUE, (_T("to 0x%08x "), *p));

	p = (DWORD*)m_hGPIO;
	p += (GPDR2_OFFSET / sizeof(DWORD));

	DEBUGMSG(TRUE, (_T("    GPDR2 changed from 0x%08x "), *p));

	if(direction & GPIO80)
	{
		// output
		*p |= GP80_BIT;
	}
	else
	{
		// input
		*p &= ~GP80_BIT;
	}
	DEBUGMSG(TRUE, (_T("to 0x%08x "), *p));

	DEBUGMSG(TRUE, (_T("-SetDirection()\r\n")));
*/

}


#define	MEMORY_SIZE					0x10000  // 64kiB memory space; max allocation for VirtualAlloc is 64MiB

/////////////////////////////////////////////
// MapAddress 
//  Maps the desired memory address.
//  This function should be called first and its
//  return value is then passed to the ReadData16 or
//  WriteData16 functions as the baseAddress.
//
// [I] baseAddress - base address to map
// [O] Virtual Address pointer to mapped region
// 
/////////////////////////////////////////////
LPVOID MapAddress(DWORD baseAddress)
{
	LPVOID pAddr = VirtualAlloc(0, MEMORY_SIZE, MEM_RESERVE, PAGE_NOACCESS);
	
	if(pAddr)	
	{
		if(VirtualCopy (pAddr, (PVOID)(baseAddress >> 8), 
				MEMORY_SIZE, PAGE_PHYSICAL|PAGE_READWRITE|PAGE_NOCACHE) == TRUE) 
		{
				DEBUGMSG(1, (_T("0x%08x mapped to: 0x%08x\r\n"), baseAddress, pAddr));
		}
		else 
		{
			RETAILMSG(1, (_T("Error! at VirtualCopy()\r\n")));

			return NULL;
		}
	}
	else 
	{
		RETAILMSG(1, (_T("Error! at VirtualAlloc()\r\n")));
		return NULL;
	}

	return pAddr;
}

void UnmapAddress(LPVOID address)
{
	VirtualFree(address, 0, MEM_RELEASE);
	address = NULL;
}

