/**
*
* This example uses polled mode to queue up multiple frames in the packet
* FIFOs before sending them in a single burst. Receive packets are handled in
* a similar way.
*
* @param    None.
*
* @return   XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note     None.
*
******************************************************************************/
int TemacMultipleFramesPolledExample(void)
{
	u32 FramesToLoopback;
	u32 PayloadSize;
	u32 TxFrameLength;
	u32 RxFrameLength;
	u32 FifoFreeBytes;
	u32 Index;

	/*
	 * Start the TEMAC device
	 */
	XLlTemac_Start(&TemacInstance);

	/*
	 * Setup the number of frames to loopback (FramesToLoopback) and the size
	 * of the frame (PayloadSize) to loopback. The default settings should
	 * work for every case. Modifying the settings can cause problems, see
	 * discussion below:
	 *
	 * If PayloadSize is set small and FramesToLoopback high, then it is
	 * possible to cause the transmit status FIFO to overflow.
	 *
	 * If PayloadSize is set large and FramesToLoopback high, then it is
	 * possible to cause the transmit packet FIFO to overflow.
	 *
	 * Either of these scenarios may be worth trying out to observe how the
	 * driver reacts. The exact values to cause these types of errors
	 * will vary due to the sizes of the FIFOs selected at hardware build
	 * time. But the following settings should create problems for all
	 * FIFO sizes:
	 *
	 * Transmit status FIFO overflow
	 *    PayloadSize = 1
	 *    FramesToLoopback = 1000
	 *
	 * Transmit packet FIFO overflow
	 *    PayloadSize = 1500
	 *    FramesToLoopback = 16
	 *
	 * These values should always work without error
	 *    PayloadSize = 100
	 *    FramesToLoopback = 5
	 */
	PayloadSize = 100;
	FramesToLoopback = 5;

	/*
	 * Calculate Tx frame length (not including FCS)
	 */
	TxFrameLength = XTE_HDR_SIZE + PayloadSize;

	/*
	 * Setup the packet to be transmitted
	 */
	TemacUtilFrameHdrFormatMAC(&TxFrame, TemacMAC);
	TemacUtilFrameHdrFormatType(&TxFrame, PayloadSize);
	TemacUtilFrameSetPayloadData(&TxFrame, PayloadSize);

	/****************/
	/* Send packets */
	/****************/

	/*
	 * Since we may be interested to see what happens when FIFOs overflow, don't
	 * check for room in the transmit packet FIFO prior to writing to it.
	 */

	/*
	 * Write frame data to FIFO
	 * Fifo core only allows loading and sending one frame at a time.
	 */
	for (Index = 0; Index < FramesToLoopback; Index++) {
		/* Make sure there is room in the FIFO */
		do {
			FifoFreeBytes = XLlFifo_TxVacancy(&FifoInstance);
		} while (FifoFreeBytes < TxFrameLength);

		XLlFifo_Write(&FifoInstance, TxFrame, TxFrameLength);
		XLlFifo_TxSetLen(&FifoInstance, TxFrameLength);

		switch (TemacPollForTxStatus()) {
		case XST_SUCCESS:	/* Got a sucessfull transmit status */
			break;

		case XST_NO_DATA:	/* Timed out */
			TemacUtilErrorTrap("Tx timeout");
			return XST_FAILURE;
			break;

		default:	/* Some other error */
			TemacResetDevice();
			return XST_FAILURE;
		}
	}

	/**********************/
	/* Receive the packet */
	/**********************/

	/*
	 * Wait for the packets to arrive
	 * The Fifo core only allows us to pull out one frame at a time.
	 */
	for (Index = 0; Index < FramesToLoopback; Index++) {
		/*
		 * Wait for packet Rx
		 */
		switch (TemacPollForRxStatus()) {
		case XST_SUCCESS:	/* Got a successfull receive status */
			break;

		case XST_NO_DATA:	/* Timed out */
			TemacUtilErrorTrap("Rx timeout");
			return XST_FAILURE;
			break;

		default:	/* Some other error */
			TemacResetDevice();
			return XST_FAILURE;
		}

		while(XLlFifo_RxOccupancy(&FifoInstance)) {
			/*
			 * A packet has arrived, get its length
			 */
			RxFrameLength = XLlFifo_RxGetLen(&FifoInstance);
	
			/*
			 * Verify the received frame length
			 */
			if ((RxFrameLength) != TxFrameLength) {
				TemacUtilErrorTrap("Receive length incorrect");
				return XST_FAILURE;
			}
			/*
			 * Read the received packet data
			 */
			XLlFifo_Read(&FifoInstance, &RxFrame, RxFrameLength);

			if (TemacUtilFrameVerify(&TxFrame, &RxFrame) != 0) {
				TemacUtilErrorTrap("Receive Data Mismatch");
				return XST_FAILURE;
			}
		}
	}

	/*
	 * Stop device
	 */
	XLlTemac_Stop(&TemacInstance);

	return XST_SUCCESS;
}
/**
*
* This function demonstrates the usage of the TEMAC by sending and receiving
* a single frame in SGDMA interrupt mode.
* The source packet will be described by two descriptors. It will be received
* into a buffer described by a single descriptor.
*
* @param    TemacInstancePtr is a pointer to the instance of the Temac
*           component.
*
* @return   XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note     None.
*
******************************************************************************/
int TemacSgDmaIntrSingleFrameExample(XLlTemac * TemacInstancePtr,
				     XLlDma * DmaInstancePtr)
{
	int Status;
	u32 TxFrameLength;
	int PayloadSize = 1000;
	XLlDma_BdRing *RxRingPtr = &XLlDma_GetRxRing(DmaInstancePtr);
	XLlDma_BdRing *TxRingPtr = &XLlDma_GetTxRing(DmaInstancePtr);
	XLlDma_Bd *Bd1Ptr;
	XLlDma_Bd *Bd2Ptr;

	/*
	 * Clear variables shared with callbacks
	 */
	FramesRx = 0;
	FramesTx = 0;
	DeviceErrors = 0;

	/*
	 * Calculate the frame length (not including FCS)
	 */
	TxFrameLength = XTE_HDR_SIZE + PayloadSize;

	/*
	 * Setup packet to be transmitted
	 */
	TemacUtilFrameHdrFormatMAC(&TxFrame, TemacMAC);
	TemacUtilFrameHdrFormatType(&TxFrame, PayloadSize);
	TemacUtilFrameSetPayloadData(&TxFrame, PayloadSize);

        /*
         * Flush the TX frame before giving it to DMA TX channel to transmit,
         * in case D-Caching is turned on.
         */
	XCACHE_FLUSH_DCACHE_RANGE(&TxFrame, TxFrameLength);

	/*
	 * Clear out receive packet memory area
	 */
	TemacUtilFrameMemClear(&RxFrame);

        /*
         * Invalidate the RX frame before giving it to DMA RX channel to
         * receive data, in case D-Caching is turned on.
         */
	XCACHE_INVALIDATE_DCACHE_RANGE(&RxFrame, TxFrameLength);

	/*
	 * Start the LLTEMAC device and enable the ERROR interrupt
	 */
	XLlTemac_Start(TemacInstancePtr);
	XLlTemac_IntEnable(TemacInstancePtr, XTE_INT_RECV_ERROR_MASK);

	/*
	 * Allocate 1 RxBD. Note that TEMAC utilizes an in-place allocation
	 * scheme. The returned Bd1Ptr will point to a free BD in the memory
	 * segment setup with the call to XLlTemac_SgSetSpace()
	 */
	Status = XLlDma_BdRingAlloc(RxRingPtr, 1, &Bd1Ptr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error allocating RxBD");
		return XST_FAILURE;
	}

	/*
	 * Setup the BD. The BD template used in the call to XLlTemac_SgSetSpace()
	 * set the "last" field of all RxBDs. Therefore we are not required to
	 * issue a XLlDma_Bd_mSetLast(Bd1Ptr) here.
	 */
	XLlDma_BdSetBufAddr(Bd1Ptr, &RxFrame);
	XLlDma_BdSetLength(Bd1Ptr, sizeof(RxFrame));
	XLlDma_BdSetStsCtrl(Bd1Ptr, XLLDMA_BD_STSCTRL_SOP_MASK | XLLDMA_BD_STSCTRL_EOP_MASK);

	/*
	 * Enqueue to HW
	 */
	Status = XLlDma_BdRingToHw(RxRingPtr, 1, Bd1Ptr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error committing RxBD to HW");
		return XST_FAILURE;
	}

	/*
	 * Enable DMA RX interrupt.
	 *
	 * Interrupt coalescing parameters are left at their default settings
	 * which is to interrupt the processor after every frame has been
	 * processed by the DMA engine.
	 */
	XLlDma_BdRingIntEnable(RxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);

	/*
	 * Start DMA RX channel. Now it's ready to receive data.
	 */
	Status = XLlDma_BdRingStart(RxRingPtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Allocate, setup, and enqueue 2 TxBDs. The first BD will describe
	 * the first 32 bytes of TxFrame and the second BD will describe the
	 * rest of the frame.
	 *
	 * The function below will allocate two adjacent BDs with Bd1Ptr being
	 * set as the lead BD.
	 */
	Status = XLlDma_BdRingAlloc(TxRingPtr, 2, &Bd1Ptr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error allocating TxBD");
		return XST_FAILURE;
	}

	/*
	 * Setup TxBD #1
	 */
	XLlDma_BdSetBufAddr(Bd1Ptr, &TxFrame);
	XLlDma_BdSetLength(Bd1Ptr, 32);
	XLlDma_BdSetStsCtrl(Bd1Ptr, XLLDMA_BD_STSCTRL_SOP_MASK);

	/*
	 * Setup TxBD #2
	 */
	Bd2Ptr = XLlDma_BdRingNext(TxRingPtr, Bd1Ptr);
	XLlDma_BdSetBufAddr(Bd2Ptr, (u32) (&TxFrame) + 32);
	XLlDma_BdSetLength(Bd2Ptr, TxFrameLength - 32);
	XLlDma_BdSetStsCtrl(Bd2Ptr, XLLDMA_BD_STSCTRL_EOP_MASK);

	/*
	 * Enqueue to HW
	 */
	Status = XLlDma_BdRingToHw(TxRingPtr, 2, Bd1Ptr);
	if (Status != XST_SUCCESS) {
		/*
		 * Undo BD allocation and exit
		 */
		XLlDma_BdRingUnAlloc(TxRingPtr, 2, Bd1Ptr);
		TemacUtilErrorTrap("Error committing TxBD to HW");
		return XST_FAILURE;
	}

	/*
	 * Enable DMA transmit interrupts
	 */
	XLlDma_BdRingIntEnable(TxRingPtr, XLLDMA_CR_IRQ_ALL_EN_MASK);

	/*
	 * Start DMA TX channel. Transmission starts at once.
	 */
	Status = XLlDma_BdRingStart(TxRingPtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Wait for transmission to complete
	 */
	while (!FramesTx);

	/*
	 * Now that the frame has been sent, post process our TxBDs.
	 * Since we have only submitted 2 to HW, then there should be only 2 ready
	 * for post processing.
	 */
	if (XLlDma_BdRingFromHw(TxRingPtr, 2, &Bd1Ptr) == 0) {
		TemacUtilErrorTrap("TxBDs were not ready for post processing");
		return XST_FAILURE;
	}

	/*
	 * Examine the TxBDs.
	 *
	 * There isn't much to do. The only thing to check would be DMA exception
	 * bits. But this would also be caught in the error handler. So we just
	 * return these BDs to the free list
	 */
	Status = XLlDma_BdRingFree(TxRingPtr, 2, Bd1Ptr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error freeing up TxBDs");
		return XST_FAILURE;
	}


	/*
	 * Wait for Rx indication
	 */
	while (!FramesRx);

    printf("Transmitted Packet!\r\n");
    printf("\r\n");

	/*
	 * Now that the frame has been received, post process our RxBD.
	 * Since we have only submitted 1 to HW, then there should be only 1 ready
	 * for post processing.
	 */
	if (XLlDma_BdRingFromHw(RxRingPtr, 1, &Bd1Ptr) == 0) {
		TemacUtilErrorTrap("RxBD was not ready for post processing");
		return XST_FAILURE;
	}

	/*
	 * There is no device status to check. If there was a DMA error, it
	 * should have been reported to the error handler. Check the receive
	 * length against the transmitted length, then verify the data.
	 *
	 * Note in LLTEMAC case, USR4_OFFSET word in the RX BD is used to store
	 * the real length of the received packet
	 */
        if ((XLlDma_BdRead(Bd1Ptr, XLLDMA_BD_USR4_OFFSET) & 0x3FFF)

                != TxFrameLength) {

                TemacUtilErrorTrap("Length mismatch");

                return XST_FAILURE;

        }



        if (TemacUtilFrameVerify(&TxFrame, &RxFrame) != 0) {

                TemacUtilErrorTrap("Data mismatch");

                return XST_FAILURE;

        }


	/*
	 * Return the RxBD back to the channel for later allocation. Free the
	 * exact number we just post processed.
	 */
	Status = XLlDma_BdRingFree(RxRingPtr, 1, Bd1Ptr);
	if (Status != XST_SUCCESS) {
		TemacUtilErrorTrap("Error freeing up TxBDs");
		return XST_FAILURE;
	}

	/*
	 * Finished this example. If everything worked correctly, all TxBDs and
	 * RxBDs should be free for allocation. Stop the device.
	 */
	XLlTemac_Stop(TemacInstancePtr);

	return XST_SUCCESS;
}
/**
*
* This function demonstrates the usage of the TEMAC by sending and receiving
* a single frame in polled mode.
*
* @param    None.
*
* @return   XST_SUCCESS to indicate success, otherwise XST_FAILURE.
*
* @note     None.
*
******************************************************************************/
int TemacSingleFramePolledExample(void)
{
	u32 FifoFreeBytes;
	int PayloadSize = 100;
	u32 TxFrameLength;
	u32 RxFrameLength;

	/*
	 * Start the TEMAC device
	 */
	XLlTemac_Start(&TemacInstance);

	/*
	 * Setup the packet to be transmitted
	 */
	TemacUtilFrameHdrFormatMAC(&TxFrame, TemacMAC);
	TemacUtilFrameHdrFormatType(&TxFrame, PayloadSize);
	TemacUtilFrameSetPayloadData(&TxFrame, PayloadSize);

	/*
	 * Clear out the receive packet memory area
	 */
	TemacUtilFrameMemClear(&RxFrame);

	/*
	 * Calculate frame length (not including FCS)
	 */
	TxFrameLength = XTE_HDR_SIZE + PayloadSize;

	/*******************/
	/* Send the packet */
	/*******************/

	/*
	 * Wait for enough room in FIFO to become available
	 */
	do {
		FifoFreeBytes = XLlFifo_TxVacancy(&FifoInstance);
	} while (FifoFreeBytes < TxFrameLength);

	/*
	 * Write the frame data to FIFO
	 */
	XLlFifo_Write(&FifoInstance, TxFrame, TxFrameLength);

	/*
	 * Initiate transmit
	 */
	XLlFifo_TxSetLen(&FifoInstance, TxFrameLength);

	/*
	 * Wait for status of the transmitted packet
	 */
	switch (TemacPollForTxStatus()) {
	case XST_SUCCESS:	/* Got a sucessfull transmit status */
		break;

	case XST_NO_DATA:	/* Timed out */
		TemacUtilErrorTrap("Tx timeout");
		return XST_FAILURE;

	default:		/* Some other error */
		return XST_FAILURE;
	}

	/**********************/
	/* Receive the packet */
	/**********************/

	/*
	 * Wait for packet Rx
	 */
	switch (TemacPollForRxStatus()) {
	case XST_SUCCESS:	/* Got a sucessfull receive status */
		break;

	case XST_NO_DATA:	/* Timed out */
		TemacUtilErrorTrap("Rx timeout");
		return XST_FAILURE;

	default:		/* Some other error */
		return XST_FAILURE;
	}

	while(XLlFifo_RxOccupancy(&FifoInstance)) {
		/*
		 * A packet as arrived, get its length
		 */
		RxFrameLength = XLlFifo_RxGetLen(&FifoInstance);

		/*
		 * Read the received packet data
		 */
		XLlFifo_Read(&FifoInstance, &RxFrame, RxFrameLength);
	
		/*
		 * Verify the received frame length
		 */
		if ((RxFrameLength) != TxFrameLength) {
			TemacUtilErrorTrap("Receive length incorrect");
			return XST_FAILURE;
		}

		/*
		 * Validate frame data
		 */
		if (TemacUtilFrameVerify(&TxFrame, &RxFrame) != 0) {
			TemacUtilErrorTrap("Receive Data mismatch");
			return XST_FAILURE;
		}
	}

	/*
	 * Stop device
	 */
	XLlTemac_Stop(&TemacInstance);

	return XST_SUCCESS;
}