/**
* The example to do the simple transfer through polling. The constant
* NUMBER_OF_TRANSFERS defines how many times a simple transfer is repeated.
*
* @param	DeviceId is the Device Id of the XAxiCdma instance
*
* @return
*		- XST_SUCCESS if example finishes successfully
*		- XST_FAILURE if error occurs
*
* @note		If the hardware build has problems with interrupt,
*			then this function hangs
*
*
******************************************************************************/
int XAxiCdma_SimplePollExample(u16 DeviceId)
{
	XAxiCdma_Config *CfgPtr;
	int Status;
	int SubmitTries = 10;	/* try 10 times on submission */
	int Tries = NUMBER_OF_TRANSFERS;
	int Index;

	/* Initialize the XAxiCdma device.
	 */
	CfgPtr = XAxiCdma_LookupConfig(DeviceId);
	if (!CfgPtr) {
		return XST_FAILURE;
	}

	Status = XAxiCdma_CfgInitialize(&AxiCdmaInstance, CfgPtr,
		CfgPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/* Disable interrupts, we use polling mode
	 */
	XAxiCdma_IntrDisable(&AxiCdmaInstance, XAXICDMA_XR_IRQ_ALL_MASK);

	for (Index = 0; Index < Tries; Index++) {
		Status = DoSimplePollTransfer(&AxiCdmaInstance,
			BUFFER_BYTESIZE, SubmitTries);
		if (Status != XST_SUCCESS) {
				return XST_FAILURE;
		}
	}

	/* Test finishes successfully
	 */
	return XST_SUCCESS;
}
int XAxiCdma_HybridIntrExample(XScuGic *IntcInstancePtr, XAxiCdma *InstancePtr,
						u16 DeviceId,u32 IntrId)
#endif
{
	XAxiCdma_Config *CfgPtr;
	int Status;
	int SubmitTries = 10;		/* Retry to submit */

	/* Initialize the XAxiCdma device.
	 */
	CfgPtr = XAxiCdma_LookupConfig(DeviceId);
	if (!CfgPtr) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Cannot find config structure for device %d\r\n",
			XPAR_AXICDMA_0_DEVICE_ID);

		return XST_FAILURE;
	}

	Status = XAxiCdma_CfgInitialize(InstancePtr, CfgPtr,
						CfgPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Initialization failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Setup the interrupt system
	 */
	Status = SetupIntrSystem(IntcInstancePtr, InstancePtr, IntrId);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Setup Intr system failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Enable all (completion/error/delay) interrupts
	 */
	XAxiCdma_IntrEnable(InstancePtr, XAXICDMA_XR_IRQ_ALL_MASK);

	/* First simple transfer
	 */
	Done = 0;
	Error = 0;

	Status = DoSimpleTransfer(InstancePtr,
		   BUFFER_BYTESIZE, SubmitTries);

	if(Status != XST_SUCCESS) {
		DisableIntrSystem(IntcInstancePtr, IntrId);

		return XST_FAILURE;
	}

	xil_printf("First simple transfer successful\r\n");

	/* The scatter gather transfer
	 */
	Done = 0;
	Error = 0;

	Status = DoSgTransfer(InstancePtr);
	if(Status != XST_SUCCESS) {
		DisableIntrSystem(IntcInstancePtr, IntrId);

		return XST_FAILURE;
	}

	xil_printf("Scatter gather transfer successful\r\n");

	/* Second simple transfer
	 */
	Done = 0;
	Error = 0;

	Status = DoSimpleTransfer(InstancePtr,
		   BUFFER_BYTESIZE, SubmitTries);

	if(Status != XST_SUCCESS) {
		DisableIntrSystem(IntcInstancePtr, IntrId);

		return XST_FAILURE;
	}

	xil_printf("Second simple transfer successful\r\n");

	/* Test finishes successfully, clean up and return
	 */
	DisableIntrSystem(IntcInstancePtr, IntrId);

	return XST_SUCCESS;
}
/**
* This function transfers data from Source Address to Destination Address
* using the AXI CDMA.
* User has to specify the Source Address, Destination Address and Transfer
* Length in AXICDMA_SRC_ADDR, AXICDMA_DEST_ADDR and AXICDMA_LENGTH defines
* respectively.
*
* @param	DeviceId is device ID of the XAxiCdma Device.
*
* @return	- XST_SUCCESS if successful
*		- XST_FAILURE.if unsuccessful.
*
* @note		If the hardware system is not built correctly, this function
*		may never return to the caller.
*
******************************************************************************/
int DmaDataTransfer (u16 DeviceID)
{
	int Status;
	volatile int Error;
	XAxiCdma_Config *ConfigPtr;

	Error = 0;

	/*
	 * Make sure we have a valid addresses for Src and Dst.
	 */
	if (AXICDMA_SRC_ADDR == 0) {
		return XST_FAILURE;
	}

	if (AXICDMA_DEST_ADDR == 0) {
		return XST_FAILURE;
	}

	/*
	 * Initialize the AXI CDMA IP.
	 */
	ConfigPtr = XAxiCdma_LookupConfig(DeviceID);
	if (ConfigPtr == NULL) {
		return XST_FAILURE;
	}

	Status = XAxiCdma_CfgInitialize(&CdmaInstance,
				ConfigPtr, ConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/*
	 * Reset the AXI CDMA device.
	 */
	XAxiCdma_Reset(&CdmaInstance);

	/*
	 * Disable AXI CDMA Interrupts
	 */
	XAxiCdma_IntrDisable(&CdmaInstance, XAXICDMA_XR_IRQ_ALL_MASK);

	/*
	 * Start Transferring Data from source to destination in polled mode
	 */
	XAxiCdma_SimpleTransfer (&CdmaInstance, AXICDMA_SRC_ADDR,
					AXICDMA_DEST_ADDR, AXICDMA_LENGTH, 0, 0);

	/*
	 * Poll Status register waiting for either Completion or Error
	 */
	while (XAxiCdma_IsBusy(&CdmaInstance));

	Error = XAxiCdma_GetError(&CdmaInstance);

	if (Error != 0x0) {

		xil_printf("AXI CDMA Transfer Error =  %8.8x\r\n");
		return XST_FAILURE;
	}

	xil_printf("AXI CDMA Transfer is Complete\r\n");


	return XST_SUCCESS;
}
/**
* The example to do the scatter gather transfer through polling.
*
* @param	DeviceId is the Device Id of the XAxiCdma instance
*
* @return
* 		- XST_SUCCESS if example finishes successfully
* 		- XST_FAILURE if error occurs
*
* @note		None
*
******************************************************************************/
int XAxiCdma_SgPollExample(u16 DeviceId)
{
	XAxiCdma_Config *CfgPtr;
	int Status;
	u8 *SrcPtr;
	u8 *DstPtr;

	SrcPtr = (u8 *)TransmitBufferPtr;
	DstPtr = (u8 *)ReceiveBufferPtr;

#ifdef __aarch64__
	Xil_SetTlbAttributes(BD_SPACE_BASE, MARK_UNCACHEABLE);
#endif

	/* Initialize the XAxiCdma device.
	 */
	CfgPtr = XAxiCdma_LookupConfig(DeviceId);
	if (!CfgPtr) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Cannot find config structure for device %d\r\n",
			XPAR_AXICDMA_0_DEVICE_ID);

		return XST_FAILURE;
	}

	Status = XAxiCdma_CfgInitialize(&AxiCdmaInstance, CfgPtr,
		CfgPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Initialization failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Setup the BD ring
	 */
	Status = SetupTransfer(&AxiCdmaInstance);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Setup BD ring failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	Done = 0;
	Error = 0;

	/* Start the DMA transfer
	 */
	Status = DoTransfer(&AxiCdmaInstance);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Do transfer failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Wait until the DMA transfer is done or error occurs
	 */
	while ((CheckCompletion(&AxiCdmaInstance) < NUMBER_OF_BDS_TO_TRANSFER)
		&& !Error) {
		/* Wait */
	}

	if(Error) {
		int TimeOut = RESET_LOOP_COUNT;

		xdbg_printf(XDBG_DEBUG_ERROR, "Transfer has error %x\r\n",
				Error);

		/* Need to reset the hardware to restore to the correct state
		 */
		XAxiCdma_Reset(&AxiCdmaInstance);

		while (TimeOut) {
			if (XAxiCdma_ResetIsDone(&AxiCdmaInstance)) {
				break;
			}
			TimeOut -= 1;
		}

		/* Reset has failed, print a message to notify the user
		 */
		if (!TimeOut) {
			xdbg_printf(XDBG_DEBUG_ERROR,
			    "Reset hardware failed with %d\r\n", Status);

		}

		return XST_FAILURE;
	}

	/* Transfer completed successfully, check data
	 */
	Status = CheckData(SrcPtr, DstPtr,
		MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR, "Check data failed for sg "
		    "transfer\r\n");
		return XST_FAILURE;
	}

	/* Test finishes successfully, return successfully
	 */
	return XST_SUCCESS;
}
int XAxiCdma_SgIntrExample(XScuGic *IntcInstancePtr, XAxiCdma *InstancePtr,
				u16 DeviceId,u32 IntrId)
#endif
{
	XAxiCdma_Config *CfgPtr;
	int Status;
	u8 *SrcPtr;
	u8 *DstPtr;

	SrcPtr = (u8 *)TransmitBufferPtr;
	DstPtr = (u8 *)ReceiveBufferPtr;

#ifdef __aarch64__
	Xil_SetTlbAttributes(BD_SPACE_BASE, MARK_UNCACHEABLE);
#endif

	/* Initialize the XAxiCdma device.
	 */
	CfgPtr = XAxiCdma_LookupConfig(DeviceId);
	if (!CfgPtr) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Cannot find config structure for device %d\r\n",
			XPAR_AXICDMA_0_DEVICE_ID);

		return XST_FAILURE;
	}

	Status = XAxiCdma_CfgInitialize(InstancePtr, CfgPtr,
						CfgPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Initialization failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Setup the BD ring
	 */
	Status = SetupTransfer(InstancePtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Setup BD ring failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Setup the interrupt system
	 */
	Status = SetupIntrSystem(IntcInstancePtr, InstancePtr, IntrId);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Setup Intr system failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Enable completion and error interrupts
	 */
	XAxiCdma_IntrEnable(InstancePtr, XAXICDMA_XR_IRQ_ALL_MASK);

	/* Start the DMA transfer
	 */
	Status = DoTransfer(InstancePtr);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR,
		    "Do transfer failed with %d\r\n", Status);

		return XST_FAILURE;
	}

	/* Wait until the DMA transfer is done
	 */

	while ((Done < NUMBER_OF_BDS_TO_TRANSFER) && !Error) {
		/* Wait */
	}

	if(Error) {
		xdbg_printf(XDBG_DEBUG_ERROR, "Transfer has error %x\r\n",
		    (unsigned int)XAxiCdma_GetError(InstancePtr));

		DisableIntrSystem(IntcInstancePtr, IntrId);

		return XST_FAILURE;
	}

	/* Transfer completes successfully, check data
	 */
	Status = CheckData(SrcPtr, DstPtr,
		MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER);
	if (Status != XST_SUCCESS) {
		xdbg_printf(XDBG_DEBUG_ERROR, "Check data failed for sg "
		    "transfer\r\n");

		DisableIntrSystem(IntcInstancePtr, IntrId);
		return XST_FAILURE;
	}

	/* Test finishes successfully, clean up and return
	 */
	DisableIntrSystem(IntcInstancePtr, IntrId);

	return XST_SUCCESS;
}
void wlan_mac_util_init( u32 type, u32 eth_dev_num ){
	int            Status;
    u32            i;
	u32            gpio_read;
	u32            queue_len;
	u64            timestamp;
	u32            log_size;
	tx_frame_info* tx_mpdu;

    // Initialize callbacks
	eth_rx_callback         = (function_ptr_t)nullCallback;
	mpdu_rx_callback        = (function_ptr_t)nullCallback;
	fcs_bad_rx_callback     = (function_ptr_t)nullCallback;
	mpdu_tx_done_callback   = (function_ptr_t)nullCallback;
	pb_u_callback           = (function_ptr_t)nullCallback;
	pb_m_callback           = (function_ptr_t)nullCallback;
	pb_d_callback           = (function_ptr_t)nullCallback;
	uart_callback           = (function_ptr_t)nullCallback;
	ipc_rx_callback         = (function_ptr_t)nullCallback;
	check_queue_callback    = (function_ptr_t)nullCallback;
	mpdu_tx_accept_callback = (function_ptr_t)nullCallback;

	wlan_mac_ipc_init();

	for(i=0;i < NUM_TX_PKT_BUFS; i++){
		tx_mpdu = (tx_frame_info*)TX_PKT_BUF_TO_ADDR(i);
		tx_mpdu->state = TX_MPDU_STATE_EMPTY;
	}

	tx_pkt_buf = 0;

#ifdef _DEBUG_
	xil_printf("locking tx_pkt_buf = %d\n", tx_pkt_buf);
#endif

	if(lock_pkt_buf_tx(tx_pkt_buf) != PKT_BUF_MUTEX_SUCCESS){
		warp_printf(PL_ERROR,"Error: unable to lock pkt_buf %d\n",tx_pkt_buf);
	}

	tx_mpdu = (tx_frame_info*)TX_PKT_BUF_TO_ADDR(tx_pkt_buf);
	tx_mpdu->state = TX_MPDU_STATE_TX_PENDING;

	//Initialize the central DMA (CDMA) driver
	XAxiCdma_Config *cdma_cfg_ptr;
	cdma_cfg_ptr = XAxiCdma_LookupConfig(XPAR_AXI_CDMA_0_DEVICE_ID);
	Status = XAxiCdma_CfgInitialize(&cdma_inst, cdma_cfg_ptr, cdma_cfg_ptr->BaseAddress);
	if (Status != XST_SUCCESS) {
		warp_printf(PL_ERROR,"Error initializing CDMA: %d\n", Status);
	}
	XAxiCdma_IntrDisable(&cdma_inst, XAXICDMA_XR_IRQ_ALL_MASK);


	Status = XGpio_Initialize(&Gpio, GPIO_DEVICE_ID);
	gpio_timestamp_initialize();

	if (Status != XST_SUCCESS) {
		warp_printf(PL_ERROR, "Error initializing GPIO\n");
		return;
	}

	Status = XUartLite_Initialize(&UartLite, UARTLITE_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		warp_printf(PL_ERROR, "Error initializing XUartLite\n");
		return;
	}


	gpio_read = XGpio_DiscreteRead(&Gpio, GPIO_INPUT_CHANNEL);
	if(gpio_read&GPIO_MASK_DRAM_INIT_DONE){
		xil_printf("DRAM SODIMM Detected\n");
		if(memory_test()==0){
			queue_dram_present(1);
			dram_present = 1;
		} else {
			queue_dram_present(0);
			dram_present = 0;
		}
	} else {
		queue_dram_present(0);
		dram_present = 0;
		timestamp = get_usec_timestamp();

		while((get_usec_timestamp() - timestamp) < 100000){
			if((XGpio_DiscreteRead(&Gpio, GPIO_INPUT_CHANNEL)&GPIO_MASK_DRAM_INIT_DONE)){
				xil_printf("DRAM SODIMM Detected\n");
				if(memory_test()==0){
					queue_dram_present(1);
					dram_present = 1;
				} else {
					queue_dram_present(0);
					dram_present = 0;
				}
				break;
			}
		}
	}

	queue_len = queue_init();

	if( dram_present ) {
		//The event_list lives in DRAM immediately following the queue payloads.
		if(MAX_EVENT_LOG == -1){
			log_size = (DDR3_SIZE - queue_len);
		} else {
			log_size = min( (DDR3_SIZE - queue_len), MAX_EVENT_LOG );
		}

		event_log_init( (void*)(DDR3_BASEADDR + queue_len), log_size );

	} else {
		log_size = 0;
	}

#ifdef USE_WARPNET_WLAN_EXP
	// Communicate the log size to WARPNet
	node_info_set_event_log_size( log_size );
#endif

	wlan_eth_init();

	//Set direction of GPIO channels
	XGpio_SetDataDirection(&Gpio, GPIO_INPUT_CHANNEL, 0xFFFFFFFF);
	XGpio_SetDataDirection(&Gpio, GPIO_OUTPUT_CHANNEL, 0);


	Status = XTmrCtr_Initialize(&TimerCounterInst, TMRCTR_DEVICE_ID);
	if (Status != XST_SUCCESS) {
		xil_printf("XTmrCtr failed to initialize\n");
		return;
	}

	//Set the handler for Timer
	XTmrCtr_SetHandler(&TimerCounterInst, timer_handler, &TimerCounterInst);

	//Enable interrupt of timer and auto-reload so it continues repeatedly
	XTmrCtr_SetOptions(&TimerCounterInst, TIMER_CNTR_FAST, XTC_DOWN_COUNT_OPTION | XTC_INT_MODE_OPTION);
	XTmrCtr_SetOptions(&TimerCounterInst, TIMER_CNTR_SLOW, XTC_DOWN_COUNT_OPTION | XTC_INT_MODE_OPTION);

	timer_running[TIMER_CNTR_FAST] = 0;
	timer_running[TIMER_CNTR_SLOW] = 0;
    
    // Get the type of node from the input parameter
    hw_info.type              = type;
    hw_info.wn_exp_eth_device = eth_dev_num;
    
#ifdef USE_WARPNET_WLAN_EXP
    // We cannot initialize WARPNet until after the lower CPU sends all the HW information to us through the IPC call
    warpnet_initialized = 0;
#endif
    
    wlan_mac_ltg_sched_init();

}