Damien George
11 years ago
1 changed files with 393 additions and 553 deletions
@ -1,553 +1,393 @@ |
|||
/**
|
|||
****************************************************************************** |
|||
* @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c |
|||
* @author MCD Application Team |
|||
* @version V1.0.1 |
|||
* @date 26-February-2014 |
|||
* @brief Source file for USBD CDC interface |
|||
****************************************************************************** |
|||
* @attention |
|||
* |
|||
* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> |
|||
* |
|||
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); |
|||
* You may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at: |
|||
* |
|||
* http://www.st.com/software_license_agreement_liberty_v2
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
* |
|||
****************************************************************************** |
|||
*/ |
|||
|
|||
/* Includes ------------------------------------------------------------------*/ |
|||
#include <stdbool.h> |
|||
#include "stm32f4xx_hal.h" |
|||
#include "usbd_cdc.h" |
|||
#include "usbd_cdc_interface.h" |
|||
#include "pendsv.h" |
|||
#include "usb.h" |
|||
|
|||
/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
|
|||
* @{ |
|||
*/ |
|||
|
|||
/** @defgroup USBD_CDC
|
|||
* @brief usbd core module |
|||
* @{ |
|||
*/ |
|||
|
|||
/* Private typedef -----------------------------------------------------------*/ |
|||
/* Private define ------------------------------------------------------------*/ |
|||
#define APP_RX_DATA_SIZE 1024 // I think this must be at least CDC_DATA_FS_OUT_PACKET_SIZE (was 2048)
|
|||
#define APP_TX_DATA_SIZE 1024 // I think this can be any value (was 2048)
|
|||
|
|||
/* Private macro -------------------------------------------------------------*/ |
|||
/* Private variables ---------------------------------------------------------*/ |
|||
|
|||
static uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; // received data from USB OUT endpoint is stored in this buffer
|
|||
static uint16_t UserRxBufCur = 0; // points to next available character in UserRxBuffer
|
|||
static uint16_t UserRxBufLen = 0; // counts number of valid characters in UserRxBuffer
|
|||
|
|||
static uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
|
|||
static uint16_t UserTxBufPtrIn = 0; // increment this pointer modulo APP_TX_DATA_SIZE when new data is available
|
|||
static uint16_t UserTxBufPtrOut = 0; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained
|
|||
|
|||
static int user_interrupt_char = VCP_CHAR_NONE; |
|||
static void *user_interrupt_data = NULL; |
|||
|
|||
/* TIM handler declaration */ |
|||
TIM_HandleTypeDef USBD_CDC_TimHandle; |
|||
/* USB handler declaration */ |
|||
extern USBD_HandleTypeDef hUSBDDevice; |
|||
|
|||
/* Private function prototypes -----------------------------------------------*/ |
|||
static int8_t CDC_Itf_Init (void); |
|||
static int8_t CDC_Itf_DeInit (void); |
|||
static int8_t CDC_Itf_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length); |
|||
static int8_t CDC_Itf_Receive (uint8_t* pbuf, uint32_t *Len); |
|||
|
|||
static void Error_Handler(void); |
|||
//static void ComPort_Config(void);
|
|||
static void TIM_Config(void); |
|||
|
|||
const USBD_CDC_ItfTypeDef USBD_CDC_fops = { |
|||
CDC_Itf_Init, |
|||
CDC_Itf_DeInit, |
|||
CDC_Itf_Control, |
|||
CDC_Itf_Receive |
|||
}; |
|||
|
|||
/* Private functions ---------------------------------------------------------*/ |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_Init |
|||
* Initializes the CDC media low layer |
|||
* @param None |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
*/ |
|||
static int8_t CDC_Itf_Init(void) |
|||
{ |
|||
#if 0 |
|||
/*##-1- Configure the UART peripheral ######################################*/ |
|||
/* Put the USART peripheral in the Asynchronous mode (UART Mode) */ |
|||
/* USART configured as follow:
|
|||
- Word Length = 8 Bits |
|||
- Stop Bit = One Stop bit |
|||
- Parity = No parity |
|||
- BaudRate = 115200 baud |
|||
- Hardware flow control disabled (RTS and CTS signals) */ |
|||
UartHandle.Instance = USARTx; |
|||
UartHandle.Init.BaudRate = 115200; |
|||
UartHandle.Init.WordLength = UART_WORDLENGTH_8B; |
|||
UartHandle.Init.StopBits = UART_STOPBITS_1; |
|||
UartHandle.Init.Parity = UART_PARITY_NONE; |
|||
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; |
|||
UartHandle.Init.Mode = UART_MODE_TX_RX; |
|||
|
|||
if(HAL_UART_Init(&UartHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
Error_Handler(); |
|||
} |
|||
|
|||
/*##-2- Put UART peripheral in IT reception process ########################*/ |
|||
/* Any data received will be stored in "UserTxBuffer" buffer */ |
|||
if(HAL_UART_Receive_IT(&UartHandle, (uint8_t *)UserTxBuffer, 1) != HAL_OK) |
|||
{ |
|||
/* Transfer error in reception process */ |
|||
Error_Handler(); |
|||
} |
|||
#endif |
|||
|
|||
/*##-3- Configure the TIM Base generation #################################*/ |
|||
TIM_Config(); |
|||
|
|||
/*##-4- Start the TIM Base generation in interrupt mode ####################*/ |
|||
/* Start Channel1 */ |
|||
if(HAL_TIM_Base_Start_IT(&USBD_CDC_TimHandle) != HAL_OK) |
|||
{ |
|||
/* Starting Error */ |
|||
Error_Handler(); |
|||
} |
|||
|
|||
/*##-5- Set Application Buffers ############################################*/ |
|||
USBD_CDC_SetTxBuffer(&hUSBDDevice, UserTxBuffer, 0); |
|||
USBD_CDC_SetRxBuffer(&hUSBDDevice, UserRxBuffer); |
|||
|
|||
UserRxBufCur = 0; |
|||
UserRxBufLen = 0; |
|||
|
|||
user_interrupt_char = VCP_CHAR_NONE; |
|||
user_interrupt_data = NULL; |
|||
|
|||
return (USBD_OK); |
|||
} |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_DeInit |
|||
* DeInitializes the CDC media low layer |
|||
* @param None |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
*/ |
|||
static int8_t CDC_Itf_DeInit(void) |
|||
{ |
|||
#if 0 |
|||
/* DeInitialize the UART peripheral */ |
|||
if(HAL_UART_DeInit(&UartHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
Error_Handler(); |
|||
} |
|||
#endif |
|||
return (USBD_OK); |
|||
} |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_Control |
|||
* Manage the CDC class requests |
|||
* @param Cmd: Command code |
|||
* @param Buf: Buffer containing command data (request parameters) |
|||
* @param Len: Number of data to be sent (in bytes) |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
*/ |
|||
static int8_t CDC_Itf_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length) |
|||
{ |
|||
switch (cmd) |
|||
{ |
|||
case CDC_SEND_ENCAPSULATED_COMMAND: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_GET_ENCAPSULATED_RESPONSE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_SET_COMM_FEATURE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_GET_COMM_FEATURE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_CLEAR_COMM_FEATURE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_SET_LINE_CODING: |
|||
#if 0 |
|||
LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\ |
|||
(pbuf[2] << 16) | (pbuf[3] << 24)); |
|||
LineCoding.format = pbuf[4]; |
|||
LineCoding.paritytype = pbuf[5]; |
|||
LineCoding.datatype = pbuf[6]; |
|||
|
|||
/* Set the new configuration */ |
|||
ComPort_Config(); |
|||
#endif |
|||
break; |
|||
|
|||
case CDC_GET_LINE_CODING: |
|||
#if 0 |
|||
pbuf[0] = (uint8_t)(LineCoding.bitrate); |
|||
pbuf[1] = (uint8_t)(LineCoding.bitrate >> 8); |
|||
pbuf[2] = (uint8_t)(LineCoding.bitrate >> 16); |
|||
pbuf[3] = (uint8_t)(LineCoding.bitrate >> 24); |
|||
pbuf[4] = LineCoding.format; |
|||
pbuf[5] = LineCoding.paritytype; |
|||
pbuf[6] = LineCoding.datatype; |
|||
#endif |
|||
|
|||
/* Add your code here */ |
|||
pbuf[0] = (uint8_t)(115200); |
|||
pbuf[1] = (uint8_t)(115200 >> 8); |
|||
pbuf[2] = (uint8_t)(115200 >> 16); |
|||
pbuf[3] = (uint8_t)(115200 >> 24); |
|||
pbuf[4] = 0; // stop bits (1)
|
|||
pbuf[5] = 0; // parity (none)
|
|||
pbuf[6] = 8; // number of bits (8)
|
|||
break; |
|||
|
|||
case CDC_SET_CONTROL_LINE_STATE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_SEND_BREAK: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
return (USBD_OK); |
|||
} |
|||
|
|||
/**
|
|||
* @brief TIM period elapsed callback |
|||
* @param htim: TIM handle |
|||
* @retval None |
|||
*/ |
|||
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) |
|||
{ |
|||
uint32_t buffptr; |
|||
uint32_t buffsize; |
|||
|
|||
if(UserTxBufPtrOut != UserTxBufPtrIn) |
|||
{ |
|||
if(UserTxBufPtrOut > UserTxBufPtrIn) /* rollback */ |
|||
{ |
|||
buffsize = APP_RX_DATA_SIZE - UserTxBufPtrOut; |
|||
} |
|||
else |
|||
{ |
|||
buffsize = UserTxBufPtrIn - UserTxBufPtrOut; |
|||
} |
|||
|
|||
buffptr = UserTxBufPtrOut; |
|||
|
|||
USBD_CDC_SetTxBuffer(&hUSBDDevice, (uint8_t*)&UserTxBuffer[buffptr], buffsize); |
|||
|
|||
if(USBD_CDC_TransmitPacket(&hUSBDDevice) == USBD_OK) |
|||
{ |
|||
UserTxBufPtrOut += buffsize; |
|||
if (UserTxBufPtrOut == APP_RX_DATA_SIZE) |
|||
{ |
|||
UserTxBufPtrOut = 0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
#if 0 |
|||
/**
|
|||
* @brief Rx Transfer completed callback |
|||
* @param huart: UART handle |
|||
* @retval None |
|||
*/ |
|||
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) |
|||
{ |
|||
/* Increment Index for buffer writing */ |
|||
UserTxBufPtrIn++; |
|||
|
|||
/* To avoid buffer overflow */ |
|||
if(UserTxBufPtrIn == APP_RX_DATA_SIZE) |
|||
{ |
|||
UserTxBufPtrIn = 0; |
|||
} |
|||
|
|||
/* Start another reception: provide the buffer pointer with offset and the buffer size */ |
|||
HAL_UART_Receive_IT(huart, (uint8_t *)(UserTxBuffer + UserTxBufPtrIn), 1); |
|||
} |
|||
#endif |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_DataRx |
|||
* Data received over USB OUT endpoint is processed here. |
|||
* @param Buf: Buffer of data received |
|||
* @param Len: Number of data received (in bytes) |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
* @note The buffer we are passed here is just UserRxBuffer, so we are |
|||
* free to modify it. |
|||
*/ |
|||
static int8_t CDC_Itf_Receive(uint8_t* Buf, uint32_t *Len) { |
|||
#if 0 |
|||
// this sends the data over the UART using DMA
|
|||
HAL_UART_Transmit_DMA(&UartHandle, Buf, *Len); |
|||
#endif |
|||
|
|||
if (user_interrupt_char == VCP_CHAR_NONE) { |
|||
// no special interrupt character
|
|||
UserRxBufLen = *Len; |
|||
|
|||
} else { |
|||
// filter out sepcial interrupt character from the buffer
|
|||
bool char_found = false; |
|||
uint8_t *dest = Buf; |
|||
uint8_t *src = Buf; |
|||
uint8_t *buf_top = Buf + *Len; |
|||
for (; src < buf_top; src++) { |
|||
if (*src == user_interrupt_char) { |
|||
char_found = true; |
|||
} else { |
|||
if (char_found) { |
|||
*dest = *src; |
|||
} |
|||
dest++; |
|||
} |
|||
} |
|||
|
|||
// set length of remaining characters
|
|||
UserRxBufLen = dest - Buf; |
|||
|
|||
if (char_found) { |
|||
// raise exception when interrupts are finished
|
|||
user_interrupt_char = VCP_CHAR_NONE; |
|||
pendsv_nlr_jump(user_interrupt_data); |
|||
} |
|||
} |
|||
|
|||
// there are new characters at the start of the buffer, so point there
|
|||
UserRxBufCur = 0; |
|||
|
|||
if (UserRxBufLen == 0) { |
|||
// initiate next USB packet transfer now that UserRxBuffer has been drained
|
|||
USBD_CDC_ReceivePacket(&hUSBDDevice); |
|||
} |
|||
|
|||
return (USBD_OK); |
|||
} |
|||
|
|||
void USBD_CDC_SetInterrupt(int chr, void *data) { |
|||
user_interrupt_char = chr; |
|||
user_interrupt_data = data; |
|||
} |
|||
|
|||
void USBD_CDC_Tx(const char *str, uint32_t len) { |
|||
for (int i = 0; i < len; i++) { |
|||
UserTxBuffer[UserTxBufPtrIn] = str[i]; |
|||
UserTxBufPtrIn = (UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1); |
|||
} |
|||
} |
|||
|
|||
int USBD_CDC_RxNum(void) { |
|||
return UserRxBufLen - UserRxBufCur; |
|||
} |
|||
|
|||
int USBD_CDC_RxGet(void) { |
|||
// wait for buffer to have at least 1 character in it
|
|||
while (USBD_CDC_RxNum() == 0) { |
|||
__WFI(); |
|||
} |
|||
|
|||
// get next character
|
|||
int c = UserRxBuffer[UserRxBufCur++]; |
|||
if (UserRxBufCur >= UserRxBufLen) { |
|||
// initiate next USB packet transfer now that UserRxBuffer has been drained
|
|||
USBD_CDC_ReceivePacket(&hUSBDDevice); |
|||
} |
|||
return c; |
|||
} |
|||
|
|||
#if 0 |
|||
/**
|
|||
* @brief Tx Transfer completed callback |
|||
* @param huart: UART handle |
|||
* @retval None |
|||
*/ |
|||
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) |
|||
{ |
|||
/* Initiate next USB packet transfer once UART completes transfer (transmitting data over Tx line) */ |
|||
USBD_CDC_ReceivePacket(&hUSBDDevice); |
|||
} |
|||
|
|||
/**
|
|||
* @brief ComPort_Config |
|||
* Configure the COM Port with the parameters received from host. |
|||
* @param None. |
|||
* @retval None. |
|||
* @note When a configuration is not supported, a default value is used. |
|||
*/ |
|||
static void ComPort_Config(void) |
|||
{ |
|||
if(HAL_UART_DeInit(&UartHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
Error_Handler(); |
|||
} |
|||
|
|||
/* set the Stop bit */ |
|||
switch (LineCoding.format) |
|||
{ |
|||
case 0: |
|||
UartHandle.Init.StopBits = UART_STOPBITS_1; |
|||
break; |
|||
case 2: |
|||
UartHandle.Init.StopBits = UART_STOPBITS_2; |
|||
break; |
|||
default : |
|||
UartHandle.Init.StopBits = UART_STOPBITS_1; |
|||
break; |
|||
} |
|||
|
|||
/* set the parity bit*/ |
|||
switch (LineCoding.paritytype) |
|||
{ |
|||
case 0: |
|||
UartHandle.Init.Parity = UART_PARITY_NONE; |
|||
break; |
|||
case 1: |
|||
UartHandle.Init.Parity = UART_PARITY_ODD; |
|||
break; |
|||
case 2: |
|||
UartHandle.Init.Parity = UART_PARITY_EVEN; |
|||
break; |
|||
default : |
|||
UartHandle.Init.Parity = UART_PARITY_NONE; |
|||
break; |
|||
} |
|||
|
|||
/*set the data type : only 8bits and 9bits is supported */ |
|||
switch (LineCoding.datatype) |
|||
{ |
|||
case 0x07: |
|||
/* With this configuration a parity (Even or Odd) must be set */ |
|||
UartHandle.Init.WordLength = UART_WORDLENGTH_8B; |
|||
break; |
|||
case 0x08: |
|||
if(UartHandle.Init.Parity == UART_PARITY_NONE) |
|||
{ |
|||
UartHandle.Init.WordLength = UART_WORDLENGTH_8B; |
|||
} |
|||
else |
|||
{ |
|||
UartHandle.Init.WordLength = UART_WORDLENGTH_9B; |
|||
} |
|||
|
|||
break; |
|||
default : |
|||
UartHandle.Init.WordLength = UART_WORDLENGTH_8B; |
|||
break; |
|||
} |
|||
|
|||
UartHandle.Init.BaudRate = LineCoding.bitrate; |
|||
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; |
|||
UartHandle.Init.Mode = UART_MODE_TX_RX; |
|||
|
|||
if(HAL_UART_Init(&UartHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
Error_Handler(); |
|||
} |
|||
|
|||
/* Start reception: provide the buffer pointer with offset and the buffer size */ |
|||
HAL_UART_Receive_IT(&UartHandle, (uint8_t *)(UserTxBuffer + UserTxBufPtrIn), 1); |
|||
} |
|||
#endif |
|||
|
|||
/**
|
|||
* @brief TIM_Config: Configure TIMx timer |
|||
* @param None. |
|||
* @retval None. |
|||
*/ |
|||
static void TIM_Config(void) |
|||
{ |
|||
/* Set TIMx instance */ |
|||
USBD_CDC_TimHandle.Instance = USBD_CDC_TIMx; |
|||
|
|||
/* Initialize TIM3 peripheral as follow:
|
|||
+ Period = 10000 - 1 |
|||
+ Prescaler = ((SystemCoreClock/2)/10000) - 1 |
|||
+ ClockDivision = 0 |
|||
+ Counter direction = Up |
|||
*/ |
|||
USBD_CDC_TimHandle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1; |
|||
USBD_CDC_TimHandle.Init.Prescaler = 84-1; |
|||
USBD_CDC_TimHandle.Init.ClockDivision = 0; |
|||
USBD_CDC_TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; |
|||
if(HAL_TIM_Base_Init(&USBD_CDC_TimHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
Error_Handler(); |
|||
} |
|||
} |
|||
|
|||
#if 0 |
|||
/**
|
|||
* @brief UART error callbacks |
|||
* @param UartHandle: UART handle |
|||
* @retval None |
|||
*/ |
|||
void HAL_UART_ErrorCallback(UART_HandleTypeDef *UartHandle) |
|||
{ |
|||
/* Transfer error occured in reception and/or transmission process */ |
|||
Error_Handler(); |
|||
} |
|||
#endif |
|||
|
|||
/**
|
|||
* @brief This function is executed in case of error occurrence. |
|||
* @param None |
|||
* @retval None |
|||
*/ |
|||
static void Error_Handler(void) |
|||
{ |
|||
/* Add your own code here */ |
|||
} |
|||
|
|||
/**
|
|||
* @} |
|||
*/ |
|||
|
|||
/**
|
|||
* @} |
|||
*/ |
|||
|
|||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |
|||
|
|||
/**
|
|||
****************************************************************************** |
|||
* @file USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c |
|||
* @author MCD Application Team |
|||
* @version V1.0.1 |
|||
* @date 26-February-2014 |
|||
* @brief Source file for USBD CDC interface |
|||
****************************************************************************** |
|||
* @attention |
|||
* |
|||
* <h2><center>© COPYRIGHT(c) 2014 STMicroelectronics</center></h2> |
|||
* |
|||
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); |
|||
* You may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at: |
|||
* |
|||
* http://www.st.com/software_license_agreement_liberty_v2
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
* |
|||
****************************************************************************** |
|||
*/ |
|||
|
|||
/* Includes ------------------------------------------------------------------*/ |
|||
#include <stdbool.h> |
|||
#include "stm32f4xx_hal.h" |
|||
#include "usbd_cdc.h" |
|||
#include "usbd_cdc_interface.h" |
|||
#include "pendsv.h" |
|||
#include "usb.h" |
|||
|
|||
/* Private typedef -----------------------------------------------------------*/ |
|||
/* Private define ------------------------------------------------------------*/ |
|||
#define APP_RX_DATA_SIZE 1024 // I think this must be at least CDC_DATA_FS_OUT_PACKET_SIZE (was 2048)
|
|||
#define APP_TX_DATA_SIZE 1024 // I think this can be any value (was 2048)
|
|||
|
|||
/* Private macro -------------------------------------------------------------*/ |
|||
/* Private variables ---------------------------------------------------------*/ |
|||
|
|||
static uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; // received data from USB OUT endpoint is stored in this buffer
|
|||
static uint16_t UserRxBufCur = 0; // points to next available character in UserRxBuffer
|
|||
static uint16_t UserRxBufLen = 0; // counts number of valid characters in UserRxBuffer
|
|||
|
|||
static uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; // data for USB IN endpoind is stored in this buffer
|
|||
static uint16_t UserTxBufPtrIn = 0; // increment this pointer modulo APP_TX_DATA_SIZE when new data is available
|
|||
static uint16_t UserTxBufPtrOut = 0; // increment this pointer modulo APP_TX_DATA_SIZE when data is drained
|
|||
|
|||
static int user_interrupt_char = VCP_CHAR_NONE; |
|||
static void *user_interrupt_data = NULL; |
|||
|
|||
/* TIM handler declaration */ |
|||
TIM_HandleTypeDef USBD_CDC_TimHandle; |
|||
/* USB handler declaration */ |
|||
extern USBD_HandleTypeDef hUSBDDevice; |
|||
|
|||
/* Private function prototypes -----------------------------------------------*/ |
|||
static int8_t CDC_Itf_Init (void); |
|||
static int8_t CDC_Itf_DeInit (void); |
|||
static int8_t CDC_Itf_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length); |
|||
static int8_t CDC_Itf_Receive (uint8_t* pbuf, uint32_t *Len); |
|||
|
|||
static void TIM_Config(void); |
|||
|
|||
const USBD_CDC_ItfTypeDef USBD_CDC_fops = { |
|||
CDC_Itf_Init, |
|||
CDC_Itf_DeInit, |
|||
CDC_Itf_Control, |
|||
CDC_Itf_Receive |
|||
}; |
|||
|
|||
/* Private functions ---------------------------------------------------------*/ |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_Init |
|||
* Initializes the CDC media low layer |
|||
* @param None |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
*/ |
|||
static int8_t CDC_Itf_Init(void) |
|||
{ |
|||
#if 0 |
|||
/*##-1- Configure the UART peripheral ######################################*/ |
|||
/* Put the USART peripheral in the Asynchronous mode (UART Mode) */ |
|||
/* USART configured as follow:
|
|||
- Word Length = 8 Bits |
|||
- Stop Bit = One Stop bit |
|||
- Parity = No parity |
|||
- BaudRate = 115200 baud |
|||
- Hardware flow control disabled (RTS and CTS signals) */ |
|||
UartHandle.Instance = USARTx; |
|||
UartHandle.Init.BaudRate = 115200; |
|||
UartHandle.Init.WordLength = UART_WORDLENGTH_8B; |
|||
UartHandle.Init.StopBits = UART_STOPBITS_1; |
|||
UartHandle.Init.Parity = UART_PARITY_NONE; |
|||
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; |
|||
UartHandle.Init.Mode = UART_MODE_TX_RX; |
|||
|
|||
if(HAL_UART_Init(&UartHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
Error_Handler(); |
|||
} |
|||
|
|||
/*##-2- Put UART peripheral in IT reception process ########################*/ |
|||
/* Any data received will be stored in "UserTxBuffer" buffer */ |
|||
if(HAL_UART_Receive_IT(&UartHandle, (uint8_t *)UserTxBuffer, 1) != HAL_OK) |
|||
{ |
|||
/* Transfer error in reception process */ |
|||
Error_Handler(); |
|||
} |
|||
#endif |
|||
|
|||
/*##-3- Configure the TIM Base generation #################################*/ |
|||
TIM_Config(); |
|||
|
|||
/*##-4- Start the TIM Base generation in interrupt mode ####################*/ |
|||
/* Start Channel1 */ |
|||
if(HAL_TIM_Base_Start_IT(&USBD_CDC_TimHandle) != HAL_OK) |
|||
{ |
|||
/* Starting Error */ |
|||
} |
|||
|
|||
/*##-5- Set Application Buffers ############################################*/ |
|||
USBD_CDC_SetTxBuffer(&hUSBDDevice, UserTxBuffer, 0); |
|||
USBD_CDC_SetRxBuffer(&hUSBDDevice, UserRxBuffer); |
|||
|
|||
UserRxBufCur = 0; |
|||
UserRxBufLen = 0; |
|||
|
|||
user_interrupt_char = VCP_CHAR_NONE; |
|||
user_interrupt_data = NULL; |
|||
|
|||
return (USBD_OK); |
|||
} |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_DeInit |
|||
* DeInitializes the CDC media low layer |
|||
* @param None |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
*/ |
|||
static int8_t CDC_Itf_DeInit(void) |
|||
{ |
|||
#if 0 |
|||
/* DeInitialize the UART peripheral */ |
|||
if(HAL_UART_DeInit(&UartHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
} |
|||
#endif |
|||
return (USBD_OK); |
|||
} |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_Control |
|||
* Manage the CDC class requests |
|||
* @param Cmd: Command code |
|||
* @param Buf: Buffer containing command data (request parameters) |
|||
* @param Len: Number of data to be sent (in bytes) |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
*/ |
|||
static int8_t CDC_Itf_Control (uint8_t cmd, uint8_t* pbuf, uint16_t length) |
|||
{ |
|||
switch (cmd) |
|||
{ |
|||
case CDC_SEND_ENCAPSULATED_COMMAND: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_GET_ENCAPSULATED_RESPONSE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_SET_COMM_FEATURE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_GET_COMM_FEATURE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_CLEAR_COMM_FEATURE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_SET_LINE_CODING: |
|||
#if 0 |
|||
LineCoding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) |\ |
|||
(pbuf[2] << 16) | (pbuf[3] << 24)); |
|||
LineCoding.format = pbuf[4]; |
|||
LineCoding.paritytype = pbuf[5]; |
|||
LineCoding.datatype = pbuf[6]; |
|||
|
|||
/* Set the new configuration */ |
|||
#endif |
|||
break; |
|||
|
|||
case CDC_GET_LINE_CODING: |
|||
#if 0 |
|||
pbuf[0] = (uint8_t)(LineCoding.bitrate); |
|||
pbuf[1] = (uint8_t)(LineCoding.bitrate >> 8); |
|||
pbuf[2] = (uint8_t)(LineCoding.bitrate >> 16); |
|||
pbuf[3] = (uint8_t)(LineCoding.bitrate >> 24); |
|||
pbuf[4] = LineCoding.format; |
|||
pbuf[5] = LineCoding.paritytype; |
|||
pbuf[6] = LineCoding.datatype; |
|||
#endif |
|||
|
|||
/* Add your code here */ |
|||
pbuf[0] = (uint8_t)(115200); |
|||
pbuf[1] = (uint8_t)(115200 >> 8); |
|||
pbuf[2] = (uint8_t)(115200 >> 16); |
|||
pbuf[3] = (uint8_t)(115200 >> 24); |
|||
pbuf[4] = 0; // stop bits (1)
|
|||
pbuf[5] = 0; // parity (none)
|
|||
pbuf[6] = 8; // number of bits (8)
|
|||
break; |
|||
|
|||
case CDC_SET_CONTROL_LINE_STATE: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
case CDC_SEND_BREAK: |
|||
/* Add your code here */ |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
return (USBD_OK); |
|||
} |
|||
|
|||
/**
|
|||
* @brief TIM period elapsed callback |
|||
* @param htim: TIM handle |
|||
* @retval None |
|||
*/ |
|||
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) |
|||
{ |
|||
uint32_t buffptr; |
|||
uint32_t buffsize; |
|||
|
|||
if(UserTxBufPtrOut != UserTxBufPtrIn) |
|||
{ |
|||
if(UserTxBufPtrOut > UserTxBufPtrIn) /* rollback */ |
|||
{ |
|||
buffsize = APP_RX_DATA_SIZE - UserTxBufPtrOut; |
|||
} |
|||
else |
|||
{ |
|||
buffsize = UserTxBufPtrIn - UserTxBufPtrOut; |
|||
} |
|||
|
|||
buffptr = UserTxBufPtrOut; |
|||
|
|||
USBD_CDC_SetTxBuffer(&hUSBDDevice, (uint8_t*)&UserTxBuffer[buffptr], buffsize); |
|||
|
|||
if(USBD_CDC_TransmitPacket(&hUSBDDevice) == USBD_OK) |
|||
{ |
|||
UserTxBufPtrOut += buffsize; |
|||
if (UserTxBufPtrOut == APP_RX_DATA_SIZE) |
|||
{ |
|||
UserTxBufPtrOut = 0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/**
|
|||
* @brief CDC_Itf_DataRx |
|||
* Data received over USB OUT endpoint is processed here. |
|||
* @param Buf: Buffer of data received |
|||
* @param Len: Number of data received (in bytes) |
|||
* @retval Result of the opeartion: USBD_OK if all operations are OK else USBD_FAIL |
|||
* @note The buffer we are passed here is just UserRxBuffer, so we are |
|||
* free to modify it. |
|||
*/ |
|||
static int8_t CDC_Itf_Receive(uint8_t* Buf, uint32_t *Len) { |
|||
#if 0 |
|||
// this sends the data over the UART using DMA
|
|||
HAL_UART_Transmit_DMA(&UartHandle, Buf, *Len); |
|||
#endif |
|||
|
|||
if (user_interrupt_char == VCP_CHAR_NONE) { |
|||
// no special interrupt character
|
|||
UserRxBufLen = *Len; |
|||
|
|||
} else { |
|||
// filter out sepcial interrupt character from the buffer
|
|||
bool char_found = false; |
|||
uint8_t *dest = Buf; |
|||
uint8_t *src = Buf; |
|||
uint8_t *buf_top = Buf + *Len; |
|||
for (; src < buf_top; src++) { |
|||
if (*src == user_interrupt_char) { |
|||
char_found = true; |
|||
} else { |
|||
if (char_found) { |
|||
*dest = *src; |
|||
} |
|||
dest++; |
|||
} |
|||
} |
|||
|
|||
// set length of remaining characters
|
|||
UserRxBufLen = dest - Buf; |
|||
|
|||
if (char_found) { |
|||
// raise exception when interrupts are finished
|
|||
user_interrupt_char = VCP_CHAR_NONE; |
|||
pendsv_nlr_jump(user_interrupt_data); |
|||
} |
|||
} |
|||
|
|||
// there are new characters at the start of the buffer, so point there
|
|||
UserRxBufCur = 0; |
|||
|
|||
if (UserRxBufLen == 0) { |
|||
// initiate next USB packet transfer now that UserRxBuffer has been drained
|
|||
USBD_CDC_ReceivePacket(&hUSBDDevice); |
|||
} |
|||
|
|||
return (USBD_OK); |
|||
} |
|||
|
|||
void USBD_CDC_SetInterrupt(int chr, void *data) { |
|||
user_interrupt_char = chr; |
|||
user_interrupt_data = data; |
|||
} |
|||
|
|||
void USBD_CDC_Tx(const char *str, uint32_t len) { |
|||
for (int i = 0; i < len; i++) { |
|||
uint timeout = 200; |
|||
while (UserTxBufPtrIn + 1 == UserTxBufPtrOut) { |
|||
if (timeout-- == 0) { |
|||
break; |
|||
} |
|||
HAL_Delay(1); |
|||
} |
|||
UserTxBuffer[UserTxBufPtrIn] = str[i]; |
|||
UserTxBufPtrIn = (UserTxBufPtrIn + 1) & (APP_TX_DATA_SIZE - 1); |
|||
} |
|||
} |
|||
|
|||
int USBD_CDC_RxNum(void) { |
|||
return UserRxBufLen - UserRxBufCur; |
|||
} |
|||
|
|||
int USBD_CDC_RxGet(void) { |
|||
// wait for buffer to have at least 1 character in it
|
|||
while (USBD_CDC_RxNum() == 0) { |
|||
__WFI(); |
|||
} |
|||
|
|||
// get next character
|
|||
int c = UserRxBuffer[UserRxBufCur++]; |
|||
if (UserRxBufCur >= UserRxBufLen) { |
|||
// initiate next USB packet transfer now that UserRxBuffer has been drained
|
|||
USBD_CDC_ReceivePacket(&hUSBDDevice); |
|||
} |
|||
return c; |
|||
} |
|||
|
|||
/**
|
|||
* @brief TIM_Config: Configure TIMx timer |
|||
* @param None. |
|||
* @retval None. |
|||
*/ |
|||
static void TIM_Config(void) |
|||
{ |
|||
/* Set TIMx instance */ |
|||
USBD_CDC_TimHandle.Instance = USBD_CDC_TIMx; |
|||
|
|||
/* Initialize TIM3 peripheral as follow:
|
|||
+ Period = 10000 - 1 |
|||
+ Prescaler = ((SystemCoreClock/2)/10000) - 1 |
|||
+ ClockDivision = 0 |
|||
+ Counter direction = Up |
|||
*/ |
|||
USBD_CDC_TimHandle.Init.Period = (USBD_CDC_POLLING_INTERVAL*1000) - 1; |
|||
USBD_CDC_TimHandle.Init.Prescaler = 84-1; |
|||
USBD_CDC_TimHandle.Init.ClockDivision = 0; |
|||
USBD_CDC_TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP; |
|||
if(HAL_TIM_Base_Init(&USBD_CDC_TimHandle) != HAL_OK) |
|||
{ |
|||
/* Initialization Error */ |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue