/**
 * \file eip_main.c
 * \brief File which contains Ethernetip init and exit functionalities
 *
 * \copyright Copyright (c) 2012 Texas Instruments Incorporated ALL RIGHTS RESERVED
 *
*/

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include <stdio.h>
#include "icss_ethdriver.h"
#include "eip_main.h"
#include "user_api.h"
#include "eip_main.h"
#include "device.h"
#include "hal.h"
#include "EipConfData.h"
#include "plat_uart.h"
#include <hw/hw_types.h>
#include "app_restart.h"
#include "osdrv_uart.h"
#include "eip_api.h"
#include "icss_eip_driver.h"
#include "icss_dlr.h"
#include "eip_utils.h"
#include "user_acd_ndk.h"

//extern uint32_t deviceIP;
/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
/**local IP Address*/
EIP_DWORD gdwIPAddress           = 0;
/**Local Mask*/
EIP_DWORD gdwMask                = 0xFFFFFF00;
/**Configuration file*/
EIP_CHAR  *gszConfigurationFile  = 0;
/**EIP Configuration File poiter*/
EIP_BYTE  *gpbyFilePtr;
/**Device Capabilities*/
EIP_DWORD gdwCapabilities = 0;
/**Shared memory pointer for IO Data Exchange*/
ST_SHM_PARAMS *gpstSharedMemory;
/**EIP Running mode status*/
EIP_BOOL ModeRunning = EIP_FALSE;
/**Flag to check uart input data processing*/
Uint8 user_input_processing = 0;
/** Variablr to receive uart input*/
Char rxByte;
/**Variable informs the IP Assign status*/
Uint8 finish_assign_ip=1;
/**Index used for getting input from Uart*/
int counter=0;
/**Flag to indicate uart input is finished*/
int flagFinish=0;
/**Variable to store IP Address*/
char chIpAddr[16];

unsigned int acdEIPStatus=EIP_ACD_DEFAULT;
DEVICE_INIT_CONFIG eipDevInitConfig;
ST_TCPIP_CONFIGURATION  eipDevTcpIpConfiguration;
unsigned int eipAppStat = 0;

Semaphore_Handle SPIReadSemaphoreHandle;

/* ========================================================================== */
/*                            Extern Variables                                */
/* ========================================================================== */
/**Variable to check for Device to be restarted or not*/
extern EIP_BOOL gbResetIdentity;
extern unsigned int uartInstance;
extern int acdIPAssign;


/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */


/**
 *  \name InitApp
 *  \brief The function initializes the Configuration file and Shared memory for IO data exchange
 *  \param none
 *  \return 0 on success,1 on failure
 *
 */
int InitApp()
{
	EIP_BYTE byMajor, byMinor, byBuild, bySpecial;
	EIP_GetVersion (&byMajor, &byMinor, &byBuild, &bySpecial);
	byMajor = GetMajorRevision();
	byMinor = GetMinorRevision();
  	/*Configuration file ptr*/
    gpbyFilePtr = (EIP_BYTE  *)EipConfData;
    /*SharedMemory Initializaation*/
    gpstSharedMemory = GetSharedMemoryPtr();
    if (gpbyFilePtr == EIP_NULL)
    {
    	return 1;
    }
	return 0;
}

/**
 *  \name ExitApp
 *  \brief The function frees the shared memory 
 *  \param none
 *  \return none
 *
 */
EIP_VOID ExitApp()
{
	if(gszConfigurationFile != EIP_NULL)
	{
		free(gszConfigurationFile);
		gszConfigurationFile = EIP_NULL;
	}

	if(gpstSharedMemory != EIP_NULL)
	{
		free(gpstSharedMemory);
		gpstSharedMemory = EIP_NULL;
	}
}

/**
 *  \name PrintMenu
 *  \brief The function prints the operation modes in uart console 
 *  \param none
 *  \return none
 *
 */
EIP_VOID PrintMenu()
{
	UARTPutString(uartInstance,"\n\r Stack is online, press T to start...\n\n\r Menu:");
	UARTPutString(uartInstance,"\n\r\tESC-Quit\n\r\tT-Start/Stop (toggle)\n\r\tR-Run IO");
	UARTPutString(uartInstance,"\n\r\tI-Idle IO \n\r\tC-Copy IN -> OUT (toggle) \n\r\tU-Increment Data (toggle) \n\r\tN-Change IP Address \n\r\tE-Erase Non Volatile Memory");
}

/**
 *  \name InitSample
 *  \brief The function initialize the adapter
 *  \param pstEipInit
 *  \return EIP_TRUE on Success,EIP_FALSE on failure
 *
 */
static int InitSample(ST_EIP_INIT * pstEipInit,ST_EIP_ONLINE * pstEipOnline)
{
	if (EIP_Init(pstEipInit) == EIP_FALSE)
	{
		return EIP_FALSE;
	}
	/* EIP Stack Configuration*/
	if (EIP_Configure(gpbyFilePtr,gpstSharedMemory) == EIP_FALSE )
	{
		printf ("Fatal Error: EIP_Configure failed! \n");
		return EIP_FALSE;
	}
	if ( USEROBJ_Init() == EIP_FALSE )
	{
		return EIP_FALSE;
	}
	/* go online*/
	 if (EIP_Online(pstEipOnline) == EIP_FALSE )
	{
		return EIP_FALSE;
	}
	/*menu management*/
	PrintMenu();

	return EIP_TRUE;
}

/**
 *  \name ExitSample
 *  \brief The function exits the adapter
 *  \param none
 *  \return none
 *
 */
static EIP_VOID ExitSample()
{
	eipAppStat=0;
	EIP_Stop();
	EIP_Offline();
	EIP_Exit();
}



int EipAppInit()
{
	ST_EIP_INIT stEipInit = {0};
	ST_EIP_ONLINE stEipOnline = {0};

	/* Application Initialization*/
	if (InitApp () != 0)
	{
		return -1;
	}

	SetTCPIPInitConfig();

	gdwCapabilities |= EIP_CAPABILITY_ACD;
	gdwMask=eipDevTcpIpConfiguration.Network_Mask;;
	// EIP Stack Initialization
 	stEipOnline.dwLocalIP            = eipDevTcpIpConfiguration.IP_Address;
 	stEipOnline.dwSubNetMask           = eipDevTcpIpConfiguration.Network_Mask;
	stEipInit.wExpMsgTimeOut       = (EIP_WORD)10000;
	stEipInit.dwCapabilities       = gdwCapabilities;


	if(!InitSample(&stEipInit,&stEipOnline))
	{
		return -1;
	}
	
	if (!EIP_Start ())
	{
		UARTPutString(uartInstance,"\n\r Error: EIP_Start failed!");
		return -1;
	}
	else
		UARTPutString(uartInstance,"\n\r Start IO");

	return 0;
}


EIP_BOOL EIPResetImplement(EIP_DWORD resetType)
{
	ST_ETH_CONTROL   stEthControl = {0};
	ST_TCPIP_CONTROL tcpConfigControl= {0};
	CLASS_TCP_LAST_CONFLICT_DETECTED lastConflictParams={0};
	CLASS_QOS userQOSObj;
	EIP_WORD acdEnablereset =1;

	if(resetType == 1) /*Type 0 reset*/
	{
		tcpConfigControl.wStartupConfiguration=EIP_STARTUP_STATICIP;
		HAL_SetConfigurationControl(&tcpConfigControl);
		ExitSample();
		restart_application();
	}
	else if(resetType == 2) /*Type 1 reset*/
	{

		userQOSObj.byDscpUrgent      = 55; /* Urgent */
		userQOSObj.byDscpScheduled   = 47; /* Scheduled */
		userQOSObj.byDscpHigh        = 43; /* High */
		userQOSObj.byDscpLow         = 31; /* Low */
		userQOSObj.byDscpExplicit    = 27; /* Explicit */
		tcpConfigControl.wStartupConfiguration=EIP_STARTUP_DHCP;
		HAL_SetConfigurationControl(&tcpConfigControl);
		HAL_SetLastConflictDetails(&lastConflictParams);
		HAL_SetACDEnable(&acdEnablereset);
		HAL_SetQoSValues(&userQOSObj);
		stEthControl.bAutoNegotiate=1;
		stEthControl.bForceFullDuplex=0;
		stEthControl.wForceInterfaceSpeed=0;
		WritePermanentMemory((EIP_BYTE*)&stEthControl,sizeof(ST_ETH_CONTROL),SPI_EEPROM_SPEED_OFFSET);
		ExitSample();
		restart_application();
	}
	return EIP_TRUE;
}


/*
----------------------------------------------------------------------
main
----------------------------------------------------------------------
Description.....: main function
Return type.....: int
Argument........: int argc
Argument........: char* argv[]
----------------------------------------------------------------------
*/


int EIPMain ()
{
	char key;
	EIP_BOOL  bStopped = EIP_TRUE;
	SO_Open_Session();

	DisplayMacid();
	DisplayApplicationDetails();

	while(!acdIPAssign)
	{
		if(eipDevInitConfig.tcpipConfig.startupType==EIP_STARTUP_DHCP)
		{
			if(user_input_processing == 1)
			{
				key = rxByte;
				if(key == ENTER_KEY)
				{
					AssignUserIP();
					restart_application();
					break;
				}
				user_input_processing = 0;
			}
		}
		Task_sleep(200);
	}

	DisplayIPDetails();


	if(!eipDevInitConfig.acdEnable)
		SetEthernetLinkConfig();

	EipAppInit();
	bStopped = !bStopped;
	IO_SetModeRun ();
	ModeRunning = EIP_TRUE;
	UARTPutString(uartInstance,"\n\r EIP Set Mode => RUN");

	eipAppStat=1;

	do
	{
		if((user_input_processing == 1) || gbResetIdentity)
		{
			if(gbResetIdentity)
			{
				if(EIPResetImplement(gbResetIdentity))
					gbResetIdentity = EIP_FALSE;
			}

			key = rxByte;
			UARTPutString(uartInstance,"\n\r Selected Option: ");
			UARTPutChar(uartInstance,key);
			switch (key)
			{
				// START / STOP
				case 't':
				case 'T':
					if (bStopped)
					{
						if (!EIP_Start ())
							UARTPutString(uartInstance,"\n\r Error: EIP_Start failed!");
						else
							UARTPutString(uartInstance,"\n\r Start IO");
					}
					else
					{
						if (!EIP_Stop ())
							UARTPutString(uartInstance,"\n\r Error: EIP_Stop failed!");
						else
							UARTPutString(uartInstance,"\n\r Stop IO");
					}
					bStopped = !bStopped;
					break;
				// COPY IN -> OUT
				case 'c':
				case 'C':
					SHM_CopyIn_Out();
					break;
				// INC OUT
				case 'u':
				case 'U':
					SHM_Inc_Out();
					break;
				case 'i':
				case 'I':
					IO_SetModeIdle ();
					ModeRunning = EIP_FALSE;
					UARTPutString(uartInstance,"\n\r EIP Set Mode => IDLE");
					break;
				case 'r':
				case 'R':
					IO_SetModeRun ();
					ModeRunning = EIP_TRUE;
					UARTPutString(uartInstance,"\n\r EIP Set Mode => RUN");
					break;
				case 'n':
				case 'N':
					if(!AssignUserIP())
						PrintMenu();
					else
					{
						ExitSample();
						restart_application();
					}
					break;
				case 'e':
				case 'E':
					EIPResetImplement(2);
					UARTPutString(uartInstance,"\n\r Non volatile memory Erased.");
					PrintMenu();
					break;
				default:
					PrintMenu();
					break;
			}

			user_input_processing = 0;
		}
		if(acdEIPStatus == EIP_ACD_START)
		{
			if(eipAppStat!=1)
			{
				EipAppInit();
				bStopped = !bStopped;
				IO_SetModeRun ();
				ModeRunning = EIP_TRUE;
				UARTPutString(uartInstance,"\n\r EIP Set Mode => RUN");
				acdEIPStatus=EIP_ACD_DEFAULT;
				eipAppStat=1;
			}
		}
		if(acdEIPStatus == EIP_ACD_RESTART)
		{
			ExitSample();
#ifndef USE_CPSW_DRIVER
			StopSwitch();
#endif
			NC_NetStop(ACD_LINKDOWN);
			acdEIPStatus=EIP_ACD_DEFAULT;
		}
		if(acdEIPStatus == EIP_ACD_STOP)
		{
			ExitSample();
#ifndef USE_CPSW_DRIVER
			StopSwitch();
#endif
			NC_NetStop(0);
			acdEIPStatus=EIP_ACD_DEFAULT;
		}
		Task_sleep(500);

	}
	while(key != ESC_KEY);

	ExitSample();
	ExitApp();

	SO_Close_Session();
  	return 0;
}


/**
 *  \name EIPMain
 *  \brief ISR handler for the Uart input
 *  \param arg Argument if any
 *  \return none
 *
 */
void UartIsr(UArg arg)
{

	Char rxChar;

	if(finish_assign_ip == 0)
	{
		flagFinish = 1;
		UARTGetChar(uartInstance,&rxChar);
		/*check for 'ENTER*/
		if(rxChar == ENTER_KEY)
		{
			flagFinish = 2;
			chIpAddr[counter] = 0x00;
		}
		else
		{
			chIpAddr[counter] = rxChar;
			UARTPutChar(uartInstance,chIpAddr[counter]);
		}
		/*check for Backspace*/
		if(rxChar == BSPACE_KEY)
		{
			counter--;
			UARTPutString(uartInstance,"\b");
		}
		else
			counter++;
	}
	else
	{
		UARTGetChar(uartInstance,&rxChar);
		if(!user_input_processing)
		{
			rxByte = rxChar;
			user_input_processing = 1;
		}
	}
}

EIP_VOID EIPIPAddressChange(Uint32 ipAddress,Uint32 ipAddAssign)
{
	if(ipAddAssign)
	{
		acdIPAssign =1;
#ifndef USE_CPSW_DRIVER
		addDLRModuleIPAddress(ipAddress);
#endif

	}
	else
	{
		acdIPAssign =0;
#ifndef USE_CPSW_DRIVER
        addDLRModuleIPAddress(0);
#endif

	}
}

EIP_VOID EIPACDExit()
{
	if(eipDevInitConfig.acdEnable)
		ACD_Exit();
}
EIP_VOID EIPACDStart()
{
	if(eipDevInitConfig.acdEnable)
		UserACDStart();
}

EIP_VOID EIPACDStop()
{
	if(eipDevInitConfig.acdEnable)
		UserACDStop();
}

EIP_BOOL EIPACDInit()
{
    Semaphore_Params semParams;
    Semaphore_Params_init(&semParams);
    semParams.mode = Semaphore_Mode_BINARY;
    SPIReadSemaphoreHandle = Semaphore_create(1, &semParams, NULL);


	/* Read TCP/IP config stored in SpiFlash */
//	ReadPermanentMemory((EIP_BYTE*)& eipDevInitConfig.tcpipConfig,sizeof(EPROM_TCPIP),SPI_EEPROM_DEVICEIP_OFFSET);
	/* Read ACD Enable bit stored in SpiFlash */
//	ReadPermanentMemory((EIP_BYTE*)& eipDevInitConfig.acdEnable,sizeof(EIP_BYTE),SPI_EEPROM_ACD_OFFSET);
	/* Read Ethernet Link Config stored in SpiFlash */
//	ReadPermanentMemory((EIP_BYTE*)&eipDevInitConfig.ethConfig[0],sizeof(ST_ETH_CONTROL),SPI_EEPROM_SPEED_OFFSET);
//	ReadPermanentMemory((EIP_BYTE*)&eipDevInitConfig.ethConfig[0],sizeof(ST_ETH_CONTROL),SPI_EEPROM_SPEED_OFFSET);
	/* Read ACD Conflict detectd bit from SPI Flash*/
//	ReadPermanentMemory((EIP_BYTE*)(&eipDevInitConfig.acdConflictDetails),sizeof(CLASS_TCP_LAST_CONFLICT_DETECTED), SPI_EEPROM_ACD_CONFLICT_OFFSET);
//	EN

    eipDevInitConfig.tcpipConfig.deviceIP 		= 0x0A0B1220;
    eipDevInitConfig.tcpipConfig.startupType 	= 0x2;
    eipDevInitConfig.tcpipConfig.networkMask 	= 0xFFffFF00;
    eipDevInitConfig.tcpipConfig.gatewayAddress = 0x00000000;
    eipDevInitConfig.tcpipConfig.serverName 	= 0;

    eipDevInitConfig.ethConfig[0].bAutoNegotiate = 1;
    eipDevInitConfig.ethConfig[0].bForceFullDuplex = 0;
    eipDevInitConfig.ethConfig[0].wForceInterfaceSpeed = 0;

    eipDevInitConfig.ethConfig[1].bAutoNegotiate = 0;
    eipDevInitConfig.ethConfig[1].bForceFullDuplex = 0;
    eipDevInitConfig.ethConfig[1].wForceInterfaceSpeed = 0;

    eipDevInitConfig.acdEnable = 0;	// TODO: THIS IS IT
    eipDevInitConfig.qosEnable = 0;

    memset( &eipDevInitConfig.acdConflictDetails, 0x00, sizeof(CLASS_TCP_LAST_CONFLICT_DETECTED) );

	if(eipDevInitConfig.acdEnable)
	{
		eipDevInitConfig.acdEnable=1;

		if(eipDevInitConfig.acdConflictDetails.AcdActivity)
			ifConnfigACDStat|=EIP_TCPIP_ATTRB_STATUS_ACD_STATUS;

		UserACDInit();
		if (!ACD_Init())
		{
			System_abort("ACD_Init() failed\n");
		}
		RegisterLinkCallBack();
	}
	else
	{
#ifndef USE_CPSW_DRIVER
		RegisterPort0ISRCallback((icssCallBack_t)DlrPort0ProcessLinkBrk, NULL);
		/*Port 1 Link break callback */
		RegisterPort1ISRCallback((icssCallBack_t)DlrPort1ProcessLinkBrk, NULL);
#endif
	}

	return EIP_TRUE;
}
