/* * 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; }