//-------------------------------------------------------------------
// McStarSubs.cpp
//
// March 21, 2008
// Gene Massion		
//-------------------------------------------------------------------

#include "stdafx.h"
#include <windows.h>
#include "gpio.h"
#include "ssp.h"
#include "clk.h"
#include "McStar.h"
#include "MapIO.hpp"
#include "resource.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "ADSmartIO.h"

extern volatile GPIO_REGS	*GpioRegPtr;
extern volatile SSP_REGS	*SspRegPtr;
extern volatile CLKMAN_REGS	*v_pClkRegs;

void MapRegisters( VOID )
{
	ULONG	sscr0,
			sscr1,
			sspsp,
			gafr,
			gpdr,
			pcon=0;

	GpioRegPtr = (GPIO_REGS *)MapPhysicalAddr((GPIO_REGS *)GPIO_BASE_PHYSICAL,sizeof(GPIO_REGS));	// 1 Page
	if(GpioRegPtr == NULL)
		RETAILMSG(1,(L" Error 'cause GpioRegPtr == NULL \r\n"));

	SspRegPtr = (SSP_REGS *)MapPhysicalAddr((SSP_REGS *)NSSP_BASE_PHYSICAL,sizeof(SSP_REGS));	// 1 Page
	if(SspRegPtr == NULL)
		RETAILMSG(1,(L" Error 'cause SspRegPtr == NULL \r\n"));

	v_pClkRegs = (CLKMAN_REGS *)MapPhysicalAddr((CLKMAN_REGS *)CLK_BASE_PHYSICAL,sizeof(CLKMAN_REGS));	// 1 Page
	if(v_pClkRegs == NULL)
		RETAILMSG(1,(L" Error 'cause v_pClkRegs == NULL \r\n"));

	DEBUGMSG(1,(TEXT(" InitNSSP: + \r\n")));
	DEBUGMSG(1,(TEXT("Initial Register values before InitNSP \r\n")));
	gafr = READ_REGISTER_ULONG(&GpioRegPtr->GAFR2_U);
	DEBUGMSG(1,(TEXT(" SspRegPtr->GAFR2_U= 0x%x \r\n"),gafr));
	gpdr = READ_REGISTER_ULONG(&GpioRegPtr->GPDR_2);
	DEBUGMSG(1,(TEXT(" SspRegPtr->GPDR_2= 0x%x \r\n"),gpdr));
	sscr0 = READ_REGISTER_ULONG(&SspRegPtr->SSCR0);
	DEBUGMSG(1,(TEXT(" SspRegPtr->SSCR0= 0x%x \r\n"),sscr0));
	sscr1 = READ_REGISTER_ULONG(&SspRegPtr->SSCR1);
	DEBUGMSG(1,(TEXT(" SspRegPtr->SSCR1= 0x%x \r\n"),sscr1));
	sspsp = READ_REGISTER_ULONG(&SspRegPtr->SSPSP);
	DEBUGMSG(1,(TEXT(" SspRegPtr->SSPSP= 0x%x \r\n"),sspsp));
}



/*
int dwReadSSP( VOID )
{
	int		count=0x3ffff;
	ulong	value;
	LPVOID	m_hSSP3;
	DWORD	*ptr;

	m_hSSP3 = MapAddress(SSP3_BASE);

	ptr = (DWORD*)m_hSSP3;
	ptr += (SSSR_3_OFFSET / sizeof(DWORD));
	while( (*ptr & 0x00000008) == 0)  //SSSR[RNE] == 0
	{
		if(count-- == 0)
			break;
	}

	if( count <= 0)
	{
		DEBUGMSG(1,(TEXT("Read SSP timed out with RNE = 0\n")));
		return 0;
	}
	else
	{	
		ptr = (DWORD*)m_hSSP3;
		ptr += (SSDR_3_OFFSET / sizeof(DWORD));
		value = *ptr;
//		DEBUGMSG(1,(TEXT("Count = %08x SSDR Register = %08x \n"), count, value));
		return value;
	} 

	UnmapAddress(m_hSSP3);
}

*/
int dwReadSSP( unsigned int* ptr, int numSamples )
{
	int		i,
			count;

	for(i=0; i<numSamples; i++)
	{
		count=0x3ffff;
		while((READ_REGISTER_ULONG(&SspRegPtr->SSSR) & SSSR_RNE) == 0)
		{
			if(count-- == 0)
				break;
		}
	
		if( count <= 0)
		{
			DEBUGMSG(1,(TEXT("Read SSP timed out with RNE = 0\n")));
			return 0xFFFFFFFF;
		}
		else
		{	
			*(ptr + i) = READ_REGISTER_ULONG(&SspRegPtr->SSDR);
//			DEBUGMSG(1,(TEXT("Count = %08x SSDR Register = %08x \n"), count, value));
		}
	}
	return i;
}


bool ReadConfig( CFGDATA& configData )
{
	FILE *configFile;
	char inString[80],
	 	 *label,
		 *value;
	

	if ( (configFile = fopen( "\\FlashFX Disk\\McStar\\McStarConfig.txt", "r")) != NULL)
		DEBUGMSG(1,(TEXT("Opened Configuration File \n")));
	else
	{
		//process error
	}


	while( !feof(configFile) ) 
	{
		fgets(inString, 80, configFile);
		label = strtok(inString, ":");
		value = strtok(NULL, ":") ;

		if (strcmp(label, "Sample rate") == 0)
		{
			if ( (configData.sampleRate = atoi(value)) == 0)
			{
				// process error
			}
			DEBUGMSG(1,(TEXT("Sample rate %d\n"), configData.sampleRate));
			label = "";
		}
		else if (strcmp(label, "Number of samples per record") == 0)
		{
			if ( (configData.numSamples = atoi(value)) == 0)
			{
				// process error
			}
			DEBUGMSG(1,(TEXT("Samples per record %d\n"), configData.numSamples));
			label = "";
		}
		else if (strcmp(label, "Number of hydrophones") == 0)
		{
			if ( (configData.numPhones = atoi(value)) == 0)
			{
				// process error
			}
			DEBUGMSG(1,(TEXT("Hydrophones %d\n"), configData.numPhones));
			label = "";
		}
		else if (strcmp(label, "Number of records per Flash Disk file") == 0)
		{
			if ( (configData.numRecords = atoi(value)) == 0)
			{
				// process error
			}
			DEBUGMSG(1,(TEXT("Records per Flash Disk File %d\n"), configData.numRecords));
			label = "";
		}

		else if (strcmp(label, "Number of Flash Disk files per USB write") == 0)
		{
			if ( (configData.numFiles = atoi(value)) == 0)
			{
				// process error
			}
			DEBUGMSG(1,(TEXT("Flash Disk files per USB write %d\n"), configData.numFiles));
			label = "";
		}
		else if (strcmp(label, "Seconds to sleep between acquisitions") == 0)
		{
			if ( (configData.sleepPeriod = atoi(value)) == 0)
			{
				// process error
			}
			DEBUGMSG(1,(TEXT("Sleep Period rate %d\n"), configData.sleepPeriod));
			label = "";
		}
	}

	fclose(configFile);
	return TRUE;
}


bool SimData( int numSamples, int sampleRate, int* pData)
{
	// routine to read ADC for numSamples
	int	 i;
	double pi = 3.1415926535,
		   freq = 10000,
		   time,
		   dTemp;

	for(i = 0; i < numSamples; i++)
	{
		time = i / sampleRate;
		dTemp = sin( 2 * pi * freq * time );
		*(pData + i) = int(dTemp * 50000);
	}

	return TRUE;
}


void CreateFlashFilename( char fileName[80] )
{
	// routine to create a file name

	char	cTemp[10];

	__time64_t t64Time;
    
	struct tm timeNow;
    
	_time64( &t64Time );
	if( (_localtime64_s(&timeNow, &t64Time)) !=0)
	{
		// process error
	}
	
//	strcpy(fileName, "\\Hard Disk\\McStar\\Data\\");
	strcpy(fileName, "\\Storage Card\\McStar\\Data\\");
	_itoa(timeNow.tm_year, cTemp, 10);
	strcat(cTemp, "-");
	strcat(fileName, cTemp);
	_itoa(timeNow.tm_yday, cTemp, 10);
	strcat(cTemp, "-");
	strcat(fileName, cTemp);
	_itoa(timeNow.tm_hour, cTemp, 10);
	strcat(cTemp, "-");
	strcat(fileName, cTemp);
	_itoa(timeNow.tm_min, cTemp, 10);
	strcat(cTemp, "-");
	strcat(fileName, cTemp);
	_itoa(timeNow.tm_sec, cTemp, 10);
	strcat(fileName, cTemp);

	return;
}

bool WriteToUSBDisk()
{
	// routine to write files stored on flash disk to USB disk
	return TRUE;
}

void GoToSleep( int sleepPeriod )
{
	// routine to put Bitsy to sleep
}

void SetPowerState( BOOL powerState )
{
	LPVOID	m_hUSB,
			m_hCKEN,
			m_hAC97;
	DWORD	*ptr;

	ADSmartIO *smartIOCtrl	= 0;

	smartIOCtrl = new ADSmartIO;
	if (smartIOCtrl == NULL)
	{
		RETAILMSG (TRUE, (L"Out of memory\r\n"));
		return;
	}

	if(powerState == LOW_POWER)
	{
		(*smartIOCtrl).SetBacklightState (false);	//Turn off the LCD

		//Turn off the USB port
/*		m_hUSB = MapAddress(USB_BASE);
		ptr = (DWORD*)m_hUSB;
		ptr += (UHCCOMS_OFFSET / sizeof(DWORD));
		*ptr |= 0x1;		// Set the HCR bit
		Sleep(1);

		ptr = (DWORD*)m_hUSB;
		ptr += (UHCRHS_OFFSET / sizeof(DWORD));
		*ptr |= 0x1;		// Set the LPS bit

		ptr = (DWORD*)m_hUSB;
		ptr += (UHCHR_OFFSET / sizeof(DWORD));
		*ptr |= 0x1 << 5;		// Set the SSE bit

		//Turn off the USB clocks and the PWM clocks
		m_hCKEN = MapAddress(CKEN_BASE);
		ptr = (DWORD*)m_hCKEN;
		*ptr |= 0x0C00;		// Set the USB clock enable bits
		*ptr &= ~0x0C00;		// Clear the USB clock enable bits
		*ptr &= ~0x03;			// Clear the PWM clock enable bits

		UnmapAddress(m_hUSB);
*/
		//Turn off the AC97
		m_hAC97 = MapAddress(AC97_BASE);
		ptr = (DWORD*)m_hAC97;
		ptr += (AC97x26_OFFSET / sizeof(DWORD));
		*ptr |= 0x1000;		// Set AC97 Powerdown register PR4 bit

		// wait for GSR[cdone]
		ptr = (DWORD*)m_hAC97;
		ptr += (AC97GSR_OFFSET / sizeof(DWORD));
		while( (*ptr & 0x00080000) == 0)
			DEBUGMSG(1,(TEXT("AC97 GSR Register CDONE = %d\n"), (*ptr & 0x00080000)));
		
		ptr = (DWORD*)m_hAC97;
		ptr += (AC97GCR_OFFSET / sizeof(DWORD));
		*ptr |= 0x08; // Set the ACOFF bit

		//Set the AC97 bit in CKEN
		m_hCKEN = MapAddress(CKEN_BASE);
		ptr = (DWORD*)m_hCKEN;
		*ptr |= 0x80000000;

		//Wait for GSR[ACOFFD]
		ptr = (DWORD*)m_hAC97;
		ptr += (AC97GSR_OFFSET / sizeof(DWORD));
		while( (*ptr & 0x00000008) == 0)
			DEBUGMSG(1,(TEXT("AC97 GSR Register ACOFFD= %d\n"), (*ptr & 0x00080000)));

		UnmapAddress(m_hAC97);

		//Clear the AC97 bit in CKEN and clear the AC97 clock enable
		m_hCKEN = MapAddress(CKEN_BASE);
		ptr = (DWORD*)m_hCKEN;
		*ptr &= ~0x80000000;
		*ptr &= ~0x00000004;

		UnmapAddress(m_hCKEN);
	}
	else
	{
		(*smartIOCtrl).SetBacklightState (true);
	}

	delete smartIOCtrl;
}

VOID InitPSP( VOID )
{
	LPVOID	m_hSSP3,
			m_hGPIO,
			m_hCKEN;
	DWORD	*ptr;

	m_hSSP3 = MapAddress(SSP3_BASE);
	m_hCKEN = MapAddress(CKEN_BASE);
	m_hGPIO = MapAddress(GPIO_BASE);

	// Disable SSP Clock
	ptr = (DWORD*)m_hCKEN;
	*ptr &= ~(0x1 << 4);	

	//Set GPIO alternate function bits for SSP port
	ptr = (DWORD*)m_hGPIO;
	ptr += (GAFR2_U_OFFSET / sizeof(DWORD));
	*ptr &= ~(0x03 << 2);	// clear AF81 bits
	*ptr |= (0x1 << 2);		// AF81 bits set for AF1 - SSPTXD3 output
	*ptr &= ~(0x03 << 4);	// clear AF82 bits
	*ptr |= (0x1 << 4);		// AF82 bits set for AF1 - SSPRXD3 input
	*ptr &= ~(0x03 << 6);	// clear AF83 bits
	*ptr |= (0x1 << 6);		// AF83 bits set for AF1 - SSPSFRM3 output
	*ptr &= ~(0x03 << 8);	// clear AF84 bits
	*ptr |= (0x1 << 8);		// AF84 bits set for AF1 - SSPCLK3 output
	DEBUGMSG(1,(TEXT("GAFR2_U = 0x%8x \r\n"),*ptr));

	//Set SSP3 SSCR0 register
	ptr = (DWORD*)m_hSSP3;
	ptr += (SSCR0_3_OFFSET / sizeof(DWORD));
	*ptr = 0;			// clear all SSCR0 bits
	*ptr |= (0x3 << 4); // Set Frame Format to PSP 
	*ptr |= (0x1 << 20);// Set Extended Data Size Select
	*ptr &= 0xFFF000FF; // Clear Serial Clock Rate bits
	*ptr |= (0x3 << 8); // Set Serial Clock Rate
	*ptr &= 0xFFFFFFF0; // Clear Data Size Select bits
	*ptr |= 0x07;		// Set Data Size Select to 24 bits
	//Set Network mode
//	*ptr |= (0x01 << 31); 
	//Set FRDC network mode bits to 2 time slots
//	*ptr |= (0x01 << 24);	// Actual value is 1 +FRDC
	
	DEBUGMSG(1,(TEXT("SSCR0_3 = 0x%8x \r\n"),*ptr));

	//Set SSP3 SSCR1 register
	ptr = (DWORD*)m_hSSP3;
	ptr += (SSCR1_3_OFFSET / sizeof(DWORD));
	*ptr = 0;				// clear all SSCR1 bits
	*ptr |= (0x1 << 28);	// Set Slave Clock Free Running just active only during transfers just to make sure 
	*ptr |= (0x0 << 25);	// Set SSPSCLK direction to Master mode just to make sure
	*ptr |= (0x1 << 24);	// Set SSP Frame Direction to Slave 
//	*ptr |= (0x1 << 23);	// Set Receive Without Transmit mode, this also makes the clock run continuously
	// Set TTE because it says to do this in network mode
	*ptr |= (0x1 << 30);
	DEBUGMSG(1,(TEXT("SSCR1_3 = 0x%8x \r\n"),*ptr));

	//Set SSP3 SSPSP register
	ptr = (DWORD*)m_hSSP3;
	ptr += (SSPSP_3_OFFSET / sizeof(DWORD));
	*ptr = 0;				// clear all SSPSP bits
	*ptr |= (0x1 << 16);	// Set SFRMWDTH to 1 clock cycle 
	DEBUGMSG(1,(TEXT("SSPSP_3 = 0x%8x \r\n"),*ptr));

	//Set SSP3 SSRSA register
	ptr = (DWORD*)m_hSSP3;
	ptr += (SSRSA_3_OFFSET / sizeof(DWORD));
	*ptr = 0;			// clear all SSRSA bits
	*ptr |= 0x03;		// Set bits to receive in time slot 1 and 2
	DEBUGMSG(1,(TEXT("SSRSA_3 = 0x%8x \r\n"),*ptr));

	//Set GPIO direction register must be written after PSP bits are set
	ptr = (DWORD*)m_hGPIO;
	ptr += (GPDR2_OFFSET / sizeof(DWORD));
	*ptr |= (0x1 << 17); // GPIO 81 set to output
	*ptr &= ~(0x1 << 18); // GPIO 82 set to input
	*ptr &= ~(0x1 << 19); // GPIO 83 set to input
	*ptr |= (0x1 << 20); // GPIO 84 set to output
	DEBUGMSG(1,(TEXT("GPDR2 = 0x%8x \r\n"),*ptr));

	//Clear the RX FIFO Overrun bit (not sure this needs to be done for read only operations)
	ptr = (DWORD*)m_hSSP3;
	ptr += (SSSR_3_OFFSET / sizeof(DWORD));
	*ptr |= (0x1 << 7);	
	DEBUGMSG(1,(TEXT("SSSR_3 = 0x%8x \r\n"),*ptr));

	//Enable SSP Synchronous Serial Enable
	ptr = (DWORD*)m_hSSP3;
	ptr += (SSCR0_3_OFFSET / sizeof(DWORD));
	*ptr |= (0x1 << 7); // Set SSE bit
	DEBUGMSG(1,(TEXT("SSCR0_3 = 0x%8x \r\n"),*ptr));

	// Enable SSP Clock 
	ptr = (DWORD*)m_hCKEN;
	*ptr |= (0x1 << 4);	

	UnmapAddress(m_hSSP3);
	UnmapAddress(m_hCKEN);
	UnmapAddress(m_hGPIO);

	DEBUGMSG(1,(TEXT(" InitNSSP: - \r\n")));

	return ;
}

void UnmapAddress(LPVOID address)
{
	VirtualFree(address, 0, MEM_RELEASE);
	address = NULL;
}

#define	MEMORY_SIZE					0x10000  // 64kiB memory space; max allocation for VirtualAlloc is 64MiB

extern "C" BOOL VirtualCopy(LPVOID lpvDestMem, LPVOID lpvSrcMem, 
							DWORD dwSizeInBytes, DWORD dwProtectFlag);

/////////////////////////////////////////////
// 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;
}

int WriteToFlash(unsigned int* data, int numValues)
{
	char	fileName[80];
	int		numWritten;
	FILE	*outFile;

	CreateFlashFilename( fileName );
	outFile = fopen( fileName, "ab" );

	numWritten = fwrite(data, sizeof(int), numValues, outFile);
	DEBUGMSG(1, (_T("Wrote %d samples to flash \n"), numWritten));

	fclose(outFile);

	return numWritten;
	
//	for(i=0; i<configData.numSamples; i++)
//				fprintf(outFile, "%d ", *(pData + i));
}