#include "usb_desc.h"
#include "usb_cdc_uart_desc.h"

#if FUNC_USBDEV_EN

//设备描述符
//配置描述符
//字符串描述符
//Device ID

//usb device descriptor
AT(.usbdev.com.table)
const u8 desc_usb_device[18] = {
    0x12,                       // Num bytes of the descriptor
    0x01,                       // Device Descriptor type
    0x00,                       // Revision of USB Spec. LSB (in BCD)
    0x02,                       // Revision of USB Spec. MSB (in BCD)
    0x02,                      //
    0x02,                      //
    0x00,                      //
    64,                         // Max packet size of Endpoint 0

    L_BYTE(USB_DEV_VID),    // Vendor ID LSB
    H_BYTE(USB_DEV_VID),    // Vendor ID MSB
    L_BYTE(USB_DEV_PID),    // Product ID LSB
    H_BYTE(USB_DEV_PID),    // Product ID MSB
    0x00,                   // Device Revision LSB (in BCD)
    0x02,                   // Device Revision MSB (in BCD)

    1,                      // Index of Manufacture string descriptor
    2,                      // Index of Product string descriptor
    3,                      // Index of Serial No. string descriptor
    1                       // Num Configurations, Must be 1
};

//usb config descriptor
AT(.usbdev.com.table)
const u8 config_desc_usb_device[32] = {
    0x09,
    0x02,
    L_BYTE(DEV_CFG_DESC_SIZE),
    H_BYTE(DEV_CFG_DESC_SIZE),
    0x02,
    0x01,
    0x00,
    0xc0,
    0x32,//0x00,//9byte 配置描述符

    0x09,
    USB_DESC_TYPE_IF,
    0x00,
    0x00,
    0x01,//0x02,
    0x02,//0x07,
    0x02,//0x01,
    0x01,//0x02,
    0x00,//0x04,//9byte 接口描述符

    0x05,//0x07,
    0x24,//USB_DESC_TYPE_EP,
    0x00,//USB_DEV_IN_EP | 0x80,
    0x10,//0x02,
    0x01,//L_BYTE(EP_IN_MAX_SIZE),
//    H_BYTE(EP_IN_MAX_SIZE),
//    0x00,//7byte 端点描述符

    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Call Management Func Desc */
    0x01,
    /* bmCapabilities: D0+D1 */
    0x00,
    /* bDataInterface: 1 */
    0x01,

    /* bFunctionLength */
    0x04,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Abstract Control Management desc */
    0x02,
    /* bmCapabilities */
    0x02,

    /* CDC Union Function Descriptor */
    /* bFunctionLength */
    0x05,
    /* bDescriptorType: CS_INTERFACE */
    0x24,
    /* bDescriptorSubtype: Union func desc */
    0x06,
    /* bMasterInterface: Communication class interface */
    0x00,
    /* bSlaveInterface0: Data Class Interface */
    0x01,

    /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    0x05,
    /* bEndpointAddress */
    0x82,
    /* bmAttributes */
    0x03,
    /* wMaxPacketSize: */
    L_BYTE(0x08),
    H_BYTE(0x08),
    /* bInterval: */
    16,

    /* bLength */
    0x09,
    /* bDescriptorType */
    0x04,
    /* bInterfaceNumber */
    0x01,
    /* bAlternateSetting */
    0x00,
    /* bNumEndpoints */
    0x02,
    /* bInterfaceClass */
    0x0A,
    /* bInterfaceSubClass */
    0x00,
    /* bInterfaceProtocol */
    0x00,
    /* iInterface */
    0x00,

    0x07,
    0x05,
    0x01,
    0x02,
    L_BYTE(0x40),
    H_BYTE(0x40),
    0x00,//7byte 端点描述符

     /* bLength */
    0x07,
    /* bDescriptorType: Endpoint */
    0x05,
    /* bEndpointAddress */
    0x81,
    /* bmAttributes */
    0x02,
    /* wMaxPacketSize: */
    L_BYTE(0x40),
    H_BYTE(0x40),
    /* bInterval: */
    0x00,
};

//Language ID
AT(.usbdev.com.table)
const u8 str_language_id[] = {
    4,
    3,
    L_BYTE(USB_DEV_LANG_ID),
    H_BYTE(USB_DEV_LANG_ID),
};

AT(.usbdev.com.table)
const u8 device_id[37-8] = {
    0x00,0x50,0x4d,0x46,0x47,0x3a,//"MFG:"
    'G','e','e','h','y',
    0x3b,0x4d,0x44,0x4c,0x3a,//";MDL:"
    ' ','P','r','i','n','t','e','r',
    0x3b,0x43,0x4d,0x44,0x3a,0x50,0x50,0x4c,0x49,0x3b//";CMD:PPLI;"

};

AT(.usb_buf.com.buf)
u8 string_desc_buf[USB_MAX_STR_DESC_SIZE];

void usb_desc_config(u8 *dest, char *src, u8 *length)
{
    u8 str_length = 0;
    u8 idx = 0;

    if (src != NULL) {
        while (src[str_length] != '\0' && str_length < USB_MAX_STR_DESC_SIZE) {
            str_length++;
        }

        *length = str_length * 2 + 2;
        dest[idx++] = *length;
        dest[idx++] = USB_DESC_TYPE_STR;

        while (*src != '\0') {
            dest[idx++] = *src++;
            dest[idx++] = 0x00;
        }
    }
}

u8 *usb_get_device_descriptor(u8 *length)
{
    *length = sizeof(desc_usb_device);
    printf("usb_get_device_descriptor\n");
	return (u8 *)desc_usb_device;
}

u8 *usb_get_lang_id_str_descriptor(u8 *length)
{
    *length = sizeof(str_language_id);
    printf("usb_get_id_str_descriptor\n");
    return (u8 *)str_language_id;
}

u8 *usb_get_manufacturer_str_descriptor(u8 *length)
{
    usb_desc_config(string_desc_buf, USB_DESC_MANUF, length);
    printf("usb_get_manuf_descriptor\n");
    return string_desc_buf;
}

u8 *usb_get_product_str_descriptor(u8 *length)
{
    usb_desc_config(string_desc_buf, USB_DESC_PRODUCT, length);
    return string_desc_buf;
}

u8 *usb_get_serial_str_descriptor(u8 *length)
{
    usb_desc_config(string_desc_buf, USB_DESC_SERIAL, length);
    return string_desc_buf;
}

u8 port[2]={0x18,0x0};
u8 port1[7]={0x00,0x00,0x00,0x00,0x00,0x00,0x00};  //回复7个0

//* Just recipient=1 && dir=1 will notice upper layer */
bool usb_itf_in_req(uint8_t *cmd, uint8_t **response, uint32_t *length)
{
    bool proc = true;

    spb_wrap_t std_cmd;

    memcpy(&std_cmd, cmd, 8);

    printf("ITF: 0x%04x  REQ: 0x%02x\n", std_cmd.wIndex, std_cmd.bRequest);
//    printf(" %x \n",std_cmd.bRequest);
    switch (std_cmd.wIndex) {
        case 0:

            switch (std_cmd.bRequest) {
                case 0:
                    *response = (u8 *)device_id;
                    *length = sizeof(device_id);
                    break;

                case 1:
                    *response = (u8 *)port;
                    *length = 1;
                    printf("should process get status\n");
                    break;

                case 0x21:  //21回复正常
                    *response = (u8 *)port1;
                    *length = 7;
//                    printf("21OK %x \n",std_cmd.bmRequest);
                    break;

                default:
                    printf("Unknown request - 0x%02x, set un-process that core maybe halt or process\n", std_cmd.bRequest);
                    proc = false;
                    break;
            }
            break;

        default:
            printf("No match interface - 0x%04x, set un-process that core maybe halt or process\n", std_cmd.wIndex);
            proc = false;
            break;
    }

#if 0
    /* If cmd has match but neither the application layer nor the core is expected to process it,
     * set un-proccess and let the response length to zere
     */
    *length = 0;
    proc = true;
#endif

    return proc;
}

uint8_t usb_ep0_out_data_callback(spb_wrap_t *spb, uint8_t *data, uint16_t len)
{
    switch (spb->recipient) {

    case REQ_INTERFACE:
        switch (spb->bRequest) {

        case 0x20:
//            printf("set line coding: ");
//            print_r(data,len);
            return true;

        case 0x22:
            printf("-->set control line state:%x\n",spb->wValue);
            return true;

        default:
            break;
        }
        break;

    default:
        break;
    }

    return false;
}

#endif
