Skip to content

Commit

Permalink
Incorporate CDC-ACM enhancements from the termlink project
Browse files Browse the repository at this point in the history
  • Loading branch information
devanlai committed May 21, 2017
2 parents 4149b62 + e1691cb commit ef99b35
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 65 deletions.
63 changes: 40 additions & 23 deletions src/USB/cdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,21 +204,23 @@ static void cdc_bulk_data_out(usbd_device *usbd_dev, uint8_t ep) {
// Handle flow control
if (accept_more_packets) {
cdc_clear_nak();
} else {
cdc_set_nak();
}
}

static void cdc_bulk_data_in(usbd_device *usbd_dev, uint8_t ep);
static void cdc_start_in_transfer(void);

static void cdc_set_config(usbd_device *usbd_dev, uint16_t wValue) {
(void)wValue;

usbd_ep_setup(usbd_dev, ENDP_CDC_DATA_OUT, USB_ENDPOINT_ATTR_BULK, 64,
cdc_bulk_data_out);
usbd_ep_setup(usbd_dev, ENDP_CDC_DATA_IN, USB_ENDPOINT_ATTR_BULK, 64, NULL);
usbd_ep_setup(usbd_dev, ENDP_CDC_DATA_IN, USB_ENDPOINT_ATTR_BULK, 64, cdc_bulk_data_in);
usbd_ep_setup(usbd_dev, ENDP_CDC_COMM_IN, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);

cmp_usb_register_control_class_callback(INTF_CDC_DATA, cdc_control_class_request);
cmp_usb_register_control_class_callback(INTF_CDC_COMM, cdc_control_class_request);
cmp_usb_register_sof_callback(cdc_start_in_transfer);
}

/* CDC-ACM USB UART bridge functionality */
Expand Down Expand Up @@ -330,36 +332,51 @@ void cdc_uart_app_set_timeout(uint32_t timeout_ms) {
packet_timeout = timeout_ms;
}

bool cdc_uart_app_update() {
bool active = false;

// Handle sending received data to the host
static bool transfer_complete = false;
static void cdc_start_in_transfer(void) {
transfer_complete = false;
if (packet_len < USB_CDC_MAX_PACKET_SIZE) {
uint16_t max_bytes = (USB_CDC_MAX_PACKET_SIZE- packet_len);
packet_len += console_recv_buffered(&packet_buffer[packet_len], max_bytes);
}

uint32_t now = get_ticks();
bool flush = false;
bool timeout = (now - packet_timestamp) >= packet_timeout;
if (packet_len == USB_CDC_MAX_PACKET_SIZE) {
flush = true;
} else if (timeout && (packet_len > 0 || need_zlp)) {
flush = true;
}

if (flush && cmp_usb_configured()) {
if (cdc_send_data(packet_buffer, packet_len) || (packet_len == 0)) {
active = (packet_len > 0);
need_zlp = (packet_len == USB_CDC_MAX_PACKET_SIZE);
packet_len = 0;
packet_timestamp = now;

if (packet_len > 0) {
if (cdc_send_data(packet_buffer, packet_len)) {
transfer_complete = (packet_len < USB_CDC_MAX_PACKET_SIZE);
packet_len = console_recv_buffered(packet_buffer, USB_CDC_MAX_PACKET_SIZE);
if (cdc_uart_tx_callback) {
cdc_uart_tx_callback();
}
}
} else {
transfer_complete = true;
}
}

static void cdc_bulk_data_in(usbd_device *usbd_dev, uint8_t ep) {
(void)usbd_dev;
(void)ep;

if (packet_len < USB_CDC_MAX_PACKET_SIZE) {
uint16_t max_bytes = (USB_CDC_MAX_PACKET_SIZE- packet_len);
packet_len += console_recv_buffered(&packet_buffer[packet_len], max_bytes);
}

if (!transfer_complete) {
cdc_send_data(packet_buffer, packet_len);
if (packet_len < USB_CDC_MAX_PACKET_SIZE) {
transfer_complete = true;
}
packet_len = 0;

if (cdc_uart_tx_callback) {
cdc_uart_tx_callback();
}
}
}

bool cdc_uart_app_update() {
bool active = false;

// Handle flow control for data received from the host
if (console_send_buffer_space() >= USB_CDC_MAX_PACKET_SIZE) {
Expand Down
20 changes: 20 additions & 0 deletions src/USB/composite_usb_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,22 @@ void cmp_usb_register_reset_callback(GenericCallback callback) {
}
}

static GenericCallback sof_callbacks[USB_MAX_SOF_CALLBACKS];
static uint8_t num_sof_callbacks;

void cmp_usb_register_sof_callback(GenericCallback callback) {
if (num_sof_callbacks < USB_MAX_SOF_CALLBACKS) {
sof_callbacks[num_sof_callbacks++] = callback;
}
}

static void cmp_usb_handle_sof(void) {
uint8_t i;
for (i=0; i < num_sof_callbacks; i++) {
(*sof_callbacks[i])();
}
}

/* Configuration status */
static bool configured = false;

Expand All @@ -429,6 +445,9 @@ static void cmp_usb_handle_reset(void) {
for (i=0; i < num_callbacks; i++) {
(*reset_callbacks[i])();
}

// Unregister all SOF callbacks
num_sof_callbacks = 0;
}

/* Class-specific control request handlers */
Expand Down Expand Up @@ -519,5 +538,6 @@ usbd_device* cmp_usb_setup(void) {
usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, cmp_usb_set_config);
usbd_register_reset_callback(usbd_dev, cmp_usb_handle_reset);
usbd_register_sof_callback(usbd_dev, cmp_usb_handle_sof);
return usbd_dev;
}
2 changes: 2 additions & 0 deletions src/USB/composite_usb_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ enum {
#define USB_MAX_CONTROL_CLASS_CALLBACKS 8
#define USB_MAX_SET_CONFIG_CALLBACKS 8
#define USB_MAX_RESET_CALLBACKS 8
#define USB_MAX_SOF_CALLBACKS 8

extern void cmp_set_usb_serial_number(const char* serial);
extern usbd_device* cmp_usb_setup(void);
Expand All @@ -102,5 +103,6 @@ extern void cmp_usb_register_control_class_callback(uint16_t interface,
usbd_control_callback callback);
extern void cmp_usb_register_set_config_callback(usbd_set_config_callback callback);
extern void cmp_usb_register_reset_callback(GenericCallback callback);
extern void cmp_usb_register_sof_callback(GenericCallback callback);

#endif
100 changes: 68 additions & 32 deletions src/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/

#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/dma.h>
#include <libopencm3/stm32/rcc.h>

#include "console.h"
#include "target.h"
Expand All @@ -36,16 +38,32 @@ void console_setup(uint32_t baudrate) {

usart_enable(CONSOLE_USART);
nvic_enable_irq(CONSOLE_USART_NVIC_LINE);
rcc_periph_clock_enable(CONSOLE_RX_DMA_CLOCK);
}

void console_tx_buffer_clear(void);
void console_rx_buffer_clear(void);

#define IS_POW_OF_TWO(X) (((X) & ((X)-1)) == 0)
_Static_assert(IS_POW_OF_TWO(CONSOLE_TX_BUFFER_SIZE),
"Unmasked circular buffer size must be a power of two");
_Static_assert(CONSOLE_TX_BUFFER_SIZE <= UINT16_MAX/2,
"Buffer size too big for unmasked circular buffer");

static volatile uint8_t console_tx_buffer[CONSOLE_TX_BUFFER_SIZE];
static volatile uint8_t console_rx_buffer[CONSOLE_RX_BUFFER_SIZE];

static volatile uint16_t console_tx_head = 0;
static volatile uint16_t console_tx_tail = 0;

static uint16_t console_rx_head = 0;

void console_reconfigure(uint32_t baudrate, uint32_t databits, uint32_t stopbits,
uint32_t parity) {
// Disable the UART and clear buffers
usart_disable(CONSOLE_USART);
usart_disable_rx_interrupt(CONSOLE_USART);

usart_disable_rx_dma(CONSOLE_USART);
usart_disable_tx_interrupt(CONSOLE_USART);
nvic_disable_irq(CONSOLE_USART_NVIC_LINE);

Expand All @@ -63,20 +81,27 @@ void console_reconfigure(uint32_t baudrate, uint32_t databits, uint32_t stopbits
usart_set_parity(CONSOLE_USART, parity);
usart_set_mode(CONSOLE_USART, CONSOLE_USART_MODE);

// Re-enable the UART with the new settings
usart_enable(CONSOLE_USART);
usart_enable_rx_interrupt(CONSOLE_USART);
nvic_enable_irq(CONSOLE_USART_NVIC_LINE);
}
dma_channel_reset(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL);

static volatile uint8_t console_tx_buffer[CONSOLE_TX_BUFFER_SIZE];
static volatile uint8_t console_rx_buffer[CONSOLE_RX_BUFFER_SIZE];
// Configure RX DMA...
dma_set_peripheral_address(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, (uint32_t)&USART_RDR(CONSOLE_USART));
dma_set_memory_address(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, (uint32_t)console_rx_buffer);
dma_set_number_of_data(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, CONSOLE_RX_BUFFER_SIZE);
dma_set_read_from_peripheral(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL);
dma_enable_memory_increment_mode(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL);
dma_set_peripheral_size(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, DMA_CCR_PSIZE_8BIT);
dma_set_memory_size(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, DMA_CCR_MSIZE_8BIT);
dma_set_priority(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL, DMA_CCR_PL_HIGH);
dma_enable_circular_mode(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL);

static volatile uint16_t console_tx_head = 0;
static volatile uint16_t console_tx_tail = 0;
dma_enable_channel(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL);

static volatile uint16_t console_rx_head = 0;
static volatile uint16_t console_rx_tail = 0;
usart_enable_rx_dma(CONSOLE_USART);
nvic_enable_irq(CONSOLE_USART_NVIC_LINE);

// Re-enable the UART with the new settings
usart_enable(CONSOLE_USART);
}

static bool console_tx_buffer_empty(void) {
return console_tx_head == console_tx_tail;
Expand Down Expand Up @@ -107,16 +132,12 @@ size_t console_send_buffer_space(void) {
}

static bool console_rx_buffer_empty(void) {
return console_rx_head == console_rx_tail;
}

static bool console_rx_buffer_full(void) {
return console_rx_head == ((console_rx_tail + 1) % CONSOLE_RX_BUFFER_SIZE);
}

static void console_rx_buffer_put(uint8_t data) {
console_rx_buffer[console_rx_tail] = data;
console_rx_tail = (console_rx_tail + 1) % CONSOLE_RX_BUFFER_SIZE;
if (DMA_CCR(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL) & DMA_CCR_EN) {
uint16_t console_rx_tail = (CONSOLE_RX_BUFFER_SIZE - DMA_CNDTR(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL)) % CONSOLE_RX_BUFFER_SIZE;
return console_rx_tail == console_rx_head;
} else {
return true;
}
}

static uint8_t console_rx_buffer_get(void) {
Expand All @@ -127,7 +148,7 @@ static uint8_t console_rx_buffer_get(void) {

void console_rx_buffer_clear(void) {
console_rx_head = 0;
console_rx_tail = 0;
dma_disable_channel(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL);
}

size_t console_send_buffered(const uint8_t* data, size_t num_bytes) {
Expand All @@ -146,8 +167,30 @@ size_t console_send_buffered(const uint8_t* data, size_t num_bytes) {

size_t console_recv_buffered(uint8_t* data, size_t max_bytes) {
size_t bytes_read = 0;
while (!console_rx_buffer_empty() && (bytes_read < max_bytes)) {
data[bytes_read++] = console_rx_buffer_get();
if (max_bytes == 1) {
if (!console_rx_buffer_empty()) {
*data = console_rx_buffer_get();
bytes_read = 1;
}
} else if (!console_rx_buffer_empty()) {
uint16_t console_rx_tail = (CONSOLE_RX_BUFFER_SIZE - DMA_CNDTR(CONSOLE_RX_DMA_CONTROLLER, CONSOLE_RX_DMA_CHANNEL)) % CONSOLE_RX_BUFFER_SIZE;
if (console_rx_head > console_rx_tail) {
while (console_rx_head < CONSOLE_RX_BUFFER_SIZE && bytes_read < max_bytes) {
data[bytes_read++] = console_rx_buffer[console_rx_head++];
}
if (console_rx_head == CONSOLE_RX_BUFFER_SIZE) {
console_rx_head = 0;
}
}

if ((bytes_read < max_bytes) && (console_rx_head < console_rx_tail)) {
while (console_rx_head < console_rx_tail && bytes_read < max_bytes) {
data[bytes_read++] = console_rx_buffer[console_rx_head++];
}
if (console_rx_head == CONSOLE_RX_BUFFER_SIZE) {
console_rx_head = 0;
}
}
}

return bytes_read;
Expand All @@ -162,13 +205,6 @@ uint8_t console_recv_blocking(void) {
}

void CONSOLE_USART_IRQ_NAME(void) {
if (usart_get_interrupt_source(CONSOLE_USART, USART_SR_RXNE)) {
uint8_t received_byte = (uint8_t)usart_recv(CONSOLE_USART);
if (!console_rx_buffer_full()) {
console_rx_buffer_put(received_byte);
}
}

if (usart_get_interrupt_source(CONSOLE_USART, USART_SR_TXE)) {
if (!console_tx_buffer_empty()) {
usart_word_t buffered_byte = console_tx_buffer_get();
Expand Down
5 changes: 4 additions & 1 deletion src/stm32f042/brain3.3/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

#define CONSOLE_USART USART2
#define CONSOLE_TX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 1024

#define CONSOLE_USART_GPIO_PORT GPIOA
#define CONSOLE_USART_GPIO_PINS (GPIO2|GPIO3)
Expand All @@ -44,6 +44,9 @@

#define CONSOLE_USART_IRQ_NAME usart2_isr
#define CONSOLE_USART_NVIC_LINE NVIC_USART2_IRQ
#define CONSOLE_RX_DMA_CONTROLLER DMA1
#define CONSOLE_RX_DMA_CLOCK RCC_DMA
#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL5

#define DFU_AVAILABLE 1
#define nBOOT0_GPIO_CLOCK RCC_GPIOB
Expand Down
5 changes: 4 additions & 1 deletion src/stm32f042/dap42/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

#define CONSOLE_USART USART2
#define CONSOLE_TX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 1024

#define CONSOLE_USART_GPIO_PORT GPIOA
#define CONSOLE_USART_GPIO_PINS (GPIO2|GPIO3)
Expand All @@ -44,6 +44,9 @@

#define CONSOLE_USART_IRQ_NAME usart2_isr
#define CONSOLE_USART_NVIC_LINE NVIC_USART2_IRQ
#define CONSOLE_RX_DMA_CONTROLLER DMA1
#define CONSOLE_RX_DMA_CLOCK RCC_DMA
#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL5

#define DFU_AVAILABLE 1
#define nBOOT0_GPIO_CLOCK RCC_GPIOB
Expand Down
5 changes: 4 additions & 1 deletion src/stm32f042/dap42k6u/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

#define CONSOLE_USART USART1
#define CONSOLE_TX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 1024

#define CONSOLE_USART_GPIO_PORT GPIOB
#define CONSOLE_USART_GPIO_PINS (GPIO6|GPIO7)
Expand All @@ -44,6 +44,9 @@

#define CONSOLE_USART_IRQ_NAME usart1_isr
#define CONSOLE_USART_NVIC_LINE NVIC_USART1_IRQ
#define CONSOLE_RX_DMA_CONTROLLER DMA1
#define CONSOLE_RX_DMA_CLOCK RCC_DMA
#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL3

#define DFU_AVAILABLE 1
#define nBOOT0_GPIO_CLOCK RCC_GPIOF
Expand Down
5 changes: 4 additions & 1 deletion src/stm32f042/kitchen42/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

#define CONSOLE_USART USART2
#define CONSOLE_TX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 128
#define CONSOLE_RX_BUFFER_SIZE 1024

#define CONSOLE_USART_GPIO_PORT GPIOA
#define CONSOLE_USART_GPIO_PINS (GPIO2|GPIO3)
Expand All @@ -44,6 +44,9 @@

#define CONSOLE_USART_IRQ_NAME usart2_isr
#define CONSOLE_USART_NVIC_LINE NVIC_USART2_IRQ
#define CONSOLE_RX_DMA_CONTROLLER DMA1
#define CONSOLE_RX_DMA_CLOCK RCC_DMA
#define CONSOLE_RX_DMA_CHANNEL DMA_CHANNEL5

#define DFU_AVAILABLE 1
#define nBOOT0_GPIO_CLOCK RCC_GPIOF
Expand Down
Loading

0 comments on commit ef99b35

Please sign in to comment.