Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Revision:
0:01f31e923fe2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/usb/cdc/usbd_cdc_acm.c	Tue Apr 07 12:55:42 2020 +0200
@@ -0,0 +1,823 @@
+/**
+ * @file    usbd_cdc_acm.c
+ * @brief   Communication Device Class driver
+ *
+ * DAPLink Interface Firmware
+ * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.
+ */
+
+#include <string.h>
+
+#include "rl_usb.h"
+#include "usb_for_lib.h"
+
+
+/* Module global variables                                                    */
+
+/** \ingroup  USBD_CDC_ACM_global_variables
+    \defgroup USBD_CDC_ACM_GLOBAL_VAR  Global Variables (GLOBAL_VAR)
+    \brief      Global variables used in USBD CDC ACM module
+ */
+int32_t data_send_access;              /*!< Flag active while send data (in the send intermediate buffer) is being accessed */
+int32_t data_send_active;              /*!< Flag active while data is being sent */
+int32_t data_send_zlp;                 /*!< Flag active when ZLP needs to be sent */
+int32_t data_to_send_wr;               /*!< Number of bytes written to the send intermediate buffer */
+int32_t data_to_send_rd;               /*!< Number of bytes read from the send intermediate buffer */
+uint8_t *ptr_data_to_send;             /*!< Pointer to the send intermediate buffer to the data to be sent */
+uint8_t *ptr_data_sent;                /*!< Pointer to the send intermediate buffer to the data already sent */
+
+int32_t data_read_access;              /*!< Flag active while read data (in the receive intermediate buffer) is being accessed */
+int32_t data_receive_int_access;       /*!< Flag active while read data (in the receive intermediate buffer) is being accessed from the IRQ function*/
+int32_t data_received_pending_pckts;   /*!< Number of packets received but not handled (pending) */
+int32_t data_no_space_for_receive;     /*!< Flag active while there is no more space for reception */
+uint8_t *ptr_data_received;            /*!< Pointer to the receive intermediate buffer to the received unread data */
+uint8_t *ptr_data_read;                /*!< Pointer to the receive intermediate buffer to the received read data */
+
+uint16_t control_line_state;           /*!< Control line state settings bitmap (0. bit - DTR state, 1. bit - RTS state) */
+
+CDC_LINE_CODING line_coding;           /*!< Communication settings */
+
+/* end of group USBD_CDC_ACM_GLOBAL_VAR */
+
+
+/* Functions that should be provided by user to use standard Virtual COM port
+   functionality                                                              */
+__weak int32_t USBD_CDC_ACM_PortInitialize(void)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_PortUninitialize(void)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_PortReset(void)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_PortSetLineCoding(CDC_LINE_CODING *line_coding)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_PortGetLineCoding(CDC_LINE_CODING *line_coding)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_PortSetControlLineState(uint16_t ctrl_bmp)
+{
+    return (0);
+}
+
+/* Functions that can be used by user to use standard Virtual COM port
+   functionality                                                              */
+int32_t USBD_CDC_ACM_DataSend(const uint8_t *buf, int32_t len);
+int32_t USBD_CDC_ACM_PutChar(const uint8_t  ch);
+int32_t USBD_CDC_ACM_DataRead(uint8_t *buf, int32_t len);
+int32_t USBD_CDC_ACM_GetChar(void);
+__weak int32_t USBD_CDC_ACM_DataReceived(int32_t len)
+{
+    return (0);
+}
+int32_t USBD_CDC_ACM_DataAvailable(void);
+int32_t USBD_CDC_ACM_Notify(uint16_t stat);
+
+/* Functions handling CDC ACM requests (can be overridden to provide custom
+   handling of CDC ACM requests)                                              */
+__weak int32_t USBD_CDC_ACM_SendEncapsulatedCommand(void)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_GetEncapsulatedResponse(void)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_SetCommFeature(uint16_t feat)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_GetCommFeature(uint16_t feat)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_ClearCommFeature(uint16_t feat)
+{
+    return (0);
+}
+__weak int32_t USBD_CDC_ACM_SendBreak(uint16_t dur)
+{
+    return (0);
+}
+
+
+/* Local function prototypes                                                  */
+static void USBD_CDC_ACM_EP_BULKOUT_HandleData(void);
+static void USBD_CDC_ACM_EP_BULKIN_HandleData(void);
+
+
+/*----------------- USB CDC ACM class handling functions ---------------------*/
+
+/** \brief  Initialization of the USB CDC class (ACM)
+
+    The function calls USBD_CDC_ACM_PortInitialize function which
+    initializes Virtual COM Port.
+
+    \return             0        Function failed.
+    \return             1        Function succeeded.
+ */
+
+__weak int32_t USBD_CDC_ACM_Initialize(void)
+{
+    data_send_access            = 0;
+    data_send_active            = 0;
+    data_send_zlp               = 0;
+    data_to_send_wr             = 0;
+    data_to_send_rd             = 0;
+    ptr_data_to_send            = USBD_CDC_ACM_SendBuf;
+    ptr_data_sent               = USBD_CDC_ACM_SendBuf;
+    data_read_access            = 0;
+    data_receive_int_access     = 0;
+    data_received_pending_pckts = 0;
+    data_no_space_for_receive   = 0;
+    ptr_data_received           = USBD_CDC_ACM_ReceiveBuf;
+    ptr_data_read               = USBD_CDC_ACM_ReceiveBuf;
+    control_line_state          = 0;
+    line_coding.dwDTERate       = 9600;
+    line_coding.bCharFormat     = 0;
+    line_coding.bParityType     = 0;
+    line_coding.bDataBits       = 8;
+    return (USBD_CDC_ACM_PortInitialize());
+}
+
+
+/** \brief  Uninitialization of the USB CDC class (ACM)
+
+    The function calls USBD_CDC_ACM_PortUninitialize function which
+    uninitializes Virtual COM Port.
+
+    \return             0        Function failed.
+    \return             1        Function succeeded.
+ */
+
+__weak int32_t USBD_CDC_ACM_Uninitialization(void)
+{
+    return (USBD_CDC_ACM_PortUninitialize());
+}
+
+
+/** \brief  Reset of the USB CDC class (ACM) variables and states
+
+    The function resets class variables and states, it calls
+    USBD_CDC_ACM_PortReset function which resets Virtual COM Port variables
+    and states and calls USBD_CDC_ACM_PortSetLineCoding function with
+    default parameters to set default communication settings for the
+    Virtual COM Port.
+
+    \return             0        Function failed.
+    \return             1        Function succeeded.
+ */
+
+__weak int32_t USBD_CDC_ACM_Reset(void)
+{
+    data_send_access            = 0;
+    data_send_active            = 0;
+    data_send_zlp               = 0;
+    data_to_send_wr             = 0;
+    data_to_send_rd             = 0;
+    ptr_data_to_send            = USBD_CDC_ACM_SendBuf;
+    ptr_data_sent               = USBD_CDC_ACM_SendBuf;
+    data_read_access            = 0;
+    data_receive_int_access     = 0;
+    data_received_pending_pckts = 0;
+    data_no_space_for_receive   = 0;
+    ptr_data_received           = USBD_CDC_ACM_ReceiveBuf;
+    ptr_data_read               = USBD_CDC_ACM_ReceiveBuf;
+    control_line_state          = 0;
+    USBD_CDC_ACM_PortReset();
+    line_coding.dwDTERate       = 9600;
+    line_coding.bCharFormat     = 0;
+    line_coding.bParityType     = 0;
+    line_coding.bDataBits       = 8;
+    return (USBD_CDC_ACM_PortSetLineCoding(&line_coding));
+}
+
+
+/** \brief  Sets Line Coding for the USB CDC ACM Virtual COM Port
+
+    The function is a callback function that forwards USB CDC ACM request
+    to set communication settings to the Virtual COM Port.
+
+    \return             0        Function failed.
+    \return             1        Function succeeded.
+ */
+
+__weak int32_t USBD_CDC_ACM_SetLineCoding(void)
+{
+    line_coding.dwDTERate   = (USBD_EP0Buf[0] <<  0) |
+                              (USBD_EP0Buf[1] <<  8) |
+                              (USBD_EP0Buf[2] << 16) |
+                              (USBD_EP0Buf[3] << 24) ;
+    line_coding.bCharFormat =  USBD_EP0Buf[4];
+    line_coding.bParityType =  USBD_EP0Buf[5];
+    line_coding.bDataBits   =  USBD_EP0Buf[6];
+    return (USBD_CDC_ACM_PortSetLineCoding(&line_coding));
+}
+
+
+/** \brief  Gets Line Coding from the USB CDC ACM Virtual COM Port
+
+    The function is a callback function that forwards USB CDC ACM request
+    to get communication settings from the Virtual COM Port.
+
+    \return             0        Function failed.
+    \return             1        Function succeeded.
+ */
+
+__weak int32_t USBD_CDC_ACM_GetLineCoding(void)
+{
+    if (USBD_CDC_ACM_PortGetLineCoding(&line_coding)) {
+        USBD_EP0Buf[0] = (line_coding.dwDTERate >>  0) & 0xFF;
+        USBD_EP0Buf[1] = (line_coding.dwDTERate >>  8) & 0xFF;
+        USBD_EP0Buf[2] = (line_coding.dwDTERate >> 16) & 0xFF;
+        USBD_EP0Buf[3] = (line_coding.dwDTERate >> 24) & 0xFF;
+        USBD_EP0Buf[4] =  line_coding.bCharFormat;
+        USBD_EP0Buf[5] =  line_coding.bParityType;
+        USBD_EP0Buf[6] =  line_coding.bDataBits;
+        return (1);
+    }
+
+    return (0);
+}
+
+
+/** \brief  Sets Control Line State for the USB CDC ACM Virtual COM Port
+
+    The function is a callback function that forwards USB CDC ACM request
+    to set desired control line state to the Virtual COM Port.
+
+    \param [in]         ctrl_bmp Control line settings bitmap (
+                          0. bit - DTR state,
+                          1. bit - RTS state).
+    \return             0        Function failed.
+    \return             1        Function succeeded.
+ */
+
+__weak int32_t USBD_CDC_ACM_SetControlLineState(uint16_t ctrl_bmp)
+{
+    control_line_state = ctrl_bmp;
+    return (USBD_CDC_ACM_PortSetControlLineState(ctrl_bmp));
+}
+
+
+/*----------------- USB CDC ACM user API functions ---------------------------*/
+
+/** \brief Number of free bytes in the Send buffer
+*/
+int32_t USBD_CDC_ACM_DataFree(void)
+{
+    return ((int32_t)usbd_cdc_acm_sendbuf_sz) - (data_to_send_wr - data_to_send_rd);
+}
+
+/** \brief  Sends data over the USB CDC ACM Virtual COM Port
+
+    The function puts requested data to the send intermediate buffer and
+    prepares it for sending over the Virtual COM Port.
+
+    \param [in]         buf      Buffer containing data to be sent.
+    \param [in]         len      Maximum number of bytes to be sent.
+    \return                      Number of bytes accepted to be sent.
+ */
+
+int32_t USBD_CDC_ACM_DataSend(const uint8_t *buf, int32_t len)
+{
+    int32_t  len_data, len_available, len_before_wrap;
+    uint8_t *buf_loc;
+    buf_loc       = (uint8_t *)buf;       /* Pointer to buf                     */
+    len_data      = data_to_send_wr - data_to_send_rd;  /* Num of data in buffer*/
+    len_available = ((int32_t)usbd_cdc_acm_sendbuf_sz) - len_data;  /* Num of
+                                           bytes of space available           */
+
+    if (len_available <= 0) {             /* If no space for data to send       */
+        return (0);
+    }
+
+    if (len > len_available)              /* If more data requested for sending
+                                           then available space               */
+    {
+        len = len_available;    /* Correct to maximum available       */
+    }
+
+    len_before_wrap = 0;                  /* Circular buffer size before wrap   */
+
+    if ((ptr_data_to_send >= ptr_data_sent) && /* If wrap is possible to happen */
+            ((ptr_data_to_send + len) >= (USBD_CDC_ACM_SendBuf + usbd_cdc_acm_sendbuf_sz))) {
+        /* If data wraps around end of buffer */
+        len_before_wrap   = USBD_CDC_ACM_SendBuf + usbd_cdc_acm_sendbuf_sz - ptr_data_to_send;
+        memcpy(ptr_data_to_send, buf_loc, len_before_wrap); /* Copy data till end */
+        buf_loc          += len_before_wrap;            /* Increment buf pointer  */
+        len              -= len_before_wrap;            /* Decrement bytes to send*/
+        ptr_data_to_send  = USBD_CDC_ACM_SendBuf;       /* Wrap send buffer
+                                                       pointer to beginning of
+                                                       the send buffer        */
+    }
+
+    if (len) {                            /* If there are bytes to send         */
+        memcpy(ptr_data_to_send, buf_loc, len);   /* Copy data to send buffer     */
+        ptr_data_to_send += len;            /* Correct position of write pointer  */
+    }
+
+    len += len_before_wrap;               /* Total number of bytes prepared for
+                                           send                               */
+    data_to_send_wr += len;               /* Bytes prepared to send counter     */
+    return (len);                         /* Number of bytes accepted for send  */
+}
+
+
+/** \brief  Sends a single character over the USB CDC ACM Virtual COM Port
+
+    The function puts requested data character to the send intermediate buffer
+    and prepares it for sending over the Virtual COM Port.
+
+    \param [in]         ch       Character to be sent.
+    \return             -1       Function failed.
+    \return                      Character accepted to be sent.
+ */
+
+int32_t USBD_CDC_ACM_PutChar(const uint8_t ch)
+{
+    if ((USBD_CDC_ACM_DataSend(&ch, 1)) == 1) {
+        return ((uint32_t) ch);
+    }
+
+    return (-1);
+}
+
+
+/** \brief  Reads data received over the USB CDC ACM Virtual COM Port
+
+    The function reads data from the receive intermediate buffer that was
+    received over the Virtual COM Port.
+
+    \param [in]         buf      Buffer to where data will be read.
+    \param [in]         len      Maximum number of bytes to be read.
+    \return                      Number of bytes actually read.
+ */
+
+int32_t USBD_CDC_ACM_DataRead(uint8_t *buf, int32_t len)
+{
+    int32_t len_data;
+
+    if (ptr_data_received > ptr_data_read) { /*If there is already received data   */
+        len_data = ptr_data_received - ptr_data_read; /* Available bytes of data  */
+
+        if (len > len_data) {               /* If more requested then available   */
+            len = len_data;    /* correct to return maximum available*/
+        }
+
+        memcpy(buf, ptr_data_read, len);    /* Copy received data to provided buf */
+        ptr_data_read      += len;          /* Correct position of read pointer   */
+    } else {
+        len = 0;                            /* No data received                   */
+    }
+
+    return (len);                         /* Number of bytes actually read      */
+}
+
+
+/** \brief  Reads one character of data received over the USB CDC ACM Virtual COM Port
+
+    The function reads data character from the receive intermediate buffer that
+    was received over the Virtual COM Port.
+
+    \return             -1       No character available.
+    \return                      Received character.
+ */
+
+int32_t USBD_CDC_ACM_GetChar(void)
+{
+    uint8_t ch;
+
+    if ((USBD_CDC_ACM_DataRead(&ch, 1)) == 1) {
+        return ((int32_t) ch);
+    }
+
+    return (-1);
+}
+
+
+/** \brief  Retrieves number of bytes received over the USB CDC ACM Virtual COM Port
+
+    The function retrieves number of bytes available in the intermediate buffer
+    that were received over the Virtual COM Port.
+
+    \return                      Number of bytes available for read.
+ */
+
+int32_t USBD_CDC_ACM_DataAvailable(void)
+{
+    return (ptr_data_received - ptr_data_read);
+}
+
+
+/** \brief  Sends a notification of Virtual COM Port statuses and line states
+
+    The function sends error and line status of the Virtual COM Port over the
+    Interrupt endpoint. (SerialState notification is defined in usbcdc11.pdf, 6.3.5.)
+
+    \param [in]         stat     Error and line statuses (
+                                   6. bit - bOverRun,
+                                   5. bit - bParity,
+                                   4. bit - bFraming,
+                                   3. bit - bRingSignal,
+                                   2. bit - bBreak,
+                                   1. bit - bTxCarrier (DSR line state),
+                                   0. bit - bRxCarrier (DCD line status)).
+    \return             0        Function failed.
+    \return             1        Function succeeded.
+ */
+
+int32_t USBD_CDC_ACM_Notify(uint16_t stat)
+{
+    if (USBD_Configuration) {
+        USBD_CDC_ACM_NotifyBuf[0] = 0xA1;   /* bmRequestType                      */
+        USBD_CDC_ACM_NotifyBuf[1] = CDC_NOTIFICATION_SERIAL_STATE;/* bNotification
+                                          (SERIAL_STATE)                      */
+        USBD_CDC_ACM_NotifyBuf[2] = 0x00;   /* wValue                             */
+        USBD_CDC_ACM_NotifyBuf[3] = 0x00;
+        USBD_CDC_ACM_NotifyBuf[4] = 0x00;   /* wIndex (Interface 0)               */
+        USBD_CDC_ACM_NotifyBuf[5] = 0x00;
+        USBD_CDC_ACM_NotifyBuf[6] = 0x02;   /* wLength                            */
+        USBD_CDC_ACM_NotifyBuf[7] = 0x00;
+        USBD_CDC_ACM_NotifyBuf[8] = stat >> 0; /* UART State Bitmap                  */
+        USBD_CDC_ACM_NotifyBuf[9] = stat >> 8;
+        /* Write notification to be sent      */
+        USBD_WriteEP(usbd_cdc_acm_ep_intin | 0x80, USBD_CDC_ACM_NotifyBuf, 10);
+        return (1);
+    }
+
+    return (0);
+}
+
+
+/*----------------- USB CDC ACM communication event handlers -----------------*/
+
+/** \brief  Handle Reset Events
+
+    The function handles Reset events.
+ */
+
+void USBD_CDC_ACM_Reset_Event(void)
+{
+    USBD_CDC_ACM_Reset();
+}
+
+
+/** \brief  Handle SOF Events
+
+    The function handles Start Of Frame events. It checks if there is pending
+    data on the Bulk Out endpoint and handles it
+    (USBD_CDC_ACM_EP_BULKOUT_HandleData) if there is enough space in the
+    intermediate receive buffer and it calls received function callback
+    (USBD_CDC_ACM_DataReceived) it also activates data send over the Bulk In
+    endpoint if there is data to be sent (USBD_CDC_ACM_EP_BULKIN_HandleData).
+ */
+
+void USBD_CDC_ACM_SOF_Event(void)
+{
+    if (!USBD_Configuration) {
+        // Don't process events until CDC is
+        // configured and the endpoints enabled
+        return;
+    }
+    if ((!data_read_access)         &&    /* If not read active                 */
+            (ptr_data_received == ptr_data_read) &&     /* If received and read
+                                                     pointers point to same
+                                                     the location             */
+            (ptr_data_received != USBD_CDC_ACM_ReceiveBuf)) {
+        /* and if receive
+                                                       pointer does not already
+                                                       point to the start of
+                                                       the receive buffer       */
+        data_read_access = 1;               /* Block access to read data          */
+        ptr_data_received = USBD_CDC_ACM_ReceiveBuf;  /* Correct received pointer
+                                                     to point to the start of
+                                                     the receive buffer       */
+        ptr_data_read     = USBD_CDC_ACM_ReceiveBuf;  /* Correct read pointer to
+                                                     point to the start of the
+                                                     receive buffer           */
+        data_no_space_for_receive  = 0;               /* There is space for
+                                                     reception available      */
+        data_read_access = 0;               /* Allow access to read data          */
+    }
+
+    if (data_received_pending_pckts &&    /* If packets are pending             */
+            (!data_read_access)          &&    /* and if not read active             */
+            (!data_no_space_for_receive)) {    /* and if there is space to receive   */
+        data_read_access = 1;               /* Disable access to read data        */
+        USBD_CDC_ACM_EP_BULKOUT_HandleData(); /* Handle received data             */
+        data_read_access = 0;               /* Enable access to read data         */
+
+        if (ptr_data_received != ptr_data_read) {
+            USBD_CDC_ACM_DataReceived(ptr_data_received - ptr_data_read);
+        }  /* Call
+
+                                           received callback                  */
+    }
+
+    if ((!data_send_access)         &&    /* If send data is not being accessed */
+            (!data_send_active)         &&    /* and send is not active             */
+            (data_to_send_wr - data_to_send_rd) /* and if there is data to be sent    */
+//&& ((control_line_state & 3) == 3)    /* and if DTR and RTS is 1            */
+       ) {
+        data_send_access = 1;               /* Block access to send data          */
+        data_send_active = 1;               /* Start data sending                 */
+        USBD_CDC_ACM_EP_BULKIN_HandleData();/* Handle data to send                */
+        data_send_access = 0;               /* Allow access to send data          */
+    }
+}
+
+
+/** \brief  Handle Interrupt In Endpoint Events
+
+    The function handles Interrupt In endpoint events.
+
+    \param [in]         event    Type of event (USBD_EVT_IN - input event).
+ */
+
+void USBD_CDC_ACM_EP_INTIN_Event(uint32_t event)
+{
+    /* Notification will be loadad aynchronously and sent automatically upon
+       Interrupt IN token reception                                             */
+}
+
+
+/** \brief  Handle Bulk Out Endpoint Received Data
+
+    The function handles data received on the Bulk Out endpoint. It reads the
+    received data to the receive intermediate buffer if there is enough space
+    available.
+ */
+
+static void USBD_CDC_ACM_EP_BULKOUT_HandleData()
+{
+    uint32_t len_free_to_recv;
+    int32_t len_received;
+
+    if ((usbd_cdc_acm_receivebuf_sz - (ptr_data_received - USBD_CDC_ACM_ReceiveBuf)) >= usbd_cdc_acm_maxpacketsize1[USBD_HighSpeed]) {
+        /* If there is space for 1 max packet */
+        /* Read received packet to receive buf*/
+        len_free_to_recv = usbd_cdc_acm_receivebuf_sz - (ptr_data_received - USBD_CDC_ACM_ReceiveBuf);
+        len_received       = USBD_ReadEP(usbd_cdc_acm_ep_bulkout, ptr_data_received, len_free_to_recv);
+        ptr_data_received += len_received;  /* Correct pointer to received data   */
+
+        if (data_received_pending_pckts &&  /* If packet was pending              */
+                !data_receive_int_access) {      /* and not interrupt access           */
+            data_received_pending_pckts--;    /* Decrement pending packets number   */
+        }
+    } else {
+        data_no_space_for_receive = 1;      /* There is no space in receive buffer
+                                           for the newly received data        */
+
+        if (data_receive_int_access) {
+            /* If this access is from interrupt
+                                                   function                           */
+            data_received_pending_pckts++;    /* then this is new unhandled packet  */
+        }
+    }
+}
+
+
+/** \brief  Handle Bulk In Endpoint Data to Send
+
+    The function handles data to be sent on the Bulk In endpoint. It transmits
+    pending data to be sent that is already in the send intermediate buffer,
+    and it also sends Zero Length Packet if last packet sent was not a short
+    packet.
+ */
+
+static void USBD_CDC_ACM_EP_BULKIN_HandleData(void)
+{
+    int32_t len_to_send, len_sent;
+
+    if (!data_send_active) {              /* If sending is not active           */
+        return;
+    }
+
+    len_to_send = data_to_send_wr - data_to_send_rd;  /* Num of data to send    */
+
+    /* Check if sending is finished                                             */
+    if (!len_to_send    &&                /* If all data was sent               */
+            !data_send_zlp)  {                /* and ZLP was sent if necessary also */
+        data_send_active = 0;               /* Sending not active any more        */
+        return;
+    }
+
+    /* Check if data needs to be sent                                           */
+    if (len_to_send) {
+        /* If there is data available do be
+                                                 sent                               */
+        if ((ptr_data_sent >= ptr_data_to_send) && /* If data before end of buf avail*/
+                ((ptr_data_sent + len_to_send) >= (USBD_CDC_ACM_SendBuf + usbd_cdc_acm_sendbuf_sz))) {
+            /* and if available data wraps around
+               the end of the send buffer         */
+            /* Correct bytes to send to data
+               available untill end of send buf   */
+            len_to_send = USBD_CDC_ACM_SendBuf + usbd_cdc_acm_sendbuf_sz - ptr_data_sent;
+        }
+
+        if (len_to_send > usbd_cdc_acm_maxpacketsize1[USBD_HighSpeed]) {
+            /* If
+                                                   there is more data to be sent then
+                                                   can be sent in a single packet     */
+            /* Correct to send maximum pckt size  */
+            len_to_send = usbd_cdc_acm_maxpacketsize1[USBD_HighSpeed];
+        }
+    } else if (data_send_zlp) {           /* or if ZLP should be sent           */
+        len_to_send = 0;
+    }
+
+    data_send_zlp = 0;
+    /* Send data                          */
+    len_sent = USBD_WriteEP(usbd_cdc_acm_ep_bulkin | 0x80, ptr_data_sent, len_to_send);
+    ptr_data_sent    += len_sent;         /* Correct position of sent pointer   */
+    data_to_send_rd  += len_sent;         /* Correct num of bytes left to send  */
+
+    if (ptr_data_sent == USBD_CDC_ACM_SendBuf + usbd_cdc_acm_sendbuf_sz)
+        /* If pointer to sent data wraps      */
+    {
+        ptr_data_sent = USBD_CDC_ACM_SendBuf;
+    } /* Correct it to beginning of send
+
+                                           buffer                             */
+
+    if ((data_to_send_wr == data_to_send_rd) &&   /* If there are no more
+                                           bytes available to be sent         */
+            (len_sent == usbd_cdc_acm_maxpacketsize1[USBD_HighSpeed])) {
+        /* If last packet size was same as
+           maximum packet size                */
+        data_send_zlp = 1;                  /* ZLP packet should be sent          */
+    } else {
+        data_send_zlp = 0;                  /* No ZLP packet should be sent       */
+    }
+}
+
+
+/** \brief  Handle Bulk Out Endpoint Events
+
+    The function handles Bulk Out endpoint events. It calls
+    USBD_CDC_ACM_EP_BULKOUT_HandleData function to handle received data
+    unless data was being accessed in which case function just acknowledges
+    that there is data to be handled later.
+
+    \param [in]         event    Type of event (USBD_EVT_OUT - output event).
+ */
+
+void USBD_CDC_ACM_EP_BULKOUT_Event(uint32_t event)
+{
+    if (data_read_access) {
+        /* If data is being accessed from
+                                                 read function                      */
+        data_received_pending_pckts++;      /* 1 more packet received and not
+                                           handled                            */
+        return;
+    }
+
+    data_read_access = 1;                 /* Block access to read data          */
+    data_receive_int_access = 1;          /* Read access from interrupt function*/
+    USBD_CDC_ACM_EP_BULKOUT_HandleData(); /* Handle received data               */
+    data_receive_int_access = 0;          /* Read access from interrupt func end*/
+    data_read_access = 0;                 /* Allow access to read data          */
+
+    if (ptr_data_received != ptr_data_read) {
+        USBD_CDC_ACM_DataReceived(ptr_data_received - ptr_data_read);
+    }    /* Call
+
+                                           received callback                  */
+}
+
+
+/** \brief  Handle Bulk In Endpoint Events
+
+    The function handles Bulk In endpoint events. It calls
+    USBD_CDC_ACM_EP_BULKIN_HandleData function to handle send data
+    unless data was being accessed in which case function just returns.
+
+    \param [in]         event    Type of event (USBD_EVT_IN - input event).
+ */
+
+void USBD_CDC_ACM_EP_BULKIN_Event(uint32_t event)
+{
+    if (data_send_access                  /* If send data is being accessed     */
+// ||((control_line_state & 3) != 3)    /* or if DTR or RTS is 0              */
+       ) {
+        return;
+    }
+
+    data_send_access = 1;                 /* Block access to send data          */
+    USBD_CDC_ACM_EP_BULKIN_HandleData();  /* Handle data to send                */
+    data_send_access = 0;                 /* Allow access to send data          */
+}
+
+
+/** \brief  Handle Bulk In/Out Endpoint Events
+
+    The function handles Bulk In/Out endpoint events. It is used for endpoints
+    that do In and Out functionality on the same endpoint number. It dispatches
+    events to appropriate In or Out event handlers.
+
+    \param [in]         event    Type of event (
+                                   USBD_EVT_IN  - input event,
+                                   USBD_EVT_OUT - output event).
+ */
+
+void USBD_CDC_ACM_EP_BULK_Event(uint32_t event)
+{
+    if (event & USBD_EVT_OUT) {
+        USBD_CDC_ACM_EP_BULKOUT_Event(event);
+    }
+
+    if (event & USBD_EVT_IN) {
+        USBD_CDC_ACM_EP_BULKIN_Event(event);
+    }
+}
+
+
+#ifdef __RTX                            /* RTX tasks for handling events      */
+
+/** \brief  Task Handling Interrupt In Endpoint Events
+
+    The task dispatches Interrupt In events to the Interrupt In handling
+    function (USBD_CDC_ACM_EP_INTIN_Event).
+ */
+
+void USBD_RTX_CDC_ACM_EP_INTIN_Event(void)
+{
+    for (;;) {
+        usbd_os_evt_wait_or(0xFFFF, 0xFFFF);
+        USBD_CDC_ACM_EP_INTIN_Event(usbd_os_evt_get());
+    }
+}
+
+
+/** \brief  Task Handling Bulk In Endpoint Events
+
+    The task dispatches Bulk In events to the Bulk In handling
+    function (USBD_CDC_ACM_EP_BULKIN_Event).
+ */
+
+void USBD_RTX_CDC_ACM_EP_BULKIN_Event(void)
+{
+    for (;;) {
+        usbd_os_evt_wait_or(0xFFFF, 0xFFFF);
+
+        if (usbd_os_evt_get() & USBD_EVT_IN) {
+            USBD_CDC_ACM_EP_BULKIN_Event(0);
+        }
+    }
+}
+
+
+/** \brief  Task Handling Bulk Out Endpoint Events
+
+    The task dispatches Bulk Out events to the Bulk Out handling
+    function (USBD_CDC_ACM_EP_BULKOUT_Event).
+ */
+
+void USBD_RTX_CDC_ACM_EP_BULKOUT_Event(void)
+{
+    for (;;) {
+        usbd_os_evt_wait_or(0xFFFF, 0xFFFF);
+
+        if (usbd_os_evt_get() & USBD_EVT_OUT) {
+            USBD_CDC_ACM_EP_BULKOUT_Event(0);
+        }
+    }
+}
+
+
+/** \brief  Task Handling Bulk In/Out Endpoint Events
+
+    The task dispatches Bulk In/Out events to the Bulk In/Out handling
+    function (USBD_CDC_ACM_EP_BULK_Event).
+ */
+
+void USBD_RTX_CDC_ACM_EP_BULK_Event(void)
+{
+    for (;;) {
+        usbd_os_evt_wait_or(0xFFFF, 0xFFFF);
+        USBD_CDC_ACM_EP_BULK_Event(usbd_os_evt_get());
+    }
+}
+#endif
+