/********************************** (C) COPYRIGHT ******************************* * File Name : usbd_compatibility_hid.c * Author : WCH * Version : v0.01 * Date : 2024/02/05 * Description: ******************************************************************************* * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. * Attention: This software (modified or not) and binary are used for * microcontroller manufactured by Nanjing Qinheng Microelectronics. *******************************************************************************/ #include "debug.h" #include "string.h" #include "usbd_compatibility_hid.h" void TIM2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); __attribute__ ((aligned(4))) uint8_t UART2_RxBuffer[DEF_UART2_BUF_SIZE]; // UART2 Rx Buffer __attribute__ ((aligned(4))) uint8_t HID_Report_Buffer[DEF_USBD_MAX_PACK_SIZE]; // HID Report Buffer __attribute__ ((aligned(4))) uint8_t HIDTxBuffer[DEF_USBD_MAX_PACK_SIZE]; // HID Tx Buffer volatile uint16_t UART2_TimeOut; // UART2 RX timeout flag volatile uint8_t UART2_Tx_Flag; // UART2 TX flag volatile uint16_t UART2_RX_CurCnt = 0; // UART2 DMA current remain count volatile uint16_t UART2_RX_LastCnt = 0; // UART2 DMA last remain count volatile uint16_t UART2_Rx_RemainLen = 0; // UART2 RX data remain len volatile uint16_t UART2_Rx_Deal_Ptr = 0; // UART2 RX data deal pointer extern uint8_t USBD_ENDPx_DataUp( uint8_t endp, uint8_t *pbuf, uint16_t len ); extern uint8_t USBD_Endp2_Busy; /********************************************************************* * @fn TIM2_Init * * @brief Timer2 100us initialisation * * @return none */ void TIM2_Init( void ) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0}; NVIC_InitTypeDef NVIC_InitStructure = {0}; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = 71; TIM_TimeBaseStructure.TIM_Prescaler =100; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM2, ENABLE); } /********************************************************************* * @fn TIM2_IRQHandler * * @brief TIM2 IRQ handler * * @return none */ void TIM2_IRQHandler(void) { UART2_TimeOut++; TIM_ClearITPendingBit(TIM2,TIM_IT_Update); } /********************************************************************* * @fn UART2_DMA_Init * * @brief UART2 DMA initialization * * @return none */ void UART2_DMA_Init( void ) { DMA_InitTypeDef DMA_InitStructure = {0}; RCC_AHBPeriphClockCmd( RCC_AHBPeriph_DMA1, ENABLE ); /* UART2 Tx DMA initialization */ DMA_Cmd( DMA1_Channel7, DISABLE ); DMA_DeInit( DMA1_Channel7 ); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART2->DATAR); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)Data_Buffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; DMA_InitStructure.DMA_BufferSize = DEF_USBD_MAX_PACK_SIZE; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init( DMA1_Channel7, &DMA_InitStructure ); /* UART2 Rx DMA initialization */ DMA_Cmd( DMA1_Channel6, DISABLE ); DMA_DeInit( DMA1_Channel6 ); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)UART2_RxBuffer; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = DEF_UART2_BUF_SIZE; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_Init( DMA1_Channel6, &DMA_InitStructure ); DMA_Cmd( DMA1_Channel6, ENABLE ); USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE); } /********************************************************************* * @fn UART2_Init * * @brief UART2 DMA initialization * * @return none */ void UART2_Init( void ) { GPIO_InitTypeDef GPIO_InitStructure = {0}; USART_InitTypeDef USART_InitStructure = {0}; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* UART2 GPIO Init */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); /* UART2 Init */ USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART2, &USART_InitStructure); USART_ClearFlag( USART2, USART_FLAG_TC ); USART_Cmd(USART2, ENABLE); } void UART2_DMA_Tx(uint8_t *pbuf,uint16_t len) { USART_ClearFlag(USART2, USART_FLAG_TC); DMA_Cmd( DMA1_Channel7, DISABLE ); DMA1_Channel7->MADDR = (uint32_t)pbuf; DMA1_Channel7->CNTR = (uint32_t)len; DMA_Cmd( DMA1_Channel7, ENABLE ); USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE); } /********************************************************************* * @fn UART2_Rx_Service * * @brief UART2 rx service routine that sends the data received by * uart2 via USB-HID. * * @return none */ void UART2_Rx_Service( void ) { uint16_t pkg_len; uint16_t u16_temp; uint16_t remain_len; /* Get uart2 rx data */ UART2_RX_CurCnt = DMA_GetCurrDataCounter(DMA1_Channel6); // Get DMA remaining count if (UART2_RX_LastCnt != UART2_RX_CurCnt) { if (UART2_RX_LastCnt > UART2_RX_CurCnt) { u16_temp = UART2_RX_LastCnt - UART2_RX_CurCnt; } else { u16_temp = UART2_RX_LastCnt + ( DEF_UART2_BUF_SIZE - UART2_RX_CurCnt ); } UART2_RX_LastCnt = UART2_RX_CurCnt; if ((UART2_Rx_RemainLen + u16_temp) > DEF_UART2_BUF_SIZE ) { printf("Uart2 RX_buffer overflow\n"); // overflow: New data overwrites old data } else { UART2_Rx_RemainLen += u16_temp; } UART2_TimeOut = 0; } /* Pass-through uart2 data to USB-HID */ if (UART2_Rx_RemainLen) { /* Determine if the USB endpoint is allowed to upload */ if ( USBD_Endp2_Busy == 0x00) { /* Calculate the length of this packet upload via USB. */ remain_len = UART2_Rx_RemainLen; pkg_len = 0x00; if (remain_len >= ( DEF_USBD_MAX_PACK_SIZE - 1 )) { remain_len = ( DEF_USBD_MAX_PACK_SIZE - 1 ); pkg_len = remain_len; } else { if (UART2_TimeOut > DEF_UART2_TOUT_TIME) { pkg_len = remain_len; } } if ( pkg_len > ( DEF_UART2_BUF_SIZE - UART2_Rx_Deal_Ptr ) ) { pkg_len = ( DEF_UART2_BUF_SIZE - UART2_Rx_Deal_Ptr ); // The data at the end of the buffer will be sent directly. } /* Upload packet via USB. */ if (pkg_len) { HIDTxBuffer[0] = pkg_len; memcpy(HIDTxBuffer + 1,&UART2_RxBuffer[UART2_Rx_Deal_Ptr],pkg_len); USBD_ENDPx_DataUp( ENDP2, HIDTxBuffer, pkg_len + 1 ); UART2_Rx_RemainLen -= pkg_len; UART2_Rx_Deal_Ptr += pkg_len; if (UART2_Rx_Deal_Ptr >= DEF_UART2_BUF_SIZE) { UART2_Rx_Deal_Ptr = 0x00; } } } } } /********************************************************************* * @fn UART2_Tx_Service * * @brief UART2 tx service routine that sends the data received by * USB-HID via uart2. * * @return none */ void UART2_Tx_Service( void ) { uint16_t pkg_len = 0; uint8_t *pbuf; if (UART2_Tx_Flag) { if (USART_GetFlagStatus(USART2, USART_FLAG_TC)) // Check whether uart2 has finished sending. { USART_ClearFlag(USART2, USART_FLAG_TC); USART_DMACmd(USART2, USART_DMAReq_Tx, DISABLE); UART2_Tx_Flag = 0; NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); // Disable USB interrupts RingBuffer_Comm.RemainPack--; RingBuffer_Comm.DealPtr++; if(RingBuffer_Comm.DealPtr == DEF_Ring_Buffer_Max_Blks) { RingBuffer_Comm.DealPtr = 0; } NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); // Enable USB interrupts } } else { /* Pass-through USB-HID data to uart2 */ if(RingBuffer_Comm.RemainPack) { pkg_len = Data_Buffer[(RingBuffer_Comm.DealPtr) * DEF_USBD_MAX_PACK_SIZE]; // Get the valid data length if (pkg_len) { if (pkg_len > ( DEF_USBD_MAX_PACK_SIZE - 1 ) ) { pkg_len = DEF_USBD_MAX_PACK_SIZE - 1; // Limit the length of this transmission } pbuf = &Data_Buffer[(RingBuffer_Comm.DealPtr) * DEF_USBD_MAX_PACK_SIZE] + 1; UART2_DMA_Tx( pbuf, pkg_len ); UART2_Tx_Flag = 1; } else { /* drop out */ NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); // Disable USB interrupts RingBuffer_Comm.RemainPack--; RingBuffer_Comm.DealPtr++; if(RingBuffer_Comm.DealPtr == DEF_Ring_Buffer_Max_Blks) { RingBuffer_Comm.DealPtr = 0; } NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn); // Enable USB interrupts } } } /* Monitor whether the remaining space is available for further downloads */ if(RingBuffer_Comm.RemainPack < (DEF_Ring_Buffer_Max_Blks - DEF_RING_BUFFER_RESTART)) { if(RingBuffer_Comm.StopFlag) { printf("USB ring buffer full, stop receiving further data.\n"); RingBuffer_Comm.StopFlag = 0; SetEPRxValid(ENDP1); } } }