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

#ifndef FNG_H_
#define FNG_H_

//#include "../src/ma_types.h"
#include <api_oam_sdk/mep/inc/mep.h>
#include "egl_types.h"
#include "osal.h"

#define FNG_QUEUE_SIZE	(MAX_NUM_MEPS * 4)
#define FNG_MAX_TIMERS	(MAX_NUM_MEPS + 4)
#define FNG_TASK_STACKSIZE (KB(2))

#ifdef __GNUC__
#ifndef ALIGN_DATA_STRUCT
#define 	ALIGN_DATA_STRUCT(bytes)	__attribute__ ((aligned (bytes)))
#endif
#else
#ifndef ALIGN_DATA_STRUCT
#define 	ALIGN_DATA_STRUCT(bytes)
#endif
#endif


struct mibLMepIndices_s
{
	mdIndex_t	mdIndex;
	maIndex_t	maIndex;
	mepId_t		lMepID;
};

struct mibRMepIndices_s
{
	mdIndex_t	mdIndex;
	maIndex_t	maIndex;
	mepId_t		lMepId;
	mepId_t		rMepId;
};

typedef struct
{
	fngDefect_t 	fngPriority;		// priority of last defect reported in a fault alarm
	fngDefect_t		fngDefect;			// last defect reported in a fault alarm
	mepFngInfo_t	mepFngInfo;			// Holds the MIB FNG parameters
	uint8_t			_previousDefects;	// holds a previous copy of mepFngInfo.defects. This is updated each time the FNG SM is called
} fngEntry_t;


typedef struct
{
	bool		eventOccurred;		// Set to TRUE if an event occurred, set to false if no event occurred
	bool		connIsDown;			// True if the connection is lost, false if the connection is up (good)
	union {
		rMepNum_t	rMepNum;		// The remote MEP num that reported the connectivity event.
		struct mibRMepIndices_s rMepIndices;
	};
} fngConnInfo_t ALIGN_DATA_STRUCT(4) ;

typedef enum
{
	XCON_INVALID_DR1		= 0,
	XCON_UNEXPECTED_LEVEL	= 1,
	XCON_UNMATCHED_MAID		= 2,
	XCON_AIS_DETECTED		= 4
} xConnDefectReason_t;

typedef struct
{
	bool			eventOccurred;	// Set to TRUE if an event occurred, set to false if no event occurred
	bool			errDetected;	// true if an error was detected or false if an error was cleared
	xConnDefectReason_t	defectReason;	// Bits are set to identify the reason for the defect
	#ifdef WIN_DLL_PADDING
	uint8_t			pad1b;			// required to word align variables for use in windows DLL
	#endif
	union {
		lMepNum_t		lMepNum;	// The MEP Num of local MEP on which the cross connect occurred.
		struct mibRMepIndices_s rMepIndices;
	};

	packetBuffer_t	captPkt;		// If a Cross Connect event occurred the captured packet is available here

} fngXConInfo_t;

typedef enum
{
	RMEP_INVALID_DR2			= 0,
	RMEP_UNEXPECTED_MEPID		= 1,
	RMEP_UNEXPECTED_INTERVAL	= 2,
	RMEP_LCK_DETECTED			= 4
} rMepErrDefectReason_t;

typedef struct
{
	bool			eventOccurred;	// Set to TRUE if an event occurred, set to false if no event occurred
	bool			errDetected;	// true if an error was detected or false if an error was cleared
	rMepErrDefectReason_t	defectReason;// Bits are set to identify the reason for the defect
	#ifdef WIN_DLL_PADDING
	uint8_t			pad1b;			// required to word align variables for use in windows DLL
	#endif
	union {
		lMepNum_t		lMepNum;	// The MEP Num of local MEP on which the remote MEP Error occurred.
		struct mibRMepIndices_s rMepIndices;
	};
	packetBuffer_t	captPkt;		// If a remote MEP Error event occurred the captured packet is available here
} fngRMepErrInfo_t;

typedef struct
{
	bool			eventOccurred;	// Set to TRUE if an event occurred, set to false if no event occurred
	macAddress_t	value;			// The new Source MAC Address
	union {
		rMepNum_t		rMepNum;		// The MEP Num of the remote MEP on which the SA change occurred.
		struct mibRMepIndices_s rMepIndices;
	};
} fngSaChngInfo_t;

typedef struct
{
	bool			eventOccurred;	// Set to TRUE if an event occurred, set to false if no event occurred
	bool			rdiIsSet;		// true if RDI was set in received CCM or false if RDI was cleared in received CCM
	union {
		rMepNum_t		rMepNum;		// The MEP Num of the remote MEP on which the RDI change occurred.
		struct mibRMepIndices_s rMepIndices;
	};
} fngRdiChngInfo_t;

typedef struct
{
	bool			eventOccurred;	// Set to TRUE if an event occurred, set to false if no event occurred
	uint8_t			changeMask;		// bits indicate which TLVs changed, [0]-PS [1]-IS [2]-Org [3]-Sid
	union {
		rMepNum_t		rMepNum;		// The MEP Num of the remote MEP on which the TLVs changed.
		struct mibRMepIndices_s rMepIndices;
	};
	union {
	ccmTlv_t		newTlv;			// The new value of the TLVs in hierarchial structure
	ccmTlvByteArray_t	newTlvBytes;// The new value of the TLVs in byte array format
	};
} fngTlvChngInfo_t;

typedef struct
{
	bool			eventOccurred;	// Set to TRUE if an event occurred, set to false if no event occurred
	uint32_t		probeMask;
	union {
		lMepNum_t		lMepNum;
		rMepNum_t		rMepNum;
		struct mibRMepIndices_s rMepIndices;
	};
	packetBuffer_t	captPkt;		// If a packet Probe event occurred the captured packet is available here
} fngPktProbeInfo_t;

enum eventTLV
{
	EVENT_TLV				= 1,
	EVENT_TLV_CONN			= 2,
	EVENT_TLV_XCONN			= 3,
	EVENT_TLV_RMEP_ERR		= 4,
	EVENT_TLV_SA_CNG		= 5,
	EVENT_TLV_RDI_CNG		= 6,
	EVENT_TLV_ANY_TLV_CNG	= 7,
	EVENT_TLV_PROBE_STORE	= 8
};

#define EVENT_TLV_SIG	0x5A5A5A5A

// The 3 following structs are are for accessing the same TLV.
// A different struct is needed depending on what is needed
// It's further complicated by the fact that enums vary in size
// depending on the compiler! Code must work regardless of enum size.
struct eventTLV_s
{
	enum eventTLV	type;
	uint32_t		length;
	void			*dataPtr;
};

struct eventTLVextract_s
{
	enum eventTLV	type;
	uint32_t		length;
	uint8_t			data;
};

struct eventTLVsize_s
{
	enum eventTLV	type;
	uint32_t		length;
};

struct eventFrame_s
{
	uint32_t		signature;
	uint16_t		length;
	uint16_t		pad2b;
	time_t			timeStamp;
	uint32_t		intMask;
} ;

typedef enum
{
	fng_invalidMsg			= 0,
	fng_cfmEventMsg			= 1,
	fng_updateFngStateMsg	= 2,
	fng_resetSMForMepMsg	= 3,
	fng_releaseSMForMepMsg	= 4
} fngMsgId_t;

typedef struct
{
	uint16_t	payloadSize;
	fngMsgId_t	msgID;
	uint8_t		*payload;
} fngMsg_t;

/*
 * @brief Initialise the Fault Notification Generator (FNG) State Machine (S/M)
 *
 * This will launch an OS task to handle receive of Interrupt events from the cfm_isr module.
 * The events are processed by the FNG S/M and events are flaged and notifications sent
 * if/when the S/M determines they should be.
 */
void fngInit(void);


/*
 * @brief This function adds a CFM Event message to the FNG message Queue.
 *
 * If the FNG message Queue is full the function will continue to
 * try to send the message every 5ms, sleeping while waiting.
 */
void fngAddCfmEventMsgToQ( uint8_t *data, uint16_t length);

/*
 * @brief This function adds a SM re-evaluate message to the FNG message Queue.
 *
 * If the FNG message Queue is full the function will continue to
 * try to send the message every 5ms, sleeping while waiting.
 */
void fngReEvaluateSM(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, lMepNum_t lMepNum);

/*
 * @brief Send a request to the FNG SM to put the FNG state of a particular MEP into the 'fngReset' state
 *
 * This should be called when a MEP is Administratively disabled
 */
void fngResetSM(lMepNum_t lMepNum);

/*
 * @brief This will release/de-allocate the FNG S/M associated with a Local MEP
 *
 * This should be called to release the FNG S/M when a Local MEP is deleted from the
 * system or when it is disabled (in which case the FNG S/M is reset to defaults)
 */
void fngReleaseSM(lMepNum_t lMepNum);

/*
 * @brief Read all FNG related parameters for the selected local MEP
 *
 * @param[in] mdIndex of the parent MD
 * @param[in] maIndex of the parent MA
 * @param[in] lMepId is the MEPID of the local MEP this FNG service is on
 * @param[out] mepFngInfo is a pointer to mepFngInfo_t struct that will be updated if it's a non NULL value
 *
 * Read the Fault Notification Generator information for the selected local MEP.
 * If the mepFngInfo is NULL then it will not be updated.
 * This function forms a subsection of the local MEP lMepRead() function. That function handles the
 * return values.
 */
void fngRead(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepFngInfo_t *mepFngInfo);

lowPrDef_t _getFngLowPrDef(lMepNum_t lMepNum);
void _setFngLowPrDef(lMepNum_t lMepNum, lowPrDef_t newVal);
uint16_t _getFngAlarmTime(lMepNum_t lMepNum);
void _setFngAlarmTime(lMepNum_t lMepNum, uint16_t newVal);
uint16_t _getFngResetTime(lMepNum_t lMepNum);
void _setFngResetTime(lMepNum_t lMepNum, uint16_t newVal);
#endif /* FNG_H_ */
