/*
 * ENET.c
 *
 *  Created on: Feb 27, 2017
 *      Author: B55840
 */

#include "ENET.h"

/**********************************************************************************************
 * Constants and macros
 **********************************************************************************************/
/* Buffer sizes in bytes -- The maximum allowable frame size is 1518
 * (or 1522 if VLAN tags are supported). The buffer size must be divisable
 * by 64. 1536 is the smallest 64 multiple that fits 1522 bytes.
 */
#define RX_BUFFER_SIZE 1536
#define TX_BUFFER_SIZE 1536
#define DUMMY_HEADER_SIZE 22

/* Number of Receive and Transmit Buffers and Buffer Descriptors per Queue */
#define NUM_RXBDS 2
#define NUM_TXBDS 2

static uint8_t TxBuffer[NUM_TXBDS][TX_BUFFER_SIZE] __attribute__ ((aligned (64))); /* Create transmission buffer. Size must be divisible over 16 */
static uint8_t RxBuffer[NUM_RXBDS][RX_BUFFER_SIZE] __attribute__ ((aligned (64))); /* Create reception buffer. Size must be divisible over 16 */

static eNBUF txbd[NUM_TXBDS] __attribute__ ((aligned (64)));       /* Create Transmission Buffer Descriptors */
static eNBUF rxbd[NUM_RXBDS] __attribute__ ((aligned (64)));       /* Create Reception Buffer Descriptors */

// Next buffer to use
uint8_t nextTxBD = 0;
uint8_t nextRxBD = 0;

uint8_t DummyPacket[] = {
		/* Starts Ethernet frame */
#ifdef PHY_MASTER
//		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
		DESTMAC1, DESTMAC2, DESTMAC3, DESTMAC4, DESTMAC5, DESTMAC6,     // Destination MAC Address
		ORIGMAC1, ORIGMAC2, ORIGMAC3, ORIGMAC4, ORIGMAC5, ORIGMAC6,     // Origin MAC Address
#else
		ORIGMAC1, ORIGMAC2, ORIGMAC3, ORIGMAC4, ORIGMAC5, ORIGMAC6,     // Destination MAC Address
		DESTMAC1, DESTMAC2, DESTMAC3, DESTMAC4, DESTMAC5, DESTMAC6,     // Origin MAC Address
#endif
		0x08, 0x00,                             // EtherType (IPV4)
		0x01, 0x02, 0x03, 0x04,                 // correct dummy data
		//		0xCA, 0xFE, 0xBE, 0xEF,                 // wrong dummy data
		0x00, 0x00, 0x00, 0x00                  // Ethernet frame checksum
};

static void ENET_BUFFER_Init(void);
void markRxBDEmpty(eNBUF *used);
eNBUF *getActiveRxBD(void);

void ENET_dummy_tx(void)
{
	uint32_t i;

	/* Copy the indicated packet into the data buffer
	    Includes Ethernet header + layer 3 (which can contain a transport protocol header)
	 */
	for(i = 0; i < DUMMY_HEADER_SIZE; i++){
		TxBuffer[nextTxBD][i] = DummyPacket[i];
	}

	//txbd[nextTxBD].data = &TxBuffer[nextTxBD][0];  // Set address of this data Buffer
	txbd[nextTxBD].data_low = (uint16_t)((uint32_t)(&TxBuffer[nextTxBD][0])&0x0000FFFF);
	txbd[nextTxBD].data_high = (uint16_t)(((uint32_t)(&TxBuffer[nextTxBD][0])&0xFFFF0000)>>16);
	txbd[nextTxBD].status12 = 0;

	/* Set the length of the packet */
	txbd[nextTxBD].length = DUMMY_HEADER_SIZE;

	/* Mark packet as ready to send */
	txbd[nextTxBD].status2 = TX_BD_S2_L | TX_BD_S2_TC; 	// Mark buffer as the last one and transmit CRC
	txbd[NUM_TXBDS-1].status2 |= TX_BD_S2_W;     		// Set the Wrap Bit on the last BD of each queue
	txbd[nextTxBD].status2 |= TX_BD_S2_R;					// Mark buffer as ready


	ENET -> TDAR |= ENET_TDAR_TDAR_MASK; // Start transmission

	nextTxBD++;   // Next frame will be processed on the next buffer descriptor
	if(nextTxBD >= NUM_TXBDS)  // Wrap if reached last buffer descriptor
	{
		nextTxBD = 0;
	}

}

void ENET_GPIO_Init(void)
{
	uint32_t delay;

	PCC->PCCn[PCC_PORTA_INDEX] |= PCC_PCCn_CGC_MASK;  /* CGC=1: Clock enabled for PORTA */
	PCC->PCCn[PCC_PORTB_INDEX] |= PCC_PCCn_CGC_MASK;  /* CGC=1: Clock enabled for PORTB */
	PCC->PCCn[PCC_PORTC_INDEX] |= PCC_PCCn_CGC_MASK;  /* CGC=1: Clock enabled for PORTC */
	PCC->PCCn[PCC_PORTD_INDEX] |= PCC_PCCn_CGC_MASK;  /* CGC=1: Clock enabled for PORTD */
	PCC->PCCn[PCC_PORTE_INDEX] |= PCC_PCCn_CGC_MASK;  /* CGC=1: Clock enabled for PORTE */

#ifdef GPIO_STRAP_CONFIGURATION
	  /* LED_YEL D56 for LINK Indicator */
	  PTC->PCOR  = 1<<28;   /* Turn-off D56 */
	  PTC->PDDR |= 1<<28;
	  PORTC->PCR[28] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTC->PCR[28] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTC28  */

	  /* LED_YEL D9 for Correct Rx Indicator */
	  PTA->PCOR  = 1<<16;   /* Turn-off D9 */
	  PTA->PDDR |= 1<<16;
	  PORTA->PCR[16] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTA->PCR[16] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTA16  */

	  /* LED_YEL D10 for Rx Data Error Indicator */
	  PTE->PCOR  = 1<<20;   /* Turn-off D10 */
	  PTE->PDDR |= 1<<20;
	  PORTE->PCR[20] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTE->PCR[20] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTE20  */

	  /* TJA1100 Strapping to boot with AUTO_OP=1 */
	  /* RST_b - PTA17 */
	  PTA->PCOR  = 1<<17;   /* Assert RST_b */
	  PTA->PDDR |= 1<<17;
	  PORTA->PCR[17] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTA->PCR[17] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTA17  */

	  /* INT_b - PTB20 */
	  PTB->PSOR  = 1<<20;   /* Deassert INT_b */
	  PTB->PDDR |= 1<<20;
	  PORTB->PCR[20] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTB->PCR[20] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTB20  */

	  /* WAKE - PTB21 */
	  PTB->PSOR  = 1<<21;   /* Asssert WAKE */
	  PTB->PDDR |= 1<<21;
	  PTB->PDDR &= ~( 1<<21 );  /* Configure as input */
	  PORTB->PCR[21] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTB->PCR[21] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTB21  */
	  PORTB->PCR[21] |= PORT_PCR_MUX(1)   |             /* MUX=1: Select GPIO on PTB21  */
	                    PORT_PCR_PE_MASK  |             /* PE=1: Internal pullup or pulldown resistor is enabled on the corresponding pin */
	                    PORT_PCR_PS_MASK;               /* PS=1: Internal pullup resistor is enabled on the corresponding pin */

	  /* RXD0 - PTC1 */
	  PTC->PCOR  = 1<<1;   /* PHYAD0 = 0 */
	  PTC->PDDR |= 1<<1;
	  PORTC->PCR[1] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTC->PCR[1] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTC1  */

	  /* RXD1 - PTC0 */
	  PTC->PCOR  = 1<<0;   /* PHYAD1 = 0 */
	  PTC->PDDR |= 1<<0;
	  PORTC->PCR[0] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTC->PCR[0] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTC0  */

	  /* RXD2 - PTD9 */
	#if (PHY_MASTER==1)
	  PTD->PSOR  = 1<<9;   /* CONFIG0 = 1 (PHY configured as Master) */
	#else
	  PTD->PCOR  = 1<<9;   /* CONFIG0 = 0 (PHY configured as Slave) */
	#endif
	  PTD->PDDR |= 1<<9;
	  PORTD->PCR[9] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTD->PCR[9] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTD9  */

	  /* RXD3 - PTD8 */
	  PTD->PSOR  = 1<<8;   /* CONFIG1 = 1 (Autonomous operation) */
	  PTD->PDDR |= 1<<8;
	  PORTD->PCR[8] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTD->PCR[8] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTD8  */

	  /* RX_DV - PTC17 */
	  PTC->PCOR  = 1<<17;   /* CONFIG2 = 0 (Normal MII mode) */
	  PTC->PDDR |= 1<<17;
	  PORTC->PCR[17] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTC->PCR[17] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTC17  */

	  /* RX_ER - PTC16 */
	  PTC->PCOR  = 1<<16;   /* CONFIG3 = 0 (Normal MII mode) */
	  PTC->PDDR |= 1<<16;
	  PORTC->PCR[16] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	  PORTC->PCR[16] |= PORT_PCR_MUX(1);                /* MUX=1: Select GPIO on PTC16  */

	  delay = 100000;
	  while( delay-- ) {}
	  PTA->PSOR  = 1<<17;   /* Deassert RST_b */
	  delay = 100000;
	  while( delay-- ) {}
#endif

	PORTE->PCR[22] |= PORT_PCR_MUX(1);                /* MUX=5: Select MII_RMII_RXD[0] on PTC1  */
	PTE->PDDR |= 1<<22;        /* Port E22: Data Direction= output */
	/* Configure ENET Pins */
	/* RXD0 - PTC1 */
	PORTC->PCR[1] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTC->PCR[1] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_RXD[0] on PTC1  */

	/* RXD1 - PTC0 */
	PORTC->PCR[0] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTC->PCR[0] |= PORT_PCR_MUX(4);                /* MUX=4: Select MII_RMII_RXD[1] on PTC0  */

	/* RXD2 - PTD9 */
	PORTD->PCR[9] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[9] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RXD2 on PTD9  */

	/* RXD3 - PTD8 */
	PORTD->PCR[8] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[8] |= PORT_PCR_MUX(3);                /* MUX=3: Select MII_RXD3 on PTD8  */

	/* RX_DV - PTC17 */
	PORTC->PCR[17] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTC->PCR[17] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_RX_DV on PTC17  */

	/* RX_ER - PTC16 */
	PORTC->PCR[16] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTC->PCR[16] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_RX_ER on PTC16  */

	/* MDIO - PTB4 */
	PORTB->PCR[4] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTB->PCR[4] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_MDIO on PTB4  */

	/* MDC - PTB5 */
	PORTB->PCR[5] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTB->PCR[5] |= PORT_PCR_MUX(7);                /* MUX=7: Select MII_RMII_MDC on PTB5  */

	/* TX_EN - PTD12 */
	PORTD->PCR[12] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[12] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_TX_EN on PTD12  */

	/* TDXD0 - PTC2 */
	PORTC->PCR[2] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTC->PCR[2] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_TXD[0] on PTC2  */

	/* TDXD1 - PTD7 */
	PORTD->PCR[7] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[7] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_TXD[1] on PTD7  */

	/* TDXD2 - PTD6 */
	PORTD->PCR[6] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[6] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_TXD2 on PTD6  */

	/* TDXD3 - PTD5 */
	PORTD->PCR[5] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[5] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_TXD3 on PTD5  */

	/* TX_ER - PTC3 */
	PORTC->PCR[3] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTC->PCR[3] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_TX_ER on PTC3  */

	/* COL */

	/* CRS */

	/* TX_CLK - PTD11 */
	PORTD->PCR[11] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[11] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RMII_TX_CLK on PTD11  */

	/* RX_CLK - PTD10 */
	PORTD->PCR[10] &= ~PORT_PCR_MUX_MASK;             /* Set MUX=0 temporarily */
	PORTD->PCR[10] |= PORT_PCR_MUX(5);                /* MUX=5: Select MII_RX_CLK on PTD10  */
}

void SMI_Write( uint8_t RegNum, uint16_t CmdVal )
{
	if( ( ENET->EIR & ENET_EIR_MII_MASK ) != 0 )
	{
		ENET->EIR = ENET_EIR_MII_MASK;  /* Write 1 to clear MII flag */
	}
	ENET->MMFR = ENET_MMFR_ST(1)  |       /* ST=1: for Standard MDIO (Clause 22) */
			ENET_MMFR_OP(1)  |       /* OP=1: Write operation */
			ENET_MMFR_PA(4)  |       /* PA=4: PHY Address 4 */
			ENET_MMFR_RA(RegNum)  |  /* RA=RegNum */
			ENET_MMFR_TA(0)  |       /* TA=0: Turnaround time is 0 */
			ENET_MMFR_DATA(CmdVal);  /* DATA=CmdVal */
	while( ( ENET->EIR & ENET_EIR_MII_MASK ) == 0 ) {}
}

uint16_t SMI_Read( uint8_t RegNum )
{
	if( ( ENET->EIR & ENET_EIR_MII_MASK ) != 0 )
	{
		ENET->EIR = ENET_EIR_MII_MASK;  /* Write 1 to clear MII flag */
	}
	ENET->MMFR = ENET_MMFR_ST(1)  |       /* ST=1: for Standard MDIO (Clause 22) */
			ENET_MMFR_OP(2)  |       /* OP=2: Read operation */
			ENET_MMFR_PA(4)  |       /* PA=4: PHY Address 4 */
			ENET_MMFR_RA(RegNum)  |  /* RA=RegNum */
			ENET_MMFR_TA(3)  |       /* TA=3: Turnaround time is 3 */
			ENET_MMFR_DATA(0);       /* DATA=0 for read */
	while( ( ENET->EIR & ENET_EIR_MII_MASK ) == 0 ) {}
	return( ( uint16_t)ENET->MMFR );
}

void ENET_init(void)
{
	static uint16_t data_val;

	PCC->PCCn[PCC_ENET_INDEX] &= ~PCC_PCCn_CGC_MASK; /* Disable clock to change PCS */
	PCC->PCCn[PCC_ENET_INDEX] &= ~PCC_PCCn_PCS_MASK; /* Temporarily clear PCS  */
	PCC->PCCn[PCC_ENET_INDEX] |= PCC_PCCn_PCS(6);    /* PCS=6: Select SPLLDIV1_CLK */
	PCC->PCCn[PCC_ENET_INDEX] |= PCC_PCCn_CGC_MASK;  /* Enables ENET clock */

	ENET_BUFFER_Init(); /* prepare description buffers */

	/* reset the ENET - clears EIR */
	ENET->ECR |= ENET_ECR_RESET_MASK;   /* Ethernet MAC Reset.  It clears the ETHEREN field. */
	ENET->ECR |= ENET_ECR_EN1588_MASK;  /* Enhanced frame time-stamping functions enabled */
	ENET->ECR |= ENET_ECR_DBGEN_MASK;   /* MAC enters hardware freeze mode when the processor is in debug mode */
	ENET->ECR |= ENET_ECR_DBSWP_MASK;   /* The buffer descriptor bytes are swapped to support little-endian devices */

	/* set source MAC address for the controller */
#ifdef PHY_MASTER
	ENET->PALR = ((ORIGMAC1<<24) + (ORIGMAC2<<16) + (ORIGMAC3<<8) + ORIGMAC4);  //set to match DA in packet
	ENET->PAUR = ((ORIGMAC5<<24) + (ORIGMAC6<<16));
#else
	ENET->PALR = ((DESTMAC1<<24) + (DESTMAC2<<16) + (DESTMAC3<<8) + DESTMAC4);  //set to match DA in packet
	ENET->PAUR = ((DESTMAC5<<24) + (DESTMAC6<<16));
#endif

	/* initially no hash matching */
	ENET->IALR = 0x00000000; //no individual hash matching
	ENET->IAUR = 0x00000000;
	ENET->GALR = 0x00000000; //no group hash matching
	ENET->GAUR = 0x00000000;

	/* Set Receive Buffer Size */
	ENET->MRBR = (uint16_t)RX_BUFFER_SIZE;
	/* Point to the start of the circular Rx buffer descriptor queue */
	ENET->RDSR = (uint32_t)&rxbd[0];
	/* Point to the start of the circular Tx buffer descriptor queue */
	ENET->TDSR = (uint32_t)&txbd[0];

	ENET->RCR = ENET_RCR_PADEN_MASK;  /* Padding is removed from received frames */

	/* Set the transceiver interface to MII mode */
	ENET->RCR |= ENET_RCR_MAX_FL(1518);   /* MAX_FL = 1500 payload + 18(for DA(6), SA(6), Ethertype(2) and CRC(4)) */
	ENET->RCR |= ENET_RCR_MII_MODE_MASK;  /* MII or RMII mode, as indicated by the RMII_MODE field */
	ENET->RCR |= ENET_RCR_RMII_MODE_MASK;   /* MAC configured for RMII operation */
	EnableIRQ(ENET_RX_IRQn);
	// ENET->RCR &= ~ENET_RCR_RMII_MODE_MASK;  /* MAC configured for MII mode */
	ENET->RCR &= ~ENET_RCR_DRT_MASK;        /* Disable reception of frames while transmitting. (Normally used for half-duplex mode.) */

	/* LOOPBACK */
	//  SCG->SOSCDIV |= SCG_SOSCDIV_SOSCDIV1(1);
	//  SIM->MISCTRL0 |= SIM_MISCTRL0_RMII_CLK_OBE_MASK  |
	//                   SIM_MISCTRL0_RMII_CLK_SEL_MASK;
	ENET->RCR &= ~ENET_RCR_LOOP_MASK;        /* Loopback disabled */
	//ENET->RCR |= ENET_RCR_LOOP_MASK;        /* Transmitted frames are looped back internal to the device and transmit MII output signals are not asserted. DRT must be cleared. */

	/* Operate in full-duplex mode */
	ENET->TCR |= 0x0004; /* full duplex mode */

	ENET->MSCR |= ENET_MSCR_DIS_PRE_MASK; /* Preamble (32 ones) is not prepended to the MII management frame */

	/* Set MII speed to be 40 / ( ( MSCR + 1 ) * 2 ) = 2.5MHz MDC frequency */
	//  ENET->MSCR |= ENET_MSCR_MII_SPEED(0x7);
	/* Set MII speed to be 40 / ( ( MSCR + 1 ) * 2 ) = 312.5kHz MDC frequency */
	ENET->MSCR |= ENET_MSCR_MII_SPEED(63);

	/* Enable ENET */
	ENET->ECR |= ENET_ECR_ETHEREN_MASK;  /* MAC is enabled, and reception and transmission are possible */

	ENET_GPIO_Init();       // Initialize PADs

	PTC->PSOR  = 1<<28;   /* Turn-on D56 */
}

/*
Initialise the receive path
Install the interrupt handler and enable interrupts on Rx frame
 */
void ENET_Rx_Init()
{
	// Enable the generation of Rx frame interrupts
	ENET -> EIMR |= ENET_EIMR_RXF_MASK;

	// Indicate Empty buffers have been produced
	ENET -> RDAR |= ENET_RDAR_RDAR_MASK;
}

void ENET_BUFFER_Init(void){
	uint8_t j = 0;

	/* Initialize receive descriptor ring */
	for (j = 0; j < NUM_RXBDS; j++)
	{
		rxbd[j].status2 = RX_BD_S2_E;        //Mark buffer as empty
		rxbd[j].length = 0;
		rxbd[j].statusA = RX_BD_SA_INT;      //Enable transmit and receive flags
		rxbd[j].data_low = (uint16_t)((uint32_t)(&RxBuffer[j][0])&0x0000FFFF);
		rxbd[j].data_high = (uint16_t)(((uint32_t)(&RxBuffer[j][0])&0xFFFF0000)>>16);

		rxbd[j].status8 = 0;
		rxbd[j].statusC = 0;
		rxbd[j].statusE = 0;
		rxbd[j].status12 = 0;
		rxbd[j].timestamp = 0;
	}
	rxbd[NUM_RXBDS-1].status2 |= RX_BD_S2_W;     //Set the Wrap Bit on the last BD of each queue


	/* Initialize transmit descriptor ring only for Queue0 */
	for (j = 0; j < NUM_TXBDS; j++)
	{
		txbd[j].status2 = TX_BD_S2_L | TX_BD_S2_TC;  //Mark buffer as the last one and transmit CRC
		txbd[j].statusA =
				TX_BD_SA_PINS |
				//TX_BD_SA_IINS |
				TX_BD_SA_INT;       //Add Protocol header checksum and IP header checksum
		txbd[j].length = 0;
		txbd[j].data_low = (uint16_t)((uint32_t)(&TxBuffer[j][0])&0x0000FFFF);
		txbd[j].data_high = (uint16_t)(((uint32_t)(&TxBuffer[j][0])&0xFFFF0000)>>16);
		//txbd[j].data = (&TxBuffer[j][0]&&);   //Set address of this data Buffer

		txbd[j].statusA |= 0; //FTYPE 0=non-avb, 1=avb class a, 2=avb class b

		txbd[j].status8 = 0;
		txbd[j].statusC = 0;
		txbd[j].statusE = 0;
		txbd[j].status12 = 0;
		txbd[j].timestamp = 0;
	}
	txbd[NUM_TXBDS-1].status2 |= TX_BD_S2_W;     //Set the
}

void ENET_RX_IRQHandler(void)
{
	static eNBUF *rxBD;
	static EthernetFrame *rxFrame;

	/* Get the active BD and increment pointer */
	PTE->PTOR  = 1<<22;   /* Toggle PTE22 */
	rxBD = getActiveRxBD();


	/* If the data buffer has not been filled do nothing */
	if ((rxBD->status2 & RX_BD_S2_E) == RX_BD_S2_E) return;

	/* Extract the frame */
	rxFrame = (EthernetFrame *)( ( rxBD->data_high<<16 ) | rxBD->data_low );

	/* Mark the receive buffer empty */
	markRxBDEmpty(rxBD);

	/* Flag that descriptors are available to allow reception */
	ENET->RDAR = 0x0100000;

	/* Clear interrupt */
	ENET->EIR = 0x02000000;

	/* To check if receiver is working or not.... */
	/* If receiver handler exists successfully then LED will toggle at each receive event */
	if( ( rxFrame->data[0] == 0x01 ) & ( rxFrame->data[1] == 0x02 ) &
			( rxFrame->data[2] == 0x03 ) & ( rxFrame->data[3] == 0x04 ) )
	{
		PTE->PCOR  = 1<<23;   /* Turn off PTE23 */
	}
	else
	{
		PTE->PSOR  = 1<<23;   /* Turn-on PTE23 */
	}
}

/* Returns the active Rx buffer descriptor. Increments the pointer */
eNBUF *getActiveRxBD()
{
	eNBUF *ret = &rxbd[nextRxBD];

	// If current Rx bd is the last, wrap around
	nextRxBD++;
	if(nextRxBD >= NUM_RXBDS)  // Wrap if reached last buffer descriptor
		nextRxBD = 0;

	return ret;
}

/* Mark specified Rx descriptor as empty */
void markRxBDEmpty(eNBUF *used)
{
	if (used == &rxbd[NUM_RXBDS-1]) // If it is the last buffer descriptor in the ring
	{
		used->status2 		 =  RX_BD_S2_W | RX_BD_S2_E;		// Wrap and Empty
		used->length		 = 0;
	}
	else
	{
		used->status2 		 = RX_BD_S2_E;		// Empty
		used->length		 = 0;
	}
}
