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

#include <api_oam_sdk/common/types/inc/mr_api_types.h>
#include <api_oam_sdk/continuity_check/src/cc_types.h>
#include <api_oam_sdk/mep/src/mep_types.h>
#include <api_oam_sdk/rmep_db/src/rmep_types.h>
#include <api_oam_sdk/system/inc/system.h>
#include <api_oam_sdk/table_access/inc/table_access.h>
#include <api_oam_sdk/table_config/inc/table_config.h>
#include "string.h"
#include "stdio.h"
#include "egl_types.h"
#include "egl_assert.h"
#include "egl_log.h"

static rMepEntry_t	rMepArray[MAX_NUM_RMEPS];
static uint16_t		log_handle				= 0;		// handle used to log messages for this module
static osMutex_t	rMepListLock			= NULL;
static bool			rMepInitialised			= false;
static rMepNum_t	s_rMepCount				= 0;

#if 1
	#define LOCK_RMEP_LIST(timeout)	lockMDBranch(0,timeout)	//osRecursiveMutexTake(rMepListLock,timeout)
	#define UNLOCK_RMEP_LIST()		unlockMDBranch(0)		//osRecursiveMutexGive(rMepListLock)
#else
	void lockMepBranch(lMepNum_t lMepNum, uint32_t timeout);
	void unlockMepBranch(lMepNum_t lMepNum);

	#define LOCK_RMEP_LIST(timeout)	lockMepBranch(0,timeout)
	#define UNLOCK_RMEP_LIST()		unlockMepBranch(0)
#endif
/*
 * @brief	This sets the mepEntry values to their default
 *
 * In most cases this should only be done with mepLock enabled
 * to ensure thread safe operation
 */
static void setRMepDefaults(rMepEntry_t *rMepEntry)
{
	memset(rMepEntry,0,sizeof(rMepEntry_t));
	rMepEntry->rMepDB.rMepIsActive = false;
}

/*
 * @brief Clears the Mep list
 *
 * This should be called to initialise the MA list.
 * Any MAs on the list will be lost.
 */
static void clearRMepList(void)
{
	uint16_t	k;

	// Initialise all entries in the MA array to defaults
	for (k = 0; k < MAX_NUM_RMEPS; k++)
	{
		setRMepDefaults(&rMepArray[k]);
	}
	s_rMepCount = 0;
	DO_LOG_DEBUG(log_handle,"Initialised the MEP List");
}

/*
 * @brief	Called at device startup to initialise rMepDB module
 *
 * Safe to call repeatedly.
 */
void rMepDBInit(void)
{
	log_init();	// Initialises the logging system if it's not already initialised

	// Get a log handle if we don't already have one
	if (log_handle == 0)
		log_handle = log_register("rMepDB");

	// Create a mutex to protect the MA list if we don't already have one
	if (rMepListLock == NULL)
	{
		rMepListLock = osMutexCreate();
		ASSERT_NOT_NULL(rMepListLock);
	}

	// If not already initialised clear the RMep list for first use.
	if (!rMepInitialised)
	{
		// Set the default logging level to NOTICE
		setModuleLogLevel(log_handle, eLOG_LEVEL_NOTICE);

		DO_LOG_DEBUG(log_handle,"Preparing the RMEP DB List for first use");
		LOCK_RMEP_LIST(0);
		clearRMepList();
		UNLOCK_RMEP_LIST();
		rMepInitialised = true;
	}
}

/*
 * @brief Convert a rMepNum into a mepId
 */
static mepId_t _rMepNumToMepId(rMepNum_t rMepNum, lMepNum_t *parentLMepNum)
{
	mepId_t theMepId = 0;

	LOCK_RMEP_LIST(0);
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		theMepId = rMepArray[rMepNum].rMepCtxt.mepId;
		if (parentLMepNum != NULL)
		{
			*parentLMepNum = rMepArray[rMepNum].rMepCtxt.parentLMepNum;
		}
		UNLOCK_RMEP_LIST();
		return (theMepId);
	}
	UNLOCK_RMEP_LIST();
	return (0);				//rMepNum not in use
}

/*
 * @brief Convert a mepId into a mepNum
 */
static lMepNum_t rMepIdToRMepNumNoLocking(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepEntry_t	*rMepEntryPtr;
	rMepNum_t	rMepNum = -1;

	// Start searching valid lMeps at the head of the list
	rMepEntryPtr = TAILQ_FIRST(_getRMepDBListHead(mdIndex,maIndex,lMepId));
	while (rMepEntryPtr != NULL)
	{
		if (rMepEntryPtr->rMepCtxt.mepId == rMepId)
		{
			rMepNum = rMepEntryPtr->rMepCtxt.rMepNum;
			return (rMepNum);	//found it
		}
		rMepEntryPtr = TAILQ_NEXT(rMepEntryPtr,ll);
	}
	return -1;	// mepId not found
}

/*
 * @brief Convert a rMepId into a rMepNum
 */
rMepNum_t _rMepIdToRMepNum(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepNum_t rMepNum;

	LOCK_RMEP_LIST(0);
	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	UNLOCK_RMEP_LIST();
	return rMepNum;
}

/*
 * @brief Read the next entry in the Remote Mep List
 */
mepId_t rMepReadList(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t nextRMepId)
{
	rMepNum_t 	nextRMepNum;
	mepId_t		theMepId;

	// Validate the MD, MA and local MEPID Index before using them
	if(!mepIsLMepIdValid(mdIndex, maIndex, lMepId))
	{
		DO_LOG_DEBUG(log_handle,"Operation rejected due to invalid MD (%d) or MA (%d) Index or MEPID (%d)",mdIndex, maIndex, lMepId);
		return (0);
	}

	LOCK_RMEP_LIST(0);
	if (nextRMepId == 0)
	{
		// Get the first rMep on the list...
		if (!TAILQ_EMPTY(_getRMepDBListHead(mdIndex, maIndex, lMepId)))
		{
			theMepId = TAILQ_FIRST(_getRMepDBListHead(mdIndex, maIndex, lMepId))->rMepCtxt.mepId;
			UNLOCK_RMEP_LIST();
			return theMepId;
		}
	}
	else
	{
		if (mepIdIsValid(nextRMepId))
		{
			nextRMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, nextRMepId);
			if (nextRMepNum != -1)
			{
				if (TAILQ_NEXT(&rMepArray[nextRMepNum],ll) != NULL)
				{
					theMepId = TAILQ_NEXT(&rMepArray[nextRMepNum],ll)->rMepCtxt.mepId;
					UNLOCK_RMEP_LIST();
					return theMepId;
				}
			}
		}
	}
	UNLOCK_RMEP_LIST();
	return 0;
}

/*
 * @brief	Find the next free rMep Entry
 */
static rMepEntry_t* getNextFreeRMepEntry(void)
{
	rMepNum_t	k;

	for (k = 0; k < MAX_NUM_RMEPS; k++)
	{
		if (!rMepArray[k].rMepCtxt.inUse)
		{
			rMepArray[k].rMepCtxt.rMepNum = k;
			rMepArray[k].rMepCtxt.inUse = true;
			return (&rMepArray[k]);
		}
	}
	return NULL;
}

/*
 * @brief	Add a new rMepEntry into the rMep List
 */
static void addRMepToList(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, rMepEntry_t *rMepEntry)
{
	ASSERT_NOT_NULL(rMepEntry);

	TAILQ_INSERT_TAIL(_getRMepDBListHead(mdIndex, maIndex, lMepId), rMepEntry, ll);
}

/*
 * @brief	Remove the rMep Entry, pointed to by rMepEntry, from the rMep List
 */
static void removeRMepFromList(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, rMepEntry_t *rMepEntry)
{
	ASSERT_NOT_NULL(rMepEntry);

	TAILQ_REMOVE(_getRMepDBListHead(mdIndex, maIndex, lMepId), rMepEntry, ll);
	setRMepDefaults(rMepEntry);
}

/*
 * @brief	Add a new remote MEP DB entry to the selected Local MEP
 */
void rMepDBAdd(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	// This function is only called from the local MEP module
	// so MD,MA and mepIds have already been verified

	rMepEntry_t	*rMepEntryPtr;
	maNetInfo_t	maNetInfo;
	lMepNum_t	lMepNum;
	int 		retVal;

	LOCK_RMEP_LIST(0);
	// Get the next free remote MEP entry
	rMepEntryPtr = getNextFreeRMepEntry();

	// get the necessary info from the MA
	maRead(mdIndex, maIndex, &maNetInfo, NULL, NULL, NULL, NULL,NULL);
	lMepNum = _mepIdToMepNum(mdIndex, maIndex, lMepId);
	if (lMepNum == -1)
	{
		UNLOCK_RMEP_LIST();
		DO_LOG_ERROR(log_handle,"rMepDBAdd() failed because local MEP %lu.%lu.%d could not be found",mdIndex, maIndex, lMepId);
		return;
	}
	//ASSERT(lMepNum != -1, 1);
	retVal = addRemoteMep(
		lMepNum,
		lMepId,
		rMepId,
		maNetInfo.ccmInterval,
		NULL,
		rMepEntryPtr->rMepCtxt.rMepNum);

	if (retVal != 0)
	{
		setRMepDefaults(rMepEntryPtr);
		UNLOCK_RMEP_LIST();
	}

	rMepEntryPtr->rMepCtxt.mepId			= rMepId;

	// To facilitate re-verse lookup save the parent Local MEP HW index
	rMepEntryPtr->rMepCtxt.parentLMepNum	= lMepNum;

	s_rMepCount++;	// update the count of remote MEPs

	addRMepToList(mdIndex, maIndex, lMepId, rMepEntryPtr);
	UNLOCK_RMEP_LIST();
	DO_LOG_NOTICE(log_handle,"Added peer MEPID %d to local MEP %lu.%lu.%d",rMepId, mdIndex, maIndex, lMepId);
}

/*
 * @brief	Remove the selected remote MEP DB entry from the Local MEP
 */
void rMepDBRemove(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepNum_t	rMepNum;

	LOCK_RMEP_LIST(0);
	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);

	// Delete this Remote MEP
	deleteRemoteMep(rMepNum);

	removeRMepFromList(mdIndex, maIndex, lMepId, &rMepArray[rMepNum]);
	s_rMepCount--;	// update the count of Remote MEPs

	UNLOCK_RMEP_LIST();
	DO_LOG_NOTICE(log_handle,"Removed peer MEPID %d from local MEP %lu.%lu.%d",rMepId, mdIndex, maIndex, lMepId);
}

rMepState_t readRMepState(rMepNum_t rMepNum, bool *rdi)
{
	rMepSMEntry_t	rMepSMEntry;

	readRMepSMRam(rMepNum,&rMepSMEntry);
	*rdi = rMepSMEntry.rdi;				// State of the RDI bit in the last received CCM (true for RDI=1), or false if none has been received

	// translate the rMEP SM States to the correct ones
	switch(rMepSMEntry.state)
	{
		case SM_IDLE:			//0
		{
			return(rMepIdle);
			break;
		}
		case SM_INIT_WAIT: 		//3
		case SM_START: 			//2
		{
			return(rMepStart);
			break;
		}
		case SM_OK:				//4
		{
			return(rMepOk);
			break;
		}
		case SM_FAIL:			//6
		{
			return(rMepFailed);
			break;
		}
		default:
			return(rMepIdle);
	}
}
/*
 * @brief	Read the database information for the Remote MEP
 */
int rMepDBRead(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId, rMepDB_t *rMepDB)
{
	rMepNum_t	rMepNum;

	if (!mepIsLMepIdValid(mdIndex, maIndex, lMepId))
	{
		DO_LOG_INFO(log_handle,"Operation rejected due to invalid MD (%d), MA (%d) or local MEPID (%d) ", mdIndex, maIndex, lMepId);
		return (1);
	}

	if (!mepIdIsValid(rMepId))
	{
		goto RMEP_DB_READ_RMEPID_INVALID;
	}

	if (!_maIsMepIdOnList(mdIndex, maIndex, rMepId))
	{
RMEP_DB_READ_RMEPID_INVALID:
		DO_LOG_INFO(log_handle,"Operation rejected due to remote MEPID (%d) not configured on MA", mdIndex, maIndex, lMepId);
		return (2);
	}
	LOCK_RMEP_LIST(0);
	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum < 0)
	{
		UNLOCK_RMEP_LIST();
		DO_LOG_ERROR(log_handle,"rMepDBRead() failed because remote MEP %lu.%lu.%d.%d could not be found",mdIndex, maIndex, lMepId, rMepId);
		return (2);
		//ASSERT(0,1);		// The indices and MEP IDs have already been validated so this shouldn't happen
	}

	rMepDbTblEntry_t	rMepDbTblEntry;
	ccmTlv_t 			ccmTlv;
	if (rMepDB != NULL)
	{
		rMepDB->rMepIsActive = rMepArray[rMepNum].rMepDB.rMepIsActive;
		rMepDB->failedOkTime = rMepArray[rMepNum].rMepDB.failedOkTime;

		rMepDB->state = readRMepState(rMepNum, &rMepDB->rdi);

		readRMepDB(rMepNum, &rMepDbTblEntry);

		rMepDB->_lastReceivedSeqNum = rMepDbTblEntry.seqNum;

		memcpy(rMepDB->macAddress,rMepDbTblEntry.SA,6);

		// TODO: make sure that the FNG will update the failedOkTime for the remote MEP
		memcpy(&rMepDB->failedOkTime,&rMepArray[rMepNum].rMepDB.failedOkTime,sizeof(rMepDB->failedOkTime));

		if (_extractTlvsFromArray(rMepDbTblEntry.tlv, &ccmTlv)  == 0)
		{
			if (ccmTlv.psTlv.present)
			{
				rMepDB->portStatusTlv		= ccmTlv.psTlv.value;
			}
			else
			{
				rMepDB->portStatusTlv		= psNoPortStatusTLV;
			}
			if (ccmTlv.isTlv.present)
			{
				rMepDB->interfaceStatusTlv	= ccmTlv.isTlv.value;
			}
			else
			{
				rMepDB->interfaceStatusTlv	= isNoInterfaceStatusTLV;
			}

#if 0 // TODO: restore this to add support for Sender ID TLV
			if (ccmTlv.sidTlv.present)
			{
				// TODO : Update code below once the Sender ID TLV parser is added to _extractTlvsFromArray
				rMepDB->chassisIdSubType	= cid_non;
				rMepDB->chassisId[0]		= '\n';
				rMepDB->manAddrDomain[0]	= '\n';
				rMepDB->manAddress[0]		= '\n';
			}
			else
			{
				// No Sender ID TLV present... set to null values
				rMepDB->chassisIdSubType	= cid_non;
				rMepDB->chassisId[0]		= '\n';
				rMepDB->manAddrDomain[0]	= '\n';
				rMepDB->manAddress[0]		= '\n';
			}
#else
			if (ccmTlv.sidTlv.present)
			{
				// this is a temporary hack to pass the unprocessed SID TLV up to higher layer software
				rMepDB->chassisIdSubType	= cid_local;
				sprintf(rMepDB->manAddrDomain,"%d",ccmTlv.sidTlv.length);
				memcpy(rMepDB->chassisId,ccmTlv.sidTlv.value,ccmTlv.sidTlv.length);
				rMepDB->manAddress[0]		= '\n';
			}
			else
			{
				rMepDB->chassisIdSubType	= cid_non;
				rMepDB->chassisId[0]		= '\n';
				rMepDB->manAddrDomain[0]	= '\n';
				rMepDB->manAddress[0]		= '\n';
			}
#endif
			// Custom support for the ORG TLV...
			if (ccmTlv.orgTlv.present)
			{
				memcpy(&rMepDB->_orgTlv,&ccmTlv.orgTlv,sizeof(orgTlv_t));
			}
			else
			{
				memset(&rMepDB->_orgTlv,0,sizeof(orgTlv_t));
			}
		}
		else
		{
			// There was a problem extracting the TLV...assume there was none
			rMepDB->portStatusTlv		= psNoPortStatusTLV;
			rMepDB->interfaceStatusTlv	= isNoInterfaceStatusTLV;
			rMepDB->chassisIdSubType	= cid_non;
			rMepDB->chassisId[0]		= '\n';
			rMepDB->manAddrDomain[0]	= '\n';
			rMepDB->manAddress[0]		= '\n';
		}

	}
	UNLOCK_RMEP_LIST();
	DO_LOG_DEBUG(log_handle,"Read data for remote MD=%d, MA=%d, local MEPID=%d, remote MEPID=%d", mdIndex, maIndex, lMepId, rMepId);
	return (3);	// Operation accepted
}

/*
 * @brief Read the Remote MEP MAC address for this remote MEP
 */
void rMepGetMAC(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId, bool *macValid, macAddress_t macAddress)
{
	rMepNum_t	rMepNum;

	// This function cannot handle IDs = 0 so return false if any are 0 (TODO: Fix possible infinte loop)
	if(mdIndex == 0 | maIndex == 0 | lMepId == 0 | rMepId == 0)
	{
		DO_LOG_ERROR(log_handle,"rMepGetMAC called with index %d.%d.%d.%d, indices = 0 not allowed.", mdIndex, maIndex, lMepId, rMepId);
		*macValid = false;
		return;
	}
	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum >= 0)
	{
		readSAInRMepDB(rMepNum,macAddress);
		*macValid = rMepArray[rMepNum].macValid;
	}
	else
	{
		*macValid = false;
	}
}

/*
 * @brief Enable the Remote MEP State Machine for this remote MEP
 */
void rMepEnable(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepNum_t 			rMepNum;
	maNetInfo_t			maNetInfo;
	rMepDbTblEntry_t	rMepDbTblEntry;

	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum >= 0)
	{
		// Clear the TLV field because TLVs may have changed while the SM was disabled - this forces a new interrupt to occur.
		readRMepDB(rMepNum,&rMepDbTblEntry);
		// Write the initial TLV bytes to 0's
		memset(rMepDbTblEntry.tlv,0,sizeof(rMepDbTblEntry.tlv));
		// Clear the MAC - it may have changed or the MEP gone off-line
		memset(rMepDbTblEntry.SA,0,6);
		// Reset the last received sequence number
		rMepDbTblEntry.seqNum = 0;
		writeRMepDB(rMepNum,&rMepDbTblEntry);

		// We need some info about the MA so read it
		EGL_ASSERT(maRead(mdIndex, maIndex, &maNetInfo, NULL, NULL, NULL, NULL,NULL) == 2, 1);
		enableRMepSM(rMepNum, maNetInfo.ccmInterval);
		rMepArray[rMepNum].rMepDB.rMepIsActive = true;
	}
}

/*
 * @brief Disable the Remote MEP State Machine for this remote MEP
 */
void rMepDisable(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepNum_t 	rMepNum;

	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum >= 0)
	{
		disableRMepSM(rMepNum);
	}
}

/*
 * @brief Return true if the Remote MEP is in the active state, otherwise return false
 */
bool rMepIsActive(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepNum_t 	rMepNum;

	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum >= 0)
	{
		return(rMepArray[rMepNum].rMepDB.rMepIsActive);
	}
	return(false);
}

/*
 * @brief Set the context value for the Active state for this Remote MEP to true
 *
 * Note the context state and actual state of the remote MEP State Machine are
 * kept separate because the Active state of the Local MEP can determine the
 * actual state of the Remote MEP State Machine while the context value is
 * left unchanged (i.e. Local Mep Active=false, Remote MEP SM = disabled but
 * Remote MEP (context)Active=true.
 */
void rMepSetActive(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepNum_t 	rMepNum;

	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum >= 0)
	{
		rMepArray[rMepNum].rMepDB.rMepIsActive = true;
	}
}

/*
 * @brief Clear the context value for the Active state for this Remote MEP to false
 *
 * Note the context state and actual state of the remote MEP State Machine are
 * kept separate because the Active state of the Local MEP can determine the
 * actual state of the Remote MEP State Machine while the context value is
 * left unchanged (i.e. Local Mep Active=false, Remote MEP SM = disabled but
 * Remote MEP (context)Active=true.
 */
void rMepClrActive(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId)
{
	rMepNum_t 	rMepNum;

	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum >= 0)
	{
		rMepArray[rMepNum].rMepDB.rMepIsActive = false;
	}
}

void _rMepSetFailedOkTime(rMepNum_t rMepNum, time_t theTime)
{
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		rMepArray[rMepNum].rMepDB.failedOkTime = theTime;
		return;
	}
	DO_LOG_ERROR(log_handle,"_rMepSetFailedOkTime called with an index that is not in use %d", rMepNum);
	//ASSERT(0,1);		// We shouldn't be given a rMepNum that is not in use!
}

void _rMepSetLinkStatus(rMepNum_t rMepNum, bool linkIsUp)
{
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		rMepArray[rMepNum].rMepDB.linkIsUp = linkIsUp;
		return;
	}
	DO_LOG_ERROR(log_handle,"_rMepSetLinkStatus called with an index that is not in use %d", rMepNum);
	//ASSERT(0,1);		// We shouldn't be given a rMepNum that is not in use!
}

void _rMepSetRxRdiStatus(rMepNum_t rMepNum, bool rxRdiIsSet)
{
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		rMepArray[rMepNum].rMepDB.rxRdiIsSet = rxRdiIsSet;
		return;
	}
	DO_LOG_ERROR(log_handle,"_rMepSetRxRdiStatus called with an index that is not in use %d", rMepNum);
	//ASSERT(0,1);		// We shouldn't be given a rMepNum that is not in use!
}

void _rMepSetPsValue(rMepNum_t rMepNum, psValue_t newVlaue)
{
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		rMepArray[rMepNum].rMepDB.lastRxPSValue = newVlaue;
		return;
	}
	DO_LOG_ERROR(log_handle,"_rMepSetPsValue called with an index that is not in use %d", rMepNum);
	//ASSERT(0,1);		// We shouldn't be given a rMepNum that is not in use!
}

void _rMepSetIsValue(rMepNum_t rMepNum, isValue_t newVlaue)
{
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		rMepArray[rMepNum].rMepDB.lastRxISValue = newVlaue;
		return;
	}
	DO_LOG_ERROR(log_handle,"_rMepSetIsValue called with an index that is not in use %d", rMepNum);
	//ASSERT(0,1);		// We shouldn't be given a rMepNum that is not in use!
}

void _rMepGetIntInfo(mdIndex_t mdIndex, maIndex_t maIndex, mepId_t lMepId, mepId_t rMepId, rMepDBint_t *rMepDBint)
{
	rMepNum_t 	rMepNum;

	rMepNum = rMepIdToRMepNumNoLocking(mdIndex, maIndex, lMepId, rMepId);
	if (rMepNum >= 0)
	{
		memcpy(rMepDBint, &rMepArray[rMepNum].rMepDB, sizeof(rMepDBint_t));
	}
}

lMepNum_t _rMepGetParentLMepNum(rMepNum_t rMepNum)
{
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		return (rMepArray[rMepNum].rMepCtxt.parentLMepNum);
	}
	DO_LOG_ERROR(log_handle,"_rMepSetIsValue called with an index that is not in use %d", rMepNum);
	//ASSERT(0,1);		// We shouldn't be given a rMepNum that is not in use!
	return(-1);
}

void _rMepGetParentsIndices(rMepNum_t rMepNum, mepParentIndices_t *mepParentIndices)
{
	lMepNum_t	lMepNum;

	mepParentIndices->rMepId = _rMepNumToMepId(rMepNum, &lMepNum);
	EGL_ASSERT(mepParentIndices->rMepId != 0,1);

	_lMepGetParentsIndices(lMepNum, mepParentIndices);
}

uint16_t rMepDBGetRMepCount(void)
{
	return (s_rMepCount);
}

void _rMepSetMacValid(rMepNum_t rMepNum, bool valid)
{
	rMepArray[rMepNum].macValid = valid;
}

bool _rMepNumIsValid(rMepNum_t rMepNum)
{
	if (rMepArray[rMepNum].rMepCtxt.inUse)
	{
		return (true);
	}
	return (false);
}

/*
 * This function is used to change the lowest level severity to log for
 * this module. Values of eLOG_LEVEL_DEBUG (lowest) to eLOG_LEVEL_ERROR
 * can be selected. Levels with greater severity than eLOG_LEVEL_ERROR
 * will default to eLOG_LEVEL_ERROR since severity of eLOG_LEVEL_ERROR
 * and higher are non maskable.
 */
void setRMepDbLogLevel(log_level_t logLevel)
{
	setModuleLogLevel(log_handle,logLevel);
}
