diff --git a/applications/services/cli/cli_vcp.c b/applications/services/cli/cli_vcp.c index cdabaaa05..a74710284 100644 --- a/applications/services/cli/cli_vcp.c +++ b/applications/services/cli/cli_vcp.c @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include #define TAG "CliVcp" @@ -43,6 +47,13 @@ typedef struct { FuriHalUsbInterface* usb_if_prev; uint8_t data_buffer[USB_CDC_PKT_LEN]; + + // CLI icon + Gui* gui; + ViewPort* view_port; + + // Autolocking inhibition + Desktop* desktop; } CliVcp; static int32_t vcp_worker(void* context); @@ -64,6 +75,13 @@ static CliVcp* vcp = NULL; static const uint8_t ascii_soh = 0x01; static const uint8_t ascii_eot = 0x04; +static void cli_vcp_icon_draw_callback(Canvas* canvas, void* context) { + furi_assert(canvas); + furi_assert(context); + const Icon* icon = context; + canvas_draw_icon(canvas, 0, 0, icon); +} + static void cli_vcp_init(void) { if(vcp == NULL) { vcp = malloc(sizeof(CliVcp)); @@ -103,6 +121,15 @@ static int32_t vcp_worker(void* context) { FURI_LOG_D(TAG, "Start"); vcp->running = true; + // GUI icon + vcp->desktop = furi_record_open(RECORD_DESKTOP); + const Icon* icon = &I_Console_active_8x8; + vcp->gui = furi_record_open(RECORD_GUI); + vcp->view_port = view_port_alloc(); + view_port_set_width(vcp->view_port, icon_get_width(icon)); + // casting const away. we know that we cast it right back in the callback + view_port_draw_callback_set(vcp->view_port, cli_vcp_icon_draw_callback, (void*)icon); + while(1) { uint32_t flags = furi_thread_flags_wait(VCP_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever); @@ -115,6 +142,8 @@ static int32_t vcp_worker(void* context) { if(vcp->connected == false) { vcp->connected = true; furi_stream_buffer_send(vcp->rx_stream, &ascii_soh, 1, FuriWaitForever); + gui_add_view_port(vcp->gui, vcp->view_port, GuiLayerStatusBarLeft); + desktop_api_add_external_inhibitor(vcp->desktop); } } @@ -126,6 +155,8 @@ static int32_t vcp_worker(void* context) { vcp->connected = false; furi_stream_buffer_receive(vcp->tx_stream, vcp->data_buffer, USB_CDC_PKT_LEN, 0); furi_stream_buffer_send(vcp->rx_stream, &ascii_eot, 1, FuriWaitForever); + gui_remove_view_port(vcp->gui, vcp->view_port); + desktop_api_remove_external_inhibitor(vcp->desktop); } } @@ -190,6 +221,10 @@ static int32_t vcp_worker(void* context) { } if(flags & VcpEvtStop) { + if(vcp->connected) { + gui_remove_view_port(vcp->gui, vcp->view_port); + desktop_api_remove_external_inhibitor(vcp->desktop); + } vcp->connected = false; vcp->running = false; furi_hal_cdc_set_callbacks(VCP_IF_NUM, NULL, NULL); @@ -203,6 +238,11 @@ static int32_t vcp_worker(void* context) { break; } } + + view_port_free(vcp->view_port); + furi_record_close(RECORD_DESKTOP); + furi_record_close(RECORD_GUI); + FURI_LOG_D(TAG, "End"); return 0; } diff --git a/applications/services/desktop/desktop.c b/applications/services/desktop/desktop.c index e57e1eb00..ceea867ba 100644 --- a/applications/services/desktop/desktop.c +++ b/applications/services/desktop/desktop.c @@ -19,6 +19,8 @@ static void desktop_auto_lock_arm(Desktop*); static void desktop_auto_lock_inhibit(Desktop*); static void desktop_start_auto_lock_timer(Desktop*); static void desktop_apply_settings(Desktop*); +static void desktop_auto_lock_add_inhibitor(Desktop* desktop); +static void desktop_auto_lock_remove_inhibitor(Desktop* desktop); static void desktop_loader_callback(const void* message, void* context) { furi_assert(context); @@ -130,16 +132,22 @@ static bool desktop_custom_event_callback(void* context, uint32_t event) { animation_manager_unload_and_stall_animation(desktop->animation_manager); } - desktop_auto_lock_inhibit(desktop); + desktop_auto_lock_add_inhibitor(desktop); desktop->app_running = true; furi_semaphore_release(desktop->animation_semaphore); } else if(event == DesktopGlobalAfterAppFinished) { animation_manager_load_and_continue_animation(desktop->animation_manager); - desktop_auto_lock_arm(desktop); + desktop_auto_lock_remove_inhibitor(desktop); desktop->app_running = false; + } else if(event == DesktopGlobalAddExternalInhibitor) { + desktop_auto_lock_add_inhibitor(desktop); + + } else if(event == DesktopGlobalRemoveExternalInhibitor) { + desktop_auto_lock_remove_inhibitor(desktop); + } else if(event == DesktopGlobalAutoLock) { if(!desktop->app_running && !desktop->locked) { desktop_lock(desktop); @@ -205,6 +213,24 @@ static void desktop_auto_lock_arm(Desktop* desktop) { } } +static void desktop_auto_lock_add_inhibitor(Desktop* desktop) { + furi_check(furi_semaphore_release(desktop->auto_lock_inhibitors) == FuriStatusOk); + FURI_LOG_D( + TAG, + "%lu autolock inhibitors (+1)", + furi_semaphore_get_count(desktop->auto_lock_inhibitors)); + desktop_auto_lock_inhibit(desktop); +} + +static void desktop_auto_lock_remove_inhibitor(Desktop* desktop) { + furi_check(furi_semaphore_acquire(desktop->auto_lock_inhibitors, 0) == FuriStatusOk); + uint32_t inhibitors = furi_semaphore_get_count(desktop->auto_lock_inhibitors); + FURI_LOG_D(TAG, "%lu autolock inhibitors (-1)", inhibitors); + if(inhibitors == 0) { + desktop_auto_lock_arm(desktop); + } +} + static void desktop_auto_lock_inhibit(Desktop* desktop) { desktop_stop_auto_lock_timer(desktop); if(desktop->input_events_subscription) { @@ -371,6 +397,7 @@ static Desktop* desktop_alloc(void) { desktop->notification = furi_record_open(RECORD_NOTIFICATION); desktop->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); + desktop->auto_lock_inhibitors = furi_semaphore_alloc(UINT32_MAX, 0); desktop->auto_lock_timer = furi_timer_alloc(desktop_auto_lock_timer_callback, FuriTimerTypeOnce, desktop); @@ -503,6 +530,18 @@ void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings view_dispatcher_send_custom_event(instance->view_dispatcher, DesktopGlobalSaveSettings); } +void desktop_api_add_external_inhibitor(Desktop* instance) { + furi_assert(instance); + view_dispatcher_send_custom_event( + instance->view_dispatcher, DesktopGlobalAddExternalInhibitor); +} + +void desktop_api_remove_external_inhibitor(Desktop* instance) { + furi_assert(instance); + view_dispatcher_send_custom_event( + instance->view_dispatcher, DesktopGlobalRemoveExternalInhibitor); +} + /* * Application thread */ @@ -523,7 +562,7 @@ int32_t desktop_srv(void* p) { scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); - if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { + if(desktop_pin_code_is_set()) { desktop_lock(desktop); } diff --git a/applications/services/desktop/desktop.h b/applications/services/desktop/desktop.h index e83bc3ee4..4f1556f7c 100644 --- a/applications/services/desktop/desktop.h +++ b/applications/services/desktop/desktop.h @@ -21,3 +21,17 @@ FuriPubSub* desktop_api_get_status_pubsub(Desktop* instance); void desktop_api_get_settings(Desktop* instance, DesktopSettings* settings); void desktop_api_set_settings(Desktop* instance, const DesktopSettings* settings); + +/** + * @brief Adds 1 to the count of active external autolock inhibitors + * + * Autolocking will not get triggered while there's at least 1 inhibitor + */ +void desktop_api_add_external_inhibitor(Desktop* instance); + +/** + * @brief Removes 1 from the count of active external autolock inhibitors + * + * Autolocking will not get triggered while there's at least 1 inhibitor + */ +void desktop_api_remove_external_inhibitor(Desktop* instance); diff --git a/applications/services/desktop/desktop_i.h b/applications/services/desktop/desktop_i.h index 1dc7c7d21..b62dac63c 100644 --- a/applications/services/desktop/desktop_i.h +++ b/applications/services/desktop/desktop_i.h @@ -73,6 +73,7 @@ struct Desktop { FuriPubSub* input_events_pubsub; FuriPubSubSubscription* input_events_subscription; + FuriSemaphore* auto_lock_inhibitors; FuriTimer* auto_lock_timer; FuriTimer* update_clock_timer; diff --git a/applications/services/desktop/views/desktop_events.h b/applications/services/desktop/views/desktop_events.h index ba91a30cc..e0e4aa875 100644 --- a/applications/services/desktop/views/desktop_events.h +++ b/applications/services/desktop/views/desktop_events.h @@ -62,4 +62,6 @@ typedef enum { DesktopGlobalApiUnlock, DesktopGlobalSaveSettings, DesktopGlobalReloadSettings, + DesktopGlobalAddExternalInhibitor, + DesktopGlobalRemoveExternalInhibitor, } DesktopEvent; diff --git a/assets/icons/StatusBar/Console_active_8x8.png b/assets/icons/StatusBar/Console_active_8x8.png new file mode 100644 index 000000000..f2230a374 Binary files /dev/null and b/assets/icons/StatusBar/Console_active_8x8.png differ diff --git a/scripts/serial_cli.py b/scripts/serial_cli.py index 8e35d57fa..a48647bd5 100644 --- a/scripts/serial_cli.py +++ b/scripts/serial_cli.py @@ -13,7 +13,9 @@ def main(): parser.add_argument("-p", "--port", help="CDC Port", default="auto") args = parser.parse_args() if not (port := resolve_port(logger, args.port)): - logger.error("Is Flipper connected via USB and not in DFU mode?") + logger.error( + "Is Flipper connected via USB, currently unlocked and not in DFU mode?" + ) return 1 subprocess.call( [