Skip to content

Commit

Permalink
Import SOF/callback driven CDC-ACM code
Browse files Browse the repository at this point in the history
Port the SOF/data-in-complete callback driven CDC-ACM code from the
termlink project
  • Loading branch information
devanlai committed May 21, 2017
1 parent f354dc0 commit e1691cb
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 23 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

0 comments on commit e1691cb

Please sign in to comment.