/**
 * \file icss_dlr.c
 * \brief Main DLR Implementation
 *
 * Contains Interrupt Service Routines used to implement DLR Functionality
 *
 * \copyright Copyright (c) 2013 Texas Instruments Incorporated ALL RIGHTS RESERVED
 * \date May 23, 2013
 * \author a0131726@ti.com
 */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */
#ifndef USE_CPSW_DRIVER
#include <ti/sysbios/family/arm/a8/intcps/Hwi.h>
#include <ti/sysbios/interfaces/IHwi.h>
#include "icss_dlr.h"
#include "icss_eip_driver.h"
#include "icss_iSwitchDrv.h"
#include "icss_switch.h"
#include "icss_ethdriver.h"

/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */
/**Main DLR Object**/
dlrStruct dlrObj;

/**Timer Handle for Port 0 Beacon Timeout**/
Timer_Handle dlrTimer_PORT0;
/**Timer Handle for Port 1 Beacon Timeout**/
Timer_Handle dlrTimer_PORT1;

/**Clock handle for neighbor timeout timers**/
Clock_Handle dlrNeighborTimeoutClock[NUM_PORTS];

/**Buffer used for General DLR Messages **/
Uint8 dlrEmptyFrame[DEFAULT_DLR_PACKET_SIZE];

Uint8 DLR_NCREQ_MAC_ID[6] = {0x01, 0x21, 0x6C, 0x00, 0x00, 0x02};

/**Device IP*/
Uint32 deviceIP = 0;

/**Sequence ID as per DLR spec*/
Uint32 sequenceID = 0;


/**Learning table exception for MAC ID*/
exceptionList exclusionList;

#ifdef DLR_DEBUG
Uint8 sequenceOfEvents[MAX_EVENTS_CAPTURED] = {0};
Uint32 seqNumber = 0;
#endif

/*trace packet to find out if loop exists in network*/
Uint8  tempDLRFrame[MAXMTU];

/*trace packet to find out if loop exists in network*/
/**A trace packet used to find out network loops*/
Uint8 tracePkt[60] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
		0x45,0x00,0x00,0x2E,0x00,0x00,0x40,0x00,0x40,0x00,0x3A,0xD1};

Uint8 checkForLoop = 0;

volatile unsigned short regVal[31];
volatile unsigned short magicRegister;

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */
/*DLR Packet Generation Macros*/
#define addFrameOffset(src, offset) *(src + DLR_FRAME_TYPE_OFFSET) = offset;
#define addSourcePort(src, port) *(src + DLR_SOURCE_PORT_OFFSET) = port;
#define addReqSrcPort(src, port) *(src + DLR_REQ_SRC_PORT_OFFSET) = port;
#define addLinkStat(src, status) *(src + DLR_LINK_STATUS_OFFSET) = status;

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

/**
 * \name initDLR
 * \brief Initializes variables and timers & clocks, call once at the beginning
 * \param  none
 * \return none
 */
void initDLR(void) {

	/*Timer initialization variables*/
	Timer_Params timerParams;
	Clock_Params clockParams;
	Error_Block eb;

	/*Common frame header which is to be copied for every frame*/
	Uint8 dlrCommonFrameHeader[DLR_COMMON_FRAME_HEADER_SIZE] = {
		0x81,0x00,                              /*802.1 Tag Type*/
		0xE0,0x00,                              /*802.1 Tag Control*/
		0x80,0xE1,                              /*Ring Ethertype*/
		0x02,                                   /*Ring Subtype*/
		0x01                                    /*Ring Protocol Ver*/
	};

	/*Copy common DLR part*/
	initDLRFrameHeader(dlrEmptyFrame, dlrCommonFrameHeader);

	/*Initialize the state machine variables on DRAM*/
	dlrDRAMInit();

	/*Configure DM Timer 4 and 5*/
	DMTimer4ModuleClkConfig(); /*PORT 0 timer*/
	DMTimer5ModuleClkConfig(); /*PORT 1 timer*/
;
	/*Initialize DLR Object parameters*/
	dlrSetDefaultValue();

	/*Timer setup init*/
	Error_init(&eb);
	Timer_Params_init(&timerParams);

	/*This is irrelevant since timeout value is received from the supervisor*/
	timerParams.period = DEFAULT_BEACON_TIMEOUT_VARIABLE;
	timerParams.periodType = Timer_PeriodType_MICROSECS;
	timerParams.arg = 1;
	/*24 Mhz, care must be taken to ensure that this value
	 * is modified if the source clock frequency is modified */
	timerParams.extFreq.lo = DMTIMER_SRC_CLK_FREQ;
	timerParams.extFreq.hi = 0;
	timerParams.startMode = Timer_StartMode_USER;

	dlrTimer_PORT0 = Timer_create(DMTIMER4_ID, beaconTimerPort0, &timerParams,  &eb); /* DMTIMER4 */
	dlrTimer_PORT1 = Timer_create(DMTIMER5_ID, beaconTimerPort1, &timerParams,  &eb); /* DMTIMER5 */

	if ((dlrTimer_PORT0 == NULL)|| (dlrTimer_PORT1 == NULL)) {
		System_abort("Timer create failed");
	}

	/*Setup clock for Neighbor timeout check on port 0*/
	Error_init(&eb);
	Clock_Params_init(&clockParams);
	clockParams.period = DEFAULT_NEIGHBOR_TIMEOUT_INTERVAL;
	clockParams.startFlag = FALSE;	/*Manual start*/
	clockParams.arg = 0x5555;
	dlrNeighborTimeoutClock[HWPORT0] = Clock_create(neighborTimeoutISR0, DEFAULT_NEIGHBOR_TIMEOUT_INTERVAL, &clockParams, &eb);

	if (dlrNeighborTimeoutClock[HWPORT0] == NULL) {
		System_abort("Clock create failed");
	}

	/*set up clock for Neighbor timeout check on port 1*/
	Error_init(&eb);
	Clock_Params_init(&clockParams);
	clockParams.period = DEFAULT_NEIGHBOR_TIMEOUT_INTERVAL;
	clockParams.startFlag = FALSE;	/*Manual start*/
	clockParams.arg = 0x5555;
	dlrNeighborTimeoutClock[HWPORT1] = Clock_create(neighborTimeoutISR1, DEFAULT_NEIGHBOR_TIMEOUT_INTERVAL, &clockParams, &eb);

	if (dlrNeighborTimeoutClock[HWPORT1] == NULL) {
		System_abort("Clock create failed");
	}

	if (dlrIsrInit() != 0)
	{
		System_abort("DLR Interrupt create failed");
	}
	/*Populate MAC ID*/
	addMACID(dlrEmptyFrame + DLR_SRC_MAC_OFFSET, ifMAC);

 	/*Populate source MAC ID*/
 	addMACID(tracePkt + 6, ifMAC);

	/*Populate IP Address*/
	addWord(dlrEmptyFrame + DLR_SOURCE_IP_OFFSET, deviceIP);

	/*Register Learning callback*/
	RegisterLearningCallBack((icssCallBackRet_t)checkSupervisorException);
	/*Packet processing callback*/
	RegisterProtocolCallback((icssCallBack_t)processDLRFrame, NULL);


	/*Port 0 Link break callback */
	//RegisterPort0ISRCallback((icssCallBack_t)DlrPort0ProcessLinkBrk, NULL);
	/*Port 1 Link break callback */
	//RegisterPort1ISRCallback((icssCallBack_t)DlrPort1ProcessLinkBrk, NULL);

	RegisterPeriodicCallback((icssCallBack_t)periodicProcessing);

	/* Enabling the GPIO module. */
//	GPIOModuleEnable(SOC_GPIO_1_REGS);

	/* Configuring GPIO0[7] pin as an output pin. */
//	GPIODirModeSet(SOC_GPIO_1_REGS, 9, GPIO_DIR_OUTPUT);

}


/**
 * \name StartDLR
 * \brief Start DLR. Calling this enables DLR on the device
 * \param  none
 * \return none
 */
void StartDLR(void) {

	volatile Uint8 * dlrEnabledBitPtr;

	/*Enable DLR state machine on Firmware*/
	dlrEnabledBitPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ENABLED_OFFSET);
	*(dlrEnabledBitPtr) = DLR_TRUE;
}

/**
 * \name StopDLR
 * \brief Halt DLR. Calling this disables DLR on the device
 * \param  none
 * \return none
 */
void StopDLR(void) {

	volatile Uint8 * dlrEnabledBitPtr;

	/*Enable DLR state machine on Firmware*/
	dlrEnabledBitPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ENABLED_OFFSET);
	*(dlrEnabledBitPtr) = DLR_FALSE;
}


/**
 * \name DLR_Port0ISR
 * \brief Fast ISR for Port 0, bypasses the buffer copy and NDK
 * \param  none
 * \return none
 */
void DLR_Port0ISR(void* args) {

	volatile Uint32 *wordPtr;
	volatile Uint32 *portEvtsPtr;
	volatile Uint16 *commonEvtsPtr;
	volatile Uint32 *otherPortPtr;

	volatile Uint32 portEvtsFlag;
	volatile Uint16 commonEvtsFlag;
	volatile Uint32 regVal;
	volatile Uint32 otherPortFlag;

	activeSuperAddr *actSupAddrPtr = &(dlrObj.addr);

	portEvtsPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	portEvtsFlag = *(portEvtsPtr);

	commonEvtsPtr = (UInt16*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	commonEvtsFlag = *(commonEvtsPtr);

	/*when a new supervisor comes online, timers are restarted*/
	if(commonEvtsFlag & DLR_STOP_BOTH_TIMERS_MASK) {

#ifdef DLR_DEBUG
		genSeqOfEvents(STOP_BOTH_TIMERS_PORT0);
#endif
		//set the flag
		commonEvtsFlag |= (DLR_RESET_EVENT_OCCURED_MASK);
		*(commonEvtsPtr) = commonEvtsFlag;

		otherPortPtr = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
		otherPortFlag = *(otherPortPtr);

		//clear the flag
		commonEvtsFlag &= ~(DLR_STOP_BOTH_TIMERS_MASK);
		//write back the flag
		*(commonEvtsPtr) = commonEvtsFlag;
		//stop the timer on port1
		Timer_stop(dlrTimer_PORT0);
		//stop the timer on port1
		Timer_stop(dlrTimer_PORT1);

		//clear the flags
		otherPortFlag &= ~DLR_TIMER_RUNNING_MASK;
		*(otherPortPtr) = otherPortFlag;

		portEvtsFlag &= ~DLR_TIMER_RUNNING_MASK;

	}

	/*when the node receives a beacon with ring state set to ring fault*/
	if(portEvtsFlag & DLR_RING_FAULT_RCVD_MASK) {
#ifdef DLR_DEBUG
		genSeqOfEvents(RING_FAULT_RCVD_PORT0);
#endif
		otherPortPtr = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
		otherPortFlag = *(otherPortPtr);

		//stop the timer on port1
		Timer_stop(dlrTimer_PORT1);

		/*write back the flag*/
		otherPortFlag &= ~DLR_TIMER_RUNNING_MASK;
		*(otherPortPtr) = otherPortFlag;

		//flush learning table
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

		/*change CIP object variables*/
		dlrSwitchToFault();

		//clear the flag
		portEvtsFlag &= ~DLR_RING_FAULT_RCVD_MASK;

		/*write back the flag*/
		*(portEvtsPtr) = portEvtsFlag;
	}

	/*ring transitions from idle to fault*/
	if(commonEvtsFlag & DLR_RING_FAULT_TRANSITION_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(RING_FAULT_TRANSITION_PORT0);
#endif
		//clear the flag
		commonEvtsFlag &= ~(DLR_RING_FAULT_TRANSITION_MASK);
		//write back the flag
		*(commonEvtsPtr) = commonEvtsFlag;

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_BEACON_TIMEOUT_OFFSET);
		//read beacon timeout value
		dlrObj.supConfig.beaconTimeout = *(wordPtr);

		Timer_setPeriodMicroSecs(dlrTimer_PORT0, dlrObj.supConfig.beaconTimeout);
		Timer_setPeriodMicroSecs(dlrTimer_PORT1, dlrObj.supConfig.beaconTimeout);

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_BEACON_INTERVAL_OFFSET);
		//read beacon timeout value
		dlrObj.supConfig.beaconInterval = *(wordPtr);

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_VLAN_ID_SUPID_OFFSET);
		regVal = *(wordPtr);
		//read beacon timeout value
		dlrObj.supConfig.vLanId = (Uint16) (regVal & 0xffff);
		dlrObj.supConfig.supPrecedence = (Uint8) ((regVal & 0xff0000) >> 16);
		dlrObj.activeSuperPred = dlrObj.supConfig.supPrecedence;

		addVlanID(dlrEmptyFrame, dlrObj.supConfig.vLanId);

		/*update the current supervisor MAC id*/
		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ACTIVE_SUP_MAC_0123);
		getMACId((Uint8*)wordPtr, actSupAddrPtr->supMACAddress);
		addToExceptionList(actSupAddrPtr->supMACAddress);

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ACTIVE_SUP_IP_OFFSET);
		actSupAddrPtr->supIPAddress = convBigEndianToLittleEndianWord((Uint8 *)wordPtr);

		/*change CIP object variables*/
		dlrSwitchToFault();

		//flush learning table
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

	}

	/*ring transitions from fault to normal*/
	if(commonEvtsFlag & DLR_RING_NORMAL_TRANSITION_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(RING_NORMAL_TRANSITION_PORT0);
#endif
		/*flush learning table*/
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

		/*change CIP object variables*/
		dlrSwitchToNormal();

		/*clear the flag*/
		commonEvtsFlag &= ~(DLR_RING_NORMAL_TRANSITION_MASK);
		*(commonEvtsPtr) = commonEvtsFlag;
	}

	/*start the timer if the flag is set*/
	if(portEvtsFlag & DLR_START_TIMER_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(START_TIMER0);
#endif
		//start the timer on port0
		Timer_start(dlrTimer_PORT0);
		/*set the flag*/
		portEvtsFlag |= DLR_TIMER_RUNNING_MASK;
		/*clear the flag*/
		portEvtsFlag &= ~DLR_START_TIMER_MASK;
	}

	/*Process a neighbor check response for port 0*/
	if(portEvtsFlag & DLR_NCRES_RCVD_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(NCRES_RCVD_PORT0);
#endif
		/*stop the neighbor timeout clock for port 0*/
		Clock_stop(dlrNeighborTimeoutClock[HWPORT0]);
		portEvtsFlag &= ~(DLR_NCRES_RCVD_MASK);
	}

	/*Process a locate fault response*/
	if(portEvtsFlag & DLR_LOCFAULT_RCVD_MASK) {

#ifdef DLR_DEBUG
	genSeqOfEvents(LOCFAULT_RCVD_PORT0);
#endif
		/*Both links are up, send neighbor request on both frames*/
		if(GetLinkStatus(DLR_PORT1)) {

			genNCReqFrame(dlrEmptyFrame, DLR_PORT0);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT0, 1, DEFAULT_DLR_PACKET_SIZE);
			Clock_start(dlrNeighborTimeoutClock[HWPORT0]);

			genNCReqFrame(dlrEmptyFrame, DLR_PORT1);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT1, 1, DEFAULT_DLR_PACKET_SIZE);
			Clock_start(dlrNeighborTimeoutClock[HWPORT1]);


		} else { /*Send a link status to supervisor*/
			/*Since the message has come to port 0 hence port 1 is down*/
			genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT0, IS_A_LINK_STATUS_FRAME, DLR_PORT1_FAIL);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT0, 1, DEFAULT_DLR_PACKET_SIZE);

		}

		/*clear the flag*/
		portEvtsFlag &= ~(DLR_LOCFAULT_RCVD_MASK);
	}

	/*write back the flag*/
	*(portEvtsPtr) = portEvtsFlag;

	/*clear int 22 (write 1 to bit number 22)*/
	CLR_INT23
}

/**
 * \name DLR_Port1ISR
 * \brief ISR for Port 1, bypasses the buffer copy and NDK
 * \param  none
 * \return none
 */
void DLR_Port1ISR(void* args) {

	volatile Uint32 *wordPtr;
	volatile Uint32 *portEvtsPtr;
	volatile Uint16 *commonEvtsPtr;
	volatile Uint32 *otherPortPtr;

	volatile Uint32 portEvtsFlag;
	volatile Uint16 commonEvtsFlag;
	volatile Uint32 regVal;
	volatile Uint32 otherPortFlag;

	portEvtsPtr = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	portEvtsFlag = *(portEvtsPtr);

	commonEvtsPtr = (UInt16*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	commonEvtsFlag = *(commonEvtsPtr);

	activeSuperAddr *actSupAddrPtr = &(dlrObj.addr);

	/*when a new supervisor comes online, timers are restarted*/
	if(commonEvtsFlag & DLR_STOP_BOTH_TIMERS_MASK) {

#ifdef DLR_DEBUG
		genSeqOfEvents(STOP_BOTH_TIMERS_PORT1);
#endif
		//set the flag
		commonEvtsFlag |= (DLR_RESET_EVENT_OCCURED_MASK);
		*(commonEvtsPtr) = commonEvtsFlag;

		otherPortPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
		otherPortFlag = *(otherPortPtr);

		//clear the flag
		commonEvtsFlag &= ~(DLR_STOP_BOTH_TIMERS_MASK);
		//write back the flag
		*(commonEvtsPtr) = commonEvtsFlag;
		//stop the timer on port1
		Timer_stop(dlrTimer_PORT0);
		//stop the timer on port1
		Timer_stop(dlrTimer_PORT1);

		otherPortFlag &= ~DLR_TIMER_RUNNING_MASK;
		*(otherPortPtr) = otherPortFlag;

		portEvtsFlag &= ~DLR_TIMER_RUNNING_MASK;

		/*write back the flag*/
		*(portEvtsPtr) = portEvtsFlag;

	}

	/*when the node receives a beacon with ring state set to ring fault*/
	if(portEvtsFlag & DLR_RING_FAULT_RCVD_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(RING_FAULT_RCVD_PORT1);
#endif
		otherPortPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
		otherPortFlag = *(otherPortPtr);

		//stop the timer on port0
		Timer_stop(dlrTimer_PORT0);

		/*write back the flag*/
		otherPortFlag &= ~DLR_TIMER_RUNNING_MASK;
		*(otherPortPtr) = otherPortFlag;

		//flush learning table
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

		/*change CIP object variables*/
		dlrSwitchToFault();

		/*clear the flag*/
		portEvtsFlag &= ~DLR_RING_FAULT_RCVD_MASK;
	}

	/*ring transitions from idle to fault*/
	if(commonEvtsFlag & DLR_RING_FAULT_TRANSITION_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(RING_FAULT_TRANSITION_PORT1);
#endif
		//clear the flag
		commonEvtsFlag &= ~(DLR_RING_FAULT_TRANSITION_MASK);
		*(commonEvtsPtr) = commonEvtsFlag;

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_BEACON_TIMEOUT_OFFSET);
		//read beacon timeout value
		dlrObj.supConfig.beaconTimeout = *(wordPtr);

		Timer_setPeriodMicroSecs(dlrTimer_PORT0, dlrObj.supConfig.beaconTimeout);
		Timer_setPeriodMicroSecs(dlrTimer_PORT1, dlrObj.supConfig.beaconTimeout);

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_BEACON_INTERVAL_OFFSET);
		//read beacon timeout value
		dlrObj.supConfig.beaconInterval = *(wordPtr);

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_VLAN_ID_SUPID_OFFSET);
		regVal = *(wordPtr);
		//read beacon timeout value
		dlrObj.supConfig.vLanId = (Uint16) (regVal & 0xffff);
		dlrObj.supConfig.supPrecedence = (Uint8) ((regVal & 0xff0000) >> 16);
		dlrObj.activeSuperPred = dlrObj.supConfig.supPrecedence;

		addVlanID(dlrEmptyFrame, dlrObj.supConfig.vLanId);

		/*update the current supervisor MAC id*/
		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ACTIVE_SUP_MAC_0123);
		getMACId((Uint8*)wordPtr, actSupAddrPtr->supMACAddress);
		addToExceptionList(actSupAddrPtr->supMACAddress);

		wordPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ACTIVE_SUP_IP_OFFSET);
		actSupAddrPtr->supIPAddress = convBigEndianToLittleEndianWord((Uint8*)wordPtr);

		/*change CIP object variables*/
		dlrSwitchToFault();

		//flush learning table
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

	}

	/*ring transitions from fault to normal*/
	if(commonEvtsFlag & DLR_RING_NORMAL_TRANSITION_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(RING_NORMAL_TRANSITION_PORT1);
#endif
		//clear the flag
		commonEvtsFlag &= ~(DLR_RING_NORMAL_TRANSITION_MASK);
		*(commonEvtsPtr) = commonEvtsFlag;

		/*change CIP object variables*/
		dlrSwitchToNormal();

		//flush learning table
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

	}

	/*start the timer if the flag is set*/
	if(portEvtsFlag & DLR_START_TIMER_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(START_TIMER1);
#endif
		//start the timer on port0
		Timer_start(dlrTimer_PORT1);
		//set the flag
		portEvtsFlag |= DLR_TIMER_RUNNING_MASK;
		//clear the flag
		portEvtsFlag &= ~DLR_START_TIMER_MASK;
	}

	/*Process a neighbor check response for port 0*/
	if(portEvtsFlag & DLR_NCRES_RCVD_MASK) {
#ifdef DLR_DEBUG
	genSeqOfEvents(NCRES_RCVD_PORT1);
#endif
		/*stop the neighbor timeout clock for port 0*/
		Clock_stop(dlrNeighborTimeoutClock[HWPORT1]);
		portEvtsFlag &= ~(DLR_NCRES_RCVD_MASK);
	}

	/*Process a locate fault response*/
	if(portEvtsFlag & DLR_LOCFAULT_RCVD_MASK) {

#ifdef DLR_DEBUG
	genSeqOfEvents(LOCFAULT_RCVD_PORT1);
#endif
		/*Both links are up, send neighbor request on both frames*/
		if(GetLinkStatus(DLR_PORT0)) {

			genNCReqFrame(dlrEmptyFrame, DLR_PORT0);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT0, 1, DEFAULT_DLR_PACKET_SIZE);
			Clock_start(dlrNeighborTimeoutClock[HWPORT0]);

			genNCReqFrame(dlrEmptyFrame, DLR_PORT1);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT1, 1, DEFAULT_DLR_PACKET_SIZE);
			Clock_start(dlrNeighborTimeoutClock[HWPORT1]);

		} else {
			/*Since the message has come to port 1 hence port 0 is down*/
			genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT1, IS_A_LINK_STATUS_FRAME, DLR_PORT0_FAIL);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT1, 1, DEFAULT_DLR_PACKET_SIZE);

		}

		//clear the flag
		portEvtsFlag &= ~(DLR_LOCFAULT_RCVD_MASK);
	}

	//write back the flag
	*(portEvtsPtr) = portEvtsFlag;

	//clear int 23, write 1 to bit number 23

	CLR_INT24
}


/**
 * \name beaconTimerPort0
 * \brief beacon timeout ISR for port0
 * \param  none
 * \return none
 */
void beaconTimerPort0(void) {

	volatile Uint32 *stateMachinePtr;
	volatile Uint32 *commonEvtsPtr;
	volatile Uint32 *portEvtsPtr;

	volatile Uint8 lastPortBcnRcvd;
	volatile Uint8 node_state;

	volatile Uint32 portEvtsFlag;
	volatile Uint32 commonEvtsFlag;
	volatile Uint32 stateMachine;

	static Uint8 ISRcountPort0 = 0;

	portEvtsPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	portEvtsFlag = *(portEvtsPtr);

	/*Find out if Beacon ISR's are stalling the Host
	 * Stop the timer if that's the case*/
	if(ISRcountPort0++ > BEACON_CPU_STALL_THRESHOLD) {
		ISRcountPort0 = 0;
		Timer_stop(dlrTimer_PORT0);

		/*clear timer flag*/
		portEvtsFlag &= ~DLR_TIMER_RUNNING_MASK;
		*(portEvtsPtr) = portEvtsFlag;

#ifdef DLR_DEBUG
	genSeqOfEvents(PORT0_BEACON_STALL);
#endif

		return;
	}

	portEvtsPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	portEvtsFlag = *(portEvtsPtr);

	commonEvtsPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	commonEvtsFlag = *(commonEvtsPtr);

	stateMachinePtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_STATE_MACHINE_OFFSET);
	stateMachine = *(stateMachinePtr);

	node_state = stateMachine & 0xff;
	lastPortBcnRcvd = (Uint8) ((stateMachine >> 8) & 0xff);

#ifdef DLR_DEBUG
	genSeqOfEvents(BEACON0_MISSED);
#endif

	if(NODE_FAULT == node_state) {
		if(lastPortBcnRcvd == DLR_PORT0) {
#ifdef DLR_DEBUG
	genSeqOfEvents(BEACON0_MISSED_FAULT);
#endif
			/*Stop neighbor checkout timers*/
			Clock_stop(dlrNeighborTimeoutClock[HWPORT0]);
			Clock_stop(dlrNeighborTimeoutClock[HWPORT1]);

			/*Transition to idle*/
			dlrResetStateMachine();
		}

	}

	if(NODE_NORMAL == node_state) {
#ifdef DLR_DEBUG
	genSeqOfEvents(BEACON0_MISSED_NORMAL);
#endif
		lastPortBcnRcvd = DLR_PORT1;
		/*transition to fault*/
		node_state = NODE_FAULT;

		commonEvtsFlag |= DLR_PORT1_BEACON_RCVD_MASK;
		commonEvtsFlag &= ~DLR_PORT0_BEACON_RCVD_MASK;

		stateMachine = 0;
		stateMachine |= (node_state & 0xff);
		stateMachine |= DLR_RING_FAULT_MASK;
		stateMachine |= ((lastPortBcnRcvd & 0xff) << 8);

		/*write back the flag*/
		*(stateMachinePtr) = stateMachine;
		*(commonEvtsPtr) = commonEvtsFlag;

		/*change CIP object variables*/
		dlrSwitchToFault();

		/*flush the learning table*/
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

	}

}

/**
 * \name beaconTimerPort1
 * \brief beacon timeout ISR for port1
 * \param  none
 * \return none
 */
void beaconTimerPort1(void) {

	volatile Uint32 *stateMachinePtr;
	volatile Uint32 *commonEvtsPtr;
	volatile Uint32 *portEvtsPtr;

	volatile Uint8 lastPortBcnRcvd;
	volatile Uint8 node_state;

	volatile Uint32 commonEvtsFlag;
	volatile Uint32 stateMachine;
	volatile Uint32 portEvtsFlag;

	static Uint8 ISRcountPort1 = 0;

	portEvtsPtr = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	portEvtsFlag = *(portEvtsPtr);

	/*Find out if Beacon ISR's are stalling the Host
	 * Stop the timer if that's the case*/
	if(ISRcountPort1++ > BEACON_CPU_STALL_THRESHOLD) {

		ISRcountPort1 = 0;
		Timer_stop(dlrTimer_PORT1);
		/*clear timer flag*/
		portEvtsFlag &= ~DLR_TIMER_RUNNING_MASK;
		*(portEvtsPtr) = portEvtsFlag;

#ifdef DLR_DEBUG
	genSeqOfEvents(PORT1_BEACON_STALL);
#endif

		return;
	}

	commonEvtsPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	commonEvtsFlag = *(commonEvtsPtr);

	stateMachinePtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_STATE_MACHINE_OFFSET);
	stateMachine = *(stateMachinePtr);

	node_state = stateMachine & 0xff;
	lastPortBcnRcvd = (Uint8) ((stateMachine >> 8) & 0xff);

#ifdef DLR_DEBUG
	genSeqOfEvents(BEACON1_MISSED);
#endif

	if(NODE_FAULT == node_state) {
		if(lastPortBcnRcvd == DLR_PORT1) {
#ifdef DLR_DEBUG
	genSeqOfEvents(BEACON1_MISSED_FAULT);
#endif
			/*Stop neighbor checkout timers*/
			Clock_stop(dlrNeighborTimeoutClock[HWPORT0]);
			Clock_stop(dlrNeighborTimeoutClock[HWPORT1]);
			/*Transition to idle*/
			dlrResetStateMachine();
		}

	}

	if(NODE_NORMAL == node_state) {
#ifdef DLR_DEBUG
	genSeqOfEvents(BEACON1_MISSED_NORMAL);
#endif
		lastPortBcnRcvd = DLR_PORT0;
		/*transition to fault*/
		node_state = NODE_FAULT;

		commonEvtsFlag |= DLR_PORT0_BEACON_RCVD_MASK;
		commonEvtsFlag &= ~DLR_PORT1_BEACON_RCVD_MASK;

		stateMachine = 0;
		stateMachine |= (node_state & 0xff);
		stateMachine |= DLR_RING_FAULT_MASK;
		stateMachine |= ((lastPortBcnRcvd & 0xff) << 8);

		/*write back the flag*/
		*(stateMachinePtr) = stateMachine;
		*(commonEvtsPtr) = commonEvtsFlag;

		/*change CIP object variables*/
		dlrSwitchToFault();

		/*flush the learning table*/
		purgeTable(HWPORT0);
		purgeTable(HWPORT1);

	}

}

/**
 * \name neighborTimeoutISR0
 * \brief ISR for Neighbor timeout timer for port 0
 * \param  none
 * \return none
 */
void neighborTimeoutISR0(void) {
	volatile Uint8 *bytePtr = (Uint8*)(PRU0_DRAM_BASE_ADDRESS + DLR_NCREQ_NUM_RETRIES_OFFSET);
	volatile Uint32 *stateMachinePtr;

	/*Number of times slave will ping it's neighbor. This is set in PRU*/
	volatile Uint8 numRetries;
	volatile Uint32 stateMachine;

	/*Load the state machine*/
	stateMachinePtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_STATE_MACHINE_OFFSET);
	stateMachine = *(stateMachinePtr);

	/*Don't run neighbor check if state has switched to normal*/
	if((stateMachine & 0xff) == DLR_NORMAL_STATE_VAL) {
		*(bytePtr) = 0;
		/*stop the timer*/
		Clock_stop(dlrNeighborTimeoutClock[HWPORT0]);
	}

	numRetries = *(bytePtr);

	if(numRetries < MAX_NUM_RETRIES) {
#ifdef DLR_DEBUG
	genSeqOfEvents(NEIGHBOR_TIMEOUT_PORT0_RETRY);
#endif
		/*send a Neighbor check request again*/
		genNCReqFrame(dlrEmptyFrame, DLR_PORT0);
		TxPacketEnqueue(dlrEmptyFrame, DLR_PORT0, 1, DEFAULT_DLR_PACKET_SIZE);

		numRetries++;
		*(bytePtr) = numRetries;

	} else {

#ifdef DLR_DEBUG
	genSeqOfEvents(NEIGHBOR_TIMEOUT_PORT0_MAX);
#endif
		/*The neighbor has failed to respond,
		 * send a neighbor status frame to the host on the other port
		 */
		genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT1, IS_A_NEIGHBOR_STAT_FRAME, DLR_PORT0_FAIL);
		TxPacketEnqueue(dlrEmptyFrame, DLR_PORT1, 1, DEFAULT_DLR_PACKET_SIZE);

		/*stop the timer*/
		Clock_stop(dlrNeighborTimeoutClock[HWPORT0]);

		*(bytePtr) = 0;
	}

}

/**
 * \name neighborTimeoutISR1
 * \brief ISR for Neighbor timeout timer for port 1
 * \param  none
 * \return none
 */
void neighborTimeoutISR1() {
	volatile Uint8 *bytePtr = (Uint8*)(PRU1_DRAM_BASE_ADDRESS + DLR_NCREQ_NUM_RETRIES_OFFSET);
	volatile Uint32 *stateMachinePtr;

	volatile Uint8 numRetries;
	volatile Uint32 stateMachine;

	/*Load the state machine*/
	stateMachinePtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_STATE_MACHINE_OFFSET);
	stateMachine = *(stateMachinePtr);

	/*Don't run neighbor check if state has switched to normal*/
	if((stateMachine & 0xff) == DLR_NORMAL_STATE_VAL) {
		*(bytePtr) = 0;
		/*stop the timer*/
		Clock_stop(dlrNeighborTimeoutClock[HWPORT1]);
	}

	numRetries = *(bytePtr);

	if(numRetries < MAX_NUM_RETRIES) {

#ifdef DLR_DEBUG
	genSeqOfEvents(NEIGHBOR_TIMEOUT_PORT1_RETRY);
#endif
		/*send a Neighbor check request again*/
		genNCReqFrame(dlrEmptyFrame, DLR_PORT1);
		TxPacketEnqueue(dlrEmptyFrame, DLR_PORT1, 1, DEFAULT_DLR_PACKET_SIZE);

		numRetries++;
		*(bytePtr) = numRetries;
	} else {

#ifdef DLR_DEBUG
	genSeqOfEvents(NEIGHBOR_TIMEOUT_PORT1_MAX);
#endif
		/*The neighbor has failed to respond,
		 * send a neighbor status frame to the host on the other port
		 */
		genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT0, IS_A_NEIGHBOR_STAT_FRAME, DLR_PORT1_FAIL);
		TxPacketEnqueue(dlrEmptyFrame, DLR_PORT0, 1, DEFAULT_DLR_PACKET_SIZE);

		/*stop the timer*/
		Clock_stop(dlrNeighborTimeoutClock[HWPORT1]);
		*(bytePtr) = 0;
	}
}

/**
 * \name processDLRFrame
 * \brief Processes a sign on and Neighbor check request frame
 * \param startOfPktPtr pointer to bytestream
 * \param size size of the packet
 * \param portNum port number on which the packet was received
 * \return none
 */
void processDLRFrame(Uint32* queue_number) {

	Uint16 size;
	Uint32 portNum;
	Int32 port;
	Int32 more;

	size = RxPktGet((Uint32)tempDLRFrame, *queue_number, &port, &more);

	portNum = (Uint32)port-1;

	volatile Uint8 *signOnRcvdStatus;
	volatile Uint8 signOnRcvdFlag;

	volatile Uint32 *portEvtsPtr;
	volatile Uint32 portEvtsFlag;

	/*Number of slaves in the network*/
	volatile Uint16 numNodes;
	volatile Uint16 offset;

	volatile Uint32 sequenceId;

	Uint8 *dlrSrc = (Uint8*)tempDLRFrame;

	signOnRcvdStatus = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_SIGNON_PKT_RCVD_OFFSET);
	signOnRcvdFlag = *(signOnRcvdStatus);

	if(portNum) {
		portEvtsPtr = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
		portEvtsFlag = *(portEvtsPtr);
	} else {
		portEvtsPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
		portEvtsFlag = *(portEvtsPtr);
	}

	/*Process a neighbor check request*/
	if(portEvtsFlag & DLR_NCREQ_RCVD_MASK) {

		volatile Uint32 sequenceId;
		volatile Uint8 reqSrcPort;
#ifdef DLR_DEBUG
	if(portNum) {
		genSeqOfEvents(NCREQ_RCVD_PORT1);
	} else {
		genSeqOfEvents(NCREQ_RCVD_PORT0);
	}
#endif
		sequenceId = convBigEndianToLittleEndianWord((Uint8*)(dlrSrc + DLR_SEQUENCE_ID_OFFSET));

		reqSrcPort = *(dlrSrc + DLR_SOURCE_PORT_OFFSET);

		/*generate the neighbor check response frame*/
		genNCResFrame(dlrEmptyFrame, portNum + 1, reqSrcPort, sequenceId);
		/*send the neighbor check response frame*/
		TxPacketEnqueue(dlrEmptyFrame, portNum + 1, 1, DEFAULT_DLR_PACKET_SIZE);

		/*clear the flag*/
		portEvtsFlag &= ~(DLR_NCREQ_RCVD_MASK);
		*(portEvtsPtr) = portEvtsFlag;
	}

	if(signOnRcvdFlag != DLR_TRUE) {
		return;

	} else {
		/*clear the flag*/
		signOnRcvdFlag =  DLR_FALSE;
		*(signOnRcvdStatus) = signOnRcvdFlag;
	}

	activeSuperAddr *actSupAddrPtr = &(dlrObj.addr);

#ifdef DLR_DEBUG
	genSeqOfEvents(COMPLETE_SIGNON_FRAME_RCVD);
#endif

	/*send on the other port*/
	portNum++;
	portNum = ~portNum;
	portNum = portNum & 0x3;

	/*check if the size exceeds max size
	 * If it does then send the frame directly to host*/
	if(size > DLR_SIGNON_FRAME_SIZE) {
		/*modify the src and destination mac address field*/
		/*Add the source MAC id to DLR packet*/
		addMACID(dlrSrc + DLR_SRC_MAC_OFFSET, ifMAC);
		/*This packet is meant for the ring supervisor*/
		addMACID(dlrSrc, actSupAddrPtr->supMACAddress);
		TxPacketEnqueue(dlrSrc, portNum, 1, size);

	} else {

		/*Modify the source MAC Id field*/
		addMACID(dlrSrc+6, ifMAC);

		/*get a list of all devices*/
		numNodes = convBigEndianToLittleEndianHalfWord(dlrSrc + DLR_SIGNON_NUM_NODES_OFFSET);
		/*jump straight to where new mac id and ip address needs to be added*/
		offset = (DLR_SIGNON_SUP_MAC_ADD_OFFSET + (numNodes * 10));

		numNodes++;
		/*Increment the number of nodes in the network*/
		addSignOnNumNodes(dlrSrc, numNodes);

		dlrSrc += offset;
		/*append the device's own mac id and IP address*/
		addMACID(dlrSrc, ifMAC);
		addWord(dlrSrc + 6, deviceIP);
		offset += 10;

		if(offset < 60) {
			TxPacketEnqueue(tempDLRFrame, portNum, 1, 60);
		} else {
			TxPacketEnqueue(tempDLRFrame, portNum, 1, offset);
		}

	}
}

/**
 * \name DlrPort0ProcessLinkBrk
 * \brief Process DLR state machine in the event of a link break on Port0
 * \param none
 * \return none
 */
void DlrPort0ProcessLinkBrk(void) {

	volatile Uint32 *stateMachinePtr;
	volatile Uint32 *port0EvtsPtr;
	volatile Uint32 *commonEvtsPtr;

	volatile Uint32 stateMachine;
	volatile Uint32 port0EvtsFlag;
	volatile Uint32 commonEvtsFlag;

	volatile Uint8 node_state;
	volatile Uint8 lastPortBcnRcvd;
	volatile Uint8 ifLoopExists;

	volatile Uint8 *loopDetectedPtr;

	if (NODE_IDLE == dlrObj.SMVariables.node_state) {
		/*If link broken*/
		if(!GetLinkStatus(HWPORT0+1)) {
			/*Since there is a link break update loop in network status*/
			loopDetectedPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_LOOP_DETECTED_OFFSET);
			*(loopDetectedPtr) =  FALSE_VAL;
			dlrObj.SMVariables.status = NORMAL_STAT;
			checkForLoop = DLR_FALSE;

		} else {
			if(GetLinkStatus(HWPORT1+1)) {
				checkForLoop = DLR_TRUE;
			} else {
				checkForLoop = DLR_FALSE;
			}
		}

		return;
	}

	/*Load port 0 events flag*/
	port0EvtsPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	port0EvtsFlag = *(port0EvtsPtr);

	/*Load the state machine*/
	stateMachinePtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_STATE_MACHINE_OFFSET);
	stateMachine = *(stateMachinePtr);

	/*Load common events flag*/
	commonEvtsPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	commonEvtsFlag = *(commonEvtsPtr);

	node_state = stateMachine & 0xff;
	lastPortBcnRcvd = (Uint8) ((stateMachine >> 8) & 0xff);

	if(DLR_FALSE == GetLinkStatus(HWPORT0+1)) { /*Link 0 down*/

		/*In case state machine is still running with both links disabled*/
		if(DLR_FALSE == GetLinkStatus(HWPORT1+1)) {
			dlrResetStateMachine();
			return;
		}
		/*Fault state*/
		if(NODE_FAULT == node_state) {
#ifdef DLR_DEBUG
		genSeqOfEvents(LINK1_FAULT_BREAK);
#endif
			/*check last port on which beacon was received*/
			if(lastPortBcnRcvd == DLR_PORT0) {
				/*Stop neighbor checkout timers*/
				Clock_stop(dlrNeighborTimeoutClock[HWPORT0]);
				Clock_stop(dlrNeighborTimeoutClock[HWPORT1]);

				/*if it's the same port then go to idle state*/
				dlrResetStateMachine();
			} else {
				/*send a link status message to active
				 * ring supervisor on link 1 that link 0 has failed */
				genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT1, IS_A_LINK_STATUS_FRAME, DLR_PORT0_FAIL);
				TxPacketEnqueue(dlrEmptyFrame, DLR_PORT1, 1, DEFAULT_DLR_PACKET_SIZE);
			}

		}

		/*Normal state*/
		if (NODE_NORMAL == node_state) { //normal state
#ifdef DLR_DEBUG
genSeqOfEvents(LINK1_NORMAL_BREAK);
#endif
			/*transition to fault*/
			node_state = NODE_FAULT;
			Timer_stop(dlrTimer_PORT0);

			port0EvtsFlag &= ~DLR_TIMER_RUNNING_MASK;
			*(port0EvtsPtr) = port0EvtsFlag;

			//flush learning table
			purgeTable(HWPORT0);
			purgeTable(HWPORT1);
			stateMachine = 0;
			lastPortBcnRcvd = DLR_PORT1;
			stateMachine |= (node_state & 0xff);
			stateMachine |= DLR_RING_FAULT_MASK;
			stateMachine |= (lastPortBcnRcvd << 8);
			*(stateMachinePtr) = stateMachine;

			commonEvtsFlag |= DLR_PORT1_BEACON_RCVD_MASK;
			commonEvtsFlag &= ~DLR_PORT0_BEACON_RCVD_MASK;

			*(commonEvtsPtr) = commonEvtsFlag;

			/*send link status frame to active ring supervisor*/
			genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT1, IS_A_LINK_STATUS_FRAME, DLR_PORT0_FAIL);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT1, 1, DEFAULT_DLR_PACKET_SIZE);

			/*change CIP object variables*/
			dlrSwitchToFault();
		}

	}

}
/**
 * \name DlrPort1ProcessLinkBrk
 * \brief Process DLR state machine in the event of a link break on Port1
 * \param none
 * \return none
 */
void DlrPort1ProcessLinkBrk(void) {

	volatile Uint32 *stateMachinePtr;
	volatile Uint32 *port1EvtsPtr;
	volatile Uint32 *commonEvtsPtr;

	volatile Uint32 stateMachine;
	volatile Uint32 port1EvtsFlag;
	volatile Uint32 commonEvtsFlag;

	volatile Uint8 node_state;
	volatile Uint8 lastPortBcnRcvd;

	volatile Uint8 ifLoopExists;

	volatile Uint8 *loopDetectedPtr;

	if (NODE_IDLE == dlrObj.SMVariables.node_state) {
		/*If link broken*/
		if(!GetLinkStatus(HWPORT1+1)) {
			/*Since there is a link break update loop in network status*/
			loopDetectedPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_LOOP_DETECTED_OFFSET);
			*(loopDetectedPtr) =  FALSE_VAL;
			dlrObj.SMVariables.status = NORMAL_STAT;
			checkForLoop = DLR_FALSE;

		} else {
			if(GetLinkStatus(HWPORT0+1)) {
				checkForLoop = DLR_TRUE;
			} else {
				checkForLoop = DLR_FALSE;
			}
		}

		return;
	}

	/*Load port 0 events flag*/
	port1EvtsPtr = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	port1EvtsFlag = *(port1EvtsPtr);

	/*Load the state machine*/
	stateMachinePtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_STATE_MACHINE_OFFSET);
	stateMachine = *(stateMachinePtr);

	/*Load common events flag*/
	commonEvtsPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	commonEvtsFlag = *(commonEvtsPtr);

	node_state = stateMachine & 0xff;
	lastPortBcnRcvd = (Uint8) ((stateMachine >> 8) & 0xff);

	if(DLR_FALSE == GetLinkStatus(HWPORT1+1)){	/*link 1 down*/

		/*In case state machine is still running with both links disabled*/
		if(DLR_FALSE == GetLinkStatus(HWPORT0+1)) {
			dlrResetStateMachine();
			return;
		}

		/*Fault state*/
		if(NODE_FAULT == node_state) {
#ifdef DLR_DEBUG
genSeqOfEvents(LINK2_FAULT_BREAK);
#endif
			/*check last port on which beacon was received*/
			if(lastPortBcnRcvd == DLR_PORT1) {
				/*Stop neighbor checkout timers*/
				Clock_stop(dlrNeighborTimeoutClock[HWPORT0]);
				Clock_stop(dlrNeighborTimeoutClock[HWPORT1]);

				/*if it's the same port then go to idle state*/
				dlrResetStateMachine();
			} else {
				/*send a link status message to active
				 * ring supervisor on link 0 that link 1 has failed */
				genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT0, IS_A_LINK_STATUS_FRAME, DLR_PORT1_FAIL);
				TxPacketEnqueue(dlrEmptyFrame, DLR_PORT0, 1, DEFAULT_DLR_PACKET_SIZE);
			}
		}

		/*Normal state*/
		if(NODE_NORMAL == node_state) {
#ifdef DLR_DEBUG
genSeqOfEvents(LINK2_NORMAL_BREAK);
#endif
			/*set to fault*/
			node_state = NODE_FAULT;
			Timer_stop(dlrTimer_PORT1);

			port1EvtsFlag &= ~DLR_TIMER_RUNNING_MASK;
			*(port1EvtsPtr) = port1EvtsFlag;

			//flush learning table
			purgeTable(HWPORT0);
			purgeTable(HWPORT1);
			stateMachine = 0;
			lastPortBcnRcvd = DLR_PORT0;
			stateMachine |= (node_state & 0xff);
			stateMachine |= DLR_RING_FAULT_MASK;
			stateMachine |= (lastPortBcnRcvd << 8);
			*(stateMachinePtr) = stateMachine;

			commonEvtsFlag |= DLR_PORT1_BEACON_RCVD_MASK;
			commonEvtsFlag &= ~DLR_PORT0_BEACON_RCVD_MASK;

			*(commonEvtsPtr) = commonEvtsFlag;

			/*send link status frame to active ring supervisor*/
			genNeighborLinkStatFrame(dlrEmptyFrame, DLR_PORT0, IS_A_LINK_STATUS_FRAME, DLR_PORT1_FAIL);
			TxPacketEnqueue(dlrEmptyFrame, DLR_PORT0, 1, DEFAULT_DLR_PACKET_SIZE);

			/*change CIP object variables*/
			dlrSwitchToFault();
		}

	}

}

/**
 * \name dlrDRAMInit
 * \brief Initialize DLR control variables in the DRAM
 * This is defined separately because this needs to be called as part of
 * the switch initialization process after PRU code has been loaded
 * \param  none
 * \return none
 */
void dlrDRAMInit(void) {

	volatile Uint32 *SMPointer;
	volatile Uint32 *commonEventsPtr;
	volatile Uint32 *port0EventsPtr;
	volatile Uint32 *port1EventsPtr;
	volatile Uint8 *signOnRcvdStatus;
	volatile Uint32 *activeSupMacAddr;

	/*read the DLR stats flag*/
	signOnRcvdStatus = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_SIGNON_PKT_RCVD_OFFSET);
	SMPointer = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_STATE_MACHINE_OFFSET);
	commonEventsPtr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	port0EventsPtr = (UInt32*)(PRU0_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	port1EventsPtr = (UInt32*)(PRU1_DRAM_BASE_ADDRESS + DLR_PORT_EVENTS_OFFSET);
	activeSupMacAddr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ACTIVE_SUP_MAC_0123);

	*(SMPointer) = DLR_INIT_STATE_MACHINE;

	*(commonEventsPtr) = 0;
	*(port0EventsPtr) = 0;
	*(port1EventsPtr) = 0;
	*(signOnRcvdStatus) = 0;

	*(activeSupMacAddr) = 0;
	activeSupMacAddr = (UInt32*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_ACTIVE_SUP_MAC_45);
	*(activeSupMacAddr) = 0;

}
/**
 * \name dlrResetStateMachine
 * \brief Initialize the state machine when it goes back to idle state
 * \param  none
 * \return None
 */
void dlrResetStateMachine(void) {

#ifdef DLR_DEBUG
	genSeqOfEvents(DLR_RESET_MACHINE);
#endif


	/*stop the timers*/
	Timer_stop(dlrTimer_PORT0);
	Timer_stop(dlrTimer_PORT1);

	/*clear memory*/
	dlrDRAMInit();

	/*Set default values*/
	dlrSetDefaultValue();

	/*flush the learning table*/
	purgeTable(HWPORT0);
	purgeTable(HWPORT1);

}

/**
 * \name dlrSetDefaultValue
 * \brief Set Default values for the DLR CIP Object
 * \param  none
 * \return none
 */
void dlrSetDefaultValue(void) {

	/*Set default values*/

	dlrObj.dlrCapabilities = DLR_DEFAULT_CAPABILITIES;
	dlrObj.supConfig.superEnable = false;
	dlrObj.SMVariables.node_state = NODE_IDLE;
	dlrObj.SMVariables.ring_state = RING_FAULT;
	dlrObj.SMVariables.topology = LINEAR_TOP;
	dlrObj.SMVariables.superStatus = RING_NODE;
	dlrObj.SMVariables.status = NORMAL_STAT;

	dlrObj.addr.supIPAddress = 0;
	memset(dlrObj.addr.supMACAddress, 0x0, 6);

#ifdef IS_A_DLR_SUPERVISOR
	dlrObj.numRingFaultsPowerUp = 0;
	dlrObj.ringParticipantsCount = 0;
#endif
}

/**
 * \name dlrSwitchToFault
 * \brief Set CIP Object values for fault status
 * \param  none
 * \return none
 */
void dlrSwitchToFault(void) {

	dlrObj.SMVariables.node_state = NODE_FAULT;
	dlrObj.SMVariables.ring_state = RING_FAULT;
	dlrObj.SMVariables.topology = RING_TOP;
	dlrObj.SMVariables.status = RING_FAULT_STAT;
}

/**
 * \name dlrSwitchToNormal
 * \brief Set CIP Object values for normal status
 * \param  none
 * \return none
 */
void dlrSwitchToNormal(void) {

	volatile Uint8 *loopDetectedPtr;
	loopDetectedPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_LOOP_DETECTED_OFFSET);

	*(loopDetectedPtr) = DLR_TRUE;

	dlrObj.SMVariables.node_state = NODE_NORMAL;
	dlrObj.SMVariables.ring_state = RING_NORMAL;
	dlrObj.SMVariables.topology = RING_TOP;
	dlrObj.SMVariables.status = NORMAL_STAT;
}

/**
 * \name initDLRFrameHeader
 * \brief copies the common part of a DLR Frame Header
 * \param [IN] src byte stream pointer
 * \param [IN] header byte stream header pointer
 * \return none
 */
void initDLRFrameHeader(Uint8 *src, Uint8 *header) {

	/*processing common to all frames*/
	memcpy(src + DLR_COMMON_FRAME_OFFSET, header, DLR_COMMON_FRAME_HEADER_SIZE);
}

/*Helper Functions*/

/**
 * \name addSignOnNumNodes
 * \brief Add number of nodes to the sign on frame, in case of a node the number is incremented
 * \param [IN] src pointer to packet stream
 * \param [IN] numNodes  number of nodes in the ring
 * \return none
 */
void addSignOnNumNodes(Uint8 *src, Uint16 numNodes) {

	*(src + DLR_SIGNON_NUM_NODES_OFFSET) = (numNodes >> 8) & 0xff;
	*(src + DLR_SIGNON_NUM_NODES_OFFSET + 1) = numNodes & 0xff;
}
/**
 * \name genNCReqFrame
 * \brief Generates a Neighbor check request frame
 *
 * When a node receives a locate fault request from the supervisor
 * it sends neighbor check request frames out of both ports to get the
 * status of it's neighbors, if the neighbor doesn't respond it sends
 * a link status frame to the supervisor
 *
 * \param [IN] src pointer to the packet
 * \param [IN] sourcePort port on which the frame will be sent
 * \return none
 */
void genNCReqFrame(Uint8 *src, Uint8 sourcePort) {

	sequenceID++;
	addWord(src + DLR_SEQUENCE_ID_OFFSET, sequenceID);

	addMACID(src, DLR_NCREQ_MAC_ID);

	addSourcePort(src, sourcePort);

	addFrameOffset(src, DLR_NCREQ_FRAME_TYPE);
	memset(src + DLR_NCREQ_RESERVED_BYTES_OFFSET, 0x0, DLR_NCREQ_RESERVED_BYTES_SIZE);

}
/**
 * \name genNCResFrame
 * \brief Generates a Neighbor check response frame
 *
 * A neighbor check response frame is sent in response to a
 * neighbor request frame
 *
 * \param [IN] src pointer to the packet
 * \param [IN] sourcePort port on which the frame will be sent
 * \param [IN] reqSrcPort request source port of the neighbor check request
 * \param [IN] sequenceId sequence Id of the neighbor check request
 * \return none
 */
void genNCResFrame(Uint8 *src, Uint8 sourcePort, Uint8 reqSrcPort, Uint32 sequenceId) {

	addWord(src + DLR_SEQUENCE_ID_OFFSET, sequenceId);

	/*Add MAC identifier*/
	addMACID(src, DLR_NCREQ_MAC_ID);

	addSourcePort(src, sourcePort);
	addReqSrcPort(src, reqSrcPort);

	addFrameOffset(src, DLR_NCRES_FRAME_TYPE);
	memset(src + DLR_NCRES_RESERVED_BYTES_OFFSET, 0x0, DLR_NCRES_RESERVED_BYTES_SIZE);
}
/**
 * \name genNeighborLinkStatFrame
 * \brief Generates a Link/Neighbor status frame
 *
 * A neighbor check response frame is sent in response to a
 * neighbor request frame
 *
 * \param [IN] src pointer to the packet
 * \param [IN] sourcePort port on which the frame will be sent
 * \param [IN] linkOrNeighbor whether the packet is a link status or a neighbor status frame. If it's a link the value is true and vice versa
 * \param [IN] linkStatus indicates which link is down. Possible values are DLR_PORT0_FAIL or DLR_PORT1_FAIL
 * \return none
 */
void genNeighborLinkStatFrame(Uint8 *src, Uint8 sourcePort, Uint8 linkOrNeighbor, Uint8 linkStatus) {

	Uint8 status = 0;

	activeSuperAddr *actSupAddrPtr = &(dlrObj.addr);

	sequenceID++;
	addWord(src + DLR_SEQUENCE_ID_OFFSET, sequenceID);

	/*This packet is meant for the ring supervisor*/
	addMACID(src, actSupAddrPtr->supMACAddress);

	/*if port 1 has failed it means port 0 is active*/
	if(DLR_PORT1_FAIL == linkStatus) {
		status |= 0x1;
	} else {
		status |= 0x2;
	}

	/*if it's a link status frame, set the appropriate bits*/
	if(!linkOrNeighbor) {
		status |= 0x80;
	}

	addLinkStat(src, status);
	addSourcePort(src, 0);

	addFrameOffset(src, DLR_LINKSTAT_FRAME_TYPE);
	memset(src + DLR_LSTAT_RESERVED_BYTES_OFFSET, 0x0, DLR_LSTAT_RESERVED_BYTES_SIZE);

}
/**
 * \name addVlanID
 * \brief Add the new VLAN ID to the message
 * \param [IN] src pointer to the packet
 * \param [IN] vlanID VLAN ID of supervisor
 * \return none
 */
void addVlanID(Uint8 *src, Uint16 vlanID) {

	Uint16 tagPlusVlan = 0xE000;
	volatile Uint8 *bytePtr;

	bytePtr = (Uint8 *)(src + DLR_START_OF_VLAN_ID);

	tagPlusVlan += vlanID;

	*(bytePtr) = ((tagPlusVlan >> 8) & 0xff);
	*(bytePtr + 1) = (tagPlusVlan & 0xff);

}
/**
 * \name dlrIsrInit
 * \brief Initialize DLR ISR's
 * \param none
 * \return none
 */
int dlrIsrInit()
{
    Hwi_Params hwiParams;
    Error_Block eb;

    Hwi_Params_init(&hwiParams);
    Error_init(&eb);

    hwiParams.arg = 0;        // just an ID
    hwiParams.eventId = ICSS_DLR_PORT0_INTNUM;
    //hwiParams.enableInt = FALSE;		// enable later
   // hwiParams.priority = ISR_DLR_PRIO;

   Hwi_create(ICSS_DLR_PORT0_INTNUM,(IHwi_FuncPtr)DLR_Port0ISR, &hwiParams, &eb);

    if (Error_check(&eb))
    {
    	printf("Error setting up DLR Port 0 Interrupt \n");
    	return -1;
    }


    hwiParams.arg = 0;        // just an ID
    hwiParams.eventId = ICSS_DLR_PORT1_INTNUM;
    //hwiParams.enableInt = FALSE;		// enable later
   // hwiParams.priority = ISR_DLR_PRIO;

    Hwi_create(ICSS_DLR_PORT1_INTNUM,(IHwi_FuncPtr)DLR_Port1ISR, &hwiParams, &eb);

    if (Error_check(&eb))
    {
    	printf("Error setting up DLR Port 0 Interrupt \n");
    	return -1;
    }

    return 0;

}
/**
 * \name addToExceptionList
 * \brief Add a macId to the exception list
 * \param  portNum port number
 * \return none
 */
void addToExceptionList(Uint8 * macId) {

	exclusionList.numExceptions = 1;
	copyMAC(exclusionList.MAC, macId);
}
/**
 * \name clearExceptionList
 * \brief Clear the mac id exception list for DLR supervisor
 * \param  none
 * \param  none
 * \return none
 */
void clearExceptionList() {
	/*do a dirty deletion*/
	exclusionList.numExceptions = 0;
}

Uint8 checkSupervisorException(Uint8 *macId) {
	/*check the exclusion list*/
	if(exclusionList.numExceptions) {
		/*if the source mac id matches the exclusion list return*/
		if(COMPARE_MAC(exclusionList.MAC,  macId)) {
			return 0;
		} else {
			return 1;
		}

	}
	return 1;
}
/**
 * \name periodicProcessing
 * \brief This is called periodically every 100ms or whatever the NDK tick period is
 * \param  none
 * \return none
 */
void periodicProcessing(void) {

	volatile Uint8 ifLoopExists;
	volatile Uint8 *loopDetectedPtr;

	volatile Uint16 *commonEvtsPtr;
	volatile Uint16 commonEvtsFlag;

	static Uint32   tracePktIntervalCount = 0;
	static Uint32   stateMachineCount = 0;
	static Uint8    pktSendCounter = 0;
	volatile unsigned short phyCtrlReg;

	commonEvtsPtr = (UInt16*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_COMMON_EVENTS_OFFSET);
	commonEvtsFlag = *(commonEvtsPtr);

	if(((stateMachineCount++ & 0x7) == 0)) {
		if(commonEvtsFlag & DLR_RESET_EVENT_OCCURED_MASK) {
			//clear the reset event flag
			commonEvtsFlag &= ~(DLR_RESET_EVENT_OCCURED_MASK);
			//write back
			*(commonEvtsPtr) = commonEvtsFlag;
			dlrResetStateMachine();
		}
		stateMachineCount = 0;
	}

	if (NODE_IDLE != dlrObj.SMVariables.node_state) {
		return;
	}

	/*Find out if a loop has been detected*/
	loopDetectedPtr = (Uint8*)(PRU_SHARED_DRAM_BASE_ADDRESS + DLR_LOOP_DETECTED_OFFSET);
	ifLoopExists = *(loopDetectedPtr);

	/*Check is unnecessary if DLR state machine is not running*/
	/*If there is a loop and there is no supervisor set the flag*/
	if(ifLoopExists) {
		dlrObj.SMVariables.status = UNEXPECTED_LOOP;
	}

	/*Once both ports are connected and Ring is not operational, the device sends three packets on both ports at an interval of 1 second*/
	if(checkForLoop && (pktSendCounter < 3)) {
		tracePktIntervalCount++;
		if(((tracePktIntervalCount & 0xf) == 0) || (0 == pktSendCounter)) { /*modulo 16 or interval of 1.6 seconds*/
			TxPacketEnqueue(tracePkt, PORT1, 1, ETHERNET_FRAME_SIZE_60);
			TxPacketEnqueue(tracePkt, PORT2, 1, ETHERNET_FRAME_SIZE_60);
			/*reset the counter*/
			tracePktIntervalCount = 0;
			pktSendCounter++;
		}
	} else {
		pktSendCounter = 0;
		checkForLoop = DLR_FALSE;
	}

}

#ifdef DLR_DEBUG
void genSeqOfEvents(Uint8 event) {
	if(seqNumber < MAX_EVENTS_CAPTURED) {
		sequenceOfEvents[seqNumber++] = event;
	}
}
#endif

void addDLRModuleIPAddress(Uint32 newIP)
{
	deviceIP = newIP;
	addWord(dlrEmptyFrame + DLR_SOURCE_IP_OFFSET, deviceIP);
}
#endif
