kopia lustrzana https://github.com/mobilinkd/tnc3-firmware
Use a ping-pong buffer for USB RX. Simplify code and improve flow control.
rodzic
88436fbd2a
commit
98ceec2559
|
@ -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 */
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
||||
|
|
|
@ -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<hdlc::IoFrame*>(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);
|
||||
|
|
Ładowanie…
Reference in New Issue