cdc_uart: add break handling Implement break set/unset and declare the interface as capable of sending line breaks.
diff --git a/src/cdc_uart.c b/src/cdc_uart.c index 690d1cf..6379aad 100644 --- a/src/cdc_uart.c +++ b/src/cdc_uart.c
@@ -32,7 +32,8 @@ #include "probe_config.h" TaskHandle_t uart_taskhandle; -TickType_t last_wake, interval = 100; +TickType_t last_wake, interval = 100, break_expiry; +bool timed_break; /* Max 1 FIFO worth of data */ static uint8_t tx_buf[32]; @@ -68,11 +69,12 @@ #endif } -void cdc_task(void) +bool cdc_task(void) { static int was_connected = 0; static uint cdc_tx_oe = 0; uint rx_len = 0; + bool keep_alive = false; // Consume uart fifo regardless even if not connected while(uart_is_readable(PROBE_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) { @@ -126,23 +128,38 @@ gpio_put(PROBE_UART_TX_LED, 0); #endif } + /* Pending break handling */ + if (timed_break) { + if (((int)break_expiry - (int)xTaskGetTickCount()) < 0) { + timed_break = false; + uart_set_break(PROBE_UART_INTERFACE, false); + } else { + keep_alive = true; + } + } } else if (was_connected) { tud_cdc_write_clear(); + uart_set_break(PROBE_UART_INTERFACE, false); + timed_break = false; was_connected = 0; cdc_tx_oe = 0; } + return keep_alive; } void cdc_thread(void *ptr) { BaseType_t delayed; last_wake = xTaskGetTickCount(); + bool keep_alive; /* Threaded with a polling interval that scales according to linerate */ while (1) { - cdc_task(); - delayed = xTaskDelayUntil(&last_wake, interval); - if (delayed == pdFALSE) - last_wake = xTaskGetTickCount(); + keep_alive = cdc_task(); + if (!keep_alive) { + delayed = xTaskDelayUntil(&last_wake, interval); + if (delayed == pdFALSE) + last_wake = xTaskGetTickCount(); + } } } @@ -236,3 +253,21 @@ } else vTaskResume(uart_taskhandle); } + +void tud_cdc_send_break_cb(uint8_t itf, uint16_t wValue) { + switch(wValue) { + case 0: + uart_set_break(PROBE_UART_INTERFACE, false); + timed_break = false; + break; + case 0xffff: + uart_set_break(PROBE_UART_INTERFACE, true); + timed_break = false; + break; + default: + uart_set_break(PROBE_UART_INTERFACE, true); + timed_break = true; + break_expiry = xTaskGetTickCount() + (wValue * (configTICK_RATE_HZ / 1000)); + break; + } +}
diff --git a/src/cdc_uart.h b/src/cdc_uart.h index 8782b64..db365c6 100644 --- a/src/cdc_uart.h +++ b/src/cdc_uart.h
@@ -28,7 +28,7 @@ void cdc_thread(void *ptr); void cdc_uart_init(void); -void cdc_task(void); +bool cdc_task(void); extern TaskHandle_t uart_taskhandle;
diff --git a/src/usb_descriptors.c b/src/usb_descriptors.c index 9c49842..9558e7e 100644 --- a/src/usb_descriptors.c +++ b/src/usb_descriptors.c
@@ -97,7 +97,7 @@ return desc_hid_report; } -uint8_t const desc_configuration[] = +uint8_t desc_configuration[] = { TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 100), // Interface 0 @@ -121,6 +121,8 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { (void) index; // for multiple configurations + /* Hack in CAP_BREAK support */ + desc_configuration[CONFIG_TOTAL_LEN - TUD_CDC_DESC_LEN + 8 + 9 + 5 + 5 + 4 - 1] = 0x6; return desc_configuration; }