/*
 * main.c
 */
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define CONTROL_BASE_ADDR                 (0x44E10000)
#define CONTROL_PADCONF_GPMC_AD0                  0x0800

#define INFILENAME  "C:\\Users\\a0157014\\Documents\\Pin Mux Utility\\Design1\\AM335x Rev 2.x\\PinMuxConfigDefault.dat"
#define OUTFILENAME "C:\\Users\\a0157014\\Documents\\Pin Mux Utility\\Design1\\AM335x Rev 2.x\\PinMuxConfigBBW.dat"
#define HEADERLINECNT 17 /* # lines before pin data */
#define DATALINECNT  125 /* # data lines to read & parse */
#define TRAILERLINECNT 1 /* # final trailing lines after data to echo */

#define LINESIZE     200
#define TOKENSPERPKG   3 /* # char tokens seen per package */

//
// echo N lines from infile to outfile
//
void CopyLines( FILE *pIn, FILE *pOut, int nCnt )
{
	int i;
	char Line[LINESIZE];
	char *pBufTest;

	for ( i = 0; i < nCnt; i++ )
	{
		pBufTest = fgets( Line, LINESIZE, pIn );
		if ( pBufTest != NULL )
			fputs( Line, pOut );
		else
			return;
	}
}

//
// read 1 space-delimited token starting at Line[*nPos] and copy it to Tok, incrementing *nPos to whitespace or \0
// return # chars in Tok, 0=EOL reached
//
int GetToken( char *Line, char *Tok, int *nPos )
{
	int nTokLen = 0;

	// skip any leading whitespace
	while ( Line[*nPos] != '\0' && isspace( Line[*nPos] ) )
		(*nPos)++;

	// copy to next whitespace/EOL
	while ( Line[*nPos] != '\0' && !isspace( Line[*nPos] ) )
		Tok[nTokLen++] = Line[(*nPos)++];

	Tok[nTokLen] = '\0';

	return nTokLen;
}

int strtoint( char *str )
{
	int val = 0;
	int sign = +1;

	if ( *str == '\0' )
		return 0;

	if ( *str == '0' && *(str+1) == 'x' )  // hex str follows
	{
		while ( /* *str != '\0' && */ isxdigit( *str ) )
		{
			val *= 16;
			if ( isdigit( *str ) )
				val += *str++ - '0';
			else if ( *str <= 'F' )
				val += *str++ - 'A' + 10;
			else
				val += *str++ - 'a' + 10;
		}
	}

	else  // get decimal value
	{
		if ( *str == '-' )
		{
			sign = -1;
			str++;
		}

		while ( /* *str != '\0' && */ isdigit( *str ) )
			val = ( val * 10 ) + ( *str++ - '0' );
	}

	return sign * val;
}

int inttostr_( int *pnum, char *str )
{
	int val, cnt;

	if ( *pnum == 0 )
	{
		*str   = '\0';
		return 0;
	}

	cnt = inttostr_( pnum, str+1 );  // ends with *str where ls digit goes

	val = *pnum / 10;

	*str = '0' + ( *pnum - (val*10) );
	*pnum = val;

	return cnt+1;
}

int inttostr( int num, char *str )
{
	if ( num == 0 )
	{
		*str++ = '0';
		*str   = '\0';
		return 1;
	}

	if ( num < 0 )
	{
		*str++ = '-';
		num *= -1;
		return inttostr_( &num, str ) + 1;
	}

	return inttostr_( &num, str );
}

//
// parse 1 input line and replace values using Pad Config register value
//
void ParseAndReplace( FILE *pIn, FILE *pOut, unsigned int uPadMuxValue )
{
	char Line[LINESIZE], OutLine[LINESIZE];
	char *tok;
	char *pBufTest;
	int nMuxMode, nPud, nIen;
	int num;
	int cnt;

	pBufTest = fgets( Line, LINESIZE, pIn );
	if ( pBufTest == NULL )
		return;

	// parse uPadMuxValue
	nMuxMode = ( uPadMuxValue & 0x07 );
	if ( uPadMuxValue & 0x08 )  // 1=disabled, translated to nPud=2
		nPud = 2;
	else
		nPud = ( uPadMuxValue >> 4 ) & 1;
	nIen = ( uPadMuxValue >> 5 ) & 1;

	// 1st tok is Pad
	tok = strtok( Line, " \t\r\n" );
	if ( *tok )
	{
		strcpy( OutLine, tok );
		tok = strtok( NULL, " \t\r\n" );
	}

	// next tok is # packages, then package name, pad designator, -
	if ( *tok )
	{
		strcat( OutLine, " " );
		strcat( OutLine, tok );

		num = strtoint( tok ) * TOKENSPERPKG;  // get # of packages, multiply by TOKENSPERPKG

		while ( *tok && num-- > 0 )
		{
			tok = strtok( NULL, " \t\r\n" );
			if ( *tok )
			{
				strcat( OutLine, " " );
				strcat( OutLine, tok );
			}
		}
		tok = strtok( NULL, " \t\r\n" );
	}

	// next tok is pad name
	if ( *tok )
	{
		strcat( OutLine, " " );
		strcat( OutLine, tok );
		tok = strtok( NULL, " \t\r\n" );
	}

	// next tok is # selections, then that many selections
	if ( *tok )
	{
		strcat( OutLine, " " );
		strcat( OutLine, tok );

		num = strtoint( tok );  // get # of selections
		cnt = 0;

		while ( *tok && num-- > 0 )
		{
			tok = strtok( NULL, " \t\r\n" );
			if ( *tok )
			{
				strcat( OutLine, " " );
				if ( strcmp( tok, "Reserved" ) == 0 )  // have to keep Reserved no matter what else is selected
					strcat( OutLine, tok );
				else if ( nMuxMode == cnt )
				{
					if ( nMuxMode == 7 )  // last one gets replaced with SafeMode
						strcat( OutLine, "SafeMode" );
					else
						strcat( OutLine, "Selected" );
				}
				else
					strcat( OutLine, "NotSelected" );
			}
			cnt++;
		}
		if ( *tok )
			tok = strtok( NULL, " \t\r\n" );
	}

	// next tok is # enable states, then InputEnable (1|0) and OffPuPd (2|1|0)
	if ( *tok )
	{
		strcat( OutLine, " " );
		strcat( OutLine, tok );

		num = strtoint( tok );  // get # of enable states

		if ( num-- > 0 )
		{
			tok = strtok( NULL, " \t\r\n" );
			if ( *tok )
			{
				strcpy( tok, " " );
				strcat( OutLine, tok );
				tok[0] = '0' + nIen;
				strcat( OutLine, tok );
			}
		}

		if ( *tok && num-- > 0 )
		{
			tok = strtok( NULL, " \t\r\n" );
			if ( *tok )
			{
				strcpy( tok, " " );
				strcat( OutLine, tok );
				tok[0] = '0' + nPud;
				strcat( OutLine, tok );
			}
		}
	}

	strcat( OutLine, "\n" );
	fputs( OutLine, pOut );
}

int main(void) {
	FILE *pInDatFile, *pOutDatFile;
	int i;
	unsigned int *pPadConfigRegs = (unsigned int *)(CONTROL_BASE_ADDR+CONTROL_PADCONF_GPMC_AD0);


	pInDatFile = fopen( INFILENAME, "r" );
	if ( pInDatFile == NULL )
	{
		printf( "Input file open failed\n" );
		return -1;
	}
	pOutDatFile = fopen( OUTFILENAME, "w" );
	if ( pOutDatFile == NULL )
	{
		printf( "Output file open failed\n" );
		return -1;
	}

	// echo first few lines
	CopyLines( pInDatFile, pOutDatFile, HEADERLINECNT );

	// read 1 pin data line, 1 pinmux value, replace data, and write
	for ( i = 0; i < DATALINECNT; i++ )
	{
		ParseAndReplace( pInDatFile, pOutDatFile, *pPadConfigRegs++ );
	}

	// echo final few lines
	CopyLines( pInDatFile, pOutDatFile, TRAILERLINECNT );

	fclose( pInDatFile );
	fclose( pOutDatFile );

	return 0;
}
