diff --git a/applications/applications.c b/applications/applications.c index 7b125f6a..8153dcfa 100644 --- a/applications/applications.c +++ b/applications/applications.c @@ -11,7 +11,6 @@ extern int32_t gui_srv(void* p); extern int32_t input_srv(void* p); extern int32_t loader_srv(void* p); extern int32_t notification_srv(void* p); -extern int32_t power_observer_srv(void* p); extern int32_t power_srv(void* p); extern int32_t storage_srv(void* p); extern int32_t desktop_srv(void* p); @@ -115,10 +114,6 @@ const FlipperApplication FLIPPER_SERVICES[] = { {.app = power_srv, .name = "PowerSrv", .stack_size = 1024, .icon = NULL}, #endif -#ifdef SRV_POWER_OBSERVER - {.app = power_observer_srv, .name = "PowerAuditSrv", .stack_size = 1024, .icon = NULL}, -#endif - #ifdef SRV_STORAGE {.app = storage_srv, .name = "StorageSrv", .stack_size = 3072, .icon = NULL}, #endif diff --git a/applications/applications.mk b/applications/applications.mk index aa17e05f..5733e761 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -18,7 +18,6 @@ SRV_INPUT = 1 SRV_LOADER = 1 SRV_NOTIFICATION = 1 SRV_POWER = 1 -SRV_POWER_OBSERVER = 1 SRV_RPC = 1 SRV_STORAGE = 1 @@ -256,13 +255,6 @@ endif endif -SRV_POWER_OBSERVER ?= 0 -ifeq ($(SRV_POWER_OBSERVER), 1) -CFLAGS += -DSRV_POWER_OBSERVER -SRV_POWER = 1 -endif - - SRV_POWER ?= 0 ifeq ($(SRV_POWER), 1) CFLAGS += -DSRV_POWER diff --git a/applications/power/power_service/power.c b/applications/power/power_service/power.c index 2659e2ec..3934b20d 100755 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -196,6 +196,11 @@ int32_t power_srv(void* p) { // Update battery view port if(need_refresh) view_port_update(power->battery_view_port); + // Check OTG status and disable it in case of fault + if(furi_hal_power_is_otg_enabled()) { + furi_hal_power_check_otg_status(); + } + osDelay(1000); } diff --git a/applications/power_observer/power_observer.c b/applications/power_observer/power_observer.c deleted file mode 100644 index b32447f0..00000000 --- a/applications/power_observer/power_observer.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include - -typedef struct { - osThreadId_t thread; - -} PowerObserverSrv; - -const NotificationMessage message_green_110 = { - .type = NotificationMessageTypeLedGreen, - .data.led.value = 110, -}; - -static const NotificationSequence sequence_overconsumption = { - &message_green_110, - &message_red_255, - &message_delay_100, - NULL, -}; - -typedef enum { - EventReset = (1 << 0), - EventRequest = (1 << 1), -} UsbEvent; - -static void usb_state_callback(FuriHalUsbStateEvent state, void* context) { - PowerObserverSrv* srv = (PowerObserverSrv*)(context); - if(state == FuriHalUsbStateEventReset) { - osThreadFlagsSet(srv->thread, EventReset); - } else if(state == FuriHalUsbStateEventDescriptorRequest) { - osThreadFlagsSet(srv->thread, EventRequest); - } -} - -int32_t power_observer_srv(void* p) { - NotificationApp* notifications = furi_record_open("notification"); - PowerObserverSrv* srv = furi_alloc(sizeof(PowerObserverSrv)); - srv->thread = osThreadGetId(); - - const float overconsumption_limit = 0.03f; - bool usb_request_pending = false; - uint8_t usb_wait_time = 0; - - furi_hal_usb_set_state_callback(usb_state_callback, srv); - - while(true) { - uint32_t flags = osThreadFlagsWait(EventReset | EventRequest, osFlagsWaitAny, 500); - if((flags & osFlagsError) == 0) { - 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; - } - } - - float current = -furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge); - if(current > overconsumption_limit) { - notification_message_block(notifications, &sequence_overconsumption); - } - if(furi_hal_power_is_otg_enabled()) { - furi_hal_power_check_otg_status(); - } - } - - free(srv); - return 0; -} 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) { diff --git a/lib/ST25RFAL002/platform.c b/lib/ST25RFAL002/platform.c index a88b1acb..a4759f2a 100644 --- a/lib/ST25RFAL002/platform.c +++ b/lib/ST25RFAL002/platform.c @@ -5,7 +5,7 @@ #include static const osThreadAttr_t platform_irq_thread_attr = { - .name = "RfalIrqWorker", + .name = "RfalIrqDriver", .stack_size = 1024, .priority = osPriorityRealtime, }; @@ -20,7 +20,7 @@ void nfc_isr(void* _ctx) { } } -void platformIrqWorker() { +void platformIrqThread() { while(1) { uint32_t flags = osThreadFlagsWait(0x1, osFlagsWaitAny, osWaitForever); if(flags & 0x1) { @@ -41,7 +41,7 @@ void platformDisableIrqCallback() { void platformSetIrqCallback(PlatformIrqCallback callback) { platform_irq_callback = callback; - platform_irq_thread_id = osThreadNew(platformIrqWorker, NULL, &platform_irq_thread_attr); + platform_irq_thread_id = osThreadNew(platformIrqThread, NULL, &platform_irq_thread_attr); hal_gpio_add_int_callback(&pin, nfc_isr, NULL); // Disable interrupt callback as the pin is shared between 2 apps // It is enabled in rfalLowPowerModeStop()