/******************************************************************************
*
* Copyright (C) 2010 - 2015 Xilinx, Inc.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/
/***************************** Include Files *********************************/

#include "xparameters.h"		/* XPAR parameters */
#include "xusbps.h"			/* USB controller driver */
#include "xscugic.h"
#include "xusbps_cdc_ch9.h"		/* Generic Chapter 9 handling code */
#include "xusbps_cdc_ch9_cdc.h"	/* Storage class handling code */
#include "xil_exception.h"
#include "xpseudo_asm.h"
#include "xreg_cortexa9.h"
#include "xil_cache.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xusbps_cdc.h"
#include "xusbps_cdc_irq.h"		/* USB interrupt processing code */
#include "xusbps_cdc_buffer.h"
#include "xgpiops.h"
#include "xspips.h"

static int setup_interrupts(XScuGic *intc) {
	int status;
	XScuGic_Config *intc_config;

	intc_config = XScuGic_LookupConfig(XPAR_SCUGIC_SINGLE_DEVICE_ID);
	if (NULL == intc_config) {
		return XST_FAILURE;
	}

	status = XScuGic_CfgInitialize(intc, intc_config, intc_config->CpuBaseAddress);
	if (status != XST_SUCCESS) {
		return status;
	}

	Xil_ExceptionInit();

	/* Connect the GIC interrupt handler to the exception vector in the processor */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
								 (Xil_ExceptionHandler)XScuGic_InterruptHandler,
								 intc);

	return XST_SUCCESS;
}

//static void reset_usb(void) {
//	// Ensure that the PHY is out of reset
//	volatile u32 *gpio_base;
//	volatile u32 *gpio_oen;
//	volatile u32 *gpio_dir;
//
//	/* Ensure that the USB PHY is not in reset */
//	gpio_base = (u32 *)0xE000A000;
//	gpio_oen = (u32 *)0xE000A208;
//	gpio_dir = (u32 *)0xE000A204;
//
//	*(gpio_oen) |= 0x00000080;
//	*(gpio_dir) |= 0x00000080;
//	*gpio_base = 0xff7f0080;
//}

static void reset_usb(void) {
    XGpioPs Gpio;
    XGpioPs_Config *ConfigPtr;

    ConfigPtr = XGpioPs_LookupConfig(XPAR_PS7_GPIO_0_DEVICE_ID);
    XGpioPs_CfgInitialize(&Gpio, ConfigPtr, ConfigPtr->BaseAddr);

    XGpioPs_SetDirectionPin(&Gpio, 46, 1);
    XGpioPs_SetOutputEnablePin(&Gpio, 46, 1);
    XGpioPs_WritePin(&Gpio, 46, 0x1);
}


int main(void) {
	int status;
	XUsbPs usb;
	XScuGic intc;
	u8 text_buffer[512];
	u32 bytes;

	xil_printf("\n\n--- USB CDC ACM Test Application ---\n\n");

	reset_usb();

	//SPIʼ
	//豸IDñвãȻʼ
	SpiConfig = XSpiPs_LookupConfig(XPAR_XSPIPS_0_DEVICE_ID);
	XSpiPs_CfgInitialize(&SPI0, SpiConfig, SpiConfig->BaseAddress);

	//SPIķƵ
	XSpiPs_SetClkPrescaler(&SPI0, XSPIPS_CLK_PRESCALE_16);

	//SPIģʽʹ
	XSpiPs_SetOptions(&SPI0, XSPIPS_MASTER_OPTION | XSPIPS_CLK_ACTIVE_LOW_OPTION | XSPIPS_CLK_PHASE_1_OPTION);

	// Set up and configure the interrupt system
	status = setup_interrupts(&intc);
	if (status != XST_SUCCESS) {
		xil_printf("ERROR: Unable to initialize interrupt system: %d\n", status);
		exit(1);
	}

	status = xusbps_cdc_register_interrupt(&intc, &usb, XPAR_PS7_USB_0_INTR);
	if (status != XST_SUCCESS) {
		xil_printf("ERROR: Unable to register USB interrupts: %d\n", status);
		exit(1);
	}

	// Enable interrupts in the processor
	Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ);

	/* Initialize the USB controller */
	status = xusb_cdc_init(&usb, XPAR_PS7_USB_0_DEVICE_ID, XPAR_PS7_USB_0_INTR, 64 * 1024);
	if (status != XST_SUCCESS) {
		xil_printf("ERROR: Unable to set up USB controller: %d\n", status);
		exit(1);
	}



//		while(1) {
//
//				bytes = xusb_cdc_rx_bytes_available() > 5 ? 5 : xusb_cdc_rx_bytes_available();
//				if (bytes != 0) {
//					bytes = xusb_cdc_receive_data(text_buffer, bytes);
//					text_buffer[bytes] = 0;
//						xusb_cdc_send_data(&usb, (u8 *)hello, 9);
//						xusb_cdc_send_data(&usb, (u8 *)text_buffer, 1);
//						xusb_cdc_send_data(&usb, (u8 *)hai, 2);
//
//						}
//		}
//	return 0;

	while(1) {

			bytes = xusb_cdc_rx_bytes_available();

			if(bytes != 0)
			{
				//xil_printf("bytes is %d\n", bytes);
				if(bytes > 512)
					bytes = 512;
				else
					bytes = xusb_cdc_rx_bytes_available();
			}

			if (bytes != 0) {
				bytes = xusb_cdc_receive_data(text_buffer, bytes);
				xusb_cdc_send_data(&usb, (u8 *)text_buffer, bytes);
			}


	}
	return 0;


}
