From fee89d520fb02b6fb673050c9d2043e14641edf6 Mon Sep 17 00:00:00 2001 From: Damien Date: Sun, 13 Oct 2013 19:02:15 +0100 Subject: Implement crude but functional CDC + MSC USB device. --- stm/lib/usbd_pyb_core.c | 726 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 726 insertions(+) create mode 100644 stm/lib/usbd_pyb_core.c (limited to 'stm/lib/usbd_pyb_core.c') diff --git a/stm/lib/usbd_pyb_core.c b/stm/lib/usbd_pyb_core.c new file mode 100644 index 0000000000..e2e8c65ca0 --- /dev/null +++ b/stm/lib/usbd_pyb_core.c @@ -0,0 +1,726 @@ +/** + ****************************************************************************** + * @file usbd_cdc_core.c + * @author MCD Application Team + * @version V1.1.0 + * @date 19-March-2012 + * @brief This file provides the high layer firmware functions to manage the + * following functionalities of the USB CDC Class: + * - Initialization and Configuration of high and low layer + * - Enumeration as CDC Device (and enumeration for each implemented memory interface) + * - OUT/IN data transfer + * - Command IN transfer (class requests management) + * - Error management + * + * @verbatim + * + * =================================================================== + * CDC Class Driver Description + * =================================================================== + * This driver manages the "Universal Serial Bus Class Definitions for Communications Devices + * Revision 1.2 November 16, 2007" and the sub-protocol specification of "Universal Serial Bus + * Communications Class Subclass Specification for PSTN Devices Revision 1.2 February 9, 2007" + * This driver implements the following aspects of the specification: + * - Device descriptor management + * - Configuration descriptor management + * - Enumeration as CDC device with 2 data endpoints (IN and OUT) and 1 command endpoint (IN) + * - Requests management (as described in section 6.2 in specification) + * - Abstract Control Model compliant + * - Union Functional collection (using 1 IN endpoint for control) + * - Data interface class + + * @note + * For the Abstract Control Model, this core allows only transmitting the requests to + * lower layer dispatcher (ie. usbd_cdc_vcp.c/.h) which should manage each request and + * perform relative actions. + * + * These aspects may be enriched or modified for a specific user application. + * + * This driver doesn't implement the following aspects of the specification + * (but it is possible to manage these features with some modifications on this driver): + * - Any class-specific aspect relative to communication classes should be managed by user application. + * - All communication classes other than PSTN are not managed + * + * @endverbatim + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT 2012 STMicroelectronics

+ * + * 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_cdc_core.h" +#include "usbd_desc.h" +#include "usbd_req.h" +#include "usbd_conf.h" +#include "usbd_msc_bot.h" +#include "usbd_msc_mem.h" + +#define USB_PYB_CONFIG_DESC_SIZ 98 + +#define MSC_EPIN_SIZE MSC_MAX_PACKET +#define MSC_EPOUT_SIZE MSC_MAX_PACKET + +/********************************************* + PYB Device library callbacks + *********************************************/ +static uint8_t usbd_pyb_Init (void *pdev, uint8_t cfgidx); +static uint8_t usbd_pyb_DeInit (void *pdev, uint8_t cfgidx); +static uint8_t usbd_pyb_Setup (void *pdev, USB_SETUP_REQ *req); +static uint8_t usbd_pyb_EP0_RxReady (void *pdev); +static uint8_t usbd_pyb_DataIn (void *pdev, uint8_t epnum); +static uint8_t usbd_pyb_DataOut (void *pdev, uint8_t epnum); +static uint8_t usbd_pyb_SOF (void *pdev); + +/********************************************* + PYB specific management functions + *********************************************/ +static void Handle_USBAsynchXfer (void *pdev); +static uint8_t *usbd_pyb_GetCfgDesc (uint8_t speed, uint16_t *length); + +/** @defgroup usbd_cdc_Private_Variables + * @{ + */ +extern CDC_IF_Prop_TypeDef APP_FOPS; +extern uint8_t USBD_DeviceDesc [USB_SIZ_DEVICE_DESC]; + +__ALIGN_BEGIN static uint8_t usbd_cdc_AltSet __ALIGN_END = 0; +__ALIGN_BEGIN static uint8_t USB_Rx_Buffer[CDC_DATA_MAX_PACKET_SIZE] __ALIGN_END; +__ALIGN_BEGIN uint8_t APP_Rx_Buffer[APP_RX_DATA_SIZE] __ALIGN_END; + +__ALIGN_BEGIN static uint8_t CmdBuff[CDC_CMD_PACKET_SZE] __ALIGN_END; + +__ALIGN_BEGIN static uint8_t USBD_MSC_MaxLun __ALIGN_END = 0; +__ALIGN_BEGIN static uint8_t USBD_MSC_AltSet __ALIGN_END = 0; + +uint32_t APP_Rx_ptr_in = 0; +uint32_t APP_Rx_ptr_out = 0; +uint32_t APP_Rx_length = 0; + +uint8_t USB_Tx_State = 0; + +static uint32_t cdcCmd = 0xFF; +static uint32_t cdcLen = 0; + +/* PYB interface class callbacks structure */ +USBD_Class_cb_TypeDef USBD_PYB_cb = +{ + usbd_pyb_Init, + usbd_pyb_DeInit, + usbd_pyb_Setup, + NULL, // EP0_TxSent + usbd_pyb_EP0_RxReady, + usbd_pyb_DataIn, + usbd_pyb_DataOut, + usbd_pyb_SOF, + NULL, // IsoINIncomplete + NULL, // IsoOUTIncomplete + usbd_pyb_GetCfgDesc, + // for OTG_HS support need to add other cfg desc here +}; + +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + #if defined ( __ICCARM__ ) /*!< IAR Compiler */ + #pragma data_alignment=4 + #endif +#endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ +/* USB PYB device Configuration Descriptor */ +__ALIGN_BEGIN static uint8_t usbd_pyb_CfgDesc[USB_PYB_CONFIG_DESC_SIZ] __ALIGN_END = +{ + //-------------------------------------------------------------------------- + // Configuration Descriptor + 0x09, // bLength: Configuration Descriptor size + USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType: Configuration + LOBYTE(USB_PYB_CONFIG_DESC_SIZ), // wTotalLength: no of returned bytes + HIBYTE(USB_PYB_CONFIG_DESC_SIZ), + 0x03, // bNumInterfaces: 3 interfaces + 0x01, // bConfigurationValue: Configuration value + 0x00, // iConfiguration: Index of string descriptor describing the configuration + 0x80, // bmAttributes: bus powered; 0xc0 for self powered + 0xfa, // bMaxPower: in units of 2mA + + //========================================================================== + // Interface Association for CDC VCP + 0x08, // bLength: 8 bytes + USB_INTERFACE_ASSOCIATION_TYPE, // bDescriptorType: IAD + 0x00, // bFirstInterface: first interface for this association + 0x02, // bInterfaceCount: nummber of interfaces for this association + 0x00, // bFunctionClass: ? + 0x00, // bFunctionSubClass: ? + 0x00, // bFunctionProtocol: ? + 0x00, // iFunction: index of string for this function + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: Interface + 0x00, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x01, // bNumEndpoints: One endpoints used + 0x02, // bInterfaceClass: Communication Interface Class + 0x02, // bInterfaceSubClass: Abstract Control Model + 0x01, // bInterfaceProtocol: Common AT commands + 0x00, // iInterface: + + // Header Functional Descriptor + 0x05, // bLength: Endpoint Descriptor size + 0x24, // bDescriptorType: CS_INTERFACE + 0x00, // bDescriptorSubtype: Header Func Desc + 0x10, // bcdCDC: spec release number + 0x01, // ? + + // Call Management Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x01, // bDescriptorSubtype: Call Management Func Desc + 0x00, // bmCapabilities: D0+D1 + 0x01, // bDataInterface: 1 + + // ACM Functional Descriptor + 0x04, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x02, // bDescriptorSubtype: Abstract Control Management desc + 0x02, // bmCapabilities + + // Union Functional Descriptor + 0x05, // bFunctionLength + 0x24, // bDescriptorType: CS_INTERFACE + 0x06, // bDescriptorSubtype: Union func desc + 0x00, // bMasterInterface: Communication class interface + 0x01, // bSlaveInterface0: Data Class Interface + + // Endpoint 2 Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint + CDC_CMD_EP, // bEndpointAddress + 0x03, // bmAttributes: Interrupt + LOBYTE(CDC_CMD_PACKET_SZE), // wMaxPacketSize: + HIBYTE(CDC_CMD_PACKET_SZE), + 0x80, // bInterval: polling interval in frames of 1ms + + //-------------------------------------------------------------------------- + // Data class interface descriptor + 0x09, // bLength: Endpoint Descriptor size + USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: interface + 0x01, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints: Two endpoints used + 0x0A, // bInterfaceClass: CDC + 0x00, // bInterfaceSubClass: ? + 0x00, // bInterfaceProtocol: ? + 0x00, // iInterface: + + // Endpoint OUT Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint + CDC_OUT_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_MAX_PACKET_SIZE), // wMaxPacketSize: + HIBYTE(CDC_DATA_MAX_PACKET_SIZE), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint IN Descriptor + 0x07, // bLength: Endpoint Descriptor size + USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint + CDC_IN_EP, // bEndpointAddress + 0x02, // bmAttributes: Bulk + LOBYTE(CDC_DATA_MAX_PACKET_SIZE), // wMaxPacketSize: + HIBYTE(CDC_DATA_MAX_PACKET_SIZE), + 0x00, // bInterval: ignore for Bulk transfer + + //========================================================================== + // MSC only has 1 interface so doesn't need an IAD + + //-------------------------------------------------------------------------- + // Interface Descriptor + 0x09, // bLength: Interface Descriptor size + USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType: interface descriptor + 0x02, // bInterfaceNumber: Number of Interface + 0x00, // bAlternateSetting: Alternate setting + 0x02, // bNumEndpoints*/ + 0x08, // bInterfaceClass: MSC Class + 0x06, // bInterfaceSubClass : SCSI transparent*/ + 0x50, // nInterfaceProtocol + 0x00, // iInterface: + + // Endpoint IN descriptor + 0x07, // bLength: Endpoint descriptor length + USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint descriptor type + MSC_IN_EP, // bEndpointAddress: IN, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer + + // Endpoint OUT descriptor + 0x07, // bLength: Endpoint descriptor length + USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType: Endpoint descriptor type + MSC_OUT_EP, // bEndpointAddress: OUT, address 3 + 0x02, // bmAttributes: Bulk endpoint type + LOBYTE(MSC_MAX_PACKET), // wMaxPacketSize + HIBYTE(MSC_MAX_PACKET), + 0x00, // bInterval: ignore for Bulk transfer +}; + + +/** @defgroup usbd_pyb_Private_Functions + * @{ + */ + +/** + * @brief usbd_pyb_Init + * Initilaize the PYB interface + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t usbd_pyb_Init(void *pdev, uint8_t cfgidx) { + // deinit first to reset + usbd_pyb_DeInit(pdev, cfgidx); + + //---------------------------------- + // CDC VCP component + + // Open EP IN + DCD_EP_Open(pdev, + CDC_IN_EP, + CDC_DATA_IN_PACKET_SIZE, + USB_OTG_EP_BULK); + + // Open EP OUT + DCD_EP_Open(pdev, + CDC_OUT_EP, + CDC_DATA_OUT_PACKET_SIZE, + USB_OTG_EP_BULK); + + // Open Command IN EP + DCD_EP_Open(pdev, + CDC_CMD_EP, + CDC_CMD_PACKET_SZE, + USB_OTG_EP_INT); + + /* + // can use this to dynamically set the device class + uint8_t *pbuf = USBD_DeviceDesc; + pbuf[4] = DEVICE_CLASS_CDC; + pbuf[5] = DEVICE_SUBCLASS_CDC; + */ + + // Initialize the Interface physical components + APP_FOPS.pIf_Init(); + + // Prepare Out endpoint to receive next packet */ + DCD_EP_PrepareRx(pdev, + CDC_OUT_EP, + (uint8_t*)(USB_Rx_Buffer), + CDC_DATA_OUT_PACKET_SIZE); + + //---------------------------------- + // MSC component + + // Open EP IN + DCD_EP_Open(pdev, + MSC_IN_EP, + MSC_EPIN_SIZE, + USB_OTG_EP_BULK); + + // Open EP OUT + DCD_EP_Open(pdev, + MSC_OUT_EP, + MSC_EPOUT_SIZE, + USB_OTG_EP_BULK); + + // Init the BOT layer + MSC_BOT_Init(pdev); + + return USBD_OK; +} + +/** + * @brief usbd_pyb_Init + * DeInitialize the CDC layer + * @param pdev: device instance + * @param cfgidx: Configuration index + * @retval status + */ +static uint8_t usbd_pyb_DeInit(void *pdev, uint8_t cfgidx) { + //---------------------------------- + // CDC VCP component + // close CDC EPs + DCD_EP_Close(pdev, CDC_IN_EP); + DCD_EP_Close(pdev, CDC_OUT_EP); + DCD_EP_Close(pdev, CDC_CMD_EP); + + // Restore default state of the Interface physical components + APP_FOPS.pIf_DeInit(); + + //---------------------------------- + // MSC component + + // Close MSC EPs + DCD_EP_Close(pdev, MSC_IN_EP); + DCD_EP_Close(pdev, MSC_OUT_EP); + + // Un Init the BOT layer + MSC_BOT_DeInit(pdev); + + return USBD_OK; +} + +#define BOT_GET_MAX_LUN 0xFE +#define BOT_RESET 0xFF + +/** + * @brief usbd_pyb_Setup + * Handle the CDC specific requests + * @param pdev: instance + * @param req: usb requests + * @retval status + */ +static uint8_t usbd_pyb_Setup(void *pdev, USB_SETUP_REQ *req) { + switch (req->bmRequest & (USB_REQ_TYPE_MASK | USB_REQ_RECIPIENT_MASK)) { + + // Standard Device Request --------------------------------------------- + case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_DEVICE): + switch (req->bRequest) { + case USB_REQ_GET_DESCRIPTOR: + { + uint16_t len = USB_CDC_DESC_SIZ; // XXX WRONG! + uint8_t *pbuf = usbd_pyb_CfgDesc + 9; + if ((req->wValue >> 8) == CDC_DESCRIPTOR_TYPE) { + pbuf = usbd_pyb_CfgDesc + 9 + (9 * USBD_ITF_MAX_NUM); // TODO + len = MIN(USB_CDC_DESC_SIZ, req->wLength); // TODO + } + return USBD_CtlSendData(pdev, pbuf, len); + } + } + break; + + // Standard Interface Request ------------------------------------------ + case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_INTERFACE): + switch (req->bRequest) { + case USB_REQ_GET_INTERFACE: + // wIndex & 0xff is the interface + if ((req->wIndex & 0xff) <= 1) { + return USBD_CtlSendData(pdev, &usbd_cdc_AltSet, 1); + } else { + return USBD_CtlSendData(pdev, &USBD_MSC_AltSet, 1); + } + + case USB_REQ_SET_INTERFACE: + if ((uint8_t)(req->wValue) < USBD_ITF_MAX_NUM) { // TODO + if ((req->wIndex & 0xff) <= 1) { + usbd_cdc_AltSet = req->wValue; + } else { + USBD_MSC_AltSet = req->wValue; + } + return USBD_OK; + } + } + break; + + // Standard Endpoint Request ------------------------------------------- + case (USB_REQ_TYPE_STANDARD | USB_REQ_RECIPIENT_ENDPOINT): + // req->wIndex is the endpoint number, including direction + if (req->wIndex == MSC_IN_EP || req->wIndex == MSC_OUT_EP) { + // MSC component + switch (req->bRequest) { + case USB_REQ_CLEAR_FEATURE: + + // Flush the FIFO and Clear the stall status + DCD_EP_Flush(pdev, (uint8_t)req->wIndex); + + // Re-activate the EP + DCD_EP_Close(pdev, (uint8_t)req->wIndex); + + if ((((uint8_t)req->wIndex) & 0x80) == 0x80) { + DCD_EP_Open(pdev, ((uint8_t)req->wIndex), MSC_EPIN_SIZE, USB_OTG_EP_BULK); + } else { + DCD_EP_Open(pdev, ((uint8_t)req->wIndex), MSC_EPOUT_SIZE, USB_OTG_EP_BULK); + } + + // Handle BOT error + MSC_BOT_CplClrFeature(pdev, (uint8_t)req->wIndex); + return USBD_OK; + } + } + break; + + // CDC Class Requests ------------------------------ + case (USB_REQ_TYPE_CLASS | USB_REQ_RECIPIENT_INTERFACE): + // req->wIndex is the recipient interface number + if (req->wIndex == 0) { + // CDC component, communications interface (TODO do we need to handle if#1?) + + // Check if the request is a data setup packet + if (req->wLength) { + if (req->bmRequest & 0x80) { + // Device-to-Host request + + // Get the data to be sent to Host from interface layer + APP_FOPS.pIf_Ctrl(req->bRequest, CmdBuff, req->wLength); + + // Send the data to the host + return USBD_CtlSendData(pdev, CmdBuff, req->wLength); + + } else { + // Host-to-Device requeset + + // Set the value of the current command to be processed */ + cdcCmd = req->bRequest; + cdcLen = req->wLength; + + // Prepare the reception of the buffer over EP0 + // Next step: the received data will be managed in usbd_cdc_EP0_TxSent() function. + return USBD_CtlPrepareRx(pdev, CmdBuff, req->wLength); + } + } else { + // Not a Data request + + // Transfer the command to the interface layer */ + return APP_FOPS.pIf_Ctrl(req->bRequest, NULL, 0); + } + + } else if (req->wIndex == 2) { + // MSC component + switch (req->bRequest) { + case BOT_GET_MAX_LUN: + if ((req->wValue == 0) && (req->wLength == 1) && ((req->bmRequest & 0x80) == 0x80)) { + USBD_MSC_MaxLun = USBD_STORAGE_fops->GetMaxLun(); + if (USBD_MSC_MaxLun > 0) { + return USBD_CtlSendData(pdev, &USBD_MSC_MaxLun, 1); + } + } + break; + + case BOT_RESET: + if ((req->wValue == 0) && (req->wLength == 0) && ((req->bmRequest & 0x80) != 0x80)) { + MSC_BOT_Reset(pdev); + return USBD_OK; + } + break; + } + } + break; + } + + printf("SU %x %x %x %x\n", req->bmRequest, req->bRequest, req->wValue, req->wIndex); + + // invalid command + USBD_CtlError(pdev, req); + return USBD_FAIL; +} + +/** + * @brief usbd_pyb_EP0_RxReady + * Data received on control endpoint + * @param pdev: device device instance + * @retval status + */ +static uint8_t usbd_pyb_EP0_RxReady(void *pdev) { + if (cdcCmd != NO_CMD) { + // Process the data + APP_FOPS.pIf_Ctrl(cdcCmd, CmdBuff, cdcLen); + + // Reset the command variable to default value + cdcCmd = NO_CMD; + } + + return USBD_OK; +} + +/** + * @brief usbd_pyb_DataIn + * Data sent on non-control IN endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t usbd_pyb_DataIn(void *pdev, uint8_t epnum) { + uint16_t USB_Tx_ptr; + uint16_t USB_Tx_length; + + switch (epnum) { + case (CDC_IN_EP & 0x7f): // TODO is this correct? + case (CDC_CMD_EP & 0x7f): // TODO is this correct? + if (USB_Tx_State == 1) { + if (APP_Rx_length == 0) { + USB_Tx_State = 0; + } else { + if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE) { + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = CDC_DATA_IN_PACKET_SIZE; + + APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE; + APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE; + } else { + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = APP_Rx_length; + + APP_Rx_ptr_out += APP_Rx_length; + APP_Rx_length = 0; + } + + // Prepare the available data buffer to be sent on IN endpoint + DCD_EP_Tx(pdev, + CDC_IN_EP, + (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr], + USB_Tx_length); + } + } + break; + + case (MSC_IN_EP & 0x7f): // TODO? + MSC_BOT_DataIn(pdev, epnum); + break; + } + + return USBD_OK; +} + +/** + * @brief usbd_pyb_DataOut + * Data received on non-control Out endpoint + * @param pdev: device instance + * @param epnum: endpoint number + * @retval status + */ +static uint8_t usbd_pyb_DataOut(void *pdev, uint8_t epnum) { + uint16_t USB_Rx_Cnt; + + switch (epnum) { + case (CDC_OUT_EP & 0x7f): // TODO is this correct? + // Get the received data buffer and update the counter */ + USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_count; + + /* USB data will be immediately processed, this allow next USB traffic being + NAKed till the end of the application Xfer */ + APP_FOPS.pIf_DataRx(USB_Rx_Buffer, USB_Rx_Cnt); + + // Prepare Out endpoint to receive next packet */ + DCD_EP_PrepareRx(pdev, + CDC_OUT_EP, + (uint8_t*)(USB_Rx_Buffer), + CDC_DATA_OUT_PACKET_SIZE); + break; + + case (MSC_OUT_EP & 0x7f): // TODO is this correct? + MSC_BOT_DataOut(pdev, epnum); + break; + } + + return USBD_OK; +} + +/** + * @brief usbd_pyb_SOF + * Start Of Frame event management + * @param pdev: instance + * @retval status + */ +static uint8_t usbd_pyb_SOF(void *pdev) { + static uint32_t FrameCount = 0; + + // TODO do we need to check that this is for CDC/VCP? can we even do that? + + if (FrameCount++ == CDC_IN_FRAME_INTERVAL) { + // Reset the frame counter */ + FrameCount = 0; + + // Check the data to be sent through IN pipe */ + Handle_USBAsynchXfer(pdev); + } + + return USBD_OK; +} + +/** + * @brief Handle_USBAsynchXfer + * Send data to USB + * @param pdev: instance + * @retval None + */ +static void Handle_USBAsynchXfer (void *pdev) +{ + uint16_t USB_Tx_ptr; + uint16_t USB_Tx_length; + + if(USB_Tx_State != 1) + { + if (APP_Rx_ptr_out == APP_RX_DATA_SIZE) + { + APP_Rx_ptr_out = 0; + } + + if(APP_Rx_ptr_out == APP_Rx_ptr_in) + { + USB_Tx_State = 0; + return; + } + + if(APP_Rx_ptr_out > APP_Rx_ptr_in) // rollback */ + { + APP_Rx_length = APP_RX_DATA_SIZE - APP_Rx_ptr_out; + + } + else + { + APP_Rx_length = APP_Rx_ptr_in - APP_Rx_ptr_out; + + } +#ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED + APP_Rx_length &= ~0x03; +#endif // USB_OTG_HS_INTERNAL_DMA_ENABLED */ + + if (APP_Rx_length > CDC_DATA_IN_PACKET_SIZE) + { + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = CDC_DATA_IN_PACKET_SIZE; + + APP_Rx_ptr_out += CDC_DATA_IN_PACKET_SIZE; + APP_Rx_length -= CDC_DATA_IN_PACKET_SIZE; + } + else + { + USB_Tx_ptr = APP_Rx_ptr_out; + USB_Tx_length = APP_Rx_length; + + APP_Rx_ptr_out += APP_Rx_length; + APP_Rx_length = 0; + } + USB_Tx_State = 1; + + DCD_EP_Tx (pdev, + CDC_IN_EP, + (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr], + USB_Tx_length); + } + +} + +/** + * @brief usbd_pyb_GetCfgDesc + * Return configuration descriptor + * @param speed : current device speed + * @param length : pointer data length + * @retval pointer to descriptor buffer + */ +static uint8_t *usbd_pyb_GetCfgDesc(uint8_t speed, uint16_t *length) { + *length = sizeof(usbd_pyb_CfgDesc); + return usbd_pyb_CfgDesc; +} -- cgit v1.2.3