diff --git a/Inc/usbd_cdc_if.h b/Inc/usbd_cdc_if.h index 140c224..bd7a0fd 100644 --- a/Inc/usbd_cdc_if.h +++ b/Inc/usbd_cdc_if.h @@ -78,6 +78,9 @@ */ /* USER CODE BEGIN EXPORTED_DEFINES */ +#define APP_RX_DATA_SIZE 64 +#define APP_TX_DATA_SIZE 64 + /* USER CODE END EXPORTED_DEFINES */ /** @@ -91,6 +94,14 @@ /* USER CODE BEGIN EXPORTED_TYPES */ +struct UsbCdcRxBuffer +{ + uint8_t buffer[APP_RX_DATA_SIZE]; + uint32_t size; +}; + +typedef struct UsbCdcRxBuffer UsbCdcRxBuffer_t; + /* USER CODE END EXPORTED_TYPES */ /** @@ -120,6 +131,10 @@ extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; /* USER CODE BEGIN EXPORTED_VARIABLES */ +// USB CDC receive ping pong buffer. +extern UsbCdcRxBuffer_t* usbCdcRxBuffer_1; +extern UsbCdcRxBuffer_t* usbCdcRxBuffer_2; + /* USER CODE END EXPORTED_VARIABLES */ /** diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index 583ee90..2e36f0e 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -97,8 +97,6 @@ /* USER CODE BEGIN PRIVATE_DEFINES */ /* Define size for the receive and transmit buffer over CDC */ /* It's up to user to redefine and/or remove those define */ -#define APP_RX_DATA_SIZE 64 -#define APP_TX_DATA_SIZE 64 /* USER CODE END PRIVATE_DEFINES */ /** @@ -124,8 +122,6 @@ */ /* Create buffer for reception and transmission */ /* It's up to user to redefine and/or remove those define */ -/** Received data over USB are stored in this buffer */ -uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; /** Data to send over USB CDC are stored in this buffer */ uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; @@ -138,6 +134,11 @@ USBD_CDC_LineCodingTypeDef LineCoding = { 0x08 // number of bits: 8 }; +// USB CDC receive ping pong buffer. +UsbCdcRxBuffer_t usbCdcRxBuffer[2]; +UsbCdcRxBuffer_t* usbCdcRxBuffer_1 = &usbCdcRxBuffer[0]; +UsbCdcRxBuffer_t* usbCdcRxBuffer_2 = &usbCdcRxBuffer[1]; + /* USER CODE END PRIVATE_VARIABLES */ /** @@ -195,7 +196,7 @@ static int8_t CDC_Init_FS(void) /* USER CODE BEGIN 3 */ /* Set Application Buffers */ USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, usbCdcRxBuffer_1->buffer); return (USBD_OK); /* USER CODE END 3 */ } @@ -304,12 +305,6 @@ static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) * @brief Data received over USB OUT endpoint are sent over CDC interface * through this function. * - * @note - * This function will block any OUT packet reception on USB endpoint - * until exiting this function. If you exit this function before transfer - * is complete on CDC interface (ie. using DMA controller) it will result - * in receiving more data while previous ones are still not sent. - * * @param Buf: Buffer of data to be received * @param Len: Number of data received (in bytes) * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL @@ -320,10 +315,8 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) if (!cdc_connected) { osMessagePut(ioEventQueueHandle, CMD_USB_CDC_CONNECT, 0); } - cdc_receive(Buf, *Len); - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); - USBD_CDC_ReceivePacket(&hUsbDeviceFS); - return (USBD_OK); + cdc_receive(Buf, *Len); + return (USBD_OK); /* USER CODE END 6 */ } diff --git a/TNC/UsbPort.cpp b/TNC/UsbPort.cpp index b3d39a6..f0bcc86 100644 --- a/TNC/UsbPort.cpp +++ b/TNC/UsbPort.cpp @@ -13,36 +13,27 @@ extern "C" void TNC_Error_Handler(int dev, int err); extern osMessageQId ioEventQueueHandle; +extern USBD_HandleTypeDef hUsbDeviceFS; extern "C" void cdc_receive(const uint8_t* buf, uint32_t len) { using namespace mobilinkd::tnc; - if (mobilinkd::tnc::getUsbPort()->queue() != 0) + + // This is running in an interrupt handler. + + UsbCdcRxBuffer_t* usbCdcRxBuffer = (UsbCdcRxBuffer_t*)(buf); + usbCdcRxBuffer->size = len; + + if (getUsbPort()->queue() != 0) { - if (len == 1) + // This should always succeed. + if (osMessagePut(getUsbPort()->queue(), (uint32_t) buf, 0) == osOK) { - // Send single byte via queue directly. Linux seems to do - // this for ttyACM ports. - osMessagePut(getUsbPort()->queue(), *buf, osWaitForever); return; } - - auto frame = hdlc::acquire(); - if (frame) - { - for (uint32_t i = 0; i != len; ++i) - { - frame->push_back(*buf++); - } - frame->source(hdlc::IoFrame::SERIAL_DATA); - if (osMessagePut(mobilinkd::tnc::getUsbPort()->queue(), - (uint32_t) frame, - osWaitForever) != osOK) - { - mobilinkd::tnc::hdlc::release(frame); - } - } } + ERROR("USB packet dropped"); + USBD_CDC_ReceivePacket(&hUsbDeviceFS); // re-enable receive. } extern "C" void startCDCTask(void const* arg) @@ -116,7 +107,7 @@ void UsbPort::add_char(uint8_t c) void UsbPort::run() { - frame_ = hdlc::acquire(); + if (frame_ == nullptr) frame_ = hdlc::acquire(); while (true) { osEvent evt = osMessageGet(queue(), osWaitForever); @@ -124,34 +115,31 @@ void UsbPort::run() continue; } - uint32_t c = evt.value.v; + auto usbCdcRxBuffer = (UsbCdcRxBuffer_t*) evt.value.p; - if (c < 0x100) // Assume single byte transfer. - { - add_char(c); - continue; + // Handle ping-pong buffers. + if (usbCdcRxBuffer == usbCdcRxBuffer_1) { + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, usbCdcRxBuffer_2->buffer); + } else { + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, usbCdcRxBuffer_1->buffer); } + USBD_CDC_ReceivePacket(&hUsbDeviceFS); - auto input = static_cast(evt.value.p); + INFO("USB p %lu", usbCdcRxBuffer->size); - if (!isOpen()) { - hdlc::release(input); - continue; + if (isOpen()) { + for (uint32_t i = 0; i != usbCdcRxBuffer->size; ++i) { + add_char(usbCdcRxBuffer->buffer[i]); + } } - - for (uint8_t c : *input) { - add_char(c); - } - hdlc::release(input); } - } void UsbPort::init() { if (cdcTaskHandle_) return; - osMessageQDef(cdcQueue, 128, void*); + osMessageQDef(cdcQueue, 4, void*); queue_ = osMessageCreate(osMessageQ(cdcQueue), 0); osMutexDef(usbMutex);