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 */
|
/* USER CODE BEGIN EXPORTED_DEFINES */
|
||||||
|
|
||||||
|
#define APP_RX_DATA_SIZE 64
|
||||||
|
#define APP_TX_DATA_SIZE 64
|
||||||
|
|
||||||
/* USER CODE END EXPORTED_DEFINES */
|
/* USER CODE END EXPORTED_DEFINES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,6 +94,14 @@
|
||||||
|
|
||||||
/* USER CODE BEGIN EXPORTED_TYPES */
|
/* 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 */
|
/* USER CODE END EXPORTED_TYPES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,6 +131,10 @@ extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
|
||||||
|
|
||||||
/* USER CODE BEGIN EXPORTED_VARIABLES */
|
/* 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 */
|
/* USER CODE END EXPORTED_VARIABLES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -97,8 +97,6 @@
|
||||||
/* USER CODE BEGIN PRIVATE_DEFINES */
|
/* USER CODE BEGIN PRIVATE_DEFINES */
|
||||||
/* Define size for the receive and transmit buffer over CDC */
|
/* Define size for the receive and transmit buffer over CDC */
|
||||||
/* It's up to user to redefine and/or remove those define */
|
/* 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 */
|
/* USER CODE END PRIVATE_DEFINES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -124,8 +122,6 @@
|
||||||
*/
|
*/
|
||||||
/* Create buffer for reception and transmission */
|
/* Create buffer for reception and transmission */
|
||||||
/* It's up to user to redefine and/or remove those define */
|
/* 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 */
|
/** Data to send over USB CDC are stored in this buffer */
|
||||||
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
|
uint8_t UserTxBufferFS[APP_TX_DATA_SIZE];
|
||||||
|
@ -138,6 +134,11 @@ USBD_CDC_LineCodingTypeDef LineCoding = {
|
||||||
0x08 // number of bits: 8
|
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 */
|
/* USER CODE END PRIVATE_VARIABLES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -195,7 +196,7 @@ static int8_t CDC_Init_FS(void)
|
||||||
/* USER CODE BEGIN 3 */
|
/* USER CODE BEGIN 3 */
|
||||||
/* Set Application Buffers */
|
/* Set Application Buffers */
|
||||||
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
|
USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0);
|
||||||
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
|
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, usbCdcRxBuffer_1->buffer);
|
||||||
return (USBD_OK);
|
return (USBD_OK);
|
||||||
/* USER CODE END 3 */
|
/* 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
|
* @brief Data received over USB OUT endpoint are sent over CDC interface
|
||||||
* through this function.
|
* 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 Buf: Buffer of data to be received
|
||||||
* @param Len: Number of data received (in bytes)
|
* @param Len: Number of data received (in bytes)
|
||||||
* @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL
|
* @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) {
|
if (!cdc_connected) {
|
||||||
osMessagePut(ioEventQueueHandle, CMD_USB_CDC_CONNECT, 0);
|
osMessagePut(ioEventQueueHandle, CMD_USB_CDC_CONNECT, 0);
|
||||||
}
|
}
|
||||||
cdc_receive(Buf, *Len);
|
cdc_receive(Buf, *Len);
|
||||||
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS);
|
return (USBD_OK);
|
||||||
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
|
|
||||||
return (USBD_OK);
|
|
||||||
/* USER CODE END 6 */
|
/* USER CODE END 6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,36 +13,27 @@
|
||||||
extern "C" void TNC_Error_Handler(int dev, int err);
|
extern "C" void TNC_Error_Handler(int dev, int err);
|
||||||
|
|
||||||
extern osMessageQId ioEventQueueHandle;
|
extern osMessageQId ioEventQueueHandle;
|
||||||
|
extern USBD_HandleTypeDef hUsbDeviceFS;
|
||||||
|
|
||||||
extern "C" void cdc_receive(const uint8_t* buf, uint32_t len)
|
extern "C" void cdc_receive(const uint8_t* buf, uint32_t len)
|
||||||
{
|
{
|
||||||
using namespace mobilinkd::tnc;
|
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;
|
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)
|
extern "C" void startCDCTask(void const* arg)
|
||||||
|
@ -116,7 +107,7 @@ void UsbPort::add_char(uint8_t c)
|
||||||
|
|
||||||
void UsbPort::run()
|
void UsbPort::run()
|
||||||
{
|
{
|
||||||
frame_ = hdlc::acquire();
|
if (frame_ == nullptr) frame_ = hdlc::acquire();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
osEvent evt = osMessageGet(queue(), osWaitForever);
|
osEvent evt = osMessageGet(queue(), osWaitForever);
|
||||||
|
@ -124,34 +115,31 @@ void UsbPort::run()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t c = evt.value.v;
|
auto usbCdcRxBuffer = (UsbCdcRxBuffer_t*) evt.value.p;
|
||||||
|
|
||||||
if (c < 0x100) // Assume single byte transfer.
|
// Handle ping-pong buffers.
|
||||||
{
|
if (usbCdcRxBuffer == usbCdcRxBuffer_1) {
|
||||||
add_char(c);
|
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, usbCdcRxBuffer_2->buffer);
|
||||||
continue;
|
} 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()) {
|
if (isOpen()) {
|
||||||
hdlc::release(input);
|
for (uint32_t i = 0; i != usbCdcRxBuffer->size; ++i) {
|
||||||
continue;
|
add_char(usbCdcRxBuffer->buffer[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t c : *input) {
|
|
||||||
add_char(c);
|
|
||||||
}
|
|
||||||
hdlc::release(input);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UsbPort::init()
|
void UsbPort::init()
|
||||||
{
|
{
|
||||||
if (cdcTaskHandle_) return;
|
if (cdcTaskHandle_) return;
|
||||||
|
|
||||||
osMessageQDef(cdcQueue, 128, void*);
|
osMessageQDef(cdcQueue, 4, void*);
|
||||||
queue_ = osMessageCreate(osMessageQ(cdcQueue), 0);
|
queue_ = osMessageCreate(osMessageQ(cdcQueue), 0);
|
||||||
|
|
||||||
osMutexDef(usbMutex);
|
osMutexDef(usbMutex);
|
||||||
|
|
Ładowanie…
Reference in New Issue