/*******************************************************************************
 * (c) Copyright 2015 Microsemi Corporation.  All rights reserved.
 *
 *
 *
 * SVN $Revision: $
 * SVN $Date: $
 */

#ifndef MEP_H_
#define MEP_H_

/**
 * @file
 * @brief The Maintenance End Point API.
 *
 * mep.h defines the structs, data types and functions used to interact with
 * Maintenance End Point (MEP) objects.
 */

#include <api_oam_sdk/common/types/inc/mr_api_types.h>
#include <api_oam_sdk/loopback/inc/lb.h>
#include <api_oam_sdk/maintenance_association/inc/ma.h>
#include <api_oam_sdk/performance_monitoring/inc/pm_dm.h>
#include <api_oam_sdk/performance_monitoring/inc/pm_lm.h>
#include "egl_types.h"
//#include "lt.h"

#ifndef MAX_RMEPS_PER_LM
#define MAX_RMEPS_PER_LM 		(8)
#endif

#ifndef BIT_MASK
#define BIT_MASK(n) 				(0x1UL << (n < 32 ? n : (n - 32)))
#endif

typedef struct
{
	uint32_t		ccmSeqErrors;		// (v)The total number of out-of-sequence CCMs received from all remote MEPs
	uint32_t		cciSentCcms;		// (w)Total number of Continuity Check messages transmitted
	mepId_t			activeRemoteMepList[MAX_RMEPS_PER_LM+1];	// (ae)List of active remote MEPs in the MA
	bool			cciEnable;			// (g)Enable/disable CCM generation
	prio_t			ccmLtmPriority;		// (h)The priority to use for CCMs and LTMs
} mepCcInfo_t;

/**
 * @brief Defines indices for 'Writable' parameters for a MEP.
 *
 * This data type defines the indices for valid writable
 * parameters that can be selected when writing to a MEP object.
 */
typedef enum
{
	mepParam_mepPrimaryVid = 1,			//!< (d)The Primary Vlan for the MEP
	mepParam_mepActive,					//!< (e)The administrative state of the MEP; true = enabled; false = disabled
	mepParam_mepCciEnable,				//!< (g)Enable/Disable CCM generation
	mepParam_mepCcmLtmPriority,			//!< (h)The Priority value to use for CCM and LTM transmit
	mepParam_mepLowPrDef,				//!< (k)Specify the lowest priority defect that is allowed generate a Fault Alarm
	mepParam_mepFngAlarmTime,			//!< (l)The time that defects MUST be present before a Fault Alarm is issued (default =250 => 2.5sec)
	mepParam_mepFngResetTime,			//!< (m)The time that defects MUST be absent before resetting a Fault Alarm (default =1000 => 10sec)
	mepParam_mepActiveRMepListAdd,		//!< (ae) Add a remote MEP to the active remote MEP list (enable remote MEP)
	mepParam_mepActiveRMepListRemove,	//!< (ae) Remove a remote MEP from the active remote MEP list (disable remote MEP)
	mepParam_mepLbMefInterval,			//!< MEF extended property for Loopback - interval (in milliseconds) between LBM messages (only relevant if _txLbmDataTlvLength)
	mepParam_mepLbMefMulticastEnable,	//!< MEF extended property for Loopback - Send LBM with/without a Multicast MAC (only relevant if _txLbmDataTlvLength)
	mepParam_mepLbMefFrameSize			//!< MEF extended property for Loopback - Set the LBM frame size (only relevant if _txLbmDataTlvLength)
} mepWrParam_t;							//!< Used to select 'Writable' parameters for an MEP

/**
 * @brief This data type defines valid Operational States for the MEP
 */
typedef enum
{
	opStateUnknown		= 1,
    opStateDisabled		= 2,
    opStateEnabled		= 3,
    opStateTesting		= 4
} mepOpState_t;		// values taken from rfc4268

/**
 * @brief This data type defines valid Connectivity States for the MEP
 */
typedef enum
{
	connInactive		= 1,				//!< Indicates the inability to exchange SOAM PDU frames among any of the UNIs of an EVC
	connActive			= 2,				//!< Indicates the ability to exchange SOAM PDU frames among all the UNIs of an EVC
	connPartiallyActive	= 3					//!< Indicates the ability to exchange SOAM PDU frames among some but not all the UNIs of an EVC
} mepConnStatus_t;

/**
 * @brief This is used to read back basic MEP information
 */
typedef struct
{
	uint16_t		primaryVid;			//!< (d-w)The primary Vlan ID for this MEP
	iFace_t			iFace;				//!< (b)The Interface (port) that the MEP is located on
	mepDir_t		direction;			//!< (c)The MEPs direction - only support 'down'
	bool			active;				//!< (e-w)Enable/disable Administrative state of MEP
} mepInfo_t;

/**
 * @brief This is used to read back information specific to MEF (Y1731) requirements for the MEP
 */
typedef struct
{
	uint32_t		_inOamFramesDiscarded;	//!< The count of incoming OAM frames discarded at the MEP
	uint32_t		_inCcmTotal;			//!< The count of the total number of valid (not malformed) CCMs received by the MEP
	uint32_t		operNextIndex;			//!< contains an unused value for a PM session number on a MEP that can be used for either LM or DM sessions, or a zero to indicate that none exist
	mepOpState_t	opState;				//!< The operational state (current capability) of the MEP
	mepConnStatus_t	connectivityStatus;		//!< The connectivity status for a MEP in an EVC ME
	psValue_t		sentPortStatus;			//!< value of the Port status TLV sent in the last CCM or the default value psNoPortStateTLV indicating no CCM has been sent or no Port Status TLV has been sent
	isValue_t		sentInterfaceStatus;	//!< value of the Interface status TLV sent in the last CCM or the default value isNoInterfaceStateTLV indicating no CCM has been sent or no Interface Status TLV has been sent
	uint8_t			lastDefectSentStatus;	//!< The state of the previous MEP defects, dot1agCfmMepDefects, that was sent with the previous mefSoamMepDefect notification. It is always some *previous* value of dot1agCfmMepDefects.
	bool			rdiTransmitStatus;		//!< Indicates whether the local MEP is generating a Remote Defect Indicator (RDI) bit in the CCM that it transmits
	bool			_dropEligible;			//!< specifies the eligibility of frames with ETH-CC and ETH-RDI information to be discarded when congestion conditions are encountered (Read only; always false)
	bool			_lmSingleEndedResponder;//!< specifies whether the Loss Measurement (LMM) single-ended Responder is enabled
	bool			slmSingleEndedResponder;//!< specifies whether the synthesised Loss Measurement (SLM) single-ended Responder is enabled
	bool			dmSingleEndedResponder;	//!< specifies whether the Delay Measurement (DMM) single-ended Responder is enabled
} mepMefInfo_t;


typedef enum
{
	fngReset			= 1,
	fngDefect			= 2,
	fngReportDefect		= 3,
	fngDefectReported	= 4,
	fngDefectClearing	= 5
} fngState_t;

typedef enum
{
	allDef			= 1,
	macRemErrXcon	= 2,						// (default value)
	remErrXcon		= 3,
	errXcon			= 4,
	xcon			= 5,
	noXcon			= 6
} lowPrDef_t;

typedef enum
{
	defNone			= 0,						//!< No Defect detected
	defRDICCM		= 1,						//!< Some remote MEP contained the RDI bit
	defMACstatus	= 2,						//!< Some remote MEP indicated an error status via the Port Status TLV or Interface Status TLV
	defRemoteCCM	= 3,						//!< This MEP is not receiving CCMs from one of its peer MEPs
	defErrorCCM		= 4,						//!< This MEP is receiving invalid CCMs
	defXconCCM		= 5							//!< This MEP is receiving CCMs that could be from some other MA
} fngDefect_t;

#define SOME_RDI_CCM_DEFECT_MASK 		(0x01)	// bDefRDICCM(0)
#define SOME_RDI_CCM_DEFECT_OFFSET 		(0)
#define SOME_MAC_STATUS_DEFECT_MASK 	(0x02)	// bDefMACstatus(1)
#define SOME_MAC_STATUS_DEFECT_OFFSET 	(1)
#define SOME_RMEP_CCM_DEFECT_MASK 		(0x04)	// bDefRemoteCCM(2)
#define SOME_RMEP_CCM_DEFECT_OFFSET 	(2)
#define DEF_ERROR_CCM_MASK 				(0x08)	// bDefErrorCCM(3)
#define DEF_ERROR_CCM_OFFSET 			(3)
#define DEF_XCON_CCM_MASK 				(0x10)	// bDefXconCCM(4)
#define DEF_XCON_CCM_OFFSET 			(4)

typedef struct
{
	uint16_t		fngAlarmTime;		// (l)The time that defects MUST be present before a Fault Alarm is issued (default =250 => 2.5sec)
	uint16_t		fngResetTime;		// (m)The time that defects MUST be absent before resetting a Fault Alarm (default =1000 => 10sec)
	fngState_t		fngState;			// (f)The current Fault Notification Generator (FNG) state
	lowPrDef_t		lowPrDef;			// (k)value specifying the lowest priority defect that is allowed to generate fault alarm
	fngDefect_t		hiPrDefect;			// (n)The highest priority defect that has been present since the MEPs Fault Notification Generator State Machine was last in the FNG_RESET state
	uint8_t			defects;			// (s,r,q,p,0) A vector of Boolean error conditions:
										// (defects[0] = o)RDI is being received from  one or more remote MEPs
										// (defects[1] = p)Any Port Status or Interface Status TLV is indicating an error
										// (defects[2] = q)CCMs are not being received on one or more remote MEPs
										// (defects[3] = r)CCMs from one or more remote MEPs is causing a rMepError
										// (defects[4] = s)CCMs are being received that are causing a xConnError
	packetBuffer_t	errCcmLastFailure;	// (t)The captured packet from the last CCM RMep Error
	packetBuffer_t	xconCcmLastFailure;	// (u)The captured packet from the last CCM XConn Error
} mepFngInfo_t;

/**
 * @brief Read the next entry in the Local MEP List associated with the specified MA
 *
 * Read the next entry in the Local MEP List associated with the
 * specified MA. If prevLMepId is 0 the function returns the MEPID
 * of the first Local MEP in the list or 0 if there are
 * no Local MEPs. If a valid prevLMepId is provided it returns
 * the MEPID of the next Local MEP in the list.
 *
 * @param[in] mdIndex of the parent MD
 * @param[in] maIndex of the parent MA
 * @param[in] prevLMepId is the previous return value from the function or 0
 * @returns	maIndex of the next entry or 0 if no more entries
 */
mepId_t lMepReadList(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t prevLMepId);

/**
 * @brief Create a local MEP on the specified MA
 *
 * Create a local MEP on the specified Maintenance Association.
 * lMepId specifies the MEPID to use for the MEP. This must be in the
 * list of MA's MEPIDs for the function to be successful.
 * The direction of the MEP must be 'down'. up MEPs are not supported.
 * iFace specifies the interface on which to place the MEP. If the
 * function is successful then the MEP is created with its administrative
 * state set to false (inactive).
 * By default all other MEPs in the MAs MEPID list other than this MEP)
 * will be configured a remote MEPs to this local MEP.
 *
 * @param[in]	mdIndex The MAs parent MD index
 * @param[in]	maIndex The local MEPs parent MA index
 * @param[in]	lMepId The MEPID of the local MEP
 * @param[in]	direction The direction of the MEP (only Down supported)
 * @param[in]	iFace The interface that the MEP is located on
 * @returns
 * \li  1: Operation rejected due to invalid MD (%d) or MA (%d) Index
 * \li  2: Operation rejected because a MEP with ID=mepId already exists on the MA
 * \li  3: Operation rejected because MEPID is not in the MA's list of MEPIDs
 * \li  4: Operation rejected due to the existence of a MEP with same port, level, VID and direction
 * \li  9: Operation accepted
 * \li -1: Operation rejected due to insufficient resources
 * \li -2: Operation rejected because up MEPs are not supported
 */
int lMepCreate(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t mepId, mepDir_t direction, iFace_t iFace);

/**
 * @brief Delete the local MEP with MEPID equal to lMepId
 *
 * @param[in]	mdIndex The MD index of the parent MD
 * @param[in]	maIndex The MA index of the parent MA
 * @param[in]	lMepId The MEPID of the local MEP to delete
 * @returns
 * \li  1: Operation rejected because nonexistent MEP
 * \li  2: Operation accepted
 */
int lMepDelete(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId);

/**
 * @brief	Read the information for the Local MEP
 *
 * Read information related to this Local MEP. It is possible to request information in specific groupings.
 * If information for a specific group is desired then a pointer to a data structure to hold that information
 * must be provided. If a NULL pointer is supplied for a group then that information is not read and returned.
 * Information is only valid if the return value is 2.
 *
 * @param[in] mdIndex The MD index of the parent MD
 * @param[in] maIndex The MA index of the parent MA
 * @param[in] lMepId The MEPID of the local MEP to read from
 * @param[out] mepInfo A pointer to a mepInfo data type or NULL. If not NULL its values will be updated
 * @param[out] mepCcInfo A pointer to a mepCcInfo data type or NULL. If not NULL its values will be updated
 * @param[out] mepLbInfo A pointer to a mepLbInfo data type or NULL. If not NULL its values will be updated
 * @param[out] mepLbMefInfo A pointer to a mepLbMefInfo data type or NULL. If not NULL its values will be updated
 * @param[out] mepLtInfo A pointer to a mepLtInfo data type or NULL. If not NULL its values will be updated
 * @param[out] mepFngInfo A pointer to a mepFngInfo data type or NULL. If not NULL its values will be updated
 * @param[out] mepMefInfo A pointer to a mepMefInfo data type or NULL. If not NULL its values will be updated
 * @param[out] macAddress The MAC address of the Port on which this MEP is created.
 *
 * @returns
 * \li 1: Operation rejected due to invalid or nonexistent MEPID
 * \li 2: Operation accepted
 */
int lMepRead(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId,
		mepInfo_t 		*mepInfo,
		mepCcInfo_t		*mepCcInfo,
		mepLbInfo_t		*mepLbInfo,
		mepLbMefInfo_t	*mepLbMefInfo,
		mepFngInfo_t	*mepFngInfo,
		//TODO: mepLtInfo_t		*mepLtInfo,
		mepMefInfo_t	*mepMefInfo,
		macAddress_t	macAddress);

/**
 * @brief	Write a new value to the selected Local MEP parameter.
 *
 * Write a new value to a writable parameter of the Local MEP. The mepParm value is used to
 * select one of the valid writable parameters (listed above) and the paramValue is
 * a pointer to the new value. The data type of the parameter (also listed above)
 * must be valid for the parameter or errors/misconfigurations may occur.
 *
 * The writable parameters for a Local MEP and the associated data type are:
 * mepParam_mepPrimaryVid 				uint16_t
 * mepParam_mepActive,					bool
 * mepParam_mepCciEnable,				bool
 * mepParam_mepCcmLtmPriority,			prio_t
 * mepParam_mepLowPrDef,				lowPrDef_t
 * mepParam_mepFngAlarmTime,			uint16_t		;Units of 0.01sec (default is 250 = 2.5sec)
 * mepParam_mepFngResetTime,			uint16_t		;Units of 0.01sec (default is 1000 = 10sec)
 * mepParam_mepActiveRMepListAdd,		mepId_t
 * mepParam_mepActiveRMepListRemove,	mepId_t
 * mepParam_mepLbMefInterval,			uint16_t		;Units of 0.001sec (default is 1000 = 1sec)
 * mepParam_mepLbMefMulticastEnable,	bool
 * mepParam_mepLbMefFrameSize,			uint16_t
 * mepParam_mepNotificationEnable,		uint32_t
 * mepParam_mepNotificationInterval		uint32_t
 *
 *
 * @param[in] mdIndex of the parent MD
 * @param[in] maIndex of the parent MA
 * @param[in] lMepId is the MEPID of the local MEP to write to
 * @param[in] mepParam is an enum value that identifies the Local MEP parameter to write to
 * @param[in] paramValue is a pointer to the new value for the selected parameter
 *
 * @returns
 * \li  1: Operation rejected due to invalid or nonexistent MEP
 * \li  2: Operation rejected due to the selected managed object being Read-Only
 * \li  3: Operation rejected due to invalid value for parameter
 * \li  4: Operation accepted
 */
int lMepWrite(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepWrParam_t mepParam, void *paramValue);

/**
 * @brief Get the primary Vid for a specified local MEP.
 *
 * This function will return 0 if the MEP cannot be found, otherwise it will
 * return the primary Vid for the MEP. The primary Vid is determined by looking at
 * the primaryVid parameter for the Local MEP. If that is 0 then the MA must be examined.
 * If that too is 0 then the default port Vid will be returned
 *
 * @param[in] mdIndex of the parent MD
 * @param[in] maIndex of the parent MA
 * @param[in] lMepId is the MEPID of the local MEP whose Vid is required
 * @returns Return 0 if the MEP cannot be found, otherwise it will
 * return the primary Vid for the MEP.
 */
uint16_t getPrimaryVidForMep(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t mepId);

/**
 * @brief This function tests to see if the selected MEP exists on the device.
 *
 * @param[in] mdIndex of the parent MD
 * @param[in] maIndex of the parent MA
 * @param[in] lMepId is the MEPID of the MEP to check
 * @return True if the MEP exists on the device, False if it doesn't
 *
 */
bool mepIsLMepIdValid(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId);

/**
 * @brief Returns then total number of local MEPs on the system.
 *
 * @returns A count of the number of local MEPs on the system
 */
uint16_t getLMepCount(void);

/**
 * @brief Returns then total number of Remote MEPs on the system.
 *
 * @returns A count of the number of Remote MEPs on the system
 */
uint16_t getRMepCount(void);

#endif /* MEP_H_ */
