#include "usbd_vendor_desc.h"
#include "usbd_vendor.h"
#include "usbd_desc.h"
#include "usbd_ctlreq.h"

static const uint8_t * USBD_VENDOR_GetDeviceDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);  
//static const uint8_t * USBD_VENDOR_GetLangIDStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length); 
static const uint8_t * USBD_VENDOR_GetManufacturerStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);  
static const uint8_t * USBD_VENDOR_GetProductStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);  
static const uint8_t * USBD_VENDOR_GetSerialStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);  
static const uint8_t * USBD_VENDOR_GetConfigurationStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length);  
static const uint8_t * USBD_VENDOR_GetInterfaceStrDescriptor( USBD_SpeedTypeDef speed , uint16_t *length); 
static const uint8_t * USBD_VENDOR_GetCfgDesc( USBD_SpeedTypeDef speed ,uint16_t *length );

static const uint8_t * USBD_VENDOR_GetMsOsStringDescriptor (USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_VENDOR_GetExtCompatIdOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t * length);
static const uint8_t * USBD_VENDOR_GetExtPropertiesOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t * length);

#define USBD_VENDOR_LANGID_STRING             1033

const USBD_DescriptorsTypeDef USBD_VENDOR_DescriptorHandlers = {

#if USBD_GETDESCRIPTORS_ALTMETHOD == 1
  // default handlers
  USBD_GETDESCRIPTOR_DEFAULT_HANDLERS_SET,
#endif
   // overrided handlers:
  .GetDeviceDescriptor                 = USBD_VENDOR_GetDeviceDescriptor,
//.GetLangIDStrDescriptor              = USBD_VENDOR_GetLangIDStrDescriptor,
  .GetManufacturerStrDescriptor        = USBD_VENDOR_GetManufacturerStrDescriptor,
  .GetProductStrDescriptor             = USBD_VENDOR_GetProductStrDescriptor,
//.GetSerialStrDescriptor              = USBD_VENDOR_GetSerialStrDescriptor,
  .GetConfigurationStrDescriptor       = USBD_VENDOR_GetConfigurationStrDescriptor,
  .GetInterfaceStrDescriptor           = USBD_VENDOR_GetInterfaceStrDescriptor, 
  .GetConfigDescriptor                 = USBD_VENDOR_GetCfgDesc,
  .GetMsOsStringDescriptor             = USBD_VENDOR_GetMsOsStringDescriptor,
  .GetExtCompatIdOsFeatureDescriptor   = USBD_VENDOR_GetExtCompatIdOsFeatureDescriptor,
  .GetExtPropertiesOsFeatureDescriptor = USBD_VENDOR_GetExtPropertiesOsFeatureDescriptor
};

#if defined ( __ICCARM__ ) /* IAR Compiler */
  #pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
/** USB standard device descriptor. */
static __ALIGN_BEGIN const uint8_t USBD_VENDOR_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
  USB_LEN_DEV_DESC,           /*bLength */
  USB_DESC_TYPE_DEVICE,       /*bDescriptorType*/
  LOBYTE(0x0200),             /*bcdUSB */
  HIBYTE(0x0200),             /*bcdUSB */
  0x02,                       /*bDeviceClass*/
  0x02,                       /*bDeviceSubClass*/
  0x00,                       /*bDeviceProtocol*/
  USB_MAX_EP0_SIZE,           /*bMaxPacketSize*/
  LOBYTE(USB_VID),            /*idVendor*/
  HIBYTE(USB_VID),            /*idVendor*/
  LOBYTE(USB_PID_VENDOR),     /*idProduct*/
  HIBYTE(USB_PID_VENDOR),     /*idProduct*/
  LOBYTE(0x0200),             /*bcdDevice rel. 2.00*/
  HIBYTE(0x0200),
  USBD_IDX_MFC_STR,           /*Index of manufacturer  string*/
  USBD_IDX_PRODUCT_STR,       /*Index of product string*/
  USBD_IDX_SERIAL_STR,        /*Index of serial number string*/
  USBD_MAX_NUM_CONFIGURATION  /*bNumConfigurations*/
};

/**
  * @brief  Return the device descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
static const uint8_t * USBD_VENDOR_GetDeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
  *length = sizeof(USBD_VENDOR_DeviceDesc);
  return USBD_VENDOR_DeviceDesc;
}

#define USB_VENDOR_CONFIG_DESC_SIZ                     18

/* USB Vendor device Configuration Descriptor */
__ALIGN_BEGIN const uint8_t USBD_VENDOR_CfgDesc[USB_VENDOR_CONFIG_DESC_SIZ] __ALIGN_END =
{
  /*Configuration Descriptor*/
  0x09,   /* bLength: Configuration Descriptor size */
  USB_DESC_TYPE_CONFIGURATION,      /* bDescriptorType: Configuration */
  USB_VENDOR_CONFIG_DESC_SIZ,                /* wTotalLength: # of returned bytes */
  0x00,
  0x01,   /* bNumInterfaces: 1 interface */
  0x01,   /* bConfigurationValue: Configuration value */
  0x00,   /* iConfiguration: Index of string descriptor describing the configuration */
  0x80,   /* bmAttributes: no options */
  0x32,   /* MaxPower 0 mA */
  
  /*---------------------------------------------------------------------------*/
  
  /*Data class interface descriptor*/
  0x09,   /* bLength: Endpoint Descriptor size */
  USB_DESC_TYPE_INTERFACE,  /* bDescriptorType: */
  0x00,   /* bInterfaceNumber: Number of Interface */
  0x00,   /* bAlternateSetting: Alternate setting */
  0x00,   /* bNumEndpoints: No endpoints used */
  0x00,   /* bInterfaceClass: */
  0x00,   /* bInterfaceSubClass: */
  0x00,   /* bInterfaceProtocol: */
  0x00,   /* iInterface: */  
};

#define USB_MICROSOFT_OS_STRING_DECRIPTOR_SIZ   18

/* USB Vendor device Configuration Descriptor */
static __ALIGN_BEGIN const uint8_t USBD_VENDOR_MSOSDESCR[USB_MICROSOFT_OS_STRING_DECRIPTOR_SIZ] __ALIGN_END =
{
  /*Configuration Descriptor*/
  0x12,   /* bLength: Configuration Descriptor size */
  USB_DESC_TYPE_STRING,             /* bDescriptorType: Configuration */
  0x4D, 0x00, 0x53,                 /* Signature: 'MSFT100'  UNICODE STRING (LE)*/
  0x00, 0x46, 0x00,
  0x54, 0x00, 0x31,
  0x00, 0x30, 0x00,
  0x30, 0x00,
  USBD_MSOS_VENDOR,   /* Vendor Code: */
  0x00,   /* Padding: */
};

#define USB_MICROSOFT_OS_COMP_DECRIPTOR_SIZ   40
/* USB Vendor device Configuration Descriptor */
static __ALIGN_BEGIN const uint8_t USBD_VENDOR_MSCOMPATIBLEDESCR[USB_MICROSOFT_OS_COMP_DECRIPTOR_SIZ] __ALIGN_END =
{
  /*Configuration Descriptor*/
  0x28, 0x00, 0x00, 0x00,   /* bLength: Descriptor length (40 bytes) */
  0x00, 0x01,               /* Version ('1.0') */
  0x04, 0x00,               /* Compatible ID Descriptor index (0x0004)*/
  0x01,                     /* Number of sections (1) */
  0x00, 0x00, 0x00, 0x00,   /* Reserved */
  0x00, 0x00, 0x00,
  0x00,                     /* Interface Number (Interface #0) */
  0x01,                     /* Reserved */
  'W', 'I', 'N', 'U',       /* Compatible ID ("WINUSB\0\0") */
  'S',  'B',  0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,   /* Sub-Compatible Id (unused) */
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,   /* Reserved */
  0x00, 0x00,
};

#define USB_MICROSOFT_EXT_PROP_SIZ   142
/* USB Vendor device Configuration Descriptor */
static __ALIGN_BEGIN const uint8_t USBD_VENDOR_EXTPROPDESCR[USB_MICROSOFT_EXT_PROP_SIZ] __ALIGN_END =
{
  /*Extended properties Descriptor Header*/
  0x8E, 0x00, 0x00, 0x00,   /* bLength: Descriptor length (142 bytes) */
  0x00, 0x01,               /* Version ('1.0') */
  0x05, 0x00,               /* Extended property descriptor index*/
  0x01, 0x00,               /* Number of sections (1) */
  /* Custom Property section 1 */
  0x84, 0x00, 0x00, 0x00,   /* Size of the property section (132 bytes) */
  0x01, 0x00, 0x00, 0x00,   /* Property data type (1 - UNICODE) */
  0x28, 0x00,               /* Property name length (40 bytes) */
  'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00,     /* 'DeviceIntefaceGUID'*/
  'I', 0x00, 'n', 0x00, 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00,
  'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, 'U', 0x00, 'I', 0x00,
  'D', 0x00, 0x00, 0x00,
  0x4E, 0x00, 0x00, 0x00,   /* Property Name {78cdcb7a-6971-4210-997c-5b8ea05e1715} */
  '{', 0x00, '7', 0x00, '8', 0x00, 'C', 0x00, 'D', 0x00, 'C', 0x00, 'B', 0x00, '7', 0x00, 'A', 0x00, '-', 0x00,
  '6', 0x00, '9', 0x00, '7', 0x00, '1', 0x00, '-', 0x00,
  '4', 0x00, '2', 0x00, '1', 0x00, '0', 0x00, '-', 0x00,
  '9', 0x00, '9', 0x00, '7', 0x00, 'C', 0x00, '-', 0x00,
  '5', 0x00, 'B', 0x00, '8', 0x00, 'E', 0x00, 'A', 0x00, '0', 0x00, '5', 0x00, 'E', 0x00, '1', 0x00, '7', 0x00, '1', 0x00, '5', 0x00, '}', 0x00, 0x00, 0x00,
};

/**
  * @brief  USBD_VENDOR_GetCfgDesc 
  *         Return configuration descriptor
  * @param  speed : current device speed
  * @param  length : pointer data length
  * @retval pointer to descriptor buffer
  */
static const uint8_t * USBD_VENDOR_GetCfgDesc (USBD_SpeedTypeDef speed, uint16_t *length)
{
  *length = sizeof (USBD_VENDOR_CfgDesc);
  return USBD_VENDOR_CfgDesc;
}

#if defined ( __ICCARM__ ) /* IAR Compiler */
  #pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */

/** USB lang indentifier descriptor. */
/*
static __ALIGN_BEGIN const uint8_t USBD_VENDOR_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END =
{
     USB_LEN_LANGID_STR_DESC,
     USB_DESC_TYPE_STRING,
     LOBYTE(USBD_VENDOR_LANGID_STRING),
     HIBYTE(USBD_VENDOR_LANGID_STRING)
};
*/

/**
  * @brief  Return the LangID string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */         
/*
static const uint8_t * USBD_VENDOR_GetLangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
  *length = sizeof(USBD_VENDOR_LangIDDesc);
  return USBD_VENDOR_LangIDDesc;
}
*/

#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_VENDOR_GetMsOsStringDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_VENDOR_GetMsOsStringDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_VENDOR_MSOSDESCR);
  return USBD_VENDOR_MSOSDESCR;
}

#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_VENDOR_GetExtCompatIdOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_VENDOR_GetExtCompatIdOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_VENDOR_MSCOMPATIBLEDESCR);
  return USBD_VENDOR_MSCOMPATIBLEDESCR;
}

#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_VENDOR_GetExtPropertiesOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_VENDOR_GetExtPropertiesOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_VENDOR_EXTPROPDESCR);
  return USBD_VENDOR_EXTPROPDESCR;
}

#if defined(CMT)
//static const uint8_t USBD_VENDOR_MANUFACTURER_STRING[] = { 122, USB_DESC_TYPE_STRING,
//  'C', 0, 'o', 0, 'p', 0, 'p', 0, 'e', 0, 'r', 0, ' ', 0, 'M', 0, 'o', 0, 'u', 0,  'n', 0, 't', 0, 'a', 0, 'i', 0, 'n', 0, ' ', 0, 'T', 0, 'e', 0, 'c', 0, 'h', 0, 'n', 0, 'o', 0, 'l', 0, 'o', 0, 'g', 0, 'i', 0, 'e', 0, 's', 0,  ' ', 0, '(', 0, 'h', 0, 't', 0,  't', 0, 'p', 0, ':', 0, '/', 0, '/', 0, 'c', 0, 'o', 0, 'p', 0, 'p', 0, 'e', 0, 'r', 0, 'm', 0, 'o', 0, 'u', 0,  'n', 0, 't', 0, 'a', 0, 'i', 0, 'n', 0, 't', 0, 'e', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'o', 0, 'm', 0, ')', 0,
//};
static const uint8_t USBD_VENDOR_MANUFACTURER_STRING[] = { 8, USB_DESC_TYPE_STRING,
  'C', 0, 'M', 0, 'T', 0,
};
#elif defined(PLANAR)
static const uint8_t USBD_VENDOR_MANUFACTURER_STRING[] = { 68, USB_DESC_TYPE_STRING,
  'P', 0,'l', 0,'a', 0,'n', 0,'a', 0,'r', 0,' ', 0,'(', 0,'h', 0,'t', 0, 't', 0,'p', 0,':', 0,'/', 0,'/', 0,'w', 0,'w', 0,'w', 0,'.', 0,'p', 0,'l', 0, 'a', 0, 'n', 0, 'a', 0, 'r', 0, 'c', 0, 'h', 0, 'e', 0, 'l', 0, '.', 0, 'r', 0, 'u', 0, ')', 0,
};
#else
#error Specify PLANAR or CMT macro in project settings!
#endif

/**
  * @brief  Return the manufacturer string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
static const uint8_t * USBD_VENDOR_GetManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
  *length = sizeof(USBD_VENDOR_MANUFACTURER_STRING);
  return USBD_VENDOR_MANUFACTURER_STRING;
}

static const uint8_t USBD_VENDOR_PRODUCT_STRING[] = { 38, USB_DESC_TYPE_STRING, 
  'M', 0,'K', 0,'2', 0,'0', 0,'7', 0,'-', 0,'0', 0, '4', 0, 'H', 0, ' ', 0,  ' ', 0, ' ', 0, ' ', 0,' ', 0,' ', 0,' ', 0,' ', 0,' ', 0,                         
};

/**
  * @brief  Return the product string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
static const uint8_t * USBD_VENDOR_GetProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
  *length = sizeof(USBD_VENDOR_PRODUCT_STRING);
  return USBD_VENDOR_PRODUCT_STRING;
}

//static const uint8_t USBD_VENDOR_SERIALNUMBER_STRING[] = { 26, USB_DESC_TYPE_STRING,
//'0',0,'0',0,'0',0,'0',0,'0',0,'0',0,'0',0,'0',0,'0',0,'0',0,'0',0,'0',0,
//};

// /**
//   * @brief  Return the serial number string descriptor
//   * @param  speed : Current device speed
//   * @param  length : Pointer to data length variable
//   * @retval Pointer to descriptor buffer
//   */
// static const uint8_t * USBD_VENDOR_GetSerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
// {  
//   *length = sizeof(USBD_VENDOR_SERIALNUMBER_STRING);
//   return USBD_VENDOR_SERIALNUMBER_STRING;
// }

static const uint8_t USBD_VENDOR_CONFIGURATION_STRING[] = { 22, USB_DESC_TYPE_STRING,
'M',0,'a',0,'i',0,'n',0,'C',0,'o',0,'n',0,'f',0,'i',0,'g',0,
};

/**
  * @brief  Return the configuration string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */            
const uint8_t * USBD_VENDOR_GetConfigurationStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{    
  *length = sizeof(USBD_VENDOR_CONFIGURATION_STRING);
  return USBD_VENDOR_CONFIGURATION_STRING;
}

static const uint8_t USBD_VENDOR_INTERFACE_STRING_FS[] = { 24, USB_DESC_TYPE_STRING,
'V',0,'e',0,'n',0,'d',0,'o',0,'r',0,'I',0,'f',0,'a',0,'c',0,'e',0,
};

/**
  * @brief  Return the interface string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
static const uint8_t * USBD_VENDOR_GetInterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{  
  *length = sizeof(USBD_VENDOR_INTERFACE_STRING_FS);
  return USBD_VENDOR_INTERFACE_STRING_FS;
}