mirror of
https://github.com/ARMmbed/DAPLink.git
synced 2025-07-16 06:30:12 +08:00
827 lines
30 KiB
C
827 lines
30 KiB
C
/**
|
|
* @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"
|
|
|
|
#ifndef CDC_ACM_DEFAULT_BAUDRATE
|
|
#define CDC_ACM_DEFAULT_BAUDRATE 9600
|
|
#endif
|
|
|
|
/* 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 = CDC_ACM_DEFAULT_BAUDRATE;
|
|
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 = CDC_ACM_DEFAULT_BAUDRATE;
|
|
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
|
|
|