#include "uac_recorder.h"

//具体 funciton 实现， 以下为uac speaker 实现

#ifdef  DUAL_DENOISE_DEFINE
    #define AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN 2
#else
    #define AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN 1
#endif


#define AUDIO_V2_RANGE_VOL_NUM  1
#define AUDIO_V2_RANGE_SAMPLRATE_NUM  1

#define MIC_CLK_UNIT_ID         11   
#define MIC_IN_TERMINAL_ID      12
#define MIC_FU_TERMINAL_ID      13
#define MIC_OUT_TERMINAL_ID     14

#define AUDIO_RECORDER_V2_EP_MAX_PACKET_SIZE     512

#define RECORDER_INTF_STR_INDEX 8


static struct udevice_descriptor dev_desc =
{
   USB_DESC_LENGTH_DEVICE,     //bLength;
   USB_DESC_TYPE_DEVICE,       //type;
   USB_BCD_VERSION,            //bcdUSB;
   USB_CLASS_AUDIO,           //bDeviceClass;
   0x00,                       //bDeviceSubClass;
   0x00,                       //bDeviceProtocol;
   64,                        //bMaxPacketSize0;
   _VENDOR_ID,                 //idVendor;
   _PRODUCT_ID,                //idProduct;
   USB_BCD_DEVICE,             //bcdDevice;
   USB_STRING_MANU_INDEX,      //iManufacturer;
   USB_STRING_PRODUCT_INDEX,   //iProduct;
   USB_STRING_SERIAL_INDEX,    //iSerialNumber;Unused.
   USB_DYNAMIC,                //bNumConfigurations;
};

static struct audio_v2_cs_if_ac_feature_unit_descriptor {
    uint8_t bLength;
    uint8_t bDescriptorType;
    uint8_t bDescriptorSubtype;
    uint8_t bUnitID;
    uint8_t bSourceID;
    uint32_t bmaControls[AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN+1];
    uint8_t iFeature;
} __attribute__((packed));

static struct audio_v2_ac_descriptor
{
#ifdef RT_USB_DEVICE_COMPOSITE
    struct uiad_descriptor iad_desc;
#endif
    struct uinterface_descriptor audio_v2_mic_ac_intf_desc;
    //**************************** wtotalLength ****************************//
    struct audio_v2_cs_if_ac_header_descriptor          audio_v2_mic_ac_header_desc;
    struct audio_v2_cs_if_ac_clock_source_descriptor    audio_v2_mic_ac_clock;
    struct audio_v2_cs_if_ac_input_terminal_descriptor  audio_v2_mic_ac_input_term;
    struct audio_v2_cs_if_ac_output_terminal_descriptor audio_v2_mic_ac_output_term;
    struct audio_v2_cs_if_ac_feature_unit_descriptor    audio_v2_mic_ac_fu_term;
    //*************************** *//
}__attribute__((packed));

static struct audio_v2_as_descriptor
{
    struct uinterface_descriptor                audio_v2_mic_as_intf_desc;
    struct audio_v2_cs_if_as_general_descriptor audio_v2_mic_as_gener_desc;
    struct audio_v2_cs_if_as_format_descriptor  audio_v2_mic_as_format_desc;
    struct audio_v2_cs_if_as_iso_ep_descriptor  audio_v2_mic_as_isoep_desc;
    struct uendpoint_descriptor                 audio_v2_mic_ac_intf_desc;

}__attribute__((packed));


static struct audio_v2_range_vol_block
{
    uint16_t wNumSubRanges;
    struct
    {
        int16_t wMin; 
        int16_t wMax;
        int16_t wRes;
    }__attribute__((packed)) subrange[AUDIO_V2_RANGE_VOL_NUM];
}__attribute__((packed));


static struct audio_v2_range_samplerate_block 
{
    uint16_t wNumSubRanges;
    struct
    {
        uint32_t wMin; 
        uint32_t wMax;
        uint32_t wRes;
    }__attribute__((packed)) subrange[AUDIO_V2_RANGE_SAMPLRATE_NUM];
}__attribute__((packed));

typedef  struct audio_v2_mic_device_info
{
	
	uint32_t mic_bitwidth_cur;
#if AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 1
    int16_t mic_volume_cur;
#elif AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 2
    int16_t mic_volume_left_cur;
    int16_t mic_volume_right_cur;
#endif
    uint32_t mic_samplerate_cur;
	struct audio_v2_range_vol_block mic_volume_range;
    struct audio_v2_range_samplerate_block mic_samplerate_range;
    uep_t recorder_ep;

}__attribute__((packed));


static struct audio_v2_mic_device_info recorder_info = 
{
    16,
#if AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 1 
    (255-12+1) << 8,//-12db  //-12的补码
#elif  AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 2
    (255-12+1) << 8,//-12db  //-12的补码
    (255-12+1) << 8,//-12db  //-12的补码
#endif

    16000,
    {
        1,          //only 1 range
        {
            {
                (255-24+1) << 8,//min -24db
                0,          //max 0ddb
                0x0180,     //0x01+ 0.5*128 = 1.5db
            },
        },
    },
    {
        1,
        {
            {
                16000,
                16000,
                0
            },
        },
    },
    RT_NULL,
};


//FS and HS needed
static struct usb_qualifier_descriptor dev_qualifier =
{
    sizeof(dev_qualifier),          //bLength
    USB_DESC_TYPE_DEVICEQUALIFIER,  //bDescriptorType
    0x0200,                         //bcdUSB
    USB_CLASS_DEVICE,                //bDeviceClass
    0x00,                           //bDeviceSubClass
    0x00,                           //bDeviceProtocol
    64,                             //bMaxPacketSize0
    0x01,                           //bNumConfigurations
    0,
};

const static char *_ustring[] =
{
    "Language",
    "RT-Thread Team.",
    "RT-Thread Audio Microphone",
    "32021919830108",
    "Configuration",
    "Interface",
};

static struct audio_v2_ac_descriptor ac_desc =
{
#ifdef RT_USB_DEVICE_COMPOSITE
    {
        USB_DESC_LENGTH_IAD,            // bLength;
        USB_DESC_TYPE_IAD,              // bDescriptorType;
        USB_DYNAMIC,                    // bFirstInterface;
        0x02,                           // bInterfaceCount;
        USB_CLASS_AUDIO,                // bFunctionClass;
        0x00,                           // bFunctionSubClass;
        0x20,                           // bFunctionProtocol;
        RECORDER_INTF_STR_INDEX,             // iFunction;
    },
#endif
    {
        USB_DESC_LENGTH_INTERFACE,
        USB_DESC_TYPE_INTERFACE,
        USB_DYNAMIC,
        0x00,
        0x00,
        USB_CLASS_AUDIO,
        1,
        0x20,                       /*bInterfaceProtocol 描述USB版本*/
        0x00,

    },
    {
        sizeof(struct audio_v2_cs_if_ac_header_descriptor),
        AUDIO_INTERFACE_DESCRIPTOR_TYPE,
        AUDIO_CONTROL_HEADER,
        0x0200,
        AUDIO_CATEGORY_MICROPHONE,
#ifndef RT_USB_DEVICE_COMPOSITE
        sizeof(struct audio_v2_ac_descriptor) - sizeof(struct uinterface_descriptor),
#else
        sizeof(struct audio_v2_ac_descriptor) - sizeof(struct uinterface_descriptor) - sizeof(struct uiad_descriptor),
#endif
        0,
    },
    { 
                      //clk unit
        0x08,                               /*bLength*/
        AUDIO_INTERFACE_DESCRIPTOR_TYPE,    /*bDescriptorType */
        AUDIO_CONTROL_CLOCK_SOURCE,         /*bDescriptorSubtype */
        MIC_CLK_UNIT_ID,                    /*bClockID */
        0x07,                               /*bmAttributes */   //internal programmable clock, synchronized sof
        0x07,                               /*bmControls */     //有控制时钟频率的能力并支持；时钟源有效
        0x00,                               /*bAssocTerminal */
        0x00,                               /*iClockSource */
    },
    {                   //INPUT TERMINAL
        0x11,                            /* bLength */                                                                              
        AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                      
        AUDIO_CONTROL_INPUT_TERMINAL,    /* bDescriptorSubtype */                                                                   
        MIC_IN_TERMINAL_ID,              /* bTerminalID */                                                                          
        AUDIO_INTERM_MIC,               /* wTerminalType : Microphone 0x0201 */                                                    
        0x00,                            /* bAssocTerminal */                                                                       
        MIC_CLK_UNIT_ID,                 /* bCSourceID */                                                                           
        AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN,   /* bNrChannels */            
        0x00000003,                     /*单声道 双声道都是表示左右两声道 */
        0x00,                           /* iChannelNames */                                                                        
        0x0000,                         /* bmControls */                                                                           
        0x00  ,                         /* iTerminal */
    },
    {                   //OUTPUT TERMINAL
        0x0c,                               /* bLength */                                                 
        AUDIO_INTERFACE_DESCRIPTOR_TYPE,    /* bDescriptorType */                                         
        AUDIO_CONTROL_OUTPUT_TERMINAL,      /* bDescriptorSubtype */                                      
        MIC_OUT_TERMINAL_ID,                /* bTerminalID */                                             
        AUDIO_TERMINAL_STREAMING,           /* wTerminalType : USB Streaming */                           
        MIC_IN_TERMINAL_ID,                               /* bAssocTerminal */   //input output terminal associate                                         
        MIC_FU_TERMINAL_ID,                 /* bSourceID */                                               
        MIC_CLK_UNIT_ID,                    /* bCSourceID */                                              
        0x0000,                             /* bmControls */                                              
        0x00                                /* iTerminal */
    
    },
    {                   //FEATURE TERMINAL
        AUDIO_V2_SIZEOF_AC_FEATURE_UNIT_DESC(AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN),     /* bLength */                    
        AUDIO_INTERFACE_DESCRIPTOR_TYPE,                            /* bDescriptorType */            
        AUDIO_CONTROL_FEATURE_UNIT,                                 /* bDescriptorSubtype */         
        MIC_FU_TERMINAL_ID,                                         /* bUnitID */                    
        MIC_IN_TERMINAL_ID,                                         /* bSourceID */    
#if  AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 1                         
        {0x00000000,0x0000000c},                                    /* bmaControls(0) Mute */  //enable control volume
#elif AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 2
        {0x00000000,0x0000000c,0x0000000c}, 
#endif      
        0x00                             /* iTerminal */
    },
};

static struct uinterface_descriptor as_desc0 =
{
    //interface descriptor
    USB_DESC_LENGTH_INTERFACE,
    USB_DESC_TYPE_INTERFACE,
    USB_DYNAMIC,
    0x00,                   // alternate setting 
    0x00,                   //ep num
    USB_CLASS_AUDIO,
    2,
    0x20,                   //uac 20 必须有~！！！
    0x00,
};

static struct audio_v2_as_descriptor as_desc =
{
    {
        //interface descriptor
        USB_DESC_LENGTH_INTERFACE,
        USB_DESC_TYPE_INTERFACE,
        USB_DYNAMIC,
        0x01,                   // alternate setting 
        0x01,                   //ep num
        USB_CLASS_AUDIO,
        2,
        0x20,
        0x00,
    },
    {
        /*as general*/
        0x10,                            /* bLength  */      /*16byte*/                                                                                                                 \
        AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                                                                \
        AUDIO_STREAMING_GENERAL,         /* bDescriptorSubtype */                                                                                                             \
        MIC_OUT_TERMINAL_ID,             /* bTerminalLink : Unit ID of the Output or Input Terminal*/                                                                         \
        0x00,                            /* bmControls */                                                                                                                     \
        AUDIO_FORMAT_TYPE_I,             /* bFormatType : AUDIO_FORMAT_TYPE_I */                                                                                              \
        0x00000001,                      /* bmFormats PCM */                                                                                                                  \
        AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN,   /* bNrChannels */                                                                                                                     
// #if 0                                                                                                  
//          0x00000003,                      /* bmChannelConfig */                                                                                                               
// #endif
        0x00000003,
        0x00,                            /* iChannelNames */    
    },
    {
        0x06,                            /* bLength */                                                                                                                        \
        AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */                                                                                                                \
        AUDIO_STREAMING_FORMAT_TYPE,     /* bDescriptorSubtype */                                                                                                             \
        AUDIO_FORMAT_TYPE_I,             /* bFormatType */                                                                                                                    \
        2,                              /* bSubslotSize */                                                                                                                   \
        16,                             /* bBitResolution */
    },
    {
        0x08,
        AUDIO_ENDPOINT_DESCRIPTOR_TYPE,
        0x01,                           /** ep_general **/
        0x00,
        0x00,
        0x02,                           //pcm sanples
        0x0002,                         //wLockDelay
    },
    {
        USB_DESC_LENGTH_ENDPOINT,
        USB_DESC_TYPE_ENDPOINT,
        USB_DYNAMIC| USB_DIR_IN,         //ep   5
        USB_EP_ATTR_ISOC,               //???同步应该是这个
        AUDIO_RECORDER_V2_EP_MAX_PACKET_SIZE,
        0x01,
    },

};

static rt_err_t _function_enable(ufunction_t func)
{
    RT_ASSERT(func != RT_NULL);
    return RT_EOK;
}

static rt_err_t _function_disable(ufunction_t func)
{
    RT_ASSERT(func != RT_NULL);
    //_record_stop(func);
    return RT_EOK;
}

static struct ufunction_ops ops =
{
    _function_enable,
    _function_disable,
    RT_NULL,
};
uint8_t send_data[4] = {0x01,0x02,0x03,0x04};
static rt_err_t _ep_data_in_handler(void *param, uint8_t ep_addr)
{
    hal_usbd_send(ep_addr,send_data,4);
    return RT_EOK;
}

#if AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 1
static rt_err_t _audio_20_recorder_update_vol(udevice_t device, rt_size_t size)
{

}
#elif AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 2
static rt_err_t _audio_20_recorder_update_left_vol(udevice_t device, rt_size_t size)
{

}

static rt_err_t _audio_20_recorder_update_right_vol(udevice_t device, rt_size_t size)
{

}
#endif

static rt_err_t _audio_20_mic_update_samplerate(udevice_t device, rt_size_t size)
{

}
static rt_err_t _interface_ac_handler(ufunction_t func, ureq_t setup)
{
    rt_uint8_t bError = 0; 
    RT_ASSERT(func != RT_NULL);
    RT_ASSERT(func->device != RT_NULL);
    RT_ASSERT(setup != RT_NULL);
    debug("_interface_ac_handler \n\r");
    if((setup->request_type & (0x01 << 7)) == 0x00 )
    {
        //host-device
        if((setup->request_type & (0x03)) == 0x01)  //确保interface setup
        {
            switch(setup->bRequest)
            {
                case AUDIO_REQUEST_CUR:
                    switch((setup->wIndex) >> 8)   //terminal 
                    {
                        case MIC_FU_TERMINAL_ID:    //vol

                        #if AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 1
                            rt_usbd_ep0_read(func->device, &recorder_info.mic_volume_cur, setup->wLength, _audio_20_recorder_update_vol);
                        #elif AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 2
                        switch(setup->wValue & 0xFF)
                        {
                            case 1:
                                rt_usbd_ep0_read(func->device, &recorder_info.mic_volume_left_cur, setup->wLength, _audio_20_recorder_update_left_vol);
                                break;
                            case 2:
                                rt_usbd_ep0_read(func->device, &recorder_info.mic_volume_right_cur, setup->wLength, _audio_20_recorder_update_right_vol);
                                break;
                            default :
                                break;
                        }
                        #endif
                            break;
                        case MIC_CLK_UNIT_ID:       //samplrate
                            rt_usbd_ep0_read(func->device, &recorder_info.mic_samplerate_cur, setup->wLength, _audio_20_mic_update_samplerate);
                            break;
                        default:
                            break;
                    }
                    break;

                default:
                    break;
            }
        }
    }
    else
    {
        //device-host
        if((setup->request_type & (0x03)) == 0x01)
        {
            switch(setup->bRequest)
            {
                case AUDIO_REQUEST_CUR:
                    switch((setup->wIndex) >> 8)   //terminal 
                    {
                        case MIC_FU_TERMINAL_ID:
                            #if AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 1
                                rt_usbd_ep0_write(func->device,&recorder_info.mic_volume_cur,setup->wLength);
                            #elif AUDIO_RECORDER_V2_NUM_AUD_CHAN_IN == 2
                                switch(setup->wValue & 0xFF)
                                {
                                    case 1:
                                        rt_usbd_ep0_write(func->device,&recorder_info.mic_volume_left_cur,setup->wLength);
                                        break;
                                    case 2:
                                        rt_usbd_ep0_write(func->device,&recorder_info.mic_volume_left_cur,setup->wLength);
                                        break;
                                    default :
                                        break;
                                }
                                    
                            #endif
                            
                            break;
                        case MIC_CLK_UNIT_ID:
                            rt_usbd_ep0_write(func->device,&recorder_info.mic_samplerate_cur,setup->wLength);
                            break;
                        default:
                            break;
                    }
                    break;

                case AUDIO_REQUEST_RANGE:
                    switch((setup->wIndex) >> 8)   //terminal 
                    {
                        case MIC_FU_TERMINAL_ID:
                            rt_usbd_ep0_write(func->device,&recorder_info.mic_volume_range,setup->wLength);
                            hal_usbd_send(recorder_info.recorder_ep->ep_desc->bEndpointAddress & 0x0F,send_data,4);
                            break;
                        case MIC_CLK_UNIT_ID:
                            rt_usbd_ep0_write(func->device,&recorder_info.mic_samplerate_range,setup->wLength);
                            break;
                        default:
                            break;
                    }
                    break;

                default:
                    break;
            }
        }
    }
    return RT_EOK;
}

static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
{
    RT_ASSERT(func != RT_NULL);
    RT_ASSERT(func->device != RT_NULL);
    RT_ASSERT(setup != RT_NULL);

    if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
    {
        switch (setup->bRequest)
        {
        case USB_REQ_GET_INTERFACE:
            break;

        case USB_REQ_SET_INTERFACE:

            if (setup->wValue == 1)
            {
                //_record_start(func);
                //hal_usbd_send(ep_addr,send_data,4);
            }
            else if (setup->wValue == 0)
            {
                //_record_stop(func);
            }

            break;

        default:
            return -RT_ERROR;
        }
    }

    return RT_EOK;
}

ufunction_t rt_usbd_function_uac_recorder_create(udevice_t device)
{
    ufunction_t func;
    uintf_t intf_ac, intf_as;
    ualtsetting_t setting_as0;
    ualtsetting_t setting_ac, setting_as;
    struct audio_v2_as_descriptor *as_desc_t;

#ifdef RT_USB_DEVICE_COMPOSITE
    rt_usbd_device_set_interface_string(device, RECORDER_INTF_STR_INDEX, _ustring[2]);
#else
    /* set usb device string description */
    rt_usbd_device_set_string(device, _ustring);
#endif
    func = rt_usbd_function_new(device, &dev_desc, &ops);

    intf_ac = rt_usbd_interface_new(device, _interface_ac_handler);
    intf_as = rt_usbd_interface_new(device, _interface_as_handler);

    setting_ac = rt_usbd_altsetting_new(sizeof(struct audio_v2_ac_descriptor));
    setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
    setting_as = rt_usbd_altsetting_new(sizeof(struct audio_v2_as_descriptor));

    /* config desc in alternate setting */
    rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
            (rt_off_t) & ((struct audio_v2_ac_descriptor *)0)->audio_v2_mic_ac_intf_desc);
    rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
    rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
            (rt_off_t) & ((struct audio_v2_as_descriptor *)0)->audio_v2_mic_as_intf_desc);

    /* create endpoint */
    as_desc_t = (struct audio_v2_as_descriptor *)setting_as->desc;
    recorder_info.recorder_ep = rt_usbd_endpoint_new(&as_desc_t->audio_v2_mic_ac_intf_desc, _ep_data_in_handler);
    /* add the endpoint to the alternate setting */
    rt_usbd_altsetting_add_endpoint(setting_as, recorder_info.recorder_ep);
    /* add the alternate setting to the interface, then set default setting of the interface */
    rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
    rt_usbd_set_altsetting(intf_ac, 0);
    rt_usbd_interface_add_altsetting(intf_as, setting_as0);
    rt_usbd_interface_add_altsetting(intf_as, setting_as);
    rt_usbd_set_altsetting(intf_as, 1);
    /* add the interface to the uac function */
    rt_usbd_function_add_interface(func, intf_ac);
    rt_usbd_function_add_interface(func, intf_as);

    return func;
}