/**
  ******************************************************************************
  * @file    usbd_req.c
  * @author  MCD Application Team
  * @version V2.4.2
  * @date    11-December-2015 
  * @brief   This file provides the standard USB requests following chapter 9.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT 2015 STMicroelectronics</center></h2>
  *
  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
  * You may not use this file except in compliance with the License.
  * You may obtain a copy of the License at:
  *
  *        http://www.st.com/software_license_agreement_liberty_v2
  *
  * Unless required by applicable law or agreed to in writing, software 
  * distributed under the License is distributed on an "AS IS" BASIS, 
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
  ******************************************************************************
  */ 

/* Includes ------------------------------------------------------------------*/
#include "usbd_ctlreq.h"
#include "usbd_ioreq.h"


static USBD_StatusTypeDef USBD_GetDescriptor(USBD_HandleTypeDef *pdev, 
                               USBD_SetupReqTypedef *req);

static USBD_StatusTypeDef USBD_SetAddress(USBD_HandleTypeDef *pdev, 
                            USBD_SetupReqTypedef *req);

static USBD_StatusTypeDef USBD_SetConfig(USBD_HandleTypeDef *pdev, 
                           USBD_SetupReqTypedef *req);

static USBD_StatusTypeDef USBD_GetConfig(USBD_HandleTypeDef *pdev, 
                           USBD_SetupReqTypedef *req);

static USBD_StatusTypeDef USBD_GetStatus(USBD_HandleTypeDef *pdev, 
                           USBD_SetupReqTypedef *req);

static USBD_StatusTypeDef USBD_SetFeature(USBD_HandleTypeDef *pdev, 
                            USBD_SetupReqTypedef *req);

static USBD_StatusTypeDef USBD_ClrFeature(USBD_HandleTypeDef *pdev, 
                            USBD_SetupReqTypedef *req);

static USBD_StatusTypeDef USBD_GetMicrosoftDescriptor(USBD_HandleTypeDef *pdev, 
                               USBD_SetupReqTypedef *req);

static uint8_t USBD_GetLen(uint8_t *buf);


/**
* @brief  USBD_StdDevReq
*         Handle standard usb device requests
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
USBD_StatusTypeDef  USBD_StdDevReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef  *req)
{
  USBD_StatusTypeDef ret = USBD_OK;
  if(req->bRequest == USB_REQ_VENDOR_FEATURE) // Debug Добавить ответ только во время работы с вендор протоколом
  {
      ret = USBD_GetMicrosoftDescriptor(pdev, req);
      
      return ret;
  }
  // ~~~~~~~~~~~~~ Legacy support ~~~~~~~~~~~~~~~~~~~~~~~
  switch (req->bmRequest & USB_REQ_TYPE_MASK)
  {    
    case USB_REQ_TYPE_VENDOR:
    {
       ret = USBD_StdEPReq( pdev, req );

       return ret;
    }
    break;
  }
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  switch (req->bRequest) 
  {
      case USB_REQ_GET_DESCRIPTOR:    
        ret = USBD_GetDescriptor(pdev, req);
      break;
        
      case USB_REQ_SET_ADDRESS:                      
        ret = USBD_SetAddress(pdev, req);
      break;
        
      case USB_REQ_SET_CONFIGURATION:                    
        ret = USBD_SetConfig(pdev, req);
      break;
        
      case USB_REQ_GET_CONFIGURATION:                 
        ret = USBD_GetConfig(pdev, req);
      break;

      case USB_REQ_GET_INTERFACE:                 
        ret = USBD_FAIL;
      break; 
     
      case USB_REQ_GET_STATUS:                                  
        ret = USBD_GetStatus(pdev, req);
      break;
        
      case USB_REQ_SET_FEATURE:   
        ret = USBD_SetFeature(pdev, req);
      break;
        
      case USB_REQ_CLEAR_FEATURE:                                   
        ret = USBD_ClrFeature(pdev, req);
      break;
      
      default:
        ret = USBD_FAIL;    
      break;
  }
  
  return ret;
}

/**
* @brief  USBD_StdItfReq
*         Handle standard usb interface requests
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
USBD_StatusTypeDef  USBD_StdItfReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef  *req)
{
  USBD_StatusTypeDef ret = USBD_OK; 
  
  switch (pdev->dev_state) 
  {
     case USBD_STATE_CONFIGURED:
     {  
        if (LOBYTE(req->wIndex) <= USBD_MAX_NUM_INTERFACES) 
        {
            ret = (USBD_StatusTypeDef)pdev->pClass->Setup(pdev, req); 
            
            if( USBD_OK == ret )
            {
                if( req->wLength == 0 )
                {
                   USBD_CtlSendStatus(pdev);
                }
            }
            else
            {
                ret = USBD_FAIL;
            }
        } 
        else 
        {    
             ret = USBD_FAIL;                                             
        }
     }
     break;
        
     default:
        ret = USBD_FAIL;     
     break;
  }

  return ret;
}

/**
* @brief  USBD_StdEPReq
*         Handle standard usb endpoint requests
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
USBD_StatusTypeDef  USBD_StdEPReq (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef  *req)
{
  
  uint8_t   ep_addr;
  USBD_StatusTypeDef ret = USBD_OK; 
  USBD_EndpointTypeDef   *pep;
  ep_addr  = LOBYTE(req->wIndex);   
    
  /* Check if it is a USB-class request or a USB-vendor request */
  switch (req->bmRequest & USB_REQ_TYPE_MASK)  
  {
    case USB_REQ_TYPE_CLASS:
    case USB_REQ_TYPE_VENDOR:
    {
       // pass the request to the class handler
       ret = (USBD_StatusTypeDef)pdev->pClass->Setup (pdev, req);

       return ret;
    }
    break;
  }
  
  switch (req->bRequest)
  {
        case USB_REQ_SET_FEATURE :
        {
          switch (pdev->dev_state) 
          {
              case USBD_STATE_ADDRESSED:          
              {
                  if ((ep_addr != 0x00) && (ep_addr != 0x80)) 
                  {
                      USBD_LL_StallEP(pdev, ep_addr);
                  }
              }
              break;	
                
              case USBD_STATE_CONFIGURED:   
              {
                  if (req->wValue == USB_FEATURE_EP_HALT)
                  {
                      if ((ep_addr != 0x00) && (ep_addr != 0x80)) 
                      { 
                          USBD_LL_StallEP(pdev, ep_addr);
                      }
                  }

                  ret = (USBD_StatusTypeDef)pdev->pClass->Setup(pdev, req);   

                  if( USBD_OK == ret )
                  {
                      USBD_CtlSendStatus(pdev);
                  }              
              }  
              break;
                
              default:                         
                ret = USBD_FAIL;
                break;    
          }
        }
        break;
        
        case USB_REQ_CLEAR_FEATURE:
        {  
            switch( pdev->dev_state ) 
            {
              case USBD_STATE_ADDRESSED:          
              {
                  if ((ep_addr != 0x00) && (ep_addr != 0x80)) 
                  {
                      USBD_LL_StallEP(pdev, ep_addr);
                  }
              }
              break;	
              
              case USBD_STATE_CONFIGURED:   
              {
                if (req->wValue == USB_FEATURE_EP_HALT)
                {
                    if ((ep_addr & 0x7F) != 0x00) 
                    {   
                        // First: clear EP status by default (VALID STATE)
                        USBD_LL_ClearStallEP(pdev, ep_addr);
                        // then: call user handler (user can override EP status now)
                        ret = (USBD_StatusTypeDef)pdev->pClass->Setup(pdev, req);
                    }

                    if( USBD_OK == ret )
                    {
                        USBD_CtlSendStatus(pdev);
                    }
                }
              }
              break;
              
              default:                         
                ret = USBD_FAIL;
              break;    
            }
       }
       break;
        
       case USB_REQ_GET_STATUS:                  
       {
          switch (pdev->dev_state) 
          {
              case USBD_STATE_ADDRESSED:          
              {
                  if ((ep_addr & 0x7F) != 0x00) 
                  {
                     USBD_LL_StallEP(pdev, ep_addr);
                  }
              }
              break;	
            
              case USBD_STATE_CONFIGURED:
              {
                  pep = ((ep_addr & 0x80) == 0x80) ? &pdev->ep_in[ep_addr & 0x7F]:\
                                                     &pdev->ep_out[ep_addr & 0x7F];
                  if(USBD_LL_IsStallEP(pdev, ep_addr))
                  {
                    pep->status = 0x0001;     
                  }
                  else
                  {
                    pep->status = 0x0000;  
                  }
                  
                  USBD_CtlSendData(pdev,
                                   (uint8_t *)&pep->status,
                                   2);
              }
              break;
            
              default:                         
                ret = USBD_FAIL;
              break;
          }
      }
      break;  
      default:
        ret = USBD_FAIL;
      break;
  }

  return ret;
}

/**
* @brief  USBD_GetMicrosoftDescriptor
*         Handle Get Microsoft Descriptor requests
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_GetMicrosoftDescriptor(USBD_HandleTypeDef *pdev, 
                               USBD_SetupReqTypedef *req)
{
  uint16_t len;
  const uint8_t *pbuf = NULL;
  USBD_StatusTypeDef ret = USBD_OK;
  
  switch(req->wIndex)
  {
    case USB_REQ_EXT_COMPAT_ID_OS_FEATURE_DESCRIPTOR:
    {
        #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
        ret = USBD_CallGetDescriptorHandler( pdev, 
                                    eGetDescriptorHandlerType_ExtCompatIdOsFeat,
                                    &pbuf,
                                    &len );
        #else
        USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetExtCompatIdOsFeatureDescriptor );
        #endif
    }
    break;
        
    case USB_REQ_EXT_PROPERTIES_OS_FEATURE_DESCRIPTOR:
    {
        #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
        ret = USBD_CallGetDescriptorHandler( pdev, 
                                    eGetDescriptorHandlerType_ExtPropertiesOsFeat,
                                    &pbuf,
                                    &len );
        #else
        USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetExtPropertiesOsFeatureDescriptor );
        #endif
    }
    break;
  }
  
  if( USBD_FAIL != ret )
  {
      if( (len != 0) && (req->wLength != 0) )
      {
          len = MIN(len , req->wLength);
          
          USBD_CtlSendData(pdev, 
                            pbuf,
                            len);
      }
      else
      {
          ret = USBD_FAIL;
      }
  }
  
  return ret;
}

/**
* @brief  USBD_GetDescriptor
*         Handle Get Descriptor requests
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_GetDescriptor(USBD_HandleTypeDef *pdev, 
                               USBD_SetupReqTypedef *req)
{
  uint16_t len;
  const uint8_t *pbuf = NULL;
  USBD_StatusTypeDef ret = USBD_OK;
  
  switch (req->wValue >> 8)
  {     
    case USB_DESC_TYPE_DEVICE:
    {   
        #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
        ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_Device,
                                             &pbuf,
                                             &len ); 
        #else
        USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetDeviceDescriptor );        
        #endif
    }
    break;
        
    case USB_DESC_TYPE_CONFIGURATION:     
    {
        #if USBD_GETDESCRIPTORS_ALTMETHOD == 0 
        ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_Config,
                                             &pbuf,
                                             &len ); 
        #else
        USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetConfigDescriptor );
        #endif
    }
    break;
        
    case USB_DESC_TYPE_STRING:
    {
        switch ((uint8_t)(req->wValue))
        {
           case USBD_IDX_LANGID_STR:
           {
                #if USBD_GETDESCRIPTORS_ALTMETHOD == 0 
                ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_LangIdStr,
                                             &pbuf,
                                             &len );
                #else
                USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetLangIDStrDescriptor );
                #endif
           }
           break;
          
           case USBD_IDX_MFC_STR:
           {
                #if USBD_GETDESCRIPTORS_ALTMETHOD == 0 
                ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_ManufacturerStr,
                                             &pbuf,
                                             &len );
                #else
                USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetManufacturerStrDescriptor );
                #endif
           }
           break;
          
           case USBD_IDX_PRODUCT_STR:
           {
                #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
                ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_ProductStr,
                                             &pbuf,
                                             &len );
                #else
                USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetProductStrDescriptor );
                #endif
           }
           break;

           #if USBD_IDX_SERIAL_STR != 0
           case USBD_IDX_SERIAL_STR:
           {
                #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
                ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_SerialStr,
                                             &pbuf,
                                             &len );
                #else
                USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetSerialStrDescriptor );
                #endif
           }
           break;
           #endif

           case USBD_IDX_CONFIG_STR:
           {
                #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
                ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_ConfigurationStr,
                                             &pbuf,
                                             &len );
                #else
                USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetConfigurationStrDescriptor );
                #endif
           }
           break;
          
           case USBD_IDX_INTERFACE_STR:
           {
                #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
                ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_InterfaceStr,
                                             &pbuf,
                                             &len );
                #else
                USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetInterfaceStrDescriptor );
                #endif
           }
           break;
           
           case USB_REQ_MS_OS_STRING_DESCRIPTOR:
           {
               #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
                ret = USBD_CallGetDescriptorHandler( pdev, 
                                             eGetDescriptorHandlerType_MsOsString,
                                             &pbuf,
                                             &len );
                #else
                USBD_CallGetDescriptorHandlerAlt( ret, pdev, pbuf, len, GetMsOsStringDescriptor );
                #endif
           }
           break;
          
           default:
           {
              #if (USBD_SUPPORT_USER_STRING == 1)
                  #if USBD_GETDESCRIPTORS_ALTMETHOD == 0
                      if( NULL != pdev->pDesc && pdev->pDesc->GetUsrStrDescriptor )
                        pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue), &len);
                      else
                         if( NULL != pdev->pClass->pDesc && pdev->pClass->pDesc->GetUsrStrDescriptor )
                           pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue), &len);
                         else
                           ret = USBD_FAIL;
                  #else
                      if( NULL != pdev->pClass->pDesc && pdev->pClass->pDesc->GetUsrStrDescriptor )
                           pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue), &len);
                      else
                           ret = USBD_FAIL;
                  #endif
              #else      
                  ret = USBD_FAIL;
              #endif   
           }
           break;
        }
    }
    break;
      
    default: 
       ret = USBD_FAIL;
    break;
  }
  
  if( USBD_FAIL != ret )
  {
      if( (len != 0) && (req->wLength != 0) )
      {
          len = MIN(len , req->wLength);
          
          USBD_CtlSendData(pdev, 
                            pbuf,
                            len);
      }
      else
      {
          ret = USBD_FAIL;
      }
  }

  return ret;
}

/**
* @brief  USBD_SetAddress
*         Set device address
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_SetAddress(USBD_HandleTypeDef *pdev, 
                            USBD_SetupReqTypedef *req)
{
  uint8_t  dev_addr; 
  USBD_StatusTypeDef ret = USBD_OK;
  
  if ((req->wIndex == 0) && (req->wLength == 0)) 
  {
      dev_addr = (uint8_t)(req->wValue) & 0x7F;     
      
      if (pdev->dev_state == USBD_STATE_CONFIGURED) 
      {
          ret = USBD_FAIL;
      } 
      else 
      {
          pdev->dev_address = dev_addr;
          USBD_LL_SetUSBAddress(pdev, dev_addr);               
          USBD_CtlSendStatus(pdev);                         
          
          if (dev_addr != 0) 
          {
              pdev->dev_state  = USBD_STATE_ADDRESSED;
          } 
          else 
          {
              pdev->dev_state  = USBD_STATE_DEFAULT; 
          }
      }
  } 
  else 
  {
     ret = USBD_FAIL;                      
  } 

  return ret;
}

/**
* @brief  USBD_SetConfig
*         Handle Set device configuration request
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_SetConfig(USBD_HandleTypeDef *pdev, 
                           USBD_SetupReqTypedef *req)
{
  
  static uint8_t  cfgidx;
  USBD_StatusTypeDef ret = USBD_OK;

  cfgidx = (uint8_t)(req->wValue);                 
  
  if (cfgidx > USBD_MAX_NUM_CONFIGURATION ) 
  {            
      ret = USBD_FAIL;
  } 
  else 
  {
      switch (pdev->dev_state) 
      {
        case USBD_STATE_ADDRESSED:
        {
            if(cfgidx > 0) 
            {                                			   							   							   				
                pdev->dev_config = cfgidx;
                pdev->dev_state = USBD_STATE_CONFIGURED;

                ret = USBD_SetClassConfig(pdev, cfgidx);
                
                if( USBD_OK == ret )
                {
                    USBD_CtlSendStatus(pdev);
                }
            }
            else 
            {
               USBD_CtlSendStatus(pdev);
            }
        }
        break;
        
        case USBD_STATE_CONFIGURED:
        {
            if (cfgidx == 0) 
            {                           
                pdev->dev_state = USBD_STATE_ADDRESSED;
                pdev->dev_config = cfgidx;          
                USBD_ClrClassConfig(pdev, cfgidx);
                USBD_CtlSendStatus(pdev);
            } 
            else if (cfgidx != pdev->dev_config) 
            {
                /* Clear old configuration */
                USBD_ClrClassConfig(pdev, pdev->dev_config);
                
                /* set new configuration */
                pdev->dev_config = cfgidx;
                ret = USBD_SetClassConfig(pdev, cfgidx);

                if( USBD_OK == ret )
                {
                    USBD_CtlSendStatus(pdev);
                }
            }
            else
            {
                USBD_CtlSendStatus(pdev);
            }
        }
        break;
        
        default:					
           ret = USBD_FAIL;
        break;
      }
  }

  return ret;
}

/**
* @brief  USBD_GetConfig
*         Handle Get device configuration request
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_GetConfig(USBD_HandleTypeDef *pdev, 
                           USBD_SetupReqTypedef *req)
{
  USBD_StatusTypeDef ret = USBD_OK;

  if (req->wLength != 1) 
  {                   
      ret = USBD_FAIL;
  }
  else 
  {
      switch (pdev->dev_state )  
      {
          case USBD_STATE_ADDRESSED:                     
          {
            pdev->dev_default_config = 0;
            USBD_CtlSendData(pdev, 
                              (uint8_t *)&pdev->dev_default_config,
                              1);
          }
          break;
            
          case USBD_STATE_CONFIGURED:   
          {  
            USBD_CtlSendData(pdev, 
                              (uint8_t *)&pdev->dev_config,
                              1);
          }
          break;
            
          default:
             ret = USBD_FAIL;
          break;
      }
  }

  return ret;
}

/**
* @brief  USBD_GetStatus
*         Handle Get Status request
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_GetStatus(USBD_HandleTypeDef *pdev, 
                           USBD_SetupReqTypedef *req)
{
  USBD_StatusTypeDef ret = USBD_OK;
    
  switch (pdev->dev_state) 
  {
      case USBD_STATE_ADDRESSED:
      case USBD_STATE_CONFIGURED:
      {  
        #if ( USBD_SELF_POWERED == 1)
            pdev->dev_config_status = USB_CONFIG_SELF_POWERED;                                  
        #else
            pdev->dev_config_status = 0;                                   
        #endif
                              
            if (pdev->dev_remote_wakeup) 
            {
               pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP;                                
            }
            
            USBD_CtlSendData(pdev, 
                              (const uint8_t *)& pdev->dev_config_status,
                              2);
      }
      break;
        
      default :
          ret = USBD_FAIL;
      break;
  }

  return ret;
}


/**
* @brief  USBD_SetFeature
*         Handle Set device feature request
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_SetFeature(USBD_HandleTypeDef *pdev, 
                            USBD_SetupReqTypedef *req)
{
  USBD_StatusTypeDef ret = USBD_OK;

  if (req->wValue == USB_FEATURE_REMOTE_WAKEUP)
  {
      pdev->dev_remote_wakeup = 1;  
      pdev->pClass->Setup(pdev, req);   
      USBD_CtlSendStatus(pdev);
  }
  else
  {
      ret = USBD_FAIL;
  }

  return ret;
}


/**
* @brief  USBD_ClrFeature
*         Handle clear device feature request
* @param  pdev: device instance
* @param  req: usb request
* @retval status
*/
static USBD_StatusTypeDef USBD_ClrFeature(USBD_HandleTypeDef *pdev, 
                            USBD_SetupReqTypedef *req)
{
  USBD_StatusTypeDef ret = USBD_OK;
  switch (pdev->dev_state)
  {
      case USBD_STATE_ADDRESSED:
      case USBD_STATE_CONFIGURED:
      { 
          if (req->wValue == USB_FEATURE_REMOTE_WAKEUP) 
          {
              pdev->dev_remote_wakeup = 0; 
              pdev->pClass->Setup(pdev, req);   
              USBD_CtlSendStatus(pdev);
          }
          else
          {
              ret = USBD_FAIL;
          }
      }
      break;
        
      default :
         ret = USBD_FAIL;
      break;
  }

  return ret;
}

/**
* @brief  USBD_ParseSetupRequest 
*         Copy buffer into setup structure
* @param  pdev: device instance
* @param  req: usb request
* @retval None
*/

void USBD_ParseSetupRequest(USBD_SetupReqTypedef *req, uint8_t *pdata)
{
  req->bmRequest     = *(uint8_t *)  (pdata);
  req->bRequest      = *(uint8_t *)  (pdata +  1);
  req->wValue        = SWAPBYTE      (pdata +  2);
  req->wIndex        = SWAPBYTE      (pdata +  4);
  req->wLength       = SWAPBYTE      (pdata +  6);

}

/**
* @brief  USBD_CtlError 
*         Handle USB low level Error
* @param  pdev: device instance
* @param  req: usb request
* @retval None
*/

void USBD_CtlError( USBD_HandleTypeDef *pdev,
                            USBD_SetupReqTypedef *req)
{
  USBD_LL_StallEP(pdev, 0x80);
  USBD_LL_StallEP(pdev, 0);
}


/**
  * @brief  USBD_GetString
  *         Convert Ascii string into unicode one
  * @param  desc : descriptor buffer
  * @param  unicode : Formatted string buffer (unicode)
  * @param  len : descriptor length
  * @retval None
  */
void USBD_GetString(uint8_t *desc, uint8_t *unicode, uint16_t *len)
{
  uint8_t idx = 0;
  
  if (desc != NULL) 
  {
    *len =  USBD_GetLen(desc) * 2 + 2;    
    unicode[idx++] = *len;
    unicode[idx++] =  USB_DESC_TYPE_STRING;
    
    while (*desc != '\0') 
    {
      unicode[idx++] = *desc++;
      unicode[idx++] =  0x00;
    }
  } 
}

/**
  * @brief  USBD_GetLen
  *         return the string length
   * @param  buf : pointer to the ascii string buffer
  * @retval string length
  */
static uint8_t USBD_GetLen(uint8_t *buf)
{
    uint8_t  len = 0;

    while (*buf != '\0') 
    {
        len++;
        buf++;
    }

    return len;
}
