#include "usbd_core.h"
#include "usbd_desc.h"
#include "usbd_conf.h"
#include "usb_config.h"
#include "app/nfm/nfm_base.h"

#if USBD_GETDESCRIPTORS_ALTMETHOD == 1
// THIS FILE CONTAINS DEFAULT DESCRIPTORS ACCESSORS
// AND THE DEFAULT DESCRIPTORS CONTENT.
// IF YOU NEED TO OVERRIDE SOME DESCRIPTOR VALUE IN THE CLASS
// YOU NEED TO DEFINE CLASS-DEFINED GETDESCRIPTORS HANDLERS SET,
// a.k.a. USBD_DescriptorsTypeDef, AND PUT
// THE "USBD_GETDESCRIPTOR_DEFAULT_HANDLERS_SET" MACRO INSIDE
// TO INITIALIZE THE STRUCTURE WITH THE DEFAULT ACCESSORS (HANDLERS).
// THEN YOU NEED TO RE-DEFINE THE ONLY ACCESSOR(S) YOU NEED TO OVERRIDE
// IN THE SAME INITIALIZER. SEE "USBD_GETDESCRIPTOR_DEFAULT_HANDLERS_SET"
// FOR DETAILS.
#else
// THIS FILE CONTAINS DEFAULT DESCRIPTORS ACCESSORS
// AND THE DEFAULT DESCRIPTORS CONTENT.
// IF YOU NEED TO OVERRIDE SOME DESCRIPTOR VALUE IN THE CLASS
// YOU NEED TO DEFINE CLASS-DEFINED GETDESCRIPTORS HANDLERS SET,
// a.k.a. USBD_DescriptorsTypeDef, AND INITIALIZE THE STRUCTURE
// WITH ACCESSOR(S) YOU NEED TO OVERRIDE IN THE SAME INITIALIZER.
// ALL THE OTHER ACCESSORS VALUES MUST BE NULL.
#endif

#define USBD_VID                       USB_VID
#define USBD_LANGID_STRING             1033
#define USBD_PID                       USB_PID_VENDOR

#if defined(CMT)
//static const uint8_t USBD_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_MANUFACTURER_STRING[] = { 8, USB_DESC_TYPE_STRING,
  'C', 0, 'M', 0, 'T', 0,
};

#elif defined(PLANAR)
static const uint8_t USBD_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

static const uint8_t USBD_PRODUCT_STRING_FS[] = { 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,                         
};

#if CONFIG_NFMBASECLASS
#else
static const uint8_t USBD_SERIALNUMBER_STRING_FS[] = { 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,
};
#endif

static const uint8_t USBD_CONFIGURATION_STRING_FS[] = { 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,
};

static const uint8_t USBD_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,
};

static const uint8_t USBD_MSOS_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,
};

#if USBD_GETDESCRIPTORS_ALTMETHOD == 0

static const uint8_t * USBD_COMMON_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_COMMON_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_COMMON_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_COMMON_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_COMMON_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_COMMON_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_COMMON_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
static const uint8_t * USBD_COMMON_GetCfgDesc (USBD_SpeedTypeDef speed, uint16_t *length);

//static const uint8_t * USBD_COMMON_GetMsOsStringDescriptor (USBD_SpeedTypeDef speed, uint16_t *length);
//static const uint8_t * USBD_COMMON_GetExtCompatIdOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t * length);
//static const uint8_t * USBD_COMMON_GetExtPropertiesOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t * length);
#endif

USBD_DescriptorsTypeDef USBD_COMMON_Desc =
{
  .GetDeviceDescriptor                 =  USBD_COMMON_DeviceDescriptor,
  .GetLangIDStrDescriptor              =  USBD_COMMON_LangIDStrDescriptor,
  .GetManufacturerStrDescriptor        =  USBD_COMMON_ManufacturerStrDescriptor,
  .GetProductStrDescriptor             =  USBD_COMMON_ProductStrDescriptor,
  .GetSerialStrDescriptor              =  USBD_COMMON_SerialStrDescriptor,
  .GetConfigurationStrDescriptor       =  USBD_COMMON_ConfigStrDescriptor,
  .GetInterfaceStrDescriptor           =  USBD_COMMON_InterfaceStrDescriptor,
  .GetConfigDescriptor                 =  USBD_COMMON_GetCfgDesc,
  //.GetMsOsStringDescriptor             =  USBD_COMMON_GetMsOsStringDescriptor,
  //.GetExtCompatIdOsFeatureDescriptor   =  USBD_COMMON_GetExtCompatIdOsFeatureDescriptor,
  //.GetExtPropertiesOsFeatureDescriptor =  USBD_COMMON_GetExtPropertiesOsFeatureDescriptor,
  #if (USBD_SUPPORT_USER_STRING)
  .GetUsrStrDescriptor           =  NULL,
  #endif
};


#if defined ( __ICCARM__ ) /* IAR Compiler */
  #pragma data_alignment=4
#endif /* defined ( __ICCARM__ ) */
/** USB standard device descriptor. */
static __ALIGN_BEGIN const uint8_t USBD_COMMON_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(USBD_VID),           /*idVendor*/
  HIBYTE(USBD_VID),           /*idVendor*/
  LOBYTE(USBD_PID),           /*idProduct*/
  HIBYTE(USBD_PID),           /*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*/
};

#define USB_CONFIG_DESC_SIZ   18

/* USB Vendor device Configuration Descriptor */
static __ALIGN_BEGIN const uint8_t USBD_COMMON_CfgDesc[USB_CONFIG_DESC_SIZ] __ALIGN_END =
{
  /*Configuration Descriptor*/
  0x09,   /* bLength: Configuration Descriptor size */
  USB_DESC_TYPE_CONFIGURATION,      /* bDescriptorType: Configuration */
  USB_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 */
  0xFF,   /* MaxPower 0 mA */ //0x32

  /*---------------------------------------------------------------------------*/

  /*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_COMMON_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_COMMON_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_COMMON_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,
//};

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

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

/**
  * @brief  Return the device descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_COMMON_DeviceDesc);
  return USBD_COMMON_DeviceDesc;
}


/**
  * @brief  USBD_VENDOR_GetCfgDesc
  *         Return configuration descriptor
  * @param  speed : current device speed
  * @param  length : pointer data length
  * @retval pointer to descriptor buffer
  */
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_GetCfgDesc (USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_GetCfgDesc (USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof (USBD_COMMON_CfgDesc);
  return USBD_COMMON_CfgDesc;
}

/**
  * @brief  Return the LangID string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_LangIDDesc);
  return USBD_LangIDDesc;
}

/**
  * @brief  Return the product string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_PRODUCT_STRING_FS);
  return USBD_PRODUCT_STRING_FS;
}

/**
  * @brief  Return the manufacturer string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_MANUFACTURER_STRING);
  return USBD_MANUFACTURER_STRING;
}


/**
  * @brief  Return the configuration string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_CONFIGURATION_STRING_FS);
  return USBD_CONFIGURATION_STRING_FS;
}

/**
  * @brief  Return the interface string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_INTERFACE_STRING_FS);
  return USBD_INTERFACE_STRING_FS;
}

//#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
//static const uint8_t * USBD_COMMON_GetMsOsStringDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
//#else
//const uint8_t * USBD_COMMON_GetMsOsStringDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
//#endif
//{
//  eNFMUSBInterface_t usbDeviceInterface;
//  NFMClass->methods.usbInterface.getInterface(&usbDeviceInterface);
//  if(usbDeviceInterface == eNFM_IfaceUSBTMC)
//  {
//      *length = 0;
//      return 0;
//  }
//  *length = sizeof(USBD_COMMON_MSOSDESCR);
//  return USBD_COMMON_MSOSDESCR;
//}
//
//#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
//static const uint8_t * USBD_COMMON_GetExtCompatIdOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
//#else
//const uint8_t * USBD_COMMON_GetExtCompatIdOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
//#endif
//{
//  eNFMUSBInterface_t usbDeviceInterface;
//  NFMClass->methods.usbInterface.getInterface(&usbDeviceInterface);
//  if(usbDeviceInterface == eNFM_IfaceUSBTMC)
//  {
//      *length = 0;
//      return 0;
//  }
//  *length = sizeof(USBD_COMMON_MSCOMPATIBLEDESCR);
//  return USBD_COMMON_MSCOMPATIBLEDESCR;
//}
//
//#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
//static const uint8_t * USBD_COMMON_GetExtPropertiesOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
//#else
//const uint8_t * USBD_COMMON_GetExtPropertiesOsFeatureDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
//#endif
//{
//  eNFMUSBInterface_t usbDeviceInterface;
//  NFMClass->methods.usbInterface.getInterface(&usbDeviceInterface);
//  if(usbDeviceInterface == eNFM_IfaceUSBTMC)
//  {
//      *length = 0;
//      return 0;
//  }
//  *length = sizeof(USBD_COMMON_EXTPROPDESCR);
//  return USBD_COMMON_EXTPROPDESCR;
//}
// Dynamic Serial Number Descriptor is implemented.
//
#define MAX_USB_SERIAL_NUMBER_LEN     10
#pragma pack( push, 1 )
static union
{
    struct
    {
        uint8_t bLength;
        uint8_t bType;
        uint8_t aSerial[ (MAX_USB_SERIAL_NUMBER_LEN) * 2 ];
    };
    uint8_t raw[1];
}
sUSBSerialNumberDescriptor;
#pragma pack(pop)

#if CONFIG_NFMBASECLASS
/**
  * @brief  Return the serial number string descriptor
  * @param  speed : Current device speed
  * @param  length : Pointer to data length variable
  * @retval Pointer to descriptor buffer
  */
const uint8_t * USBD_COMMON_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
{
  uint8_t * pDest = sUSBSerialNumberDescriptor.aSerial;
  const char * pSrc = NFMClass->properties.serialNumber;

  size_t n = strlen( pSrc );

  if( n * 2 > sizeof( sUSBSerialNumberDescriptor.aSerial) )
  {
      n = sizeof( sUSBSerialNumberDescriptor.aSerial) / 2;
  }

  sUSBSerialNumberDescriptor.bType = USB_DESC_TYPE_STRING;
  sUSBSerialNumberDescriptor.bLength = *length = sizeof(sUSBSerialNumberDescriptor.bLength)
                                               + sizeof(sUSBSerialNumberDescriptor.bType)
                                               + 2 * n;
  while( n > 0 )
  {
      n--;
      *pDest = *pSrc;
      pSrc++; pDest++;
      *pDest = '\0';
      pDest++;
  }

  return sUSBSerialNumberDescriptor.raw;
}
#else
#if USBD_GETDESCRIPTORS_ALTMETHOD == 0
static const uint8_t * USBD_COMMON_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#else
const uint8_t * USBD_COMMON_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
#endif
{
  *length = sizeof(USBD_SERIALNUMBER_STRING_FS);
  return USBD_SERIALNUMBER_STRING_FS;
}

#endif
