/**
 * Default descriptors for an Audio class with a single microphone
 */


#include "conf_usb.h"
#include "udd.h"
#include "udc_desc.h"
//#include "udi_cdc.h"
#include "udi_audio.h"
#include "usb_protocol_audio.h"

#define USB_DEVICE_NB_INTERFACE        2


//! USB Device Descriptor
# define USB_VERSION   USB_V2_0
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE usb_dev_desc_t udc_device_desc = {
	.bLength                   = sizeof(usb_dev_desc_t),
	.bDescriptorType           = USB_DT_DEVICE,
	.bcdUSB                    = LE16(USB_VERSION),
	.bDeviceClass              = AUDIO_CLASS_DEVICE,
	.bDeviceSubClass           = 0,
	.bDeviceProtocol           = 0,
	.bMaxPacketSize0           = USB_DEVICE_EP_CTRL_SIZE,
	.idVendor                  = LE16(USB_DEVICE_VENDOR_ID),
	.idProduct                 = LE16(USB_DEVICE_PRODUCT_ID),
	.bcdDevice                 = LE16((USB_DEVICE_MAJOR_VERSION << 8)
			| USB_DEVICE_MINOR_VERSION),
#ifdef USB_DEVICE_MANUFACTURE_NAME
	.iManufacturer = 1,
#else
	.iManufacturer             = 0,  // No manufacture string
#endif
#ifdef USB_DEVICE_PRODUCT_NAME
	.iProduct = 2,
#else
	.iProduct                  = 0,  // No product string
#endif
#if (defined USB_DEVICE_SERIAL_NAME || defined USB_DEVICE_GET_SERIAL_NAME_POINTER) 
	.iSerialNumber = 3,
#else
	.iSerialNumber             = 0,  // No serial string
#endif
	.bNumConfigurations = 1
};

//! Structure for USB Device Configuration Descriptor
COMPILER_PACK_SET(1)
typedef struct {
	usb_conf_desc_t conf;
    usb_iface_desc_t udi_audio_ac_iface;
    usb_audio_ac_interface_hdr_desc_t udi_audio_iface_hdr;
    usb_audio_input_terminal_desc_t udi_audio_it;
    usb_audio_output_terminal_desc_t udi_audio_ot;
    usb_iface_desc_t udi_audio_streaming_zero_iface;
    usb_iface_desc_t udi_audio_streaming_iface;
    usb_audio_cs_iface_desc_t udi_audio_cs_iface;
    usb_audio_format_type_i_desc_t udi_audio_mic_format;
    usb_ep_ext_desc_t udi_audio_mic_ep;
    usb_audio_cs_endpoint_desc_t udi_audio_mic_cs_ep;
} udc_desc_t;
COMPILER_PACK_RESET()

//! USB Device Configuration Descriptor filled for full and high speed
COMPILER_WORD_ALIGNED
UDC_DESC_STORAGE udc_desc_t udc_desc_fs = {
	.conf.bLength              = sizeof(usb_conf_desc_t),
	.conf.bDescriptorType      = USB_DT_CONFIGURATION,
	.conf.wTotalLength         = LE16(sizeof(udc_desc_t)),
	.conf.bNumInterfaces       = USB_DEVICE_NB_INTERFACE, // Audio control and Audio streaming interfaces
	.conf.bConfigurationValue  = 1,
	.conf.iConfiguration       = 0,
	.conf.bmAttributes         = 0x80, // Bus powered, not self powered, no remote wakeup
	.conf.bMaxPower            = USB_CONFIG_MAX_POWER(USB_DEVICE_POWER),

    .udi_audio_ac_iface.bLength = sizeof(usb_iface_desc_t),
    .udi_audio_ac_iface.bDescriptorType = USB_DT_INTERFACE,
    .udi_audio_ac_iface.bInterfaceNumber = 0,
    .udi_audio_ac_iface.bAlternateSetting = 0,
	.udi_audio_ac_iface.bNumEndpoints = 0,
	.udi_audio_ac_iface.bInterfaceClass = AUDIO_CLASS_DEVICE,
	.udi_audio_ac_iface.bInterfaceSubClass = AUDIO_SUBCLASS_CONTROL,
	.udi_audio_ac_iface.bInterfaceProtocol = 0,
	.udi_audio_ac_iface.iInterface = 0,

    .udi_audio_iface_hdr.bLength = sizeof(usb_audio_ac_interface_hdr_desc_t),
	.udi_audio_iface_hdr.bDescriptorType = AUDIO_CS_INTERFACE,
	.udi_audio_iface_hdr.bDescriptorSubtype = AUDIO_AC_HEADER,
	.udi_audio_iface_hdr.bcdADC = 0x0100, // Class 1.0
    .udi_audio_iface_hdr.wTotalLength = sizeof(usb_audio_ac_interface_hdr_desc_t) + 
        sizeof(usb_audio_input_terminal_desc_t) + sizeof(usb_audio_output_terminal_desc_t),
    .udi_audio_iface_hdr.bInCollection = USB_AUDIO_NR_IFACE,
    .udi_audio_iface_hdr.baInterfaceNr[0] = 1,

    .udi_audio_it.bLength = sizeof(usb_audio_input_terminal_desc_t),
    .udi_audio_it.bDescriptorType = AUDIO_CS_INTERFACE,
	.udi_audio_it.bDescriptorSubtype = AUDIO_AC_INPUT_TERMINAL,
    .udi_audio_it.bTerminalId = 1, 
    .udi_audio_it.wTerminalType = 0x0201, // Terminal is microphone
    .udi_audio_it.bAssocTerminal = 0,
    .udi_audio_it.bNrChannels = USB_AUDIO_NB_CHANNELS, 
#if USB_AUDIO_NB_CHANNELS == 1
    .udi_audio_it.wChannelConfig = 0, // No bits set for mono
#else
    .udi_audio_it.wChannelConfig = 0x0003, // (L,R)
#endif
    .udi_audio_it.iChannelNames = 0,
    .udi_audio_it.iTerminal = 0,

    .udi_audio_ot.bLength = sizeof(usb_audio_output_terminal_desc_t),
    .udi_audio_ot.bDescriptorType = AUDIO_CS_INTERFACE,
	.udi_audio_ot.bDescriptorSubtype = AUDIO_AC_OUTPUT_TERMINAL,
    .udi_audio_ot.bTerminalId = 2, 
    .udi_audio_ot.wTerminalType = 0x0101, // Terminal is usb streaming
    .udi_audio_ot.bAssocTerminal = 0,
    .udi_audio_ot.bSourceID = 1, // From microphone
    .udi_audio_ot.iTerminal = 0,

    .udi_audio_streaming_zero_iface.bLength = sizeof(usb_iface_desc_t),
    .udi_audio_streaming_zero_iface.bDescriptorType = USB_DT_INTERFACE,
    .udi_audio_streaming_zero_iface.bInterfaceNumber = 1,
    .udi_audio_streaming_zero_iface.bAlternateSetting = 0,
	.udi_audio_streaming_zero_iface.bNumEndpoints = 0,
	.udi_audio_streaming_zero_iface.bInterfaceClass = AUDIO_CLASS_DEVICE,
	.udi_audio_streaming_zero_iface.bInterfaceSubClass = AUDIO_SUBCLASS_STREAMING,
	.udi_audio_streaming_zero_iface.bInterfaceProtocol = 0,
	.udi_audio_streaming_zero_iface.iInterface = 0,

    .udi_audio_streaming_iface.bLength = sizeof(usb_iface_desc_t),
    .udi_audio_streaming_iface.bDescriptorType = USB_DT_INTERFACE,
    .udi_audio_streaming_iface.bInterfaceNumber = 1,
    .udi_audio_streaming_iface.bAlternateSetting = 1,
	.udi_audio_streaming_iface.bNumEndpoints = 1,
	.udi_audio_streaming_iface.bInterfaceClass = AUDIO_CLASS_DEVICE,
	.udi_audio_streaming_iface.bInterfaceSubClass = AUDIO_SUBCLASS_STREAMING,
	.udi_audio_streaming_iface.bInterfaceProtocol = 0,
	.udi_audio_streaming_iface.iInterface = 0,

    .udi_audio_cs_iface.bLength = sizeof(usb_audio_cs_iface_desc_t),
    .udi_audio_cs_iface.bDescriptorType = AUDIO_CS_INTERFACE,
    .udi_audio_cs_iface.bDescriptorSubtype = AUDIO_AS_GENERAL,
    .udi_audio_cs_iface.bTerminalLink = 2, // Output terminal ID
    .udi_audio_cs_iface.bDelay = 1, // Interface delay
    .udi_audio_cs_iface.wFormatTag = 0x0001, // PCM Format

    .udi_audio_mic_format.bLength = sizeof(usb_audio_format_type_i_desc_t),
    .udi_audio_mic_format.bDescriptorType = AUDIO_CS_INTERFACE,
    .udi_audio_mic_format.bDescriptorSubtype = AUDIO_AS_FORMAT_TYPE,
    .udi_audio_mic_format.bFormatType = 1, // Format Type I
    .udi_audio_mic_format.bNrChannels = USB_AUDIO_NB_CHANNELS, 
    .udi_audio_mic_format.bSubframeSize = 2, // Two bytes per subframe
    .udi_audio_mic_format.bBitResolution = 16,
    .udi_audio_mic_format.bSamFreqType = USB_AUDIO_NR_SAM_FREQ,
    .udi_audio_mic_format.tSamFreq[0] = UAC1_SAMP_RATE(UDI_AUDIO_FREQ), 

    .udi_audio_mic_ep.bLength = sizeof(usb_ep_ext_desc_t),
	.udi_audio_mic_ep.bDescriptorType = USB_DT_ENDPOINT,
	.udi_audio_mic_ep.bEndpointAddress = UDI_AUDIO_DATA_EP_IN_0,
	.udi_audio_mic_ep.bmAttributes = USB_EP_TYPE_ISOCHRONOUS | 0x04, // Asynchronous data isochronous endpoint
	.udi_audio_mic_ep.wMaxPacketSize = 256, // Max will probably be 48x2x2, but let's have some extra for fun
	.udi_audio_mic_ep.bInterval = 1,
    .udi_audio_mic_ep.bRefresh = 0,
    .udi_audio_mic_ep.bSynchAddress = 0,

    .udi_audio_mic_cs_ep.bLength = sizeof(usb_audio_cs_endpoint_desc_t),
    .udi_audio_mic_cs_ep.bDescriptorType = AUDIO_CS_ENDPOINT,
    .udi_audio_mic_cs_ep.bDescriptorSubtype = AUDIO_AS_GENERAL,
    .udi_audio_mic_cs_ep.bmAttributes = 0,
    .udi_audio_mic_cs_ep.bLockDelayUnits = 0,
    .udi_audio_mic_cs_ep.wLockDelay = 0
};

//! Associate an UDI for each USB interface
UDC_DESC_STORAGE udi_api_t *udi_apis[USB_DEVICE_NB_INTERFACE] = {
    &udi_api_audio_control,
    &udi_api_audio_streaming
};

//! Add UDI with USB Descriptors FS & HS
UDC_DESC_STORAGE udc_config_speed_t udc_config_fs[1] = { {
	.desc          = (usb_conf_desc_t UDC_DESC_STORAGE*)&udc_desc_fs,
	.udi_apis = udi_apis,
}};

//! Add all information about USB Device in global structure for UDC
UDC_DESC_STORAGE udc_config_t udc_config = {
	.confdev_lsfs = &udc_device_desc,
	.conf_lsfs = udc_config_fs,
	.conf_bos = NULL,
};
