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

#include <api_oam_sdk/common/error_codes/inc/mr_error_codes.h>
#include <api_oam_sdk/loopback/src/lb_support.h>
#include <api_oam_sdk/mep/src/mep_types.h>
#include <api_oam_sdk/metroam_hal/inc/mr_hal.h>
#include <api_oam_sdk/table_access/inc/table_access.h>
#include <math.h>


lbSvc_t	lbSvcList[MAX_LB_CHANNELS_FOR_Y1564];



// -----------------------------------------------------------------------------------------------------
// addLBSvcToLMep(uint16_t lMepNum,uint8_t multiCast,uint8_t mdLvl,txTemplateEntry_t *txLbTempl, tlvLen,uint8_t tlv[],uint8_t *lbChnl);
// -----------------------------------------------------------------------------------------------------
// This function will add a Loopback service to a local Mep using the specified loopback
// channel. It will program a new txTemplate for the LB packet in the txTemplate RAM
// and it will enter the lMepNum into the LBR ram for that channel for Rx processing.
// If adding the service is successful it will return as 0 and update the lbChnl number.
// If there is an error or are no more LB channels available it will return with
// a non zero value and lbChnl = MR_NULL_LB_CHNL.
// =====================================================================================================
int addLBSvcToLMep(uint16_t lMepNum,uint8_t multiCast,uint8_t mdLvl,txTemplateEntry_t *txLbTempl,templateType_t templType,uint8_t dirCfgMask, uint8_t lbChnl)
{
	lbrRamEntry_t	lbrRamEntry;
	uint32_t		seqNum;
	uint8_t			pcp;
	int				retVal;

	// Configure the specified LBChnl...
	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
			sprintf(msgStr, "INFO: addLBSvcToLMep --- Adding a new LoopBack service to LMepNum=%d using lbChannel %d\n",lMepNum,lbChnl);
			writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	// If dirCfgMask = 0 it means LBR packets are to be used (not TST) so MR_BOTH_TX_RX are affected
	if ((dirCfgMask & MR_TX_ONLY) || (dirCfgMask == 0))
	{
		// before proceeding disable the LB channel
		if (dirCfgMask == 0)
			disableLBChnl(lbChnl,MR_BOTH_TX_RX);
		else
			disableLBChnl(lbChnl,MR_TX_ONLY);

		// update the txTemplate with the appropriate common CFM values
		txLbTempl->comCfmHdr[0] = mdLvl << 5;
		if (templType == TST_TEMPL)
			// if a TST template is requested then change the opcode appropriately
			txLbTempl->comCfmHdr[1] = MR_TST_OPCODE;
		else
			txLbTempl->comCfmHdr[1] = MR_LBM_OPCODE;
		// even if a TST template is request...apart from the opcode change above the
		// template to use is still the basic loopback template.
		templType = LB_TEMPL;
		txLbTempl->comCfmHdr[2] = 0;
		txLbTempl->comCfmHdr[3] = MR_LB_1ST_OFF;

		// preserve the sequence number (i.e. Tx pkt count) in order to
		// match the fact that the function also preserves the Rx stats
		// The user must call a function to clear Tx & Rx stats after
		// adding the service. This scheme allows one to change the packet
		// but accumulate the Tx and Rx stats.
		if ((retVal = readSeqNumInTxTempl(lbChnl,&seqNum,templType)))
			return(retVal);
		txLbTempl->seqNum = seqNum;
		if ((retVal = writeTxTempl(lbChnl,txLbTempl,templType,0,NULL)))
			return(retVal);
	}

	// Determine the PCP field associated with the VLAN... This is needed in order
	// to configure the Rx Side to differentiate different PRIOs on a Vlan (LMEP)
	if (txLbTempl->sTagPresent)
		pcp = txLbTempl->sTagVID[0] >> 4;
	else if (txLbTempl->cTagPresent)
		pcp = txLbTempl->cTagVID[0] >> 4;
	else
		pcp = txLbTempl->sTagVID[0] >> 4;		// No Tag on packet, use the port PCP - not easy to obtain here so...
												// !!! this is encoded into the STag fields by calling function!!!
	if ((dirCfgMask & MR_RX_ONLY)  || (dirCfgMask == 0))
	{
		if ((retVal = readLBRRam(lbChnl,&lbrRamEntry)))
			return(retVal);
		// initialise the LB RAMs....
		lbrRamEntry.multicast = multiCast;
		/*
		lbrRamEntry.lastJitt = 0;
		lbrRamEntry.lastLat = 0 ;
		lbrRamEntry.expSN = txLbTempl->seqNum;
		lbrRamEntry.numRxLbr = 0;
		lbrRamEntry.minJitt = 0;
		lbrRamEntry.maxJitt = 0x3FFFFFF;
		lbrRamEntry.sumJitLow = 0;
		lbrRamEntry.sumJitUpp = 0;
		lbrRamEntry.minLat = 0;
		lbrRamEntry.maxLat = 0x3FFFFFF;
		lbrRamEntry.sumLatLow = 0;
		lbrRamEntry.sumLatUpp = 0;
		*/
		// Template: int writeLbrRam(uint32_t entryIdx,lbrRamEntry_t *lbrRamEntry)
		if ((retVal = writeLBRRam(lbChnl,&lbrRamEntry)))
			return(retVal);

		/*
		// Clear any LB error Flags (timeout and seq error) on this channel
		clearLBErrors(lbChnl);
		*/

		// associate the lMepNum with the lbChnl in the LBR RAM for use by RX logic
		if ((retVal = writeLBRLMepNum(lbChnl,lMepNum, pcp)))
			return(retVal);

		// save the lMep number associated with this LB channel for use in the enable/disable functions.
		lbSvcList[lbChnl].lMepNum = lMepNum;
		lbSvcList[lbChnl].pcp = pcp;
	}

	/*
	 * No longer auto clear the Tx stats...user must do this themselves
	if ((dirCfgMask & MR_TX_ONLY) || (dirCfgMask == 0))
	{
		// Clear the TX stats for this channel
		mrHalRegRead(LB_RESET_REG_ADDR,&data);
		data |= LB_RESET_REG_STATS_CLR_MASK << (4 * lbChnl);
		mrHalRegWrite(LB_RESET_REG_ADDR,data);
		data &= ~(LB_RESET_REG_STATS_CLR_MASK << (4 * lbChnl));
		mrHalRegWrite(LB_RESET_REG_ADDR,data);
	}
	*/

	return(NO_ERR);

}


// -----------------------------------------------------------------------------------------------------
// enableLBChnl(lbChnl);
// -----------------------------------------------------------------------------------------------------
// This function is called to enable a specified Loopback channel
// =====================================================================================================
int enableLBChnl(uint8_t lbChnl)
{
	uint32_t	data;
	int		retVal;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::enableLBChnl : Enable LB channel %d\n",lbChnl);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	// NOTE: it's important that the RX side is configured before the Tx is enabled!

	// This is needed to prevent the RX side finding multiple matches in the LBR RAM
	if ((retVal = writeLBRLMepNum(lbChnl,lbSvcList[lbChnl].lMepNum,lbSvcList[lbChnl].pcp)))
		return(retVal);

	mrHalRegRead(LB_RESET_REG_ADDR,&data);
	data &= ~((LB_RESET_REG_CHNL_DISABLE_MASK | LB_RESET_REG_STATS_CLR_MASK) << (lbChnl));	// turn on the selected lbChnl
	mrHalRegWrite(LB_RESET_REG_ADDR,data);

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// disableLBTxChnl(lbChnl);
// -----------------------------------------------------------------------------------------------------
// This function is called to disable Transmit side only of a specified Loopback channel
// =====================================================================================================
int disableLBTxChnl(uint8_t lbChnl)
{
	uint32_t	data;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::enableLBChnl : Disable Tx on LB channel %d\n",lbChnl);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	mrHalRegRead(LB_RESET_REG_ADDR,&data);
	data |= (((uint32_t) LB_RESET_REG_CHNL_DISABLE_MASK) << (lbChnl));									// turn off the selected lbChnl enable bit
	mrHalRegWrite(LB_RESET_REG_ADDR,data);

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// disableLBChnl(lbChnl);
// -----------------------------------------------------------------------------------------------------
// This function is called to disable a specified Loopback channel
// =====================================================================================================
int disableLBChnl(uint8_t lbChnl,uint8_t selDir)
{
	int		retVal;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::disableLBChnl : Disable LB channel %d in direction %d\n",lbChnl, selDir);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	if (selDir & MR_TX_ONLY)
		disableLBTxChnl(lbChnl);

	if (selDir & MR_RX_ONLY)
	{
		// This is needed to prevent the RX side finding multiple matches in the LBR RAM
		if ((retVal = writeLBRLMepNum(lbChnl,INVALID_MEP_NUM,0)))
			return(retVal);
	}

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// enableLB(lbChnlMask);
// -----------------------------------------------------------------------------------------------------
// This function can be used to enabled multiple Loopback channels simultaneously
// by specifying a channel Enable mask. Each bit of the mask represents a channel.
// Bit 0 = channel 0, Bit 1 = channel 1 and so on. If the bit is set (1) in the mask
// then loopback will be enabled for that channel. If the bit is clr (0) in the mask
// then the loopback status will not be changed for that channel.
// =====================================================================================================
int enableLB(uint16_t lbChnlMask, uint8_t dirSel)
{
	int		k;
	uint32_t	enMask;
	uint32_t	data;
	int		retVal;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::enableLB : Enable LB channel in mask = %d in direction %d\n",lbChnlMask, dirSel);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	// NOTE: it's important that the RX side is configured before the Tx is enabled!

	// This is needed to update the LBR RAM Local MEP number values to
	// prevent the RX side finding multiple matches in the LBR RAM when LBRs are received
	enMask = 0;
	for (k=0;k<MAX_LB_CHANNELS_FOR_Y1564;k++)
	{
		if (lbChnlMask & (1<<k))
		{
			if (dirSel & MR_RX_ONLY)
			{
				if ((retVal = writeLBRLMepNum(k,lbSvcList[k].lMepNum,lbSvcList[k].pcp)))	// if enabled restore the correct lMepNum
					return(retVal);
			}

			// To enable a channel the resetStats and chnlReset bits must both
			// be set to 0. These are bits 0 and 1 of each nibble. Chnl 0 is nibble 0
			// Chnl 1 is nibble 1, etc.
			enMask |= (LB_RESET_REG_STATS_CLR_MASK | LB_RESET_REG_CHNL_DISABLE_MASK) << (k);
		}
	}

	if (dirSel & MR_TX_ONLY)
	{
		// just modify the channels selected by the mask.
		// non-masked channels should be left alone.
		mrHalRegRead(LB_RESET_REG_ADDR, &data);
		data &= ~enMask;
		mrHalRegWrite(LB_RESET_REG_ADDR,data);
	}

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// disableLB(lbChnlMask);
// -----------------------------------------------------------------------------------------------------
// This function can be used to disable multiple Loopback channels simultaneously
// by specifying a channel disable mask. Each bit of the mask represents a channel.
// Bit 0 = channel 0, Bit 1 = channel 1 and so on. If the bit is set (1) in the mask
// then loopback will be disabled for that channel. If the bit is clr (0) in the mask
// then the loopback status will not be changed for that channel.
// =====================================================================================================
int disableLB(uint16_t lbChnlMask, uint8_t dirSel)
{
	int		k;
	uint32_t	disMask;
	uint32_t	data;
	int		retVal;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::disableLB : Disable LB channel in mask = %d in direction %d\n",lbChnlMask, dirSel);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	// NOTE: it's important that the RX side is configured before the Tx is enabled!

	// This is needed to update the LBR RAM Local MEP number values to
	// prevent the RX side finding multiple matches in the LBR RAM when LBRs are received
	disMask = 0;
	for (k=0;k<MAX_LB_CHANNELS_FOR_Y1564;k++)
	{
		if (lbChnlMask & (1<<k))
		{
			if (dirSel & MR_RX_ONLY)
			{
				if ((retVal = writeLBRLMepNum(k,INVALID_MEP_NUM,0)))		// if disabled replace the entry with a NULL value
					return(retVal);
			}

			// To disable a channel the chnlReset bits must be set to 1.
			// This is bits 0 of each nibble. Chnl 0 is nibble 0
			// Chnl 1 is nibble 1, etc. i.e. bits 0,4,8,12,etc.
			disMask |= 0x1 << k;
		}
	}
	if (dirSel & MR_TX_ONLY)
	{
		// just modify the channels selected by the mask.
		// non-masked channels should be left alone.
		mrHalRegRead(LB_RESET_REG_ADDR, &data);
		data |= disMask;
		mrHalRegWrite(LB_RESET_REG_ADDR,data);
	}

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// clrLBTxStats
// -----------------------------------------------------------------------------------------------------
// This function will clear the Transmit Stats counter values for all loopback channels
// =====================================================================================================
int clrLBTxStats(void)
{
	uint32_t	data;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::clrLBTxStats : Clear LB Tx Statistics on all channels\n");
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	// To clear LB stats the control bit must be toggled Hi then Low
	mrHalRegRead(LB_RESET_REG_ADDR,&data);
	data |= 0x0000FF00;
	mrHalRegWrite(LB_RESET_REG_ADDR,data);
	data &= ~(0x0000FF00);
	mrHalRegWrite(LB_RESET_REG_ADDR,data);

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// clrLBRxStats
// -----------------------------------------------------------------------------------------------------
// This function will clear the Receive loopback stats counters for a specified channel
// and will initialise the 1st expected sequence number to the value specified.
// =====================================================================================================
int clrLBRxStats(uint8_t lbChnl,uint32_t seqNum)
{
	lbrRamEntry_t	lbrRamEntry;
	int				retVal;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::clrLBRxStats : Clear LB Rx Statistics on channel %d\n",lbChnl);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	if ((retVal = readLBRRam(lbChnl,&lbrRamEntry)))
		return(retVal);

	// initialise the LB RAMs....
	//lbrRamEntry.multicast = multiCast;
	lbrRamEntry.lastJitt = 0;
	lbrRamEntry.lastLat = 0 ;
	lbrRamEntry.expSN = seqNum;
	lbrRamEntry.numRxLbr = 0;
	lbrRamEntry.minJitt = 0;
	lbrRamEntry.maxJitt = 0x3FFFFFF;
	lbrRamEntry.sumJitLow = 0;
	lbrRamEntry.sumJitUpp = 0;
	lbrRamEntry.minLat = 0;
	lbrRamEntry.maxLat = 0x3FFFFFF;
	lbrRamEntry.sumLatLow = 0;
	lbrRamEntry.sumLatUpp = 0;

	if ((retVal = writeLBRRam(lbChnl,&lbrRamEntry)))
		return(retVal);

	// Clear any LB error Flags (timeout and seq error)
	clearLBErrors(lbChnl);

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// readLBStats
// -----------------------------------------------------------------------------------------------------
// This function will read all the relevant Loopback Stats for the specified channel.
// If the function returns without error the results can be accessed it the lbStats_t
// data structure pointed to by lbStats. If there is an error then the contents
// of lbStats are invalid.
// =====================================================================================================
int readLBStats(uint8_t lbChnl, lbStats_t *lbStats)
{
	lbrRamEntry_t	lbrRamEntry;
	uint32_t		txPktCount;
	uint32_t		data;
	double			ave;
	int				retVal;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::readLBStats : Read Statistic for LB channel %d\n",lbChnl);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	// Get the tx count from the Tx Template sequence number, but subtract 1 to get the count!
	if ((retVal = readSeqNumInTxTempl(lbChnl,&txPktCount,LB_TEMPL)))
		return(retVal);

	if ((retVal = readLBRRam(lbChnl,&lbrRamEntry)))
		return(retVal);

	// read the Error Register to see if any errors were detected
	mrHalRegRead(LBR_ERR_REG_ADDR,&data);

	lbStats->sequenceErr	 = (uint8_t) ((data >> lbChnl) & 0x1);
	lbStats->timeoutErr	 = (uint8_t) ((data >> (lbChnl+8)) & 0x1);
	// initialise the LB RAMs....
	lbStats->numTxPkts = txPktCount;					// Number of transmitted LBM messages
	lbStats->numTxAtRx = lbrRamEntry.expSN-1;			// The latest Tx pkt count (i.e. seq no.) received at RX
	lbStats->multicast = lbrRamEntry.multicast;
	lbStats->numRxPkts = lbrRamEntry.numRxLbr;			// Number of received LBR messages on this loopback channel
	lbStats->minLatency = lbrRamEntry.minLat;			// Measured minimum latency. This value is stored in terms of units of 256ns
	lbStats->maxLatency = lbrRamEntry.maxLat;			// Measured maximum latency. This value is stored in terms of units of 256ns
	lbStats->minJitter = lbrRamEntry.minJitt;			// Measured minimum latency. This value is stored in terms of units of 256ns
	lbStats->maxJitter = lbrRamEntry.maxJitt;			// Measured maximum latency. This value is stored in terms of units of 256ns
	// Calculate the average values
	ave = ((double)lbrRamEntry.sumLatUpp) * pow(2,32);
	ave += lbrRamEntry.sumLatLow;
	ave = ave * 100;
	ave = ave / lbrRamEntry.numRxLbr;
	lbStats->aveLatency = (uint32_t) ave;
	ave = ((double)lbrRamEntry.sumJitUpp) * pow(2,32);
	ave += lbrRamEntry.sumJitLow;
	ave = ave * 100;
	ave = ave / (lbrRamEntry.numRxLbr-1);
	lbStats->aveJitter = (uint32_t) ave;
//	lbStats->sumJitterLow = lbrRamEntry.sumJitLow;		// Accumulated sum of measured latencies for all received Sync LBR messages
//	lbStats->sumJitterUpp = lbrRamEntry.sumJitUpp;		// Accumulated sum of measured latencies for all received Sync LBR messages
//	lbStats->sumLatencyLow = lbrRamEntry.sumLatLow;		// Accumulated sum of measured latencies for all received Sync LBR messages
//	lbStats->sumLatencyUpp = lbrRamEntry.sumLatUpp;		// Accumulated sum of measured latencies for all received Sync LBR messages

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// resetLBSeqNum
// -----------------------------------------------------------------------------------------------------
// This function will reset the Tx and Rx sequence number for the specified LB
// channel to the value supplied.
// =====================================================================================================
int resetLBSeqNum(uint8_t lbChnl, uint32_t seqNum)
{
	int	retVal;

	#if defined(MINGOA_ENABLE_DEBUG_LOGGING) && ((defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL == MINGOA_DEBUG_LEVEL_SERVICES)) || (!defined(MINGOA_DEBUG_LEVEL_MATCH) && (MINGOA_DEBUG_LEVEL <= MINGOA_DEBUG_LEVEL_SERVICES)))
		sprintf(msgStr, "INFO::resetLBSeqNum : Reset the Sequence Number to %lu for LB channel %d\n",seqNum,lbChnl);
		writeLog(MINGOA_DEBUG_LEVEL_SERVICES,msgStr);
	#endif

	// Clear the Rx Sequence number
	if ((retVal = writeLBRSeqNum(lbChnl, seqNum)))
		return(retVal);

	if ((retVal = writeSeqNumInTxTempl(lbChnl,seqNum, LB_TEMPL)))
		return(retVal);

	return(NO_ERR);
}

// -----------------------------------------------------------------------------------------------------
// initLB
// -----------------------------------------------------------------------------------------------------
// This function is called to initialise the default values of context variables
// used to manage the LB services. It must be called during system initialisation.
// =====================================================================================================
int initLB(void)
{
	lbmStoreEntry_t lbmStoreEntry;
	int		k;

	lbmStoreEntry.counter = 0;
	lbmStoreEntry.lMepNum = INVALID_MEP_NUM;

	for (k=0;k<MAX_LB_CHANNELS_FOR_Y1564;k++)
	{
		lbSvcList[k].active 	= 0;
		lbSvcList[k].multicast 	= 0;
		lbSvcList[k].lMepNum 	= INVALID_MEP_NUM;
		lbSvcList[k].pcp		= 0;

		// The initial value of the sequence number should be 1
		// The addLBSvcToLMep function preserves the current value, only the user can
		// clear the value thereafter so the initial value must be set at power up...
		resetLBSeqNum(k,1);
	}

	// Initialise the LBM store counters to 0 - Used to count LBM received/LBRs transmitted
	for (k=0;k<MAX_LB_CHANNELS_FOR_Y1564;k++)
	{
		writeLBRLMepNum(k,INVALID_MEP_NUM,0);
		writeLbmStore(k,&lbmStoreEntry,wanPort);
		writeLbmStore(k,&lbmStoreEntry,lanPort);
	}

	return(NO_ERR);
}

bool isLbActive(uint8_t chnlNum)
{
	uint32_t	data;

	mrHalRegRead(LB_CONFIG_REG_ADDR,&data);
	return ((data & LB_CONFIG_REG_BURST_ACTIVE_MASK) == LB_CONFIG_REG_BURST_ACTIVE_MASK);
}
