/**
 * \file device.c
 * \brief Contains Ethernetip Adapter device specific functions
 *
 * \copyright Copyright (c) 2012 Texas Instruments Incorporated ALL RIGHTS RESERVED
 *
*/
/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

#include <stdio.h>
#include "eip_main.h"
#include "device.h"
#include "osdrv_uart.h"
#include "icss_dlr.h"
#include "plat_uart.h"
#include "osdrv_uart.h"
#include "plat_led.h"
#include "opt_api.h"
/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
/**Responce for Get Attribute All of User Obj*/
EIP_BYTE Response[] = {0x81,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05};
extern unsigned int uartInstance;
extern dlrStruct dlrObj;
extern EIP_BOOL DLRbInit();

// ----------------------------------------------------------------------------
// Shared Memory
// ----------------------------------------------------------------------------
/**Shared Memory for IN Data*/
EIP_BYTE DataIn[IN_DATA_SIZE];
/**Shared Memory for OUT Data*/
EIP_BYTE DataOut[OUT_DATA_SIZE];
/**Control Table for Connection*/
EIP_BYTE CtrlTable[EIP_NB_IO_CNXN_MAX/8 + 1];
/**Health Table for Connection*/
EIP_BYTE HealthTable[EIP_NB_IO_CNXN_MAX/8 +1];
/**IN Status*/
EIP_SHORT StatusIn[EIP_NB_IO_CNXN_MAX+1];
/**Out Status*/
EIP_SHORT StatusOut[EIP_NB_IO_CNXN_MAX+1];
/**IN Updated*/
EIP_BYTE UpdateIn[EIP_NB_IO_CNXN_MAX+1];
/**Out Updated*/
EIP_BYTE UpdateOut[EIP_NB_IO_CNXN_MAX+1];
/**Handshake byte for data exchange between Application and stack*/
EIP_BYTE Handshake[2];

/**Max offset for OUtData*/
EIP_WORD  wMaxOffsetOut = 0;

/**Flag for new OUT data to copy into the stack*/
EIP_BOOL gbNewOutData  = EIP_FALSE;
/** Flag to copy data In into data OUT*/
EIP_BOOL gbCopyINtoOUT = EIP_FALSE;
/** Fag to increment OUT automatically*/
EIP_BOOL gbDataInc     = EIP_FALSE;

/**IO Data Connection Parameters*/
ST_CNXN_PARAMS  stCnxnParams[EIP_NB_IO_CNXN_MAX];

EIP_BOOL USEROBJ_GetAttributeAll(EIP_WORD wTransacID, LP_ST_EIP_EM_REQ pstEIP_EmReq, LP_ST_EIP_EM_RES pstEIP_EmRes);


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


/**
 *  \name GetVendorId
 *  \brief The function returns the Vendor ID
 *  \param none
 *  \return Vendor ID
 *
 */
EIP_WORD GetVendorId()
{
	return CIP_VENDOR_ID;
}

/**
 *  \name GetDeviceType
 *  \brief The function returns the Device Type
 *  \param none
 *  \return Device Type
 *
 */
EIP_WORD GetDeviceType()
{
	return CIP_DEVICE_TYPE;
}

/**
 *  \name GetDeviceType
 *  \brief The function returns the Product Code
 *  \param none
 *  \return Product Code
 *
 */
EIP_WORD GetProductCode()
{
	return CIP_PRODUCT_CODE;
}

/**
 *  \name GetDeviceType
 *  \brief The function returns the Revision number Major
 *  \param none
 *  \return Major revision number
 *
 */
EIP_BYTE GetMajorRevision()
{
	return REVISION_MAJOR;
}

/**
 *  \name GetDeviceType
 *  \brief The function returns the Revision number Minor
 *  \param none
 *  \return Minor revision number
 *
 */
EIP_BYTE GetMinorRevision()
{
	return REVISION_MINOR;
}

/**
 *  \name GetDeviceType
 *  \brief The function returns the Serial number
 *  \param none
 *  \return Serial number
 *
 */
EIP_DWORD GetSerialNum()
{
	return CIP_SERIAL_NUMBER;
}

/**
 *  \name GetDeviceType
 *  \brief The function returns the Product name
 *  \param pProductName Product Name
 *  \return Length of Product name
 *
 */
EIP_BYTE GetProductName(EIP_CHAR * pProductName)
{
	EIP_BYTE wLen;

	wLen = (EIP_BYTE) min (strlen(PRODUCT_NAME), MAX_PRODUCT_NAME_LENGTH);
	memcpy (pProductName, PRODUCT_NAME, wLen);
	return wLen;
}

/**
 *  \name GetSharedMemoryPtr
 *  \brief The function initializes the  shared memory IO Data exchange
 *  \param none
 *  \return Structure contains 
 *
 */
ST_SHM_PARAMS * GetSharedMemoryPtr()
{
	ST_SHM_PARAMS * pstSHMParams;

	pstSHMParams = malloc (sizeof(ST_SHM_PARAMS));
	if (pstSHMParams == EIP_NULL)
		return EIP_NULL;

	pstSHMParams->lpvDataIn       = DataIn;
	pstSHMParams->lpvDataOut      = DataOut;
	pstSHMParams->lpvCtrlTable    = EIP_NULL;       //CtrlTable; Not used in the sample
	pstSHMParams->lpvHealthTable  = HealthTable;
	pstSHMParams->lpvStatusIn     = StatusIn;
	pstSHMParams->lpvStatusOut    = StatusOut;
	pstSHMParams->lpvUpdateIn     = UpdateIn;
	pstSHMParams->lpvUpdateOut    = UpdateOut;
	pstSHMParams->lpbyHandshake[0] = &Handshake[0];
	pstSHMParams->lpbyHandshake[1] = &Handshake[1];

	return pstSHMParams;
}


/**
 *  \name SHM_SetInParams
 *  \brief Function sets the size and offset used for IN data
 *  \param wConnectionID Connection ID
 *  \param wSize Connection size
 *  \param wOffset Offset used for data exchange
 *  \return none 
 *
 */
EIP_VOID SHM_SetInParams(  EIP_WORD wConnectionID, EIP_WORD wSize, EIP_WORD wOffset )
{
	stCnxnParams[wConnectionID].wOffsetIn   = wOffset;
	stCnxnParams[wConnectionID].wSizeIn     = wSize;
}

/**
 *  \name SHM_SetOutParams
 *  \brief Function sets the size and offset used for Out data
 *  \param wConnectionID Connection ID
 *  \param wSize Connection size
 *  \param wOffset Offset used for data exchange
 *  \return none 
 *
 */
EIP_VOID SHM_SetOutParams(  EIP_WORD wConnectionID, EIP_WORD wSize, EIP_WORD wOffset )
{
	stCnxnParams[wConnectionID].wOffsetOut   = wOffset;
	stCnxnParams[wConnectionID].wSizeOut     = wSize;

	if (stCnxnParams[wConnectionID].wOffsetOut + stCnxnParams[wConnectionID].wSizeOut > wMaxOffsetOut)
		wMaxOffsetOut = stCnxnParams[wConnectionID].wOffsetOut + stCnxnParams[wConnectionID].wSizeOut;
}





/**
 *  \name CopyINtoOUTData
 *  \brief Function is called to copy indata to outdata
 *  \param wCId Connection id
 *  \return none 
 *
 */
EIP_VOID CopyINtoOUTData (EIP_WORD wCId)
{
	EIP_WORD wSize;
	EIP_BYTE led_status;
	wSize = min(stCnxnParams[wCId].wSizeIn, stCnxnParams[wCId].wSizeOut);

	memcpy( &DataOut[stCnxnParams[wCId].wOffsetOut], &DataIn[stCnxnParams[wCId].wOffsetIn],wSize);
  
	led_status = DataIn[stCnxnParams[1].wOffsetIn];
	LEDDIGOUTSetVal(led_status);
	// Inform that Cid has changed
	UpdateOut[wCId] = 1;

	// If OUT areas is handled by USER toggle now else flag it
	if ( (USER_OUT) == (STACK_OUT) )
	{
		gbNewOutData = EIP_FALSE;
		TOGGLE_USER_OUT;
	}
	else
		gbNewOutData = EIP_TRUE;

}


/**
 *  \name IncrementOUTData
 *  \brief Function increments the OUT Data
 *  \param none
 *  \return none 
 *
 */
EIP_VOID IncrementOUTData( )
{
	int i;

	for (i = 0 ; i < wMaxOffsetOut; i++)
		DataOut[i] = DataOut[i]+1;
    
	for (i = 0 ; i < EIP_NB_IO_CNXN_MAX; i++)
		UpdateOut[i] = 1;
}


/**
 *  \name SHM_CopyIn_Out
 *  \brief This function sets the Device in Copyinout mode
 *  \param none
 *  \return none 
 *
 */
void SHM_CopyIn_Out(void)
{
	EIP_WORD i;

	gbCopyINtoOUT = !gbCopyINtoOUT;
	if (gbCopyINtoOUT)
	{
		if (gbDataInc)
		{
			gbDataInc = EIP_FALSE;
			UARTPutString(uartInstance,"\n\r EIP Data constant");
		}
		UARTPutString(uartInstance,"\n\r Copy In -> OUT");

		if ( (USER_OUT) == (STACK_OUT) )
			TOGGLE_USER_OUT;

		// Copy value intialized first
		for(i = 0; i < EIP_NB_IO_CNXN_MAX; i++)
		{
			if(UpdateIn[i] == 1)
			{
				CopyINtoOUTData(i);
			}
		}
	}
	else
	{
		UARTPutString(uartInstance,"\n\r Stop Copy In -> OUT");
	}
}

/**
 *  \name SHM_Inc_Out
 *  \brief This function sets the Device in Incrementing mode
 *  \param none
 *  \return none 
 *
 */
void SHM_Inc_Out(void)
{
	gbDataInc = !gbDataInc;
	if (gbDataInc)
	{
		if (gbCopyINtoOUT)
		{
			gbCopyINtoOUT = EIP_FALSE;
			UARTPutString(uartInstance,"\n\r Stop Copy In -> OUT");
		}
		UARTPutString(uartInstance,"\n\r EIP Data incrementing");
  
		if ( (USER_OUT) == (STACK_OUT) )
			TOGGLE_USER_OUT;
	}
	else
	{
		UARTPutString(uartInstance,"\n\r EIP Data constant");
	}
}

/**
 *  \name SHM_NewDataIn
 *  \brief This function will be called by stack whenever there is an IN data
 *  \param none
 *  \return none 
 *
 */
void SHM_NewDataIn(void)  
{

	EIP_WORD i;
#ifdef ENABLE_CONN_INFO_DISPLAY
	EIP_WORD j;
	char sTemp[256];
#endif


	/* Receive New Data */

	/* check which IO connection */
	for ( i = 0; i<EIP_NB_IO_CNXN_MAX; i++)
	{
		if (UpdateIn[i] == 1)
		{
#ifdef ENABLE_CONN_INFO_DISPLAY
			// Display Connection information
			UARTPutString(uartInstance,"\n\r");
			sprintf(sTemp," Cnxn #%u - Status (%d:%d) - Data: ",i, StatusIn[i], StatusOut[i]);
			UARTPutString(uartInstance,sTemp);

			for (j = 0; j<stCnxnParams[i].wSizeIn; j++)
			{
				sprintf(sTemp,"%.2X ",DataIn[stCnxnParams[i].wOffsetIn + j]);
				UARTPutString(uartInstance,sTemp);
			}
#endif
			// Copy In -> Out
			if(gbCopyINtoOUT)
				CopyINtoOUTData(i);
		}
	}
	// Give IN Areas to the stack for new update
	TOGGLE_USER_IN;
}


/**
 *  \name SHM_DataOutCopied
 *  \brief This function is an acknowledgment from Stack when OUT data is transmittted.
 *  \param none
 *  \return none 
 *
 */
void SHM_DataOutCopied(void)  
{
	// Check if new data need to be copied into the stack

	if (gbNewOutData)
	{
		gbNewOutData = EIP_FALSE;
		TOGGLE_USER_OUT;
	}
  
	if (gbDataInc)
	{
		IncrementOUTData();
		TOGGLE_USER_OUT;
	}
}

/**
 *  \name USEROBJ_Init
 *  \brief Initialize the User objects
 *  \param none
 *  \return EIP_TRUE on Success,EIP_FALSE on failure 
 *
 */
EIP_BOOL USEROBJ_Init()
{
	EIP_WORD wClassId;

	// Creation of the class  #101
	wClassId = 101;
	if (!OBJ_CreateObject(wClassId))
		return EIP_FALSE;
	// Creation of the instance #1
	if (!OBJ_AddInstance(wClassId,1))
		return EIP_FALSE;

	// Add service 0x01 - get_attribute_all on instance
	if (!OBJ_AddInstanceService(wClassId,1,(LP_OBJ_CALL_BACK)USEROBJ_GetAttributeAll) )
		return EIP_FALSE;

#ifdef USE_CPSW_DRIVER
	if(board_Type != AM335X_BOARD_TYPE_IDK)/*Only one port for IDK*/
	{
		// Add instance 2 of the Link object for port 2;
		if( ! ETH_AddInstance(2))
			return EIP_FALSE;
	}
#else

	if( ! ETH_AddInstance(2))
		return EIP_FALSE;
 //	DLR supported only over ICSS switch
	if(!DLRbInit())
	{
		return EIP_FALSE;
	}
#endif


	return EIP_TRUE;
}

/**
 *  \name USEROBJ_GetAttributeAll
 *  \brief Get Attribute call for the User object
 *  \param none
 *  \return EIP_TRUE on Success
 *
 */
EIP_BOOL USEROBJ_GetAttributeAll(EIP_WORD wTransacID, LP_ST_EIP_EM_REQ pstEIP_EmReq, LP_ST_EIP_EM_RES pstEIP_EmRes)
{
	pstEIP_EmRes->lpResFrame    = Response;
	pstEIP_EmRes->wResFrameSize = sizeof(Response);
	return EIP_TRUE; // synchronous mode
}

/*---------------------------------------------------------------------------*/
/*----------------------------- END OF FILE ---------------------------------*/
/*---------------------------------------------------------------------------*/
