#include "complexity_hid.h"
#ifdef  USING_HID_EQ
#include "eq.h"
#include "hid_online_set.h"
#endif

//#define USB_DEBUG

//具体 funciton 实现， 以下为hid 实现
struct complexity_hid
{
    uep_t ep_in;
    uep_t ep_out;
    struct hid_send_ctl ep_in_buff;
    struct hid_recv_ctl ep_out_buff;
    int status;
};

struct complexity_hid comp_hid_data = {0};


static rt_err_t _function_enable(ufunction_t func)
{
    return RT_EOK;
}

static rt_err_t _function_disable(ufunction_t func)
{
    return RT_EOK;
}

static struct ufunction_ops ops =
{
    _function_enable,
    _function_disable,
    RT_NULL,
};

static struct udevice_descriptor _dev_desc =
{
    USB_DESC_LENGTH_DEVICE,     //bLength;
    USB_DESC_TYPE_DEVICE,       //type;
    USB_BCD_VERSION,            //bcdUSB;
    0x03,                        //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;
    USB_DYNAMIC,                //bNumConfigurations;
};

const static char *_ustring[] =
{
    "Language",
    "space-touch.",
    "space-touch HID-Device",
    "120893355031404273",
    "Configuration",
    "Interface",
};

#define AUDIO_HID_REPORT_ID 0x03
#define CTL_HID_REPORT_ID   0x4B

const rt_uint8_t comp_report_desc[] =
{
    /* USER CODE BEGIN 0 */
    0x05, 0x0c,             //Usage Page(Consumer)
    0x09, 0x01,             //Usage (Consumer Control)
    0xA1, 0x01,             //Collection(Application)
    0x85, AUDIO_HID_REPORT_ID,              //Report ID(3)
    0x15, 0x00,             //Logic Minimum(0)
    0x25, 0x03,             //Logic Maximum(1)
    0x75, 0x01,             //Report Size(1)
    0x95, 0x02,             //Report Count(2)
    0x09, 0xe9,             //Usage()
    0x09, 0xea,             //Usage()
    0x81, 0x02,             //Input()
    0x75, 0x01,             //report size(1)   0x95, 0x04
    0x95, 0x02,             //Report Count(2)  0x09, 0xcd
    0x09, 0xcd,             //Usage()          0x09, 0xcf
    0x09, 0xcf,             //Usage()          0x09, 0xB6
    0x81, 0x02,             //Input()          0x09, 0xB5
    0x75, 0x01,             //report size(1)   0x81, 0x02
    0x95, 0x04,             //Report Count(4)  0x95, 0x02
    0x81, 0x01,             //Input()
    0x06, 0x01, 0xff,       //Usage()
    0x85, CTL_HID_REPORT_ID,    //Report ID(75)
    0x75, 0x08,             //Report Size(8)
    0x95, 0x3f,             //Report Count(64)
    0x09, 0x01,             //Usage()
    0x81, 0x03,             //Input()
    0x95, 0x3f,             //Report Count(64)
    0x09, 0x02,             //Usage()
    0x91, 0x02,             //Output()
    0x85, 0x1,              //Report ID(1)
    0x75, 0x08,             //Report Size(8)
    0x95, 0x3f,             //Report Count(64)
    0x09, 0x03,             //Usage()
    0x81, 0x03,             //Input()
    0x95, 0x3f,             //Report Count(64)
    0x09, 0x04,             //Usage()
    0x91, 0x02,             //Output()
    0xC0                     // END_COLLECTION
};

static rt_err_t _interface_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);
#ifdef USB_DEBUG
    RT_DEBUG_LOG(RT_DEBUG_USB, ("_interface_ac_handler\n"));
    debug("hid _interface_handler \n\r");
#endif
    if ((setup->request_type & (0x01 << 7)) == 0x00)
    {
        //host-device
        if ((setup->request_type & (0x03)) == 0x01) //确保interface setup
        {
            switch (setup->bRequest)
            {
            default:
                break;
            }
        }
    }
    else
    {
        //device-host
        if ((setup->request_type & (0x03)) == 0x01)
        {
            switch (setup->bRequest)
            {
            case USB_REQ_GET_DESCRIPTOR:
                if ((setup->wValue >> 8) == USB_DESC_TYPE_REPORT)
                {
                    rt_usbd_ep0_write(func->device, (void *)(&comp_report_desc[0]), sizeof(comp_report_desc));
                    // hal_usbd_send((comp_hid_data.ep_in->ep_desc->bEndpointAddress & 0x0F), comp_hid_data.ep_in_buff, 2);
                    comp_hid_data.ep_in_buff._ep_addr =  comp_hid_data.ep_in->id->addr;
                    comp_hid_data.ep_out_buff._ep_addr =  comp_hid_data.ep_out->id->addr;
                    comp_hid_data.ep_in_buff.send_status = hid_sent;
                    debug("comp_hid_data.ep_in->id->addr %d \n\r", comp_hid_data.ep_in->id->addr);
                    debug("comp_hid_data.ep_out->id->addr %d \n\r", comp_hid_data.ep_out->id->addr);
                }
                else if ((setup->wValue >> 8) == USB_DESC_TYPE_HID)
                {
                }

                break;

            // case USB_HID_REQ_GET_REPORT:
            //     if (setup->wLength == 0)
            //     {
            //         rt_usbd_ep0_set_stall(func->device);
            //         break;
            //     }

            //     if ((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
            //         setup->wLength = MAX_REPORT_SIZE;

            //     rt_usbd_ep0_write(func->device, data->report_buf, setup->wLength);
            //     break;

            // case USB_HID_REQ_GET_IDLE:
            //     dcd_ep0_send_status(func->device->dcd);
            //     break;

            // case USB_HID_REQ_GET_PROTOCOL:
            //     rt_usbd_ep0_write(func->device, &data->protocol, 1);
            //     break;

            // case USB_HID_REQ_SET_REPORT:
            //     if ((setup->wLength == 0) || (setup->wLength > MAX_REPORT_SIZE))
            //         rt_usbd_ep0_set_stall(func->device);

            //     rt_usbd_ep0_read(func->device, data->report_buf, setup->wLength, _hid_set_report_callback);
            //     break;

            // case USB_HID_REQ_SET_IDLE:
            //     dcd_ep0_send_status(func->device->dcd);
            //     break;

            // case USB_HID_REQ_SET_PROTOCOL:
            //     data->protocol = setup->wValue;
            //     dcd_ep0_send_status(func->device->dcd);
            //     break;
            default:
                break;
            }
        }
    }

    return RT_EOK;
}

static struct comp_hid_description
{
    struct uinterface_descriptor intf_desc;
    struct uhid_descriptor      hid_desc;
    struct uendpoint_descriptor ep_in_desc;
    struct uendpoint_descriptor ep_out_desc;
} __attribute__((packed));

struct comp_hid_description comp_hid_desc =
{

    {
        USB_DESC_LENGTH_INTERFACE,
        USB_DESC_TYPE_INTERFACE,
        USB_DYNAMIC,                /* bInterfaceNumber: Number of Interface */
        0x00,                       /* bAlternateSetting: Alternate setting */
        0x02,                       /* bNumEndpoints */
        0x03,                       /* bInterfaceClass: HID */
        0x00,
        0x00,
        0,
    },
    {
        0x09,   //HID_DESCRIPTOR_SIZE,        /* bLength: HID Descriptor size */
        0x21,   //HID_DESCRIPTOR_TYPE,        /* bDescriptorType: HID */
        0x0111,                     /* bcdHID: HID Class Spec release number */
        0x00,                       /* bCountryCode: Hardware target country */
        0x01,                       /* bNumDescriptors: Number of HID class descriptors to follow */
        {
            {
                0x22,                       /* bDescriptorType */
                sizeof(comp_report_desc),       /* wItemLength: Total length of Report descriptor */
            },
        },
    },
    {
        USB_DESC_LENGTH_ENDPOINT,
        USB_DESC_TYPE_ENDPOINT,
        USB_DYNAMIC | USB_DIR_IN,
        USB_EP_ATTR_INT,
        0x40,
        0x04,
    },
    {
        USB_DESC_LENGTH_ENDPOINT,
        USB_DESC_TYPE_ENDPOINT,
        USB_DYNAMIC | USB_DIR_OUT,
        USB_EP_ATTR_INT,
        0x40,
        0x04,
    },
};

__ILM void brom_entry()
{
    AON_GLOBAL->SVDD_GLOBAL7 |= (1ul << 31);
    DEV_RMU->BOOT |= DEV_RMU_BOOT_RE_BOOT;

    while (1);
}

static uint32_t _ep_out_count = 0;
//接收到后触发中断
static void _ep_out_handler(void *param, uint8_t ep_addr)
{
#ifdef USB_DEBUG
	debug("ep_out\r\n");
#endif
    comp_hid_data.ep_out_buff.recv_status = hid_received;
    // _ep_out_count = hal_usbd_receive_count(ep_addr);
    // hal_usbd_receive(ep_addr,&comp_hid_data.ep_out_buff);
    // if(comp_hid_data.ep_out_buff.report_id == 0x4B)
    // {
    //     if(comp_hid_data.ep_out_buff.bRequestType == 0x01)
    //     {
    //         if(comp_hid_data.ep_out_buff.bCode == 0xff)
    //         {  //芯片复位
    //             delay_us(10);
    //             brom_entry();
    //         }
    //     }
    // }
    // return;
}

//发送完毕后触发中断
static void _ep_in_handler(void *param, uint8_t ep_addr)
{
    //debug("hid_ep_out\n\r");
    //hal_usbd_send(ep_addr, comp_hid_data.ep_in_buff, 2);
#ifdef USB_DEBUG
    debug("_ep_in_handler hid_sent\n\r");
#endif
    comp_hid_data.ep_in_buff.send_status = hid_sent;
    return;
}

/**
 * This function will create a hid function instance.
 *
 * @param device the usb device object.
 *
 * @return RT_EOK on successful.
 */
ufunction_t rt_usbd_function_hid_create(udevice_t device)
{
    ufunction_t     func;
    uintf_t         hid_intf;
    ualtsetting_t   hid_setting;
    struct comp_hid_description *_comp_hid_desc;
    /* parameter check */
    RT_ASSERT(device != RT_NULL);
    comp_hid_data.ep_out_buff.recv_status = hid_free;
    rt_usbd_device_set_string(device, _ustring);
    func = rt_usbd_function_new(device, &_dev_desc, &ops);
    func->user_data = (void *)&comp_hid_data;
    /* create an interface object */
    hid_intf = rt_usbd_interface_new(device, _interface_handler);
    /* create an alternate setting object */
    hid_setting = rt_usbd_altsetting_new(sizeof(struct comp_hid_description));
    /* config desc in alternate setting */
    rt_usbd_altsetting_config_descriptor(hid_setting, &comp_hid_desc, (rt_off_t) & ((struct comp_hid_description *)0)->intf_desc);
    /* configure the hid interface descriptor */
    // _hid_descriptor_config(hid_setting->desc, hid_intf->intf_num);
    /* create endpoint */
    _comp_hid_desc = (struct comp_hid_description *)hid_setting->desc;
    comp_hid_data.ep_in  = rt_usbd_endpoint_new(&_comp_hid_desc->ep_in_desc, (udep_handler_t)_ep_in_handler);
    comp_hid_data.ep_out = rt_usbd_endpoint_new(&_comp_hid_desc->ep_out_desc, (udep_handler_t)_ep_out_handler);
    /* add the int out and int in endpoint to the alternate setting */
    rt_usbd_altsetting_add_endpoint(hid_setting,  comp_hid_data.ep_out);
    rt_usbd_altsetting_add_endpoint(hid_setting,  comp_hid_data.ep_in);
    /* add the alternate setting to the interface, then set default setting */
    rt_usbd_interface_add_altsetting(hid_intf, hid_setting);
    rt_usbd_set_altsetting(hid_intf, 0);
    /* add the interface to the mass storage function */
    rt_usbd_function_add_interface(func, hid_intf);
    return func;
}

//两个对外接口
rt_size_t hid_get_recv_data(uint8_t *buff)
{
    if (comp_hid_data.ep_out_buff.recv_status == hid_received)
    {
        uint32_t count = hal_usbd_receive_count(comp_hid_data.ep_out_buff._ep_addr);
        //必须先置标志位，防止中断标志位不同步
        comp_hid_data.ep_out_buff.recv_status = hid_free;
        hal_usbd_receive(comp_hid_data.ep_out_buff._ep_addr, buff);
        return count;
    }
    return 0;
}




rt_err_t hid_send_data(uint8_t *buff, uint32_t len)
{
    if (comp_hid_data.ep_in_buff.send_status == hid_sending)
    {
#ifdef USB_DEBUG
        debug("usb hid in busy!\n\r");
#endif
        return RT_ERROR;
    }

    //必须先置标志位，防止中断标志位不同步
    comp_hid_data.ep_in_buff.send_status = hid_sending;
    hal_usbd_send(comp_hid_data.ep_in_buff._ep_addr, buff, len);
    return RT_EOK;
}

rt_err_t hid_command_analysis(uint8_t *buff)
{

    uint32_t recv_count = 0;
    struct hid_protocol *hid_pro;
    recv_count = hid_get_recv_data(buff);

    if (recv_count == 0)
        return RT_ERROR;

    hid_pro = (struct hid_protocol *)buff;
#ifdef USB_DEBUG
     for (int i = 0 ; i < recv_count; i++)
     {
    	 debug("%02x  ", buff[i]);
     }

     debug("\n\recv_count: %d\n\r", recv_count);
#endif
    if (hid_pro->report_id == 0x4B)
    {
        if (hid_pro->bRequestType == 0x01)
        {
            if (hid_pro->bCode == 0xff)
            {
#ifdef USB_DEBUG
                debug("brom_entry()\n\r");
#endif
                //芯片复位
                AON_PMU->VOL_CTL = 0x012d3525;
                AON_PMU->PWR_CTL = 0x00003f00;
                delay_us(360*MHz,500);
                brom_entry();
            }
        }
    }

#ifdef  USING_HID_EQ
    hid_eq_handle(hid_pro);
    hid_adda_handle(hid_pro);
#endif


    return RT_EOK;
}



