//
// USB library for XMega AVR CDC operation
// Homelab library
//
// Department of Mechatronics
// Tallinn University of Technology
// ITT Group
// © Copyrights 2014
//

#include "usb/usb.h"

/** LUFA CDC Class driver interface configuration and state information. This structure is
 *  passed to all CDC Class driver functions, so that multiple instances of the same class
 *  within a device can be differentiated from one another.
 */
USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface =
{
    .Config =
    {
        .ControlInterfaceNumber   = 0,
        .DataINEndpoint           =
        {
            .Address          = CDC_TX_EPADDR,
            .Size             = CDC_TXRX_EPSIZE,
            .Banks            = 1,
        },
        .DataOUTEndpoint =
        {
            .Address          = CDC_RX_EPADDR,
            .Size             = CDC_TXRX_EPSIZE,
            .Banks            = 1,
        },
        .NotificationEndpoint =
        {
            .Address          = CDC_NOTIFICATION_EPADDR,
            .Size             = CDC_NOTIFICATION_EPSIZE,
            .Banks            = 1,
        },
    },
};

//
// Initialize USB CDC interface
//
void usb_init()
{
    PORTQ.DIR |= 1;		// PQ0 as output
    PORTQ.OUT &= ~1;	// PQ0 low

    if (PORTQ.IN & (1<<1))
    {
        /* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */
        XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ);
        XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB);

        // Initialize USB
        USB_Init();

        sei();
        PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm;
    }
    else
    {
        for(uint8_t t = 0; t < 10; t++)
        {
            PORTQ.OUTTGL = 1;
            _delay_ms(50);
        }
    }

}

//
// Get USB status
// returns 1 - USB connected
// returns 0 - USB disconnected
//
uint8_t usb_get_status()
{
    return 1-CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);
}

//
// Sends char via USB
//
void usb_send_char(char character)
{
    CDC_Device_SendByte(&VirtualSerial_CDC_Interface, character);
}

//
// Send string via USB
//
void usb_send_string(char *string)
{
    CDC_Device_SendString(&VirtualSerial_CDC_Interface, string);
}

//
// Receives byte via USB
//
uint8_t usb_read_byte()
{
    return CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface);
}

//
// USB Task
//
void usb_task()
{
    CDC_Device_USBTask(&VirtualSerial_CDC_Interface);
    USB_USBTask();
}


/** Event handler for the library USB Connection event. */
void EVENT_USB_Device_Connect(void)
{
    //LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING);
    PORTQ.OUT |= 1;
}

/** Event handler for the library USB Disconnection event. */
void EVENT_USB_Device_Disconnect(void)
{
    //LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY);
    PORTQ.OUT &= ~1;
}

/** Event handler for the library USB Configuration Changed event. */
void EVENT_USB_Device_ConfigurationChanged(void)
{
    bool ConfigSuccess = true;
    ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface);

    //LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
}

/** Event handler for the library USB Control Request reception event. */
void EVENT_USB_Device_ControlRequest(void)
{
    CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface);
}
