/* * 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_Tx_Buf[DEF_CDC_TX_BUF_LEN]; /* Serial port 2 transmit data buffer */ __attribute__ ((aligned(4))) uint8_t CDC_Rx_Buf[DEF_CDC_RX_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 UART2_ParaInit * * @brief Cdc2 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_TX_BUF_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; if(mode) { Cdc.Com_Cfg[ 0 ] = (uint8_t)( DEF_CDC_BAUDRATE ); Cdc.Com_Cfg[ 1 ] = (uint8_t)( DEF_CDC_BAUDRATE >> 8 ); Cdc.Com_Cfg[ 2 ] = (uint8_t)( DEF_CDC_BAUDRATE >> 16 ); Cdc.Com_Cfg[ 3 ] = (uint8_t)( DEF_CDC_BAUDRATE >> 24 ); Cdc.Com_Cfg[ 4 ] = DEF_CDC_STOPBIT; Cdc.Com_Cfg[ 5 ] = DEF_CDC_PARITY; Cdc.Com_Cfg[ 6 ] = DEF_CDC_DATABIT; Cdc.Com_Cfg[ 7 ] = DEF_CDC_RX_TIMEOUT; } } /********************************************************************* * @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.Com_Cfg[ 3 ] << 24 ) + ( uint32_t )( Cdc.Com_Cfg[ 2 ] << 16 ); baudrate += ( uint32_t )( Cdc.Com_Cfg[ 1 ] << 8 ) + ( uint32_t )( Cdc.Com_Cfg[ 0 ] ); stopbits = Cdc.Com_Cfg[ 4 ]; parity = Cdc.Com_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_DataTx_Process( void ) { // uint16_t count; /* uart1 transmission processing */ if( Cdc.Tx_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_TX_BUF_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_PACK_LEN ); } // todo: figure out wtf all this does. /* // 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.Tx_Flag = 0x01; */ } } } /********************************************************************* * @fn UART2_DataRx_Deal * * @brief Cdc2 data receiving processing * * @return none */ void CDC_DataRx_Process( void ) { // uint16_t temp16; // uint32_t remain_len; // uint16_t packlen; /* Serial port 1 data DMA receive processing */ NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn); // process sending data over USB to the host. /* CDC_Rx_DMACurCount = DEF_UART2_RX_DMA_CH->CNTR; if( CDC_Rx_DMALastCount != CDC_Rx_DMACurCount ) { if( CDC_Rx_DMALastCount > CDC_Rx_DMACurCount ) { temp16 = CDC_Rx_DMALastCount - CDC_Rx_DMACurCount; } else { temp16 = DEF_CDC_RX_BUF_LEN - CDC_Rx_DMACurCount; temp16 += CDC_Rx_DMALastCount; } CDC_Rx_DMALastCount = CDC_Rx_DMACurCount; if( ( Cdc.Rx_RemainLen + temp16 ) > DEF_CDC_RX_BUF_LEN ) { // Overflow handling // Save frame error status printf("U0_O:%08lx\n",(uint32_t)Cdc.Rx_RemainLen); } else { Cdc.Rx_RemainLen += temp16; } // Setting reception status Cdc.Rx_TimeOut = 0x00; } */ NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn); /*****************************************************************/ /* Serial port 1 data processing via USB upload and reception */ if( Cdc.Rx_RemainLen ) { if( Cdc.USB_Up_IngFlag == 0 ) { // todo: figure out wtf this does. /* // Calculate the length of this upload remain_len = Cdc.Rx_RemainLen; packlen = 0x00; if( remain_len >= DEF_USBD_MAX_PACK_SIZE ) { packlen = DEF_USBD_MAX_PACK_SIZE; } else { if( Cdc.Rx_TimeOut >= Cdc.Rx_TimeOutMax ) { packlen = remain_len; } } if( packlen > ( DEF_CDC_RX_BUF_LEN - Cdc.Rx_DealPtr ) ) { packlen = ( DEF_CDC_RX_BUF_LEN - Cdc.Rx_DealPtr ); } // Upload serial data via usb if( packlen ) { 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, &UART2_Rx_Buf[ Cdc.Rx_DealPtr], packlen); // Calculate the variables of interest Cdc.Rx_RemainLen -= packlen; Cdc.Rx_DealPtr += packlen; if( Cdc.Rx_DealPtr >= DEF_CDC_RX_BUF_LEN ) { Cdc.Rx_DealPtr = 0x00; } // Start 0-length packet timeout timer if( packlen == DEF_CDC_RX_BUF_LEN ) { Cdc.USB_Up_Pack0_Flag = 0x01; } NVIC_EnableIRQ( USB_LP_CAN1_RX0_IRQn ); NVIC_EnableIRQ( USB_HP_CAN1_TX_IRQn ); } */ } else { /* Set the upload success flag directly if the upload is not successful after the timeout */ if(Cdc.USB_Up_TimeOut >= DEF_CDC_USB_UP_TIMEOUT) { Cdc.USB_Up_IngFlag = 0x00; USBD_Endp3_Busy = 0; } } } /*****************************************************************/ /* Determine if a 0-length packet needs to be uploaded (required for CDC mode) */ 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 ); } } } } __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; }