/**
 * \file eip_utils.c
 * \brief
 *
 * \copyright Copyright (c) 2012 Texas Instruments Incorporated ALL RIGHTS RESERVED
 *
*/

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#include"eip_main.h"

#include "plat_led.h"
#include "plat_gpio.h"
#include "plat_i2c.h"
#include "osdrv_version.h"
#include "osdrv_oledlcd.h"
#include "plat_uart.h"
#include "osdrv_uart.h"
/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
extern int acdIPAssign;
extern unsigned char board_Type;
extern unsigned int uartInstance;
extern Uint8 finish_assign_ip;
extern int counter;
extern int flagFinish;
extern char chIpAddr[16];
/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */



/**
 *  \name InitLedSeq
 *  \brief Function set the Led pattern on startup
 *  \param none
 *  \return none
 *
 */
void InitLedSeq()
{
	if(AM335X_BOARD_TYPE_ICE_V2 == board_Type)
	{
		LEDGPIOSetVal(0,16 ,1);
		Task_sleep(250);
		LEDGPIOSetVal(0,16 ,0);
		LEDGPIOSetVal(0,17 ,1);
		Task_sleep(250);
		LEDGPIOSetVal(0,17 ,0);
		LEDGPIOSetVal(0,16 ,1);
		LEDGPIOSetVal(0,20 ,1);
		Task_sleep(250);
		LEDGPIOSetVal(0,20 ,0);
		LEDGPIOSetVal(1,30 ,1);
		Task_sleep(250);
		LEDGPIOSetVal(1,30 ,0);
	}
	else
	{
		LEDDriveTriColorLeds(LED5G, 1);
		Task_sleep(250);
		LEDDriveTriColorLeds(LED5R, 1);
		Task_sleep(250);
		LEDDriveTriColorLeds(LED5G, 1);
		LEDDriveTriColorLeds(LED5G|LED6G, 1);
		Task_sleep(250);
		LEDDriveTriColorLeds(LED5G|LED6R, 1);
		Task_sleep(250);
		LEDDriveTriColorLeds(LED5G, 1);
	}
}

/**
 *  \name LedFxn
 *  \brief Function to set the Led pattern on the board
 *  \param arg0
 *  \param arg1
 *  \return none
 *
 */
void LedFxn(UArg arg0, UArg arg1)
{
	int led_val = 0;
	InitLedSeq();
	if(AM335X_BOARD_TYPE_ICE_V2 == board_Type)
	{
		char *lcd_str1 = IND_SDK_VERSION;

#ifdef USE_CPSW_DRIVER
	char lcd_str2[]={"EthernetIP Demo(CPSW)"};
#else
	char lcd_str2[]={"EthernetIP Demo(ICSS)"};
#endif

		if(FAIL != OLEDInit()) {
			OLEDShowString(1,(unsigned char *)lcd_str1,0,0);
			OLEDShowString(1,(unsigned char *)lcd_str2,1,0);
			OLEDDeactivateScroll();
			OLEDContinuousScroll(0x01,0x01,Max_Column,0x00,0x00,0x01,0x06,0x01);
		}
		while(1)
		{
			LEDGPIOSetVal(0,16 ,1);
			if(led_val == 0)
			{
				if (GetACDLEDStat())
				{
					/* MS blink red  NS Solid red*/
					LEDGPIOSetVal(0,17 ,1);
					LEDGPIOSetVal(0,16 ,0);
					LEDGPIOSetVal(0,20 ,0);
					LEDGPIOSetVal(1,30 ,1);
				}
				else
				{
					LEDGPIOSetVal(0,16 ,1);
					LEDGPIOSetVal(0,17 ,0);

						switch(USER_Get_ConnectionStat())
						{
							case EIP_CONN_TIMEOUT:
								LEDGPIOSetVal(0,20 ,0);
								LEDGPIOSetVal(1,30 ,1);
								break;
							default:
								if(acdIPAssign)
								{
									LEDGPIOSetVal(1,30 ,0);
									LEDGPIOSetVal(0,20 ,1);
								}
								break;
						}

				}
			}
			else if(led_val == 1)
			{
				if (GetACDLEDStat())//MS blink red  NS red
				{
					LEDGPIOSetVal(0,17 ,0);
					LEDGPIOSetVal(0,16 ,0);

					LEDGPIOSetVal(0,20 ,0);
					LEDGPIOSetVal(1,30 ,1);
				}
				else
				{

					LEDGPIOSetVal(0,16 ,1);
					LEDGPIOSetVal(0,17 ,0);

						switch(USER_Get_ConnectionStat())
						{
							case EIP_CONN_AVAIL:
								LEDGPIOSetVal(1,30 ,0);
								LEDGPIOSetVal(0,20 ,1);
								break;
							default:
								LEDGPIOSetVal(1,30 ,0);
								LEDGPIOSetVal(0,20 ,0);
								break;
						}
					}

			}
			led_val = (led_val + 1) % 2;
			Task_sleep(500);
		}
	}
	else
	{
		while(1)
		{
			if(led_val == 0)
			{
				if (GetACDLEDStat())
				{
					/* ACD Fault occured :MS blink red  NS Solid red */
					LEDDriveTriColorLeds(LED5R|LED6R, 1);
				}
				else
				{
					switch(USER_Get_ConnectionStat())
					{
						case EIP_CONN_TIMEOUT: /* MS Green NS Blink Red*/
							LEDDriveTriColorLeds(LED5R|LED6G, 1);
							break;
						default:
							if(acdIPAssign)
								LEDDriveTriColorLeds(LED5G|LED6G, 1);
							else
								LEDDriveTriColorLeds(LED6G, 1);
							break;
					}
				}
			}
			else if(led_val == 1)
			{
				if (GetACDLEDStat())
				{
					/* ACD Fault occured :MS blink red  NS Solid red */
					LEDDriveTriColorLeds(ALLLED, 0);
					LEDDriveTriColorLeds(LED5R, 1);
				}
				else
				{
					switch(USER_Get_ConnectionStat())
					{
						case EIP_CONN_AVAIL:
							LEDDriveTriColorLeds(LED5G|LED6G, 1);
							break;
						default:
							LEDDriveTriColorLeds(ALLLED, 0);
							LEDDriveTriColorLeds(LED6G, 1);
							break;
					}
				}
			}
			led_val = (led_val + 1) % 2;
			Task_sleep(500);
		}
	}
}


/**
 *  \name WritePermanentMemory
 *  \brief The function writes the object attributes to spiflash
 *  \param dwIp First parameter to be stored
 *  \param dwSubMask Second parameter to be stored
 *  \param offSet offset from the base address
 *  \return EIP_TRUE on Success,EIP_FALSE on failure
 *
 */
EIP_BOOL WritePermanentMemory(EIP_BYTE* varBuff, unsigned int size,unsigned int offSet )
{

	 Semaphore_pend(SPIReadSemaphoreHandle, BIOS_WAIT_FOREVER);

       EIP_BYTE  temp[256];         // 1 page size
       mmZeroInit(temp, 256);
       memcpy(temp, varBuff, size);

       if( -1 == SpiFlashWrite(offSet, 256, temp, 1))
       {
    	   	   Semaphore_post(SPIReadSemaphoreHandle);
              return EIP_FALSE;
       }
       Semaphore_post(SPIReadSemaphoreHandle);
       return EIP_TRUE;


}

/**
 *  \name ReadPermanentMemory
 *  \brief The function read data from spiflash
 *  \param lpdwIp First parameter to be read
 *  \param lpdwSubMask Second parameter to be read
 *  \param offSet offset from the base address
 *  \return EIP_TRUE on Success,EIP_FALSE on failure
 *
 */
EIP_BOOL ReadPermanentMemory(EIP_BYTE *varBuff,unsigned int size, unsigned int offSet )
{

	EIP_BYTE  temp[256];         // 1 page size
	*varBuff=0;
	Semaphore_pend(SPIReadSemaphoreHandle, BIOS_WAIT_FOREVER);
	if( -1 == SpiFlashRead(offSet, 256, temp))
	{
		Semaphore_post(SPIReadSemaphoreHandle);
		return EIP_FALSE;
	}

    memcpy(varBuff, &temp[0], size);
    Semaphore_post(SPIReadSemaphoreHandle);
    return EIP_TRUE;
}
/**
 *  \name ErasePermanentMemory
 *  \brief The function erases data from spiflash
 *  \param offSet offset from the base address
 *  \return EIP_TRUE on Success,EIP_FALSE on failure
 *
 */
EIP_BOOL ErasePermanentMemory(unsigned int offSet)
{
	Semaphore_pend(SPIReadSemaphoreHandle, BIOS_WAIT_FOREVER);
       if( -1 == SpiFlashErase(offSet, 256)){
    	   Semaphore_post(SPIReadSemaphoreHandle);
              return EIP_FALSE;
       }
       Semaphore_post(SPIReadSemaphoreHandle);
  return EIP_TRUE;
}


/**
 *  \name GetAssignedIP
 *  \brief This function sets the device in dhcp mode or in static ip mode and display the IP in Uart console
 *  \param none
 *  \return none
 *
 */
/**
 *  @b getAssignedIP
 *  @n
 *      This function sets the device in dhcp mode or in static ip mode and display the IP in Uart console
 *
 */
void DisplayApplicationDetails()
{

	if(eipDevInitConfig.acdEnable ==1)
	{
		UARTPutString(uartInstance, "\n\rACD Bit Enabled in SPIFlash. Starting the Application in ACD Mode");
		UARTPutString(uartInstance, "\n\rIP Address will be taken once Link is up");
	}
	else
		UARTPutString(uartInstance, "\n\rACD Bit Disabled in SPIFlash.Starting the Application in Normal Mode");

	if(eipDevInitConfig.tcpipConfig.startupType==EIP_STARTUP_DHCP)
	{
		UARTPutString(uartInstance, "\n\rWaiting for IP Address to be assigned by DHCP Server");
		UARTPutString(uartInstance, "\n\rPress Enter key to assign IP Manually");
	}
	else
	{
		UARTPutString(uartInstance, "\n\rAssigning IP Address obtained from SPI Flash");
	}
}

void DisplayIPDetails()
{
	EIP_CHAR chDefaultIP[16];
	GetCurrentIP(chDefaultIP);
	finish_assign_ip = 1;
	UARTPutString(uartInstance, "\n\rIP Address Assigned: ");
	UARTPutString(uartInstance, (char *)(chDefaultIP));
	UARTPutString(uartInstance, "\n\r");
}

/**
 *  \name DisplayMacid
 *  \brief his function displays Assigned macid in serial console
 *  \param none
 *  \return none
 *
 */
void DisplayMacid()
{
	int i;
	Uint8 bMacAddr[6];
	NIMU_IF_REQ if_req;
    if_req.name[0] = 0;
    if_req.index   = 1;

    int ret_code = NIMUIoctl (NIMU_GET_DEVICE_MAC, &if_req, &bMacAddr, sizeof(bMacAddr));

    char buf_str[18];
    char* buf_ptr = buf_str;
    for (i = 0; i < 6; i++)
    {
    	if(i != 5)
    		buf_ptr += sprintf(buf_ptr, "%02x:", (char)bMacAddr[i]);
    	else if(i == 5)
    		buf_ptr += sprintf(buf_ptr, "%02x", (char)bMacAddr[i]);
    }
    sprintf(buf_ptr,"\n");
    *(buf_ptr + 1) = '\0';

	UARTPutString(uartInstance, "\n\r");
    UARTPutString(uartInstance, "MAC : ");

	UARTPutString(uartInstance, buf_str );

}

/**
 *  \name RemoveIpAddress
 *  \brief The function is used to remove Assigned IP adddress.
 *  \param none
 *  \return none
 *
 */
EIP_VOID RemoveIpAddress()
{
	CI_IPNET NA;
	HANDLE      hCfgIpAddr;

	if (CfgGetImmediate( 0, CFGTAG_IPNET, 1, 1, sizeof(NA), (UINT8 *)&NA) == sizeof(NA))
	{
		/* get the current static IP entry */
		CfgGetEntry(0, CFGTAG_IPNET, 1, 1, &hCfgIpAddr);

		/* remove the current static IP entry */
		CfgRemoveEntry(0, hCfgIpAddr);
	}
}


/**
 *  \name AddIpAddress
 *  \brief The function is used to remove Add a specific IP adddress.
 *  \param IPAddress IP address to be assigned
 *  \return none
 *
 */
EIP_BOOL AddIpAddress(EIP_DWORD dwIPAddress)
{
	CI_IPNET NA;
	EIP_CHAR chvalidIP[16];

	NtIPN2Str (dwIPAddress, chvalidIP);
	if( !(IsValidIP(chvalidIP)))
	{
		return EIP_FALSE;
	}

	RemoveIpAddress();
	/* Setup manual IP address */
	bzero(&NA, sizeof(NA));


	NA.IPAddr = (IPN)dwIPAddress;
	NA.IPMask  = inet_addr("255.255.255.0");
	strcpy(NA.Domain, "demo.net");
	NA.NetType = 0;

	/* add a new static IP entry */
	CfgAddEntry(0, CFGTAG_IPNET, 1, 0,
		   sizeof(CI_IPNET), (UINT8 *)&NA, 0);
	return EIP_TRUE;
}

/**
 *  \name GetCurrentIP
 *  \brief The function returns the IP addreses assigned
 *  \param ipAddr pointer where ipaddress needs to be stored
 *  \return EIP_TRUE on success,EIP_FALSE if ip is not assigned
 *
 */
EIP_BOOL GetCurrentIP(EIP_CHAR*ipAddr)
{
	CI_IPNET NA;

	if (CfgGetImmediate( 0, CFGTAG_IPNET, 1, 1, sizeof(NA), (UINT8 *)&NA) == sizeof(NA))
	{
		NtIPN2Str (NA.IPAddr, ipAddr);
		return EIP_TRUE;
	}
	else
		return EIP_FALSE;

}

/**
 *  \name IsValidIP
 *  \brief The function is used to validate an IP adddress.
 *  \param ip_str pointer to IP address
 *  \return EIP_TRUE on success,EIP_FALSE if not a valid ip
 *
 */
int IsValidIP(const char *ip_str)
{
	unsigned int n1,n2,n3,n4;

	if(sscanf(ip_str,"%u.%u.%u.%u", &n1, &n2, &n3, &n4) != 4)
		return EIP_FALSE;

	if((n1 != 0) && (n1 <= 255) && (n2 <= 255) && (n3 <= 255) && (n4 <= 255)) {
		char buf[64];
		sprintf(buf,"%u.%u.%u.%u",n1,n2,n3,n4);
		if(strcmp(buf,ip_str)) return 0;
		return EIP_TRUE;
	}
	return EIP_FALSE;
}

/**
 *  \name Uartitoa
 *  \brief Convert the integer to char to print in UART console
 *  \param item to be print
 *  \return none
 */
void Uartitoa(int val)
{
	unsigned char tChar = (val%10)+'0';
	if(val)
	{
		val /= 10;
		Uartitoa(val);
		UARTPutChar(uartInstance,tChar);
	}
}

/**
 *  \name GetUserIP
 *  \brief Receives the Uart input from the User
 *  \param Pointer to IP Address
 *  \return EIP_TRUE on successfully receiving IP,else EIP_FALSE
 */
EIP_BOOL GetUserIP(char * chAddr)
{
	int count = 0;
	char chDeafaultIP[16] = "192.168.1.10";
	UARTPutString(uartInstance, "\n\rPlease enter IP Address:");
	while(flagFinish != 2 && count<10)
	{
		Task_sleep(3000);
		if(flagFinish==0)
		{
			Uartitoa(9-count);
			UARTPutString(uartInstance,"\b");
		}
		count++;
	}
	if(flagFinish==0)
	{
		UARTPutString(uartInstance,"\b");
		UARTPutString(uartInstance, "\n\rAssigning Default IP Address.");
		memcpy(chAddr,chDeafaultIP,16);
		return EIP_TRUE;
	}
	else
	{
		if(!IsValidIP(chIpAddr))
		{
			UARTPutString(uartInstance,"\b");
			UARTPutString(uartInstance, "\n\rInvalid IP Address Entered.Assigning Default IP Address.");
			memcpy(chAddr,chDeafaultIP,16);
			return EIP_TRUE;
		}
		else
		{

			memcpy(chAddr,chIpAddr,16);
			return EIP_TRUE;
		}
	}
}

/**
 *  \name ConvertIPEndianness
 *  \brief The function changes the endianness of the IP Address
 *  \param Pointer to IP Address
 *  \return none
 */
EIP_VOID ConvertIPEndianness(EIP_DWORD* dwIPAddress)
{
	EIP_DWORD dwTempIP;

	dwTempIP = * dwIPAddress<<24;
	dwTempIP |= (* dwIPAddress &0xFF00) <<8;
	dwTempIP |= (* dwIPAddress &0xFF0000) >>8;
	dwTempIP |= (* dwIPAddress &0xFF000000) >>24;
	* dwIPAddress=dwTempIP;
}

/**
 *  \name AssignUserIP
 *  \brief The function receives IP Address from User and assign it to the device.
 *  \param none
 *  \return none
 *
 */
EIP_BOOL AssignUserIP()
{
	EPROM_TCPIP tcpControl={0};
	char newIP[16]={0};
	finish_assign_ip = 0;
	flagFinish=0;
	counter=0;
	EIP_DWORD ipAddr;
	if(GetUserIP(newIP))
	{
		ipAddr = inet_addr(newIP);
		ConvertIPEndianness(&ipAddr);
		tcpControl.deviceIP = ipAddr;
		tcpControl.networkMask = 0xffffff00;
		tcpControl.startupType=EIP_STARTUP_STATICIP;
		WritePermanentMemory((EIP_BYTE*)&tcpControl,sizeof(EPROM_TCPIP),SPI_EEPROM_DEVICEIP_OFFSET);
		return EIP_TRUE;
	}
	else
	{
		finish_assign_ip=1;
		flagFinish=1;
		return EIP_FALSE;
	}

}
