diff options
author | Nikolay Minaylov <nm29719@gmail.com> | 2021-10-26 21:41:56 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-26 21:41:56 +0300 |
commit | 732b9546fc29d0eee07d2230e52d035b32b89c81 (patch) | |
tree | 1d4bb55c0a670e351ed097a9db92684dbc40d600 /applications/gpio | |
parent | fae8d8f23ceb971cb08119d0dc8de48a06091a13 (diff) |
[FL-1984] USB-UART improvements and fixes (#785)
* [FL-1984] USB-UART fixes
* FuriHal: fix SOF wait on CDC0
* FuriHal: fixed stuck in UART IRQ with ORE event
Co-authored-by: あく <alleteam@gmail.com>
Diffstat (limited to 'applications/gpio')
-rw-r--r-- | applications/gpio/gpio_app_i.h | 8 | ||||
-rw-r--r-- | applications/gpio/scenes/gpio_scene_start.c | 5 | ||||
-rw-r--r-- | applications/gpio/scenes/gpio_scene_usb_uart.c | 271 | ||||
-rw-r--r-- | applications/gpio/usb_uart_bridge.c | 246 | ||||
-rw-r--r-- | applications/gpio/usb_uart_bridge.h | 13 |
5 files changed, 292 insertions, 251 deletions
diff --git a/applications/gpio/gpio_app_i.h b/applications/gpio/gpio_app_i.h index bfeab404..226fa06e 100644 --- a/applications/gpio/gpio_app_i.h +++ b/applications/gpio/gpio_app_i.h @@ -12,6 +12,14 @@ #include <gui/modules/variable-item-list.h> #include "views/gpio_test.h" +#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF (0UL) +#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON (1UL) +#define GPIO_SCENE_START_CUSTOM_EVENT_TEST (2UL) +#define GPIO_SCENE_START_CUSTOM_EVENT_USB_UART (3UL) + +#define GPIO_SCENE_USB_UART_CUSTOM_EVENT_ENABLE (4UL) +#define GPIO_SCENE_USB_UART_CUSTOM_EVENT_DISABLE (5UL) + struct GpioApp { Gui* gui; ViewDispatcher* view_dispatcher; diff --git a/applications/gpio/scenes/gpio_scene_start.c b/applications/gpio/scenes/gpio_scene_start.c index b3ed40fd..b7d94fe7 100644 --- a/applications/gpio/scenes/gpio_scene_start.c +++ b/applications/gpio/scenes/gpio_scene_start.c @@ -1,11 +1,6 @@ #include "../gpio_app_i.h" #include "furi-hal-power.h" -#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_OFF (0UL) -#define GPIO_SCENE_START_CUSTOM_EVENT_OTG_ON (1UL) -#define GPIO_SCENE_START_CUSTOM_EVENT_TEST (2UL) -#define GPIO_SCENE_START_CUSTOM_EVENT_USB_UART (3UL) - enum GpioItem { GpioItemOtg, GpioItemTest, diff --git a/applications/gpio/scenes/gpio_scene_usb_uart.c b/applications/gpio/scenes/gpio_scene_usb_uart.c index 05de8e7b..c8ec0141 100644 --- a/applications/gpio/scenes/gpio_scene_usb_uart.c +++ b/applications/gpio/scenes/gpio_scene_usb_uart.c @@ -1,17 +1,6 @@ +#include "../usb_uart_bridge.h" #include "../gpio_app_i.h" #include "furi-hal.h" -#include <stream_buffer.h> -#include <furi-hal-usb-cdc_i.h> -#include "usb_cdc.h" - -#define USB_PKT_LEN CDC_DATA_SZ -#define USB_UART_RX_BUF_SIZE (USB_PKT_LEN * 3) -#define USB_UART_TX_BUF_SIZE (USB_PKT_LEN * 3) - -typedef enum { - WorkerCmdStop = (1 << 0), - -} WorkerCommandFlags; typedef enum { UsbUartLineIndexVcp, @@ -21,42 +10,7 @@ typedef enum { UsbUartLineIndexDisable, } LineIndex; -typedef enum { - UsbUartPortUSART1 = 0, - UsbUartPortLPUART1 = 1, -} PortIdx; - -typedef struct { - uint8_t vcp_ch; - PortIdx uart_ch; - uint32_t baudrate; -} UsbUartConfig; - -typedef struct { - UsbUartConfig cfg_cur; - UsbUartConfig cfg_set; - char br_text[8]; - - bool running; - osThreadId_t parent_thread; - - osThreadAttr_t thread_attr; - osThreadId_t thread; - - osThreadAttr_t tx_thread_attr; - osThreadId_t tx_thread; - - StreamBufferHandle_t rx_stream; - osSemaphoreId_t rx_done_sem; - osSemaphoreId_t usb_sof_sem; - - StreamBufferHandle_t tx_stream; - - uint8_t rx_buf[USB_PKT_LEN]; - uint8_t tx_buf[USB_PKT_LEN]; -} UsbUartParams; - -static UsbUartParams* usb_uart; +static UsbUartConfig* cfg_set; static const char* vcp_ch[] = {"0 (CLI)", "1"}; static const char* uart_ch[] = {"USART1", "LPUART1"}; @@ -73,197 +27,14 @@ static const uint32_t baudrate_list[] = { 921600, }; -static void vcp_on_cdc_tx_complete(); -static void vcp_on_cdc_rx(); -static void vcp_state_callback(uint8_t state); -static void vcp_on_cdc_control_line(uint8_t state); -static void vcp_on_line_config(struct usb_cdc_line_coding* config); - -static CdcCallbacks cdc_cb = { - vcp_on_cdc_tx_complete, - vcp_on_cdc_rx, - vcp_state_callback, - vcp_on_cdc_control_line, - vcp_on_line_config, -}; - -/* USB UART worker */ - -static void usb_uart_tx_thread(void* context); - -static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - if(ev == UartIrqEventRXNE) { - size_t ret = - xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); - furi_check(ret == 1); - ret = xStreamBufferBytesAvailable(usb_uart->rx_stream); - if(ret > USB_PKT_LEN) osSemaphoreRelease(usb_uart->rx_done_sem); - } else if(ev == UartIrqEventIDLE) { - osSemaphoreRelease(usb_uart->rx_done_sem); - } - - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -} - -static void usb_uart_worker(void* context) { - memcpy(&usb_uart->cfg_cur, &usb_uart->cfg_set, sizeof(UsbUartConfig)); - - usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1); - usb_uart->rx_done_sem = osSemaphoreNew(1, 1, NULL); - usb_uart->usb_sof_sem = osSemaphoreNew(1, 1, NULL); - - usb_uart->tx_stream = xStreamBufferCreate(USB_UART_TX_BUF_SIZE, 1); - - usb_uart->tx_thread = NULL; - usb_uart->tx_thread_attr.name = "usb_uart_tx"; - usb_uart->tx_thread_attr.stack_size = 512; - - UsbMode usb_mode_prev = furi_hal_usb_get_config(); - if(usb_uart->cfg_cur.vcp_ch == 0) { - furi_hal_usb_set_config(UsbModeVcpSingle); - furi_hal_vcp_disable(); - } else { - furi_hal_usb_set_config(UsbModeVcpDual); - } - - if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) { - furi_hal_usart_init(); - furi_hal_usart_set_irq_cb(usb_uart_on_irq_cb); - if(usb_uart->cfg_cur.baudrate != 0) - furi_hal_usart_set_br(usb_uart->cfg_cur.baudrate); - else - vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg_cur.vcp_ch)); - } else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) { - furi_hal_lpuart_init(); - furi_hal_lpuart_set_irq_cb(usb_uart_on_irq_cb); - if(usb_uart->cfg_cur.baudrate != 0) - furi_hal_lpuart_set_br(usb_uart->cfg_cur.baudrate); - else - vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg_cur.vcp_ch)); - } - - furi_hal_cdc_set_callbacks(usb_uart->cfg_cur.vcp_ch, &cdc_cb); - usb_uart->tx_thread = osThreadNew(usb_uart_tx_thread, NULL, &usb_uart->tx_thread_attr); - - while(1) { - furi_check(osSemaphoreAcquire(usb_uart->rx_done_sem, osWaitForever) == osOK); - if(osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny, 0) == WorkerCmdStop) break; - size_t len = 0; - do { - len = xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_PKT_LEN, 0); - if(len > 0) { - if(osSemaphoreAcquire(usb_uart->usb_sof_sem, 100) == osOK) - furi_hal_cdc_send(usb_uart->cfg_cur.vcp_ch, usb_uart->rx_buf, len); - else - xStreamBufferReset(usb_uart->rx_stream); - } - } while(len > 0); - } - - osThreadTerminate(usb_uart->tx_thread); - - if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) - furi_hal_usart_deinit(); - else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) - furi_hal_lpuart_deinit(); - - furi_hal_cdc_set_callbacks(usb_uart->cfg_cur.vcp_ch, NULL); - furi_hal_usb_set_config(usb_mode_prev); - if(usb_uart->cfg_cur.vcp_ch == 0) furi_hal_vcp_enable(); - - vStreamBufferDelete(usb_uart->rx_stream); - osSemaphoreDelete(usb_uart->rx_done_sem); - osSemaphoreDelete(usb_uart->usb_sof_sem); - - vStreamBufferDelete(usb_uart->tx_stream); - osThreadFlagsSet(usb_uart->parent_thread, WorkerCmdStop); - osThreadExit(); -} - -static void usb_uart_tx_thread(void* context) { - uint8_t data = 0; - while(1) { - size_t len = xStreamBufferReceive(usb_uart->tx_stream, &data, 1, osWaitForever); - if(len > 0) { - if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) - furi_hal_usart_tx(&data, len); - else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) - furi_hal_lpuart_tx(&data, len); - } - } - osThreadExit(); -} - -/* VCP callbacks */ - -static void vcp_on_cdc_tx_complete() { - osSemaphoreRelease(usb_uart->usb_sof_sem); -} - -static void vcp_on_cdc_rx() { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - uint16_t max_len = xStreamBufferSpacesAvailable(usb_uart->tx_stream); - if(max_len > 0) { - if(max_len > USB_PKT_LEN) max_len = USB_PKT_LEN; - int32_t size = furi_hal_cdc_receive(usb_uart->cfg_cur.vcp_ch, usb_uart->tx_buf, max_len); - - if(size > 0) { - size_t ret = xStreamBufferSendFromISR( - usb_uart->tx_stream, usb_uart->tx_buf, size, &xHigherPriorityTaskWoken); - furi_check(ret == size); - } - } - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); -} - -static void vcp_state_callback(uint8_t state) { -} - -static void vcp_on_cdc_control_line(uint8_t state) { -} - -static void vcp_on_line_config(struct usb_cdc_line_coding* config) { - if((usb_uart->cfg_cur.baudrate == 0) && (config->dwDTERate != 0)) { - if(usb_uart->cfg_cur.uart_ch == UsbUartPortUSART1) - furi_hal_usart_set_br(config->dwDTERate); - else if(usb_uart->cfg_cur.uart_ch == UsbUartPortLPUART1) - furi_hal_lpuart_set_br(config->dwDTERate); - } -} - -/* USB UART app */ - -static void usb_uart_enable() { - if(usb_uart->running == false) { - usb_uart->thread = NULL; - usb_uart->thread_attr.name = "usb_uart"; - usb_uart->thread_attr.stack_size = 1024; - usb_uart->parent_thread = osThreadGetId(); - usb_uart->running = true; - usb_uart->thread = osThreadNew(usb_uart_worker, NULL, &usb_uart->thread_attr); - } -} - -static void usb_uart_disable() { - if(usb_uart->running == true) { - osThreadFlagsSet(usb_uart->thread, WorkerCmdStop); - osSemaphoreRelease(usb_uart->rx_done_sem); - osThreadFlagsWait(WorkerCmdStop, osFlagsWaitAny, osWaitForever); - usb_uart->running = false; - } -} - bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) { //GpioApp* app = context; bool consumed = false; if(event.type == SceneManagerEventTypeCustom) { - if(event.event == UsbUartLineIndexEnable) { - usb_uart_enable(); - } else if(event.event == UsbUartLineIndexDisable) { + if(event.event == GPIO_SCENE_USB_UART_CUSTOM_EVENT_ENABLE) { + usb_uart_enable(cfg_set); + } else if(event.event == GPIO_SCENE_USB_UART_CUSTOM_EVENT_DISABLE) { usb_uart_disable(); } consumed = true; @@ -271,15 +42,13 @@ bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) { return consumed; } -/* Scene callbacks */ - static void line_vcp_cb(VariableItem* item) { //GpioApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); variable_item_set_current_value_text(item, vcp_ch[index]); - usb_uart->cfg_set.vcp_ch = index; + cfg_set->vcp_ch = index; } static void line_port_cb(VariableItem* item) { @@ -288,34 +57,44 @@ static void line_port_cb(VariableItem* item) { variable_item_set_current_value_text(item, uart_ch[index]); - usb_uart->cfg_set.uart_ch = index; + if(index == 0) + cfg_set->uart_ch = FuriHalUartIdUSART1; + else if(index == 1) + cfg_set->uart_ch = FuriHalUartIdLPUART1; } static void line_baudrate_cb(VariableItem* item) { //GpioApp* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); + char br_text[8]; + if(index > 0) { - snprintf(usb_uart->br_text, 7, "%lu", baudrate_list[index - 1]); - variable_item_set_current_value_text(item, usb_uart->br_text); - usb_uart->cfg_set.baudrate = baudrate_list[index - 1]; + snprintf(br_text, 7, "%lu", baudrate_list[index - 1]); + variable_item_set_current_value_text(item, br_text); + cfg_set->baudrate = baudrate_list[index - 1]; } else { variable_item_set_current_value_text(item, baudrate_mode[index]); - usb_uart->cfg_set.baudrate = 0; + cfg_set->baudrate = 0; } } static void gpio_scene_usb_uart_enter_callback(void* context, uint32_t index) { furi_assert(context); GpioApp* app = context; - view_dispatcher_send_custom_event(app->view_dispatcher, index); + if(index == UsbUartLineIndexEnable) + view_dispatcher_send_custom_event( + app->view_dispatcher, GPIO_SCENE_USB_UART_CUSTOM_EVENT_ENABLE); + else if(index == UsbUartLineIndexDisable) + view_dispatcher_send_custom_event( + app->view_dispatcher, GPIO_SCENE_USB_UART_CUSTOM_EVENT_DISABLE); } void gpio_scene_usb_uart_on_enter(void* context) { GpioApp* app = context; VariableItemList* var_item_list = app->var_item_list; - usb_uart = furi_alloc(sizeof(UsbUartParams)); + cfg_set = furi_alloc(sizeof(UsbUartConfig)); VariableItem* item; @@ -348,5 +127,5 @@ void gpio_scene_usb_uart_on_exit(void* context) { GpioApp* app = context; usb_uart_disable(); variable_item_list_clean(app->var_item_list); - free(usb_uart); -}
\ No newline at end of file + free(cfg_set); +} diff --git a/applications/gpio/usb_uart_bridge.c b/applications/gpio/usb_uart_bridge.c new file mode 100644 index 00000000..b50cc158 --- /dev/null +++ b/applications/gpio/usb_uart_bridge.c @@ -0,0 +1,246 @@ +#include "usb_uart_bridge.h" +#include "furi-hal.h" +#include <stream_buffer.h> +#include <furi-hal-usb-cdc_i.h> +#include "usb_cdc.h" + +#define USB_PKT_LEN CDC_DATA_SZ +#define USB_UART_RX_BUF_SIZE (USB_PKT_LEN * 3) +#define USB_UART_TX_BUF_SIZE (USB_PKT_LEN * 3) + +typedef enum { + WorkerEvtStop = (1 << 0), + WorkerEvtRxReady = (1 << 1), + + WorkerEvtTxStop = (1 << 2), + WorkerEvtTxReady = (1 << 3), + + WorkerEvtSof = (1 << 4), + +} WorkerEvtFlags; + +#define WORKER_ALL_RX_EVENTS (WorkerEvtStop | WorkerEvtRxReady) +#define WORKER_ALL_TX_EVENTS (WorkerEvtTxStop | WorkerEvtTxReady) + +typedef struct { + UsbUartConfig cfg; + + FuriThread* thread; + FuriThread* tx_thread; + + osEventFlagsId_t events; + + StreamBufferHandle_t rx_stream; + StreamBufferHandle_t tx_stream; + + uint8_t rx_buf[USB_PKT_LEN]; + uint8_t tx_buf[USB_PKT_LEN]; + + bool buf_full; +} UsbUartParams; + +static UsbUartParams* usb_uart; +static bool running = false; + +static void vcp_on_cdc_tx_complete(); +static void vcp_on_cdc_rx(); +static void vcp_state_callback(uint8_t state); +static void vcp_on_cdc_control_line(uint8_t state); +static void vcp_on_line_config(struct usb_cdc_line_coding* config); + +static CdcCallbacks cdc_cb = { + vcp_on_cdc_tx_complete, + vcp_on_cdc_rx, + vcp_state_callback, + vcp_on_cdc_control_line, + vcp_on_line_config, +}; + +/* USB UART worker */ + +static int32_t usb_uart_tx_thread(void* context); + +static void usb_uart_on_irq_cb(UartIrqEvent ev, uint8_t data) { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + if(ev == UartIrqEventRXNE) { + xStreamBufferSendFromISR(usb_uart->rx_stream, &data, 1, &xHigherPriorityTaskWoken); + + size_t ret = xStreamBufferBytesAvailable(usb_uart->rx_stream); + if(ret > USB_PKT_LEN) osEventFlagsSet(usb_uart->events, WorkerEvtRxReady); + } else if(ev == UartIrqEventIDLE) { + osEventFlagsSet(usb_uart->events, WorkerEvtRxReady); + } + + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +static int32_t usb_uart_worker(void* context) { + memcpy(&usb_uart->cfg, context, sizeof(UsbUartConfig)); + + usb_uart->rx_stream = xStreamBufferCreate(USB_UART_RX_BUF_SIZE, 1); + usb_uart->tx_stream = xStreamBufferCreate(USB_UART_TX_BUF_SIZE, 1); + + usb_uart->tx_thread = furi_thread_alloc(); + furi_thread_set_name(usb_uart->tx_thread, "usb_uart_tx"); + furi_thread_set_stack_size(usb_uart->tx_thread, 512); + furi_thread_set_context(usb_uart->tx_thread, NULL); + furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread); + + UsbMode usb_mode_prev = furi_hal_usb_get_config(); + if(usb_uart->cfg.vcp_ch == 0) { + furi_hal_usb_set_config(UsbModeVcpSingle); + furi_hal_vcp_disable(); + osEventFlagsSet(usb_uart->events, WorkerEvtSof); + } else { + furi_hal_usb_set_config(UsbModeVcpDual); + } + + if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) { + furi_hal_console_disable(); + } else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) { + furi_hal_uart_init(usb_uart->cfg.uart_ch, 115200); + furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb); + } + + furi_hal_uart_set_irq_cb(usb_uart->cfg.uart_ch, usb_uart_on_irq_cb); + if(usb_uart->cfg.baudrate != 0) + furi_hal_uart_set_br(usb_uart->cfg.uart_ch, usb_uart->cfg.baudrate); + else + vcp_on_line_config(furi_hal_cdc_get_port_settings(usb_uart->cfg.vcp_ch)); + + furi_hal_cdc_set_callbacks(usb_uart->cfg.vcp_ch, &cdc_cb); + + furi_thread_start(usb_uart->tx_thread); + + while(1) { + uint32_t events = osEventFlagsWait( + usb_uart->events, WORKER_ALL_RX_EVENTS, osFlagsWaitAny, osWaitForever); + furi_check((events & osFlagsError) == 0); + if(events & WorkerEvtStop) break; + if(events & WorkerEvtRxReady) { + size_t len = 0; + do { + len = xStreamBufferReceive(usb_uart->rx_stream, usb_uart->rx_buf, USB_PKT_LEN, 0); + if(len > 0) { + if((osEventFlagsWait(usb_uart->events, WorkerEvtSof, osFlagsWaitAny, 100) & + osFlagsError) == 0) + furi_hal_cdc_send(usb_uart->cfg.vcp_ch, usb_uart->rx_buf, len); + else + xStreamBufferReset(usb_uart->rx_stream); + } + } while(len > 0); + } + } + + osEventFlagsSet(usb_uart->events, WorkerEvtTxStop); + furi_thread_join(usb_uart->tx_thread); + furi_thread_free(usb_uart->tx_thread); + + if(usb_uart->cfg.uart_ch == FuriHalUartIdUSART1) + furi_hal_console_enable(); + else if(usb_uart->cfg.uart_ch == FuriHalUartIdLPUART1) + furi_hal_uart_deinit(usb_uart->cfg.uart_ch); + + furi_hal_cdc_set_callbacks(usb_uart->cfg.vcp_ch, NULL); + furi_hal_usb_set_config(usb_mode_prev); + if(usb_uart->cfg.vcp_ch == 0) furi_hal_vcp_enable(); + + vStreamBufferDelete(usb_uart->rx_stream); + vStreamBufferDelete(usb_uart->tx_stream); + + return 0; +} + +static int32_t usb_uart_tx_thread(void* context) { + uint8_t data[USB_PKT_LEN]; + while(1) { + uint32_t events = osEventFlagsWait( + usb_uart->events, WORKER_ALL_TX_EVENTS, osFlagsWaitAny, osWaitForever); + furi_check((events & osFlagsError) == 0); + if(events & WorkerEvtTxStop) break; + if(events & WorkerEvtTxReady) { + size_t len = 0; + do { + len = xStreamBufferReceive(usb_uart->tx_stream, &data, 1, 0); + if(len > 0) { + furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, len); + } + if((usb_uart->buf_full == true) && + (xStreamBufferBytesAvailable(usb_uart->tx_stream) == 0)) { + // Stream buffer was overflown, but now is free. Reading USB buffer to resume USB transfers + usb_uart->buf_full = false; + int32_t size = furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, data, USB_PKT_LEN); + if(size > 0) { + furi_hal_uart_tx(usb_uart->cfg.uart_ch, data, size); + } + } + } while(len > 0); + } + } + return 0; +} + +/* VCP callbacks */ + +static void vcp_on_cdc_tx_complete() { + osEventFlagsSet(usb_uart->events, WorkerEvtSof); +} + +static void vcp_on_cdc_rx() { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + uint16_t max_len = xStreamBufferSpacesAvailable(usb_uart->tx_stream); + if(max_len >= USB_PKT_LEN) { + //if(max_len > USB_PKT_LEN) max_len = USB_PKT_LEN; + int32_t size = furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, usb_uart->tx_buf, USB_PKT_LEN); + if(size > 0) { + size_t ret = xStreamBufferSendFromISR( + usb_uart->tx_stream, usb_uart->tx_buf, size, &xHigherPriorityTaskWoken); + furi_check(ret == size); + } + } else { + usb_uart->buf_full = true; + } + osEventFlagsSet(usb_uart->events, WorkerEvtTxReady); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +static void vcp_state_callback(uint8_t state) { +} + +static void vcp_on_cdc_control_line(uint8_t state) { +} + +static void vcp_on_line_config(struct usb_cdc_line_coding* config) { + if((usb_uart->cfg.baudrate == 0) && (config->dwDTERate != 0)) + furi_hal_uart_set_br(usb_uart->cfg.uart_ch, config->dwDTERate); +} + +void usb_uart_enable(UsbUartConfig* cfg) { + if(running == false) { + running = true; + usb_uart = furi_alloc(sizeof(UsbUartParams)); + + usb_uart->thread = furi_thread_alloc(); + furi_thread_set_name(usb_uart->thread, "usb_uart"); + furi_thread_set_stack_size(usb_uart->thread, 1024); + furi_thread_set_context(usb_uart->thread, cfg); + furi_thread_set_callback(usb_uart->thread, usb_uart_worker); + + usb_uart->events = osEventFlagsNew(NULL); + + furi_thread_start(usb_uart->thread); + } +} + +void usb_uart_disable() { + if(running == true) { + osEventFlagsSet(usb_uart->events, WorkerEvtStop); + furi_thread_join(usb_uart->thread); + furi_thread_free(usb_uart->thread); + osEventFlagsDelete(usb_uart->events); + free(usb_uart); + running = false; + } +} diff --git a/applications/gpio/usb_uart_bridge.h b/applications/gpio/usb_uart_bridge.h new file mode 100644 index 00000000..2fe6d1d8 --- /dev/null +++ b/applications/gpio/usb_uart_bridge.h @@ -0,0 +1,13 @@ +#pragma once + +#include <stdint.h> + +typedef struct { + uint8_t vcp_ch; + uint8_t uart_ch; + uint32_t baudrate; +} UsbUartConfig; + +void usb_uart_enable(UsbUartConfig* cfg); + +void usb_uart_disable(); |