373 lines
10 KiB
C
373 lines
10 KiB
C
/*
|
|
* cdc.c
|
|
*
|
|
* Created on: Nov 6, 2024
|
|
* Author: true
|
|
*/
|
|
|
|
#include "cdc.h"
|
|
|
|
#include "usb_lib.h"
|
|
|
|
#include "../../usblib/config/usb_desc.h"
|
|
#include "../../usblib/config/usb_prop.h"
|
|
|
|
|
|
|
|
#define USB_TIM TIM4
|
|
#define USB_TIM_IRQn TIM4_IRQn
|
|
|
|
|
|
|
|
/*******************************************************************************/
|
|
/* Variable Definition */
|
|
/* Global */
|
|
|
|
/* The following are serial port transmit and receive related variables and buffers */
|
|
volatile CDC_CTL Cdc;
|
|
|
|
__attribute__((aligned(4))) uint8_t cdc_from[DEF_CDC_FROM_HOST_BUF_LEN]; /* Serial port 2 transmit data buffer */
|
|
__attribute__((aligned(4))) uint8_t cdc_send[DEF_CDC_SEND_HOST_BUF_LEN]; /* Serial port 2 receive data buffer */
|
|
|
|
extern uint8_t USBD_Endp3_Busy;
|
|
|
|
|
|
/*********************************************************************
|
|
* @fn USB_TIM_Init
|
|
*
|
|
* @brief 100us Timer
|
|
* 144 * 100 * 13.8888 -----> 100uS
|
|
* todo: document why we need this counter.
|
|
*
|
|
* @return none
|
|
*/
|
|
void USB_TIM_Init( void )
|
|
{
|
|
TIM_TimeBaseInitTypeDef tim = {0};
|
|
|
|
TIM_DeInit(USB_TIM);
|
|
|
|
/* Time base configuration */
|
|
tim.TIM_Period = 100 - 1;
|
|
tim.TIM_Prescaler = SystemCoreClock / 1000000 - 1;
|
|
tim.TIM_ClockDivision = 0;
|
|
tim.TIM_CounterMode = TIM_CounterMode_Up;
|
|
TIM_TimeBaseInit(USB_TIM, &tim);
|
|
|
|
/* Clear USB_TIM update pending flag */
|
|
TIM_ClearFlag(USB_TIM, TIM_FLAG_Update);
|
|
|
|
/* TIM IT enable */
|
|
TIM_ITConfig(USB_TIM, TIM_IT_Update, ENABLE);
|
|
|
|
/* Enable Interrupt */
|
|
NVIC_EnableIRQ(USB_TIM_IRQn);
|
|
|
|
/* USB_TIM enable counter */
|
|
TIM_Cmd(USB_TIM, ENABLE);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn CDC_ParaInit
|
|
*
|
|
* @brief UART parameters initialization
|
|
* mode = 0 : Used in usb modify initialization
|
|
* mode = 1 : Used in default initializations
|
|
* @return none
|
|
*/
|
|
void CDC_ParaInit(uint8_t mode)
|
|
{
|
|
// uint8_t i;
|
|
|
|
/*
|
|
Cdc.Rx_LoadPtr = 0x00;
|
|
Cdc.Rx_DealPtr = 0x00;
|
|
Cdc.Rx_RemainLen = 0x00;
|
|
Cdc.Rx_TimeOut = 0x00;
|
|
Cdc.Rx_TimeOutMax = 30;
|
|
|
|
Cdc.Tx_LoadNum = 0x00;
|
|
Cdc.Tx_DealNum = 0x00;
|
|
Cdc.Tx_RemainNum = 0x00;
|
|
|
|
for(i = 0; i < DEF_CDC_FROM_HOST_NUM_MAX; i++) {
|
|
Cdc.Tx_PackLen[ i ] = 0x00;
|
|
}
|
|
|
|
Cdc.Tx_Flag = 0x00;
|
|
Cdc.Tx_CurPackLen = 0x00;
|
|
Cdc.Tx_CurPackPtr = 0x00;
|
|
|
|
Cdc.USB_Up_IngFlag = 0x00;
|
|
Cdc.USB_Up_TimeOut = 0x00;
|
|
Cdc.USB_Up_Pack0_Flag = 0x00;
|
|
Cdc.USB_Down_StopFlag = 0x00;
|
|
*/
|
|
|
|
Cdc.send_host_ptr = 0;
|
|
Cdc.send_host_idx = 0;
|
|
Cdc.send_host_count = 0;
|
|
|
|
if (mode) {
|
|
Cdc.cdc_cfg[ 0 ] = (uint8_t)( DEF_CDC_BAUDRATE );
|
|
Cdc.cdc_cfg[ 1 ] = (uint8_t)( DEF_CDC_BAUDRATE >> 8 );
|
|
Cdc.cdc_cfg[ 2 ] = (uint8_t)( DEF_CDC_BAUDRATE >> 16 );
|
|
Cdc.cdc_cfg[ 3 ] = (uint8_t)( DEF_CDC_BAUDRATE >> 24 );
|
|
Cdc.cdc_cfg[ 4 ] = DEF_CDC_STOPBIT;
|
|
Cdc.cdc_cfg[ 5 ] = DEF_CDC_PARITY;
|
|
Cdc.cdc_cfg[ 6 ] = DEF_CDC_DATABIT;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn CDC_USB_Init
|
|
*
|
|
* @brief CDC initialization in usb interrupt
|
|
*
|
|
* @return none
|
|
*/
|
|
void CDC_USB_Init(void)
|
|
{
|
|
uint32_t baudrate;
|
|
uint8_t stopbits __attribute__((unused));
|
|
uint8_t parity __attribute__((unused));
|
|
|
|
baudrate = ( uint32_t )( Cdc.cdc_cfg[ 3 ] << 24 ) + ( uint32_t )( Cdc.cdc_cfg[ 2 ] << 16 );
|
|
baudrate += ( uint32_t )( Cdc.cdc_cfg[ 1 ] << 8 ) + ( uint32_t )( Cdc.cdc_cfg[ 0 ] );
|
|
stopbits = Cdc.cdc_cfg[ 4 ];
|
|
parity = Cdc.cdc_cfg[ 5 ];
|
|
|
|
// this is the point where you would apply these settings.
|
|
// since we are virtual only with no real UART, there is nothing to do here.
|
|
// UART2_Init( 0, baudrate, stopbits, parity );
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn UART2_DataTx_Process
|
|
*
|
|
* @brief Cdc2 data transmission processing
|
|
*
|
|
* @return none
|
|
*/
|
|
void cdc_from_host_process(void)
|
|
{
|
|
// uint16_t count;
|
|
|
|
if(Cdc.from_host_flag) {
|
|
// process incoming data from the host.
|
|
|
|
/*
|
|
// Query whether the DMA transmission of the serial port is completed
|
|
if( USART2->STATR & USART_FLAG_TC )
|
|
{
|
|
USART2->STATR = (uint16_t)( ~USART_FLAG_TC );
|
|
USART2->CTLR3 &= ( ~USART_DMAReq_Tx );
|
|
|
|
Cdc.Tx_Flag = 0x00;
|
|
|
|
NVIC_DisableIRQ( USB_LP_CAN1_RX0_IRQn );
|
|
NVIC_DisableIRQ( USB_HP_CAN1_TX_IRQn );
|
|
|
|
// Calculate the variables of last data
|
|
count = Cdc.Tx_CurPackLen - DEF_UART2_TX_DMA_CH->CNTR;
|
|
Cdc.Tx_CurPackLen -= count;
|
|
Cdc.Tx_CurPackPtr += count;
|
|
if( Cdc.Tx_CurPackLen == 0x00 )
|
|
{
|
|
Cdc.Tx_PackLen[ Cdc.Tx_DealNum ] = 0x0000;
|
|
Cdc.Tx_DealNum++;
|
|
if( Cdc.Tx_DealNum >= DEF_CDC_FROM_HOST_NUM_MAX )
|
|
{
|
|
Cdc.Tx_DealNum = 0x00;
|
|
}
|
|
Cdc.Tx_RemainNum--;
|
|
}
|
|
|
|
// If the current serial port has suspended the downlink, restart the driver downlink
|
|
if( ( Cdc.USB_Down_StopFlag == 0x01 ) && ( Cdc.Tx_RemainNum < 2 ) )
|
|
{
|
|
SetEPRxValid( ENDP2 );
|
|
Cdc.USB_Down_StopFlag = 0x00;
|
|
}
|
|
*/
|
|
|
|
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
|
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
|
|
//}
|
|
} else {
|
|
/*
|
|
// Load data from the serial port send buffer to send
|
|
if(Cdc.Tx_RemainNum) {
|
|
// Determine whether to load from the last unsent buffer or from a new buffer
|
|
if( Cdc.Tx_CurPackLen == 0x00 ) {
|
|
Cdc.Tx_CurPackLen = Cdc.Tx_PackLen[ Cdc.Tx_DealNum ];
|
|
Cdc.Tx_CurPackPtr = ( Cdc.Tx_DealNum * DEF_USB_FS_PACKET_LEN );
|
|
}
|
|
|
|
// Configure DMA and send
|
|
USART_ClearFlag( USART2, USART_FLAG_TC );
|
|
DMA_Cmd( DEF_UART2_TX_DMA_CH, DISABLE );
|
|
DEF_UART2_TX_DMA_CH->MADDR = (uint32_t)&UART2_Tx_Buf[ Cdc.Tx_CurPackPtr ];
|
|
DEF_UART2_TX_DMA_CH->CNTR = Cdc.Tx_CurPackLen;
|
|
DMA_Cmd( DEF_UART2_TX_DMA_CH, ENABLE );
|
|
USART2->CTLR3 |= USART_DMAReq_Tx;
|
|
Cdc.from_host_flag = 0x01;
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* @fn UART2_DataRx_Deal
|
|
*
|
|
* @brief Cdc2 data receiving processing
|
|
*
|
|
* @return none
|
|
*/
|
|
void cdc_send_host_process(void)
|
|
{
|
|
uint16_t remain;
|
|
uint16_t len;
|
|
|
|
// process sending data over USB to the host.
|
|
if (Cdc.send_host_count) {
|
|
if (!Cdc.usb_send_flag) {
|
|
// Calculate the length of this transmission
|
|
remain = Cdc.send_host_count;
|
|
if (remain >= DEF_USBD_MAX_PACK_SIZE ) {
|
|
len = DEF_USBD_MAX_PACK_SIZE;
|
|
} else {
|
|
len = remain;
|
|
}
|
|
|
|
// only send end of buffer if we need to loop it
|
|
if (len > (DEF_CDC_SEND_HOST_BUF_LEN - Cdc.send_host_idx)) {
|
|
len = (DEF_CDC_SEND_HOST_BUF_LEN - Cdc.send_host_idx);
|
|
}
|
|
|
|
// send data via usb
|
|
if (len) {
|
|
Cdc.usb_send_flag = 1;
|
|
|
|
// disable interrupts while configuring
|
|
NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
|
|
NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
|
|
|
|
USBD_ENDPx_DataUp(ENDP3, &cdc_send[Cdc.send_host_idx], len);
|
|
|
|
// calculate new pointer locations
|
|
Cdc.send_host_count -= len;
|
|
Cdc.send_host_idx += len;
|
|
|
|
// reset send pointer to beginning of buffer on overflow
|
|
if (Cdc.send_host_idx >= DEF_CDC_SEND_HOST_BUF_LEN) {
|
|
Cdc.send_host_idx = 0;
|
|
}
|
|
|
|
// re-enable interrupts
|
|
NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
|
|
NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
|
|
}
|
|
}
|
|
else {
|
|
// this is where we could handle a timeout and reset, but ...
|
|
}
|
|
}
|
|
|
|
/*****************************************************************/
|
|
/* Determine if a 0-length packet needs to be uploaded (required for CDC mode)
|
|
* todo: figure out wtf this is about */
|
|
/*
|
|
if( Cdc.USB_Up_Pack0_Flag ) {
|
|
if( Cdc.USB_Up_IngFlag == 0 ) {
|
|
if( Cdc.USB_Up_TimeOut >= ( DEF_CDC_RX_TIMEOUT * 20 ) ) {
|
|
NVIC_DisableIRQ( USB_LP_CAN1_RX0_IRQn );
|
|
NVIC_DisableIRQ( USB_HP_CAN1_TX_IRQn );
|
|
Cdc.USB_Up_IngFlag = 0x01;
|
|
Cdc.USB_Up_TimeOut = 0x00;
|
|
|
|
USBD_ENDPx_DataUp( ENDP3, &CDC_Rx_Buf[ Cdc.Rx_DealPtr], 0);
|
|
|
|
Cdc.USB_Up_IngFlag = 0;
|
|
Cdc.USB_Up_Pack0_Flag = 0x00;
|
|
NVIC_EnableIRQ( USB_LP_CAN1_RX0_IRQn );
|
|
NVIC_EnableIRQ( USB_HP_CAN1_TX_IRQn );
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
int usb_cdc_puts(char *buf, int cnt)
|
|
{
|
|
int remain;
|
|
|
|
// no overflowing the buffer
|
|
// note: you can overflow on consecutive writes, be careful...
|
|
if (cnt > DEF_CDC_SEND_HOST_BUF_LEN) {
|
|
return 0;
|
|
}
|
|
|
|
remain = cnt;
|
|
|
|
if (cnt >= DEF_CDC_SEND_HOST_BUF_LEN - Cdc.send_host_ptr) {
|
|
// if we've got too much data, then copy what will fit to end of buffer
|
|
remain = DEF_CDC_SEND_HOST_BUF_LEN - Cdc.send_host_ptr;
|
|
memcpy(cdc_send + Cdc.send_host_ptr, buf, remain);
|
|
|
|
// set pointers
|
|
Cdc.send_host_ptr = 0;
|
|
|
|
buf += remain;
|
|
remain = cnt - remain;
|
|
}
|
|
|
|
// fill the buffer
|
|
memcpy(cdc_send + Cdc.send_host_ptr, buf, remain);
|
|
|
|
return cnt;
|
|
}
|
|
|
|
int usb_cdc_gets(char *buf, int cnt)
|
|
{
|
|
uint16_t idx = Cdc.from_host_idx;
|
|
uint16_t len = 0;
|
|
|
|
// can only get data if a length is requested
|
|
if (!cnt) {
|
|
return 0;
|
|
}
|
|
|
|
// there is no data to actually get
|
|
if (idx == Cdc.from_host_ptr) {
|
|
return 0;
|
|
}
|
|
|
|
for (len = 0; len < cnt; len++) {
|
|
*buf = cdc_from[idx];
|
|
buf++;
|
|
idx++;
|
|
if (idx >= DEF_CDC_FROM_HOST_BUF_LEN) {
|
|
idx = 0;
|
|
}
|
|
if (idx == Cdc.from_host_ptr) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
Cdc.from_host_idx = idx;
|
|
return len;
|
|
}
|
|
|
|
|
|
__attribute__((interrupt("WCH-Interrupt-fast")))
|
|
void TIM4_IRQHandler(void)
|
|
{
|
|
// uart timeout counts
|
|
//Cdc.Rx_TimeOut++;
|
|
//Cdc.USB_Up_TimeOut++;
|
|
|
|
// clear status
|
|
TIM4->INTFR = (uint16_t)~TIM_IT_Update;
|
|
}
|