/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : Target/usbd_conf.c
  * @version        : v1.0_Cube
  * @brief          : This file implements the board support package for the USB device library
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2021 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "usbd_def.h"
#include "usbd_core.h"

/* USER CODE BEGIN Includes */
#include "usbd_composite.h"
#if (STM32F1_DEVICE) /** for STM32F1 or similar */
#include "usb.h"
#else
#include "usb_otg.h"
#endif
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */
PCD_HandleTypeDef *hpcd_USB_OTG_PTR;
void Error_Handler(void);

/* External functions --------------------------------------------------------*/

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/
USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status);
HAL_StatusTypeDef HAL_PCDEx_SetTxFiFoInBytes(PCD_HandleTypeDef *hpcd, uint8_t fifo, uint16_t size);
HAL_StatusTypeDef HAL_PCDEx_SetRxFiFoInBytes(PCD_HandleTypeDef *hpcd, uint16_t size);
/* USER CODE END PFP */

/* Private functions ---------------------------------------------------------*/

/* USER CODE BEGIN 1 */
#if(!STM32F1_DEVICE)
HAL_StatusTypeDef HAL_PCDEx_SetTxFiFoInBytes(PCD_HandleTypeDef *hpcd, uint8_t fifo, uint16_t size)
{
	return HAL_PCDEx_SetTxFiFo(hpcd, fifo, (size/4));
}

HAL_StatusTypeDef HAL_PCDEx_SetRxFiFoInBytes(PCD_HandleTypeDef *hpcd, uint16_t size)
{
	return HAL_PCDEx_SetRxFiFo(hpcd, (size/4));
}
#endif
/* USER CODE END 1 */

/*******************************************************************************
                       LL Driver Callbacks (PCD -> USB Device Library)
*******************************************************************************/
/* MSP Init */

__weak void HAL_PCD_MspInit(PCD_HandleTypeDef *pcdHandle)
{
    /* @see usb_otg.c or usb.c for (STM32F1 or similar) generated by cube **/
}

__weak void HAL_PCD_MspDeInit(PCD_HandleTypeDef *pcdHandle)
{
    /* @see usb_otg.c or usb.c for (STM32F1 or similar) generated by cube **/
}

/**
  * @brief  Setup stage callback
  * @param  hpcd: PCD handle
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_SetupStageCallback(PCD_HandleTypeDef *hpcd)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_SetupStage((USBD_HandleTypeDef *)hpcd->pData, (uint8_t *)hpcd->Setup);
}

/**
  * @brief  Data Out stage callback.
  * @param  hpcd: PCD handle
  * @param  epnum: Endpoint number
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#else
void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_DataOutStage((USBD_HandleTypeDef *)hpcd->pData, epnum, hpcd->OUT_ep[epnum].xfer_buff);
}

/**
  * @brief  Data In stage callback.
  * @param  hpcd: PCD handle
  * @param  epnum: Endpoint number
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#else
void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_DataInStage((USBD_HandleTypeDef *)hpcd->pData, epnum, hpcd->IN_ep[epnum].xfer_buff);
}

/**
  * @brief  SOF callback.
  * @param  hpcd: PCD handle
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_SOFCallback(PCD_HandleTypeDef *hpcd)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_SOF((USBD_HandleTypeDef *)hpcd->pData);
}

/**
  * @brief  Reset callback.
  * @param  hpcd: PCD handle
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_ResetCallback(PCD_HandleTypeDef *hpcd)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_SpeedTypeDef speed = USBD_SPEED_FULL;

  if (hpcd->Init.speed == PCD_SPEED_FULL)
  {
    speed = USBD_SPEED_FULL; 
  }
  #if(!STM32F1_DEVICE)
  else if (hpcd->Init.speed == PCD_SPEED_HIGH)
  {
    speed = USBD_SPEED_HIGH;
  }
  #endif
  else
  {
    Error_Handler();
  }
  /* Set Speed. */
  USBD_LL_SetSpeed((USBD_HandleTypeDef *)hpcd->pData, speed);

  /* Reset Device. */
  USBD_LL_Reset((USBD_HandleTypeDef *)hpcd->pData);
}

/**
  * @brief  Suspend callback.
  * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
  * @param  hpcd: PCD handle
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_SuspendCallback(PCD_HandleTypeDef *hpcd)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  /* Inform USB library that core enters in suspend Mode. */
  USBD_LL_Suspend((USBD_HandleTypeDef *)hpcd->pData);
#if (!STM32F1_DEVICE)
  __HAL_PCD_GATE_PHYCLOCK(hpcd);
  /* Enter in STOP mode. */
  /* USER CODE BEGIN 2 */
  if (hpcd->Init.low_power_enable)
  {
    /* Set SLEEPDEEP bit and SleepOnExit of Cortex System Control Register. */
    SCB->SCR |= (uint32_t)((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
  }
#endif
  /* USER CODE END 2 */
}

/**
  * @brief  Resume callback.
  * When Low power mode is enabled the debug cannot be used (IAR, Keil doesn't support it)
  * @param  hpcd: PCD handle
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_ResumeCallback(PCD_HandleTypeDef *hpcd)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  /* USER CODE BEGIN 3 */

  /* USER CODE END 3 */
  USBD_LL_Resume((USBD_HandleTypeDef *)hpcd->pData);
}

/**
  * @brief  ISOOUTIncomplete callback.
  * @param  hpcd: PCD handle
  * @param  epnum: Endpoint number
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#else
void HAL_PCD_ISOOUTIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_IsoOUTIncomplete((USBD_HandleTypeDef *)hpcd->pData, epnum);
}

/**
  * @brief  ISOINIncomplete callback.
  * @param  hpcd: PCD handle
  * @param  epnum: Endpoint number
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#else
void HAL_PCD_ISOINIncompleteCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_IsoINIncomplete((USBD_HandleTypeDef *)hpcd->pData, epnum);
}

/**
  * @brief  Connect callback.
  * @param  hpcd: PCD handle
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_ConnectCallback(PCD_HandleTypeDef *hpcd)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_DevConnected((USBD_HandleTypeDef *)hpcd->pData);
}

/**
  * @brief  Disconnect callback.
  * @param  hpcd: PCD handle
  * @retval None
  */
#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
static void PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
#else
void HAL_PCD_DisconnectCallback(PCD_HandleTypeDef *hpcd)
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
{
  USBD_LL_DevDisconnected((USBD_HandleTypeDef *)hpcd->pData);
}

/*******************************************************************************
                       LL Driver Interface (USB Device Library --> PCD)
*******************************************************************************/

/**
  * @brief  Initializes the low level portion of the device driver.
  * @param  pdev: Device handle
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_Init(USBD_HandleTypeDef *pdev)
{
#if (USBD_USE_HS == 1)
  /** HIGH SPEED USB */
  hpcd_USB_OTG_PTR = &hpcd_USB_OTG_HS;

  if (pdev->id == DEVICE_HS)
  {
    /* Link the driver to the stack. */
    hpcd_USB_OTG_PTR->pData = pdev;
    pdev->pData = hpcd_USB_OTG_PTR;

    /* @see HAL_PCD_Init() usb_otg.c generated by cube **/

    HAL_PCDEx_SetRxFiFoInBytes(hpcd_USB_OTG_PTR, 1024);

    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, 0, 64); // EP0 IN

#if (USBD_USE_CDC_RNDIS == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_RNDIS_IN_EP & 0x7F), 128);
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_RNDIS_CMD_EP & 0x7F), 64);
#endif
#if (USBD_USE_CDC_ECM == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_ECM_IN_EP & 0x7F), 128);
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_ECM_CMD_EP & 0x7F), 64);
#endif
#if (USBD_USE_HID_MOUSE == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (HID_MOUSE_IN_EP & 0x7F), 64);
#endif
#if (USBD_USE_HID_KEYBOARD == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (HID_KEYBOARD_IN_EP & 0x7F), 64);
#endif
#if (USBD_USE_HID_CUSTOM == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CUSTOM_HID_IN_EP & 0x7F), 64);
#endif
#if (USBD_USE_UAC_MIC == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (AUDIO_MIC_EP & 0x7F), 128);
#endif
#if (USBD_USE_UAC_SPKR == 1)
#endif
#if (USBD_USE_UVC == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (UVC_IN_EP & 0x7F), 128);
#endif
#if (USBD_USE_MSC == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (MSC_IN_EP & 0x7F), 128);
#endif
#if (USBD_USE_DFU == 1)
#endif
#if (USBD_USE_PRNTR == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (PRNT_IN_EP & 0x7F), 128);
#endif
#if (USBD_USE_CDC_ACM == 1)
    for (uint8_t i = 0; i < USBD_CDC_ACM_COUNT; i++)
    {
      HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_IN_EP[i] & 0x7F), 128);
      HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_CMD_EP[i] & 0x7F), 64);
    }
#endif
  }
#else
  /**FULL SPEED USB */
#if (STM32F1_DEVICE) /** for STM32F1 or similar */
  hpcd_USB_OTG_PTR = &hpcd_USB_FS;  /** hpcd_USB_FS or hpcd_USB_OTG_FS*/
#else
  hpcd_USB_OTG_PTR = &hpcd_USB_OTG_FS;  /** hpcd_USB_FS or hpcd_USB_OTG_FS*/
#endif

  if (pdev->id == DEVICE_FS)
  {
    /* Link the driver to the stack. */
    hpcd_USB_OTG_PTR->pData = pdev;
    pdev->pData = hpcd_USB_OTG_PTR;

    /* @see HAL_PCD_Init() usb_otg.c generated by cube **/

#if (STM32F1_DEVICE)
    /** Device is F1 or similar or if HAL_PCDEx_PMAConfig() is used by HAL driver */
    uint16_t pma_track = 0x40; /** PMA offset*/

    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, 0x00, PCD_SNG_BUF, pma_track);
    pma_track += 0x40;

    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, 0x80, PCD_SNG_BUF, pma_track);
    pma_track += 0x40;

#if (USBD_USE_CDC_RNDIS == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_RNDIS_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_RNDIS_OUT_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_RNDIS_CMD_EP, PCD_SNG_BUF, pma_track);
    pma_track += 8;
#endif
#if (USBD_USE_CDC_ECM == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_ECM_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 48;
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_ECM_OUT_EP, PCD_SNG_BUF, pma_track);
    pma_track += 48;
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_ECM_CMD_EP, PCD_SNG_BUF, pma_track);
    pma_track += 8;
#endif
#if (USBD_USE_HID_MOUSE == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, HID_MOUSE_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 8;
#endif
#if (USBD_USE_HID_KEYBOARD == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, HID_KEYBOARD_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 8;
#endif
#if (USBD_USE_HID_CUSTOM == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CUSTOM_HID_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 8;
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CUSTOM_HID_OUT_EP, PCD_SNG_BUF, pma_track);
    pma_track += 8;
#endif
#if (USBD_USE_UAC_MIC == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, AUDIO_MIC_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
#endif
#if (USBD_USE_UAC_SPKR == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, AUDIO_SPKR_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
#endif
#if (USBD_USE_UVC == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, UVC_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
#endif
#if (USBD_USE_MSC == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, MSC_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, MSC_OUT_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
#endif
#if (USBD_USE_DFU == 1)
#endif
#if (USBD_USE_PRNTR == 1)
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, PRNT_IN_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
    HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, PRNT_OUT_EP, PCD_SNG_BUF, pma_track);
    pma_track += 128;
#endif
#if (USBD_USE_CDC_ACM == 1)
    for (uint8_t i = 0; i < USBD_CDC_ACM_COUNT; i++)
    {
      HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_IN_EP[i], PCD_SNG_BUF, pma_track);
      pma_track += 48;

      HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_OUT_EP[i], PCD_SNG_BUF, pma_track);
      pma_track += 48;

      HAL_PCDEx_PMAConfig((PCD_HandleTypeDef *)pdev->pData, CDC_CMD_EP[i], PCD_SNG_BUF, pma_track);
      pma_track += 8;
    }
#endif
#else /** if HAL_PCDEx_SetRxFiFo() is used by HAL driver */

    HAL_PCDEx_SetRxFiFoInBytes(hpcd_USB_OTG_PTR, 512); // ALL OUT EP Buffer

    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, 0, 64); // EP0 IN

#if (USBD_USE_CDC_RNDIS == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_RNDIS_IN_EP & 0x7F), 128);
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_RNDIS_CMD_EP & 0x7F), 64);
#endif

#if (USBD_USE_CDC_ECM == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_ECM_IN_EP & 0x7F), 128);
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_ECM_CMD_EP & 0x7F), 64);
#endif
#if (USBD_USE_HID_MOUSE == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (HID_MOUSE_IN_EP & 0x7F), 64);
#endif
#if (USBD_USE_HID_KEYBOARD == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (HID_KEYBOARD_IN_EP & 0x7F), 64);
#endif
#if (USBD_USE_HID_CUSTOM == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CUSTOM_HID_IN_EP & 0x7F), 64);
#endif
#if (USBD_USE_UAC_MIC == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (AUDIO_MIC_EP & 0x7F), 128);
#endif
#if (USBD_USE_UAC_SPKR == 1)
#endif
#if (USBD_USE_UVC == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (UVC_IN_EP & 0x7F), 128);
#endif
#if (USBD_USE_MSC == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (MSC_IN_EP & 0x7F), 128);
#endif
#if (USBD_USE_DFU == 1)
#endif
#if (USBD_USE_PRNTR == 1)
    HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (PRNT_IN_EP & 0x7F), 128);
#endif
#if (USBD_USE_CDC_ACM == 1)
    for (uint8_t i = 0; i < USBD_CDC_ACM_COUNT; i++)
    {
      HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_IN_EP[i] & 0x7F), 128);
      HAL_PCDEx_SetTxFiFoInBytes(hpcd_USB_OTG_PTR, (CDC_CMD_EP[i] & 0x7F), 64);
    }
#endif
#endif
  }
#endif

#if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
  /* Register USB PCD CallBacks */
  HAL_PCD_RegisterCallback(hpcd_USB_OTG_PTR, HAL_PCD_SOF_CB_ID, PCD_SOFCallback);
  HAL_PCD_RegisterCallback(hpcd_USB_OTG_PTR, HAL_PCD_SETUPSTAGE_CB_ID, PCD_SetupStageCallback);
  HAL_PCD_RegisterCallback(hpcd_USB_OTG_PTR, HAL_PCD_RESET_CB_ID, PCD_ResetCallback);
  HAL_PCD_RegisterCallback(hpcd_USB_OTG_PTR, HAL_PCD_SUSPEND_CB_ID, PCD_SuspendCallback);
  HAL_PCD_RegisterCallback(hpcd_USB_OTG_PTR, HAL_PCD_RESUME_CB_ID, PCD_ResumeCallback);
  HAL_PCD_RegisterCallback(hpcd_USB_OTG_PTR, HAL_PCD_CONNECT_CB_ID, PCD_ConnectCallback);
  HAL_PCD_RegisterCallback(hpcd_USB_OTG_PTR, HAL_PCD_DISCONNECT_CB_ID, PCD_DisconnectCallback);

  HAL_PCD_RegisterDataOutStageCallback(hpcd_USB_OTG_PTR, PCD_DataOutStageCallback);
  HAL_PCD_RegisterDataInStageCallback(hpcd_USB_OTG_PTR, PCD_DataInStageCallback);
  HAL_PCD_RegisterIsoOutIncpltCallback(hpcd_USB_OTG_PTR, PCD_ISOOUTIncompleteCallback);
  HAL_PCD_RegisterIsoInIncpltCallback(hpcd_USB_OTG_PTR, PCD_ISOINIncompleteCallback);
#endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
  return USBD_OK;
}

/**
  * @brief  De-Initializes the low level portion of the device driver.
  * @param  pdev: Device handle
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_DeInit(USBD_HandleTypeDef *pdev)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_DeInit(pdev->pData);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Starts the low level portion of the device driver.
  * @param  pdev: Device handle
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_Start(USBD_HandleTypeDef *pdev)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_Start(pdev->pData);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Stops the low level portion of the device driver.
  * @param  pdev: Device handle
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_Stop(USBD_HandleTypeDef *pdev)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_Stop(pdev->pData);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Opens an endpoint of the low level driver.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @param  ep_type: Endpoint type
  * @param  ep_mps: Endpoint max packet size
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_OpenEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_mps)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_EP_Open(pdev->pData, ep_addr, ep_mps, ep_type);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Closes an endpoint of the low level driver.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_CloseEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_EP_Close(pdev->pData, ep_addr);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Flushes an endpoint of the Low Level Driver.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_FlushEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_EP_Flush(pdev->pData, ep_addr);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Sets a Stall condition on an endpoint of the Low Level Driver.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_StallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_EP_SetStall(pdev->pData, ep_addr);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Clears a Stall condition on an endpoint of the Low Level Driver.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_ClearStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_EP_ClrStall(pdev->pData, ep_addr);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Returns Stall condition.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @retval Stall (1: Yes, 0: No)
  */
uint8_t USBD_LL_IsStallEP(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
  PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef *)pdev->pData;

  if ((ep_addr & 0x80) == 0x80)
  {
    return hpcd->IN_ep[ep_addr & 0x7F].is_stall;
  }
  else
  {
    return hpcd->OUT_ep[ep_addr & 0x7F].is_stall;
  }
}

/**
  * @brief  Assigns a USB address to the device.
  * @param  pdev: Device handle
  * @param  dev_addr: Device address
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_SetUSBAddress(USBD_HandleTypeDef *pdev, uint8_t dev_addr)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_SetAddress(pdev->pData, dev_addr);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Transmits data over an endpoint.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @param  pbuf: Pointer to data to be sent
  * @param  size: Data size
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Prepares an endpoint for reception.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @param  pbuf: Pointer to data to be received
  * @param  size: Data size
  * @retval USBD status
  */
USBD_StatusTypeDef USBD_LL_PrepareReceive(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
{
  HAL_StatusTypeDef hal_status = HAL_OK;
  USBD_StatusTypeDef usb_status = USBD_OK;

  hal_status = HAL_PCD_EP_Receive(pdev->pData, ep_addr, pbuf, size);

  usb_status = USBD_Get_USB_Status(hal_status);

  return usb_status;
}

/**
  * @brief  Returns the last transfered packet size.
  * @param  pdev: Device handle
  * @param  ep_addr: Endpoint number
  * @retval Recived Data Size
  */
uint32_t USBD_LL_GetRxDataSize(USBD_HandleTypeDef *pdev, uint8_t ep_addr)
{
  return HAL_PCD_EP_GetRxCount((PCD_HandleTypeDef *)pdev->pData, ep_addr);
}

/**
  * @brief  Delays routine for the USB device library.
  * @param  Delay: Delay in ms
  * @retval None
  */
void USBD_LL_Delay(uint32_t Delay)
{
  HAL_Delay(Delay);
}

/**
  * @brief  Retuns the USB status depending on the HAL status:
  * @param  hal_status: HAL status
  * @retval USB status
  */
USBD_StatusTypeDef USBD_Get_USB_Status(HAL_StatusTypeDef hal_status)
{
  USBD_StatusTypeDef usb_status = USBD_OK;

  switch (hal_status)
  {
  case HAL_OK:
    usb_status = USBD_OK;
    break;
  case HAL_ERROR:
    usb_status = USBD_FAIL;
    break;
  case HAL_BUSY:
    usb_status = USBD_BUSY;
    break;
  case HAL_TIMEOUT:
    usb_status = USBD_FAIL;
    break;
  default:
    usb_status = USBD_FAIL;
    break;
  }
  return usb_status;
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
