From 242241987e6bf93a428d4295ddcd92961c4d6b87 Mon Sep 17 00:00:00 2001 From: Nikolay Minaylov Date: Wed, 16 Feb 2022 20:52:34 +0300 Subject: [FL-2256] USB Service (#998) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * usb service, removed power observer * fix usb restart after disable * remove usb service from apps * Applcations: remove dead extern * New thread naming scheme for drivers * New thread symbol naming scheme for drivers Co-authored-by: あく --- firmware/targets/f6/ble_glue/ble_app.c | 2 +- firmware/targets/f6/ble_glue/ble_glue.c | 2 +- firmware/targets/f6/ble_glue/gap.c | 2 +- firmware/targets/f6/furi_hal/furi_hal.c | 1 - firmware/targets/f6/furi_hal/furi_hal_usb.c | 259 ++++++++++++++++++---------- firmware/targets/f6/furi_hal/furi_hal_vcp.c | 5 +- firmware/targets/f7/ble_glue/ble_app.c | 2 +- firmware/targets/f7/ble_glue/ble_glue.c | 2 +- firmware/targets/f7/ble_glue/gap.c | 2 +- firmware/targets/f7/furi_hal/furi_hal.c | 1 - firmware/targets/f7/furi_hal/furi_hal_usb.c | 259 ++++++++++++++++++---------- firmware/targets/f7/furi_hal/furi_hal_vcp.c | 5 +- 12 files changed, 348 insertions(+), 194 deletions(-) (limited to 'firmware') diff --git a/firmware/targets/f6/ble_glue/ble_app.c b/firmware/targets/f6/ble_glue/ble_app.c index c3359e58..6afd3648 100644 --- a/firmware/targets/f6/ble_glue/ble_app.c +++ b/firmware/targets/f6/ble_glue/ble_app.c @@ -42,7 +42,7 @@ bool ble_app_init() { ble_app->event_flags = osEventFlagsNew(NULL); // HCI transport layer thread to handle user asynch events ble_app->thread = furi_thread_alloc(); - furi_thread_set_name(ble_app->thread, "BleHciWorker"); + furi_thread_set_name(ble_app->thread, "BleHciDriver"); furi_thread_set_stack_size(ble_app->thread, 1024); furi_thread_set_context(ble_app->thread, ble_app); furi_thread_set_callback(ble_app->thread, ble_app_hci_thread); diff --git a/firmware/targets/f6/ble_glue/ble_glue.c b/firmware/targets/f6/ble_glue/ble_glue.c index 6e55b368..4c26e086 100644 --- a/firmware/targets/f6/ble_glue/ble_glue.c +++ b/firmware/targets/f6/ble_glue/ble_glue.c @@ -88,7 +88,7 @@ void ble_glue_init() { // FreeRTOS system task creation ble_glue->thread = furi_thread_alloc(); - furi_thread_set_name(ble_glue->thread, "BleShciWorker"); + furi_thread_set_name(ble_glue->thread, "BleShciDriver"); furi_thread_set_stack_size(ble_glue->thread, 1024); furi_thread_set_context(ble_glue->thread, ble_glue); furi_thread_set_callback(ble_glue->thread, ble_glue_shci_thread); diff --git a/firmware/targets/f6/ble_glue/gap.c b/firmware/targets/f6/ble_glue/gap.c index d9a2096f..1bd0cbbf 100755 --- a/firmware/targets/f6/ble_glue/gap.c +++ b/firmware/targets/f6/ble_glue/gap.c @@ -481,7 +481,7 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { // Thread configuration gap->thread = furi_thread_alloc(); - furi_thread_set_name(gap->thread, "BleGapWorker"); + furi_thread_set_name(gap->thread, "BleGapDriver"); furi_thread_set_stack_size(gap->thread, 1024); furi_thread_set_context(gap->thread, gap); furi_thread_set_callback(gap->thread, gap_app); diff --git a/firmware/targets/f6/furi_hal/furi_hal.c b/firmware/targets/f6/furi_hal/furi_hal.c index da529893..082956b1 100644 --- a/firmware/targets/f6/furi_hal/furi_hal.c +++ b/firmware/targets/f6/furi_hal/furi_hal.c @@ -38,7 +38,6 @@ void furi_hal_init() { // VCP + USB furi_hal_usb_init(); - furi_hal_usb_set_config(&usb_cdc_single); furi_hal_vcp_init(); FURI_LOG_I(TAG, "USB OK"); diff --git a/firmware/targets/f6/furi_hal/furi_hal_usb.c b/firmware/targets/f6/furi_hal/furi_hal_usb.c index 7ca8ffdf..c948a3cf 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f6/furi_hal/furi_hal_usb.c @@ -1,6 +1,7 @@ #include "furi_hal_version.h" #include "furi_hal_usb_i.h" #include "furi_hal_usb.h" +#include "furi_hal_vcp.h" #include #include @@ -10,29 +11,46 @@ #define USB_RECONNECT_DELAY 500 -static FuriHalUsbInterface* usb_if_cur; -static FuriHalUsbInterface* usb_if_next; +typedef struct { + FuriThread* thread; + osTimerId_t tmr; + bool enabled; + bool connected; + FuriHalUsbInterface* if_cur; + FuriHalUsbInterface* if_next; + FuriHalUsbStateCallback callback; + void* cb_ctx; +} UsbSrv; + +typedef enum { + EventModeChange = (1 << 0), + EventEnable = (1 << 1), + EventDisable = (1 << 2), + EventReinit = (1 << 3), + + EventReset = (1 << 4), + EventRequest = (1 << 5), + + EventModeChangeStart = (1 << 6), +} UsbEvent; + +#define USB_SRV_ALL_EVENTS \ + (EventModeChange | EventEnable | EventDisable | EventReinit | EventReset | EventRequest | \ + EventModeChangeStart) + +static UsbSrv usb; static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); static uint32_t ubuf[0x20]; usbd_device udev; -static FuriHalUsbStateCallback callback; -static void* cb_ctx; - +static int32_t furi_hal_usb_thread(void* context); static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_t* length); static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); -struct UsbCfg { - osTimerId_t reconnect_tmr; - bool enabled; - bool connected; - bool mode_changing; -} usb_config; - static void furi_hal_usb_tmr_cb(void* context); /* Low-level init */ @@ -56,79 +74,51 @@ void furi_hal_usb_init(void) { usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); // Reset callback will be enabled after first mode change to avoid getting false reset events - usb_config.enabled = false; - usb_config.reconnect_tmr = NULL; + usb.enabled = false; + usb.if_cur = NULL; HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); NVIC_EnableIRQ(USB_LP_IRQn); + usb.thread = furi_thread_alloc(); + furi_thread_set_name(usb.thread, "UsbDriver"); + furi_thread_set_stack_size(usb.thread, 1024); + furi_thread_set_callback(usb.thread, furi_hal_usb_thread); + furi_thread_start(usb.thread); + FURI_LOG_I(TAG, "Init OK"); } void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) { - if((new_if != usb_if_cur) && (usb_config.enabled)) { // Interface mode change - first stage - usb_config.mode_changing = true; - usb_if_next = new_if; - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - furi_hal_usb_disable(); - usb_config.mode_changing = true; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else if( - (usb_config.mode_changing) && - (usb_if_next != new_if)) { // Last interface mode change wasn't completed - osTimerStop(usb_config.reconnect_tmr); - usb_if_next = new_if; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else { // Interface mode change - second stage - if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); - if(new_if != NULL) { - new_if->init(&udev, new_if); - usbd_reg_event(&udev, usbd_evt_reset, reset_evt); - FURI_LOG_I(TAG, "USB Mode change done"); - usb_config.enabled = true; - usb_if_cur = new_if; - usb_config.mode_changing = false; - } + usb.if_next = new_if; + if(usb.thread == NULL) { + // Service thread hasn't started yet, so just save interface mode + return; } -} - -void furi_hal_usb_reinit() { - // Temporary disable callback to avoid getting false reset events - usbd_reg_event(&udev, usbd_evt_reset, NULL); - FURI_LOG_I(TAG, "USB Reinit"); - furi_hal_usb_disable(); - usbd_enable(&udev, false); - usbd_enable(&udev, true); - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - usb_config.mode_changing = true; - usb_if_next = usb_if_cur; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); } FuriHalUsbInterface* furi_hal_usb_get_config() { - return usb_if_cur; + return usb.if_cur; } void furi_hal_usb_disable() { - if(usb_config.enabled) { - susp_evt(&udev, 0, 0); - usbd_connect(&udev, false); - usb_config.enabled = false; - FURI_LOG_I(TAG, "USB Disable"); - } + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventDisable); } void furi_hal_usb_enable() { - if((!usb_config.enabled) && (usb_if_cur != NULL)) { - usbd_connect(&udev, true); - usb_config.enabled = true; - FURI_LOG_I(TAG, "USB Enable"); - } + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventEnable); +} + +void furi_hal_usb_reinit() { + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReinit); } static void furi_hal_usb_tmr_cb(void* context) { - furi_hal_usb_set_config(usb_if_next); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChangeStart); } /* Get device / configuration descriptors */ @@ -137,28 +127,29 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ const uint8_t dnumber = req->wValue & 0xFF; const void* desc; uint16_t len = 0; - if(usb_if_cur == NULL) return usbd_fail; + if(usb.if_cur == NULL) return usbd_fail; switch(dtype) { case USB_DTYPE_DEVICE: - if(callback != NULL) { - callback(FuriHalUsbStateEventDescriptorRequest, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventRequest); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.cb_ctx); } - desc = usb_if_cur->dev_descr; + desc = usb.if_cur->dev_descr; break; case USB_DTYPE_CONFIGURATION: - desc = usb_if_cur->cfg_descr; - len = ((struct usb_string_descriptor*)(usb_if_cur->cfg_descr))->wString[0]; + desc = usb.if_cur->cfg_descr; + len = ((struct usb_string_descriptor*)(usb.if_cur->cfg_descr))->wString[0]; break; case USB_DTYPE_STRING: if(dnumber == UsbDevLang) { desc = &dev_lang_desc; - } else if((dnumber == UsbDevManuf) && (usb_if_cur->str_manuf_descr != NULL)) { - desc = usb_if_cur->str_manuf_descr; - } else if((dnumber == UsbDevProduct) && (usb_if_cur->str_prod_descr != NULL)) { - desc = usb_if_cur->str_prod_descr; - } else if((dnumber == UsbDevSerial) && (usb_if_cur->str_serial_descr != NULL)) { - desc = usb_if_cur->str_serial_descr; + } else if((dnumber == UsbDevManuf) && (usb.if_cur->str_manuf_descr != NULL)) { + desc = usb.if_cur->str_manuf_descr; + } else if((dnumber == UsbDevProduct) && (usb.if_cur->str_prod_descr != NULL)) { + desc = usb.if_cur->str_prod_descr; + } else if((dnumber == UsbDevSerial) && (usb.if_cur->str_serial_descr != NULL)) { + desc = usb.if_cur->str_serial_descr; } else return usbd_fail; break; @@ -176,36 +167,122 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ } void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { - callback = cb; - cb_ctx = ctx; + usb.callback = cb; + usb.cb_ctx = ctx; } static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if(callback != NULL) { - callback(FuriHalUsbStateEventReset, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReset); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventReset, usb.cb_ctx); } } static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == true)) { - usb_config.connected = false; - usb_if_cur->suspend(&udev); + if((usb.if_cur != NULL) && (usb.connected == true)) { + usb.connected = false; + usb.if_cur->suspend(&udev); furi_hal_power_insomnia_exit(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventSuspend, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventSuspend, usb.cb_ctx); } } static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == false)) { - usb_config.connected = true; - usb_if_cur->wakeup(&udev); + if((usb.if_cur != NULL) && (usb.connected == false)) { + usb.connected = true; + usb.if_cur->wakeup(&udev); furi_hal_power_insomnia_enter(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventWakeup, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventWakeup, usb.cb_ctx); + } +} + +static int32_t furi_hal_usb_thread(void* context) { + usb.tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + + bool usb_request_pending = false; + uint8_t usb_wait_time = 0; + + if(usb.if_next != NULL) { + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); + } + + while(true) { + uint32_t flags = osThreadFlagsWait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500); + if((flags & osFlagsError) == 0) { + if(flags & EventModeChange) { + if(usb.if_next != usb.if_cur) { + if(usb.enabled) { // Disable current interface + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } else { + flags |= EventModeChangeStart; + } + } + } + if(flags & EventReinit) { + // Temporary disable callback to avoid getting false reset events + usbd_reg_event(&udev, usbd_evt_reset, NULL); + FURI_LOG_I(TAG, "USB Reinit"); + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + + usbd_enable(&udev, false); + usbd_enable(&udev, true); + + usb.if_next = usb.if_cur; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } + if(flags & EventModeChangeStart) { // Second stage of mode change process + if(usb.if_cur != NULL) { + usb.if_cur->deinit(&udev); + } + if(usb.if_next != NULL) { + usb.if_next->init(&udev, usb.if_next); + usbd_reg_event(&udev, usbd_evt_reset, reset_evt); + FURI_LOG_I(TAG, "USB Mode change done"); + usb.enabled = true; + usb.if_cur = usb.if_next; + } + } + if(flags & EventEnable) { + if((!usb.enabled) && (usb.if_cur != NULL)) { + usbd_connect(&udev, true); + usb.enabled = true; + FURI_LOG_I(TAG, "USB Enable"); + } + } + if(flags & EventDisable) { + if(usb.enabled) { + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + usb_request_pending = false; + FURI_LOG_I(TAG, "USB Disable"); + } + } + if(flags & EventReset) { + usb_request_pending = true; + usb_wait_time = 0; + } + if(flags & EventRequest) { + usb_request_pending = false; + } + } else if(usb_request_pending) { + usb_wait_time++; + if(usb_wait_time > 4) { + furi_hal_usb_reinit(); + usb_request_pending = false; + } + } } + return 0; } diff --git a/firmware/targets/f6/furi_hal/furi_hal_vcp.c b/firmware/targets/f6/furi_hal/furi_hal_vcp.c index 4ac59ae3..409a61a0 100644 --- a/firmware/targets/f6/furi_hal/furi_hal_vcp.c +++ b/firmware/targets/f6/furi_hal/furi_hal_vcp.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -65,7 +65,7 @@ void furi_hal_vcp_init() { vcp->rx_stream = xStreamBufferCreate(VCP_RX_BUF_SIZE, 1); vcp->thread = furi_thread_alloc(); - furi_thread_set_name(vcp->thread, "VcpWorker"); + furi_thread_set_name(vcp->thread, "VcpDriver"); furi_thread_set_stack_size(vcp->thread, 1024); furi_thread_set_callback(vcp->thread, vcp_worker); furi_thread_start(vcp->thread); @@ -79,6 +79,7 @@ static int32_t vcp_worker(void* context) { size_t missed_rx = 0; uint8_t last_tx_pkt_len = 0; + furi_hal_usb_set_config(&usb_cdc_single); furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL); while(1) { diff --git a/firmware/targets/f7/ble_glue/ble_app.c b/firmware/targets/f7/ble_glue/ble_app.c index c3359e58..6afd3648 100644 --- a/firmware/targets/f7/ble_glue/ble_app.c +++ b/firmware/targets/f7/ble_glue/ble_app.c @@ -42,7 +42,7 @@ bool ble_app_init() { ble_app->event_flags = osEventFlagsNew(NULL); // HCI transport layer thread to handle user asynch events ble_app->thread = furi_thread_alloc(); - furi_thread_set_name(ble_app->thread, "BleHciWorker"); + furi_thread_set_name(ble_app->thread, "BleHciDriver"); furi_thread_set_stack_size(ble_app->thread, 1024); furi_thread_set_context(ble_app->thread, ble_app); furi_thread_set_callback(ble_app->thread, ble_app_hci_thread); diff --git a/firmware/targets/f7/ble_glue/ble_glue.c b/firmware/targets/f7/ble_glue/ble_glue.c index 6e55b368..4c26e086 100644 --- a/firmware/targets/f7/ble_glue/ble_glue.c +++ b/firmware/targets/f7/ble_glue/ble_glue.c @@ -88,7 +88,7 @@ void ble_glue_init() { // FreeRTOS system task creation ble_glue->thread = furi_thread_alloc(); - furi_thread_set_name(ble_glue->thread, "BleShciWorker"); + furi_thread_set_name(ble_glue->thread, "BleShciDriver"); furi_thread_set_stack_size(ble_glue->thread, 1024); furi_thread_set_context(ble_glue->thread, ble_glue); furi_thread_set_callback(ble_glue->thread, ble_glue_shci_thread); diff --git a/firmware/targets/f7/ble_glue/gap.c b/firmware/targets/f7/ble_glue/gap.c index d9a2096f..1bd0cbbf 100755 --- a/firmware/targets/f7/ble_glue/gap.c +++ b/firmware/targets/f7/ble_glue/gap.c @@ -481,7 +481,7 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) { // Thread configuration gap->thread = furi_thread_alloc(); - furi_thread_set_name(gap->thread, "BleGapWorker"); + furi_thread_set_name(gap->thread, "BleGapDriver"); furi_thread_set_stack_size(gap->thread, 1024); furi_thread_set_context(gap->thread, gap); furi_thread_set_callback(gap->thread, gap_app); diff --git a/firmware/targets/f7/furi_hal/furi_hal.c b/firmware/targets/f7/furi_hal/furi_hal.c index da529893..082956b1 100644 --- a/firmware/targets/f7/furi_hal/furi_hal.c +++ b/firmware/targets/f7/furi_hal/furi_hal.c @@ -38,7 +38,6 @@ void furi_hal_init() { // VCP + USB furi_hal_usb_init(); - furi_hal_usb_set_config(&usb_cdc_single); furi_hal_vcp_init(); FURI_LOG_I(TAG, "USB OK"); diff --git a/firmware/targets/f7/furi_hal/furi_hal_usb.c b/firmware/targets/f7/furi_hal/furi_hal_usb.c index 7ca8ffdf..c948a3cf 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_usb.c +++ b/firmware/targets/f7/furi_hal/furi_hal_usb.c @@ -1,6 +1,7 @@ #include "furi_hal_version.h" #include "furi_hal_usb_i.h" #include "furi_hal_usb.h" +#include "furi_hal_vcp.h" #include #include @@ -10,29 +11,46 @@ #define USB_RECONNECT_DELAY 500 -static FuriHalUsbInterface* usb_if_cur; -static FuriHalUsbInterface* usb_if_next; +typedef struct { + FuriThread* thread; + osTimerId_t tmr; + bool enabled; + bool connected; + FuriHalUsbInterface* if_cur; + FuriHalUsbInterface* if_next; + FuriHalUsbStateCallback callback; + void* cb_ctx; +} UsbSrv; + +typedef enum { + EventModeChange = (1 << 0), + EventEnable = (1 << 1), + EventDisable = (1 << 2), + EventReinit = (1 << 3), + + EventReset = (1 << 4), + EventRequest = (1 << 5), + + EventModeChangeStart = (1 << 6), +} UsbEvent; + +#define USB_SRV_ALL_EVENTS \ + (EventModeChange | EventEnable | EventDisable | EventReinit | EventReset | EventRequest | \ + EventModeChangeStart) + +static UsbSrv usb; static const struct usb_string_descriptor dev_lang_desc = USB_ARRAY_DESC(USB_LANGID_ENG_US); static uint32_t ubuf[0x20]; usbd_device udev; -static FuriHalUsbStateCallback callback; -static void* cb_ctx; - +static int32_t furi_hal_usb_thread(void* context); static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_t* length); static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep); static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep); -struct UsbCfg { - osTimerId_t reconnect_tmr; - bool enabled; - bool connected; - bool mode_changing; -} usb_config; - static void furi_hal_usb_tmr_cb(void* context); /* Low-level init */ @@ -56,79 +74,51 @@ void furi_hal_usb_init(void) { usbd_reg_event(&udev, usbd_evt_wkup, wkup_evt); // Reset callback will be enabled after first mode change to avoid getting false reset events - usb_config.enabled = false; - usb_config.reconnect_tmr = NULL; + usb.enabled = false; + usb.if_cur = NULL; HAL_NVIC_SetPriority(USB_LP_IRQn, 5, 0); NVIC_EnableIRQ(USB_LP_IRQn); + usb.thread = furi_thread_alloc(); + furi_thread_set_name(usb.thread, "UsbDriver"); + furi_thread_set_stack_size(usb.thread, 1024); + furi_thread_set_callback(usb.thread, furi_hal_usb_thread); + furi_thread_start(usb.thread); + FURI_LOG_I(TAG, "Init OK"); } void furi_hal_usb_set_config(FuriHalUsbInterface* new_if) { - if((new_if != usb_if_cur) && (usb_config.enabled)) { // Interface mode change - first stage - usb_config.mode_changing = true; - usb_if_next = new_if; - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - furi_hal_usb_disable(); - usb_config.mode_changing = true; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else if( - (usb_config.mode_changing) && - (usb_if_next != new_if)) { // Last interface mode change wasn't completed - osTimerStop(usb_config.reconnect_tmr); - usb_if_next = new_if; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); - } else { // Interface mode change - second stage - if(usb_if_cur != NULL) usb_if_cur->deinit(&udev); - if(new_if != NULL) { - new_if->init(&udev, new_if); - usbd_reg_event(&udev, usbd_evt_reset, reset_evt); - FURI_LOG_I(TAG, "USB Mode change done"); - usb_config.enabled = true; - usb_if_cur = new_if; - usb_config.mode_changing = false; - } + usb.if_next = new_if; + if(usb.thread == NULL) { + // Service thread hasn't started yet, so just save interface mode + return; } -} - -void furi_hal_usb_reinit() { - // Temporary disable callback to avoid getting false reset events - usbd_reg_event(&udev, usbd_evt_reset, NULL); - FURI_LOG_I(TAG, "USB Reinit"); - furi_hal_usb_disable(); - usbd_enable(&udev, false); - usbd_enable(&udev, true); - if(usb_config.reconnect_tmr == NULL) - usb_config.reconnect_tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); - usb_config.mode_changing = true; - usb_if_next = usb_if_cur; - osTimerStart(usb_config.reconnect_tmr, USB_RECONNECT_DELAY); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); } FuriHalUsbInterface* furi_hal_usb_get_config() { - return usb_if_cur; + return usb.if_cur; } void furi_hal_usb_disable() { - if(usb_config.enabled) { - susp_evt(&udev, 0, 0); - usbd_connect(&udev, false); - usb_config.enabled = false; - FURI_LOG_I(TAG, "USB Disable"); - } + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventDisable); } void furi_hal_usb_enable() { - if((!usb_config.enabled) && (usb_if_cur != NULL)) { - usbd_connect(&udev, true); - usb_config.enabled = true; - FURI_LOG_I(TAG, "USB Enable"); - } + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventEnable); +} + +void furi_hal_usb_reinit() { + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReinit); } static void furi_hal_usb_tmr_cb(void* context) { - furi_hal_usb_set_config(usb_if_next); + furi_assert(usb.thread); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChangeStart); } /* Get device / configuration descriptors */ @@ -137,28 +127,29 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ const uint8_t dnumber = req->wValue & 0xFF; const void* desc; uint16_t len = 0; - if(usb_if_cur == NULL) return usbd_fail; + if(usb.if_cur == NULL) return usbd_fail; switch(dtype) { case USB_DTYPE_DEVICE: - if(callback != NULL) { - callback(FuriHalUsbStateEventDescriptorRequest, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventRequest); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventDescriptorRequest, usb.cb_ctx); } - desc = usb_if_cur->dev_descr; + desc = usb.if_cur->dev_descr; break; case USB_DTYPE_CONFIGURATION: - desc = usb_if_cur->cfg_descr; - len = ((struct usb_string_descriptor*)(usb_if_cur->cfg_descr))->wString[0]; + desc = usb.if_cur->cfg_descr; + len = ((struct usb_string_descriptor*)(usb.if_cur->cfg_descr))->wString[0]; break; case USB_DTYPE_STRING: if(dnumber == UsbDevLang) { desc = &dev_lang_desc; - } else if((dnumber == UsbDevManuf) && (usb_if_cur->str_manuf_descr != NULL)) { - desc = usb_if_cur->str_manuf_descr; - } else if((dnumber == UsbDevProduct) && (usb_if_cur->str_prod_descr != NULL)) { - desc = usb_if_cur->str_prod_descr; - } else if((dnumber == UsbDevSerial) && (usb_if_cur->str_serial_descr != NULL)) { - desc = usb_if_cur->str_serial_descr; + } else if((dnumber == UsbDevManuf) && (usb.if_cur->str_manuf_descr != NULL)) { + desc = usb.if_cur->str_manuf_descr; + } else if((dnumber == UsbDevProduct) && (usb.if_cur->str_prod_descr != NULL)) { + desc = usb.if_cur->str_prod_descr; + } else if((dnumber == UsbDevSerial) && (usb.if_cur->str_serial_descr != NULL)) { + desc = usb.if_cur->str_serial_descr; } else return usbd_fail; break; @@ -176,36 +167,122 @@ static usbd_respond usb_descriptor_get(usbd_ctlreq* req, void** address, uint16_ } void furi_hal_usb_set_state_callback(FuriHalUsbStateCallback cb, void* ctx) { - callback = cb; - cb_ctx = ctx; + usb.callback = cb; + usb.cb_ctx = ctx; } static void reset_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if(callback != NULL) { - callback(FuriHalUsbStateEventReset, cb_ctx); + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventReset); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventReset, usb.cb_ctx); } } static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == true)) { - usb_config.connected = false; - usb_if_cur->suspend(&udev); + if((usb.if_cur != NULL) && (usb.connected == true)) { + usb.connected = false; + usb.if_cur->suspend(&udev); furi_hal_power_insomnia_exit(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventSuspend, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventSuspend, usb.cb_ctx); } } static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { - if((usb_if_cur != NULL) && (usb_config.connected == false)) { - usb_config.connected = true; - usb_if_cur->wakeup(&udev); + if((usb.if_cur != NULL) && (usb.connected == false)) { + usb.connected = true; + usb.if_cur->wakeup(&udev); furi_hal_power_insomnia_enter(); } - if(callback != NULL) { - callback(FuriHalUsbStateEventWakeup, cb_ctx); + if(usb.callback != NULL) { + usb.callback(FuriHalUsbStateEventWakeup, usb.cb_ctx); + } +} + +static int32_t furi_hal_usb_thread(void* context) { + usb.tmr = osTimerNew(furi_hal_usb_tmr_cb, osTimerOnce, NULL, NULL); + + bool usb_request_pending = false; + uint8_t usb_wait_time = 0; + + if(usb.if_next != NULL) { + osThreadFlagsSet(furi_thread_get_thread_id(usb.thread), EventModeChange); + } + + while(true) { + uint32_t flags = osThreadFlagsWait(USB_SRV_ALL_EVENTS, osFlagsWaitAny, 500); + if((flags & osFlagsError) == 0) { + if(flags & EventModeChange) { + if(usb.if_next != usb.if_cur) { + if(usb.enabled) { // Disable current interface + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } else { + flags |= EventModeChangeStart; + } + } + } + if(flags & EventReinit) { + // Temporary disable callback to avoid getting false reset events + usbd_reg_event(&udev, usbd_evt_reset, NULL); + FURI_LOG_I(TAG, "USB Reinit"); + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + + usbd_enable(&udev, false); + usbd_enable(&udev, true); + + usb.if_next = usb.if_cur; + osTimerStart(usb.tmr, USB_RECONNECT_DELAY); + } + if(flags & EventModeChangeStart) { // Second stage of mode change process + if(usb.if_cur != NULL) { + usb.if_cur->deinit(&udev); + } + if(usb.if_next != NULL) { + usb.if_next->init(&udev, usb.if_next); + usbd_reg_event(&udev, usbd_evt_reset, reset_evt); + FURI_LOG_I(TAG, "USB Mode change done"); + usb.enabled = true; + usb.if_cur = usb.if_next; + } + } + if(flags & EventEnable) { + if((!usb.enabled) && (usb.if_cur != NULL)) { + usbd_connect(&udev, true); + usb.enabled = true; + FURI_LOG_I(TAG, "USB Enable"); + } + } + if(flags & EventDisable) { + if(usb.enabled) { + susp_evt(&udev, 0, 0); + usbd_connect(&udev, false); + usb.enabled = false; + usb_request_pending = false; + FURI_LOG_I(TAG, "USB Disable"); + } + } + if(flags & EventReset) { + usb_request_pending = true; + usb_wait_time = 0; + } + if(flags & EventRequest) { + usb_request_pending = false; + } + } else if(usb_request_pending) { + usb_wait_time++; + if(usb_wait_time > 4) { + furi_hal_usb_reinit(); + usb_request_pending = false; + } + } } + return 0; } diff --git a/firmware/targets/f7/furi_hal/furi_hal_vcp.c b/firmware/targets/f7/furi_hal/furi_hal_vcp.c index 4ac59ae3..409a61a0 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_vcp.c +++ b/firmware/targets/f7/furi_hal/furi_hal_vcp.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -65,7 +65,7 @@ void furi_hal_vcp_init() { vcp->rx_stream = xStreamBufferCreate(VCP_RX_BUF_SIZE, 1); vcp->thread = furi_thread_alloc(); - furi_thread_set_name(vcp->thread, "VcpWorker"); + furi_thread_set_name(vcp->thread, "VcpDriver"); furi_thread_set_stack_size(vcp->thread, 1024); furi_thread_set_callback(vcp->thread, vcp_worker); furi_thread_start(vcp->thread); @@ -79,6 +79,7 @@ static int32_t vcp_worker(void* context) { size_t missed_rx = 0; uint8_t last_tx_pkt_len = 0; + furi_hal_usb_set_config(&usb_cdc_single); furi_hal_cdc_set_callbacks(VCP_IF_NUM, &cdc_cb, NULL); while(1) { -- cgit v1.2.3