From af8d2369ca34fa34c5008f840e6853fd07b59677 Mon Sep 17 00:00:00 2001 From: SHxKenzuto Date: Tue, 23 Aug 2022 21:20:28 +0200 Subject: [PATCH] added "Shutdown on Idle" setting under power settings --- applications/power/power_service/power.c | 83 ++++++++++++++++++- applications/power/power_service/power_i.h | 6 ++ applications/power/power_settings.h | 25 ++++++ .../power_settings_app/power_settings_app.c | 4 + .../power_settings_app/power_settings_app.h | 7 ++ .../scenes/power_settings_scene_config.h | 1 + .../power_settings_scene_shutdown_idle.c | 78 +++++++++++++++++ .../scenes/power_settings_scene_start.c | 9 ++ applications/power/power_settings_filename.h | 3 + 9 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 applications/power/power_settings.h create mode 100644 applications/power/power_settings_app/scenes/power_settings_scene_shutdown_idle.c create mode 100644 applications/power/power_settings_filename.h diff --git a/applications/power/power_service/power.c b/applications/power/power_service/power.c index 9036ae1ce..6c23d6b88 100644 --- a/applications/power/power_service/power.c +++ b/applications/power/power_service/power.c @@ -37,6 +37,65 @@ static ViewPort* power_battery_view_port_alloc(Power* power) { return battery_view_port; } +static void power_start_auto_shutdown_timer(Power* power) { + furi_timer_start(power->auto_shutdown_timer, furi_ms_to_ticks(power->shutdown_idle_delay_ms)); +} + +static void power_stop_auto_shutdown_timer(Power* power) { + furi_timer_stop(power->auto_shutdown_timer); +} + +static void power_input_event_callback(const void* value, void* context) { + furi_assert(value); + furi_assert(context); + const InputEvent* event = value; + Power* power = context; + if(event->type == InputTypePress) { + power_start_auto_shutdown_timer(power); + } +} + +static void power_auto_shutdown_arm(Power* power) { + if(power->shutdown_idle_delay_ms) { + power->input_events_subscription = + furi_pubsub_subscribe(power->input_events_pubsub, power_input_event_callback, power); + power_start_auto_shutdown_timer(power); + } +} + +static void power_auto_shutdown_inhibit(Power* power) { + power_stop_auto_shutdown_timer(power); + if(power->input_events_subscription) { + furi_pubsub_unsubscribe(power->input_events_pubsub, power->input_events_subscription); + power->input_events_subscription = NULL; + } +} + + + +static void power_auto_shutdown_timer_callback(void* context) { + furi_assert(context); + Power* power = context; + power_auto_shutdown_inhibit(power); + power_off(power); +} + +static void auto_shutdown_update(Power* power) { + uint32_t old_time = power->shutdown_idle_delay_ms; + LOAD_POWER_SETTINGS(&power->shutdown_idle_delay_ms); + if(power->shutdown_idle_delay_ms) { + if(power->shutdown_idle_delay_ms != old_time) { + if(old_time) { + power_start_auto_shutdown_timer(power); + } else { + power_auto_shutdown_arm(power); + } + } + }else if(old_time){ + power_auto_shutdown_inhibit(power); + } +} + Power* power_alloc() { Power* power = malloc(sizeof(Power)); @@ -47,6 +106,9 @@ Power* power_alloc() { // Pubsub power->event_pubsub = furi_pubsub_alloc(); + power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS); + power->input_events_subscription = NULL; + // State initialization power->state = PowerStateNotCharging; power->battery_low = false; @@ -69,6 +131,10 @@ Power* power_alloc() { power->battery_view_port = power_battery_view_port_alloc(power); power->show_low_bat_level_message = true; + //Auto shutdown timer + power->auto_shutdown_timer = + furi_timer_alloc(power_auto_shutdown_timer_callback, FuriTimerTypeOnce, power); + return power; } @@ -87,6 +153,12 @@ void power_free(Power* power) { // FuriPubSub furi_pubsub_free(power->event_pubsub); + furi_pubsub_free(power->input_events_pubsub); + + if(power->input_events_subscription) { + furi_pubsub_unsubscribe(power->input_events_pubsub, power->input_events_subscription); + power->input_events_subscription = NULL; + } // Records furi_record_close(RECORD_NOTIFICATION); @@ -202,10 +274,19 @@ static void power_check_battery_level_change(Power* power) { int32_t power_srv(void* p) { UNUSED(p); Power* power = power_alloc(); + if(!LOAD_POWER_SETTINGS(&power->shutdown_idle_delay_ms)) { + memset(&power->shutdown_idle_delay_ms, 0, sizeof(uint32_t)); + SAVE_POWER_SETTINGS(&power->shutdown_idle_delay_ms); + } + power_auto_shutdown_arm(power); power_update_info(power); furi_record_create(RECORD_POWER, power); while(1) { + + //Check current setting for automatic shutdown + auto_shutdown_update(power); + // Update data from gauge and charger bool need_refresh = power_update_info(power); @@ -228,7 +309,7 @@ int32_t power_srv(void* p) { furi_delay_ms(1000); } - + power_auto_shutdown_inhibit(power); power_free(power); return 0; diff --git a/applications/power/power_service/power_i.h b/applications/power/power_service/power_i.h index c7181d0a1..f93d91c02 100755 --- a/applications/power/power_service/power_i.h +++ b/applications/power/power_service/power_i.h @@ -8,6 +8,7 @@ #include #include "views/power_off.h" +#include "power/power_settings.h" #include @@ -28,6 +29,8 @@ struct Power { Gui* gui; NotificationApp* notification; FuriPubSub* event_pubsub; + FuriPubSub* input_events_pubsub; + FuriPubSubSubscription* input_events_subscription; PowerEvent event; PowerState state; @@ -38,6 +41,9 @@ struct Power { uint8_t battery_level; uint8_t power_off_timeout; + uint32_t shutdown_idle_delay_ms; + FuriTimer* auto_shutdown_timer; + FuriMutex* api_mtx; }; diff --git a/applications/power/power_settings.h b/applications/power/power_settings.h new file mode 100644 index 000000000..52ae02934 --- /dev/null +++ b/applications/power/power_settings.h @@ -0,0 +1,25 @@ +#include +#include +#include "power_settings_filename.h" + +#define POWER_SETTINGS_VER (1) + +#define POWER_SETTINGS_PATH INT_PATH(POWER_SETTINGS_FILE_NAME) +#define POWER_SETTINGS_MAGIC (0x21) + +#define SAVE_POWER_SETTINGS(x) \ + saved_struct_save( \ + POWER_SETTINGS_PATH, \ + (x), \ + sizeof(uint32_t), \ + POWER_SETTINGS_MAGIC, \ + POWER_SETTINGS_VER) + + +#define LOAD_POWER_SETTINGS(x) \ + saved_struct_load( \ + POWER_SETTINGS_PATH, \ + (x), \ + sizeof(uint32_t), \ + POWER_SETTINGS_MAGIC, \ + POWER_SETTINGS_VER) diff --git a/applications/power/power_settings_app/power_settings_app.c b/applications/power/power_settings_app/power_settings_app.c index b01f32f75..c900fcd75 100644 --- a/applications/power/power_settings_app/power_settings_app.c +++ b/applications/power/power_settings_app/power_settings_app.c @@ -45,11 +45,13 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) { PowerSettingsAppViewBatteryInfo, battery_info_get_view(app->batery_info)); app->submenu = submenu_alloc(); + app->variable_item_list = variable_item_list_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewSubmenu, submenu_get_view(app->submenu)); app->dialog = dialog_ex_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewDialog, dialog_ex_get_view(app->dialog)); + view_dispatcher_add_view(app->view_dispatcher, PowerSettingsAppViewVariableItemList, variable_item_list_get_view(app->variable_item_list)); // Set first scene scene_manager_next_scene(app->scene_manager, first_scene); @@ -63,8 +65,10 @@ void power_settings_app_free(PowerSettingsApp* app) { battery_info_free(app->batery_info); view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewSubmenu); submenu_free(app->submenu); + variable_item_list_free(app->variable_item_list); view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewDialog); dialog_ex_free(app->dialog); + view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewVariableItemList); // View dispatcher view_dispatcher_free(app->view_dispatcher); scene_manager_free(app->scene_manager); diff --git a/applications/power/power_settings_app/power_settings_app.h b/applications/power/power_settings_app/power_settings_app.h index 8429b54b4..32e4e5928 100644 --- a/applications/power/power_settings_app/power_settings_app.h +++ b/applications/power/power_settings_app/power_settings_app.h @@ -10,7 +10,9 @@ #include "views/battery_info.h" #include #include +#include +#include "power/power_settings.h" #include "scenes/power_settings_scene.h" typedef struct { @@ -22,10 +24,15 @@ typedef struct { Submenu* submenu; DialogEx* dialog; PowerInfo info; + VariableItemList* variable_item_list; + uint32_t shutdown_idle_delay_ms; } PowerSettingsApp; typedef enum { PowerSettingsAppViewBatteryInfo, PowerSettingsAppViewSubmenu, PowerSettingsAppViewDialog, + PowerSettingsAppViewVariableItemList } PowerSettingsAppView; + + diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_config.h b/applications/power/power_settings_app/scenes/power_settings_scene_config.h index cc8656dcf..3b4fc26cc 100755 --- a/applications/power/power_settings_app/scenes/power_settings_scene_config.h +++ b/applications/power/power_settings_app/scenes/power_settings_scene_config.h @@ -2,3 +2,4 @@ ADD_SCENE(power_settings, start, Start) ADD_SCENE(power_settings, battery_info, BatteryInfo) ADD_SCENE(power_settings, reboot, Reboot) ADD_SCENE(power_settings, power_off, PowerOff) +ADD_SCENE(power_settings,shutdown_idle, ShutdownIdle) diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_shutdown_idle.c b/applications/power/power_settings_app/scenes/power_settings_scene_shutdown_idle.c new file mode 100644 index 000000000..cd07ac49f --- /dev/null +++ b/applications/power/power_settings_app/scenes/power_settings_scene_shutdown_idle.c @@ -0,0 +1,78 @@ +#include "../power_settings_app.h" +#include + +#define SHUTDOWN_IDLE_DELAY_COUNT 8 +#define SCENE_EVENT_SELECT_SHUTDOWN_IDLE_DELAY 0 + +const char* const shutdown_idle_delay_text[SHUTDOWN_IDLE_DELAY_COUNT] = { + "OFF", + "15min", + "30min", + "1h", + "6h", + "12h", + "24h", + "48h" +}; + +const uint32_t shutdown_idle_delay_value[SHUTDOWN_IDLE_DELAY_COUNT] = + {0, 900000, 1800000, 3600000, 21600000, 43200000, 86400000, 172800000}; + + static void power_settings_scene_shutodwn_idle_callback(void* context, uint32_t index) { + PowerSettingsApp* app = context; + view_dispatcher_send_custom_event(app->view_dispatcher, index); +} + +static void power_settings_scene_start_shutdown_idle_delay_changed(VariableItem* item) { + PowerSettingsApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + + variable_item_set_current_value_text(item, shutdown_idle_delay_text[index]); + app->shutdown_idle_delay_ms = shutdown_idle_delay_value[index]; +} + +void power_settings_scene_shutdown_idle_on_enter(void* context) { + PowerSettingsApp* app = context; + LOAD_POWER_SETTINGS(&app->shutdown_idle_delay_ms); + VariableItemList* variable_item_list = app->variable_item_list; + VariableItem* item; + uint8_t value_index; + + item = variable_item_list_add( + variable_item_list, + "Set Time", + SHUTDOWN_IDLE_DELAY_COUNT, + power_settings_scene_start_shutdown_idle_delay_changed, + app); + + + variable_item_list_set_enter_callback( + variable_item_list, power_settings_scene_shutodwn_idle_callback, app); + + value_index = value_index_uint32( + app->shutdown_idle_delay_ms, shutdown_idle_delay_value, SHUTDOWN_IDLE_DELAY_COUNT); + variable_item_set_current_value_index(item, value_index); + variable_item_set_current_value_text(item, shutdown_idle_delay_text[value_index]); + + view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewVariableItemList); +} + +bool power_settings_scene_shutdown_idle_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + switch(event.event) { + case SCENE_EVENT_SELECT_SHUTDOWN_IDLE_DELAY: + consumed = true; + break; + } + } + return consumed; +} + +void power_settings_scene_shutdown_idle_on_exit(void* context) { + PowerSettingsApp* app = context; + SAVE_POWER_SETTINGS(&app->shutdown_idle_delay_ms); + variable_item_list_reset(app->variable_item_list); +} diff --git a/applications/power/power_settings_app/scenes/power_settings_scene_start.c b/applications/power/power_settings_app/scenes/power_settings_scene_start.c index 63f123d89..e54b6374d 100755 --- a/applications/power/power_settings_app/scenes/power_settings_scene_start.c +++ b/applications/power/power_settings_app/scenes/power_settings_scene_start.c @@ -4,6 +4,7 @@ enum PowerSettingsSubmenuIndex { PowerSettingsSubmenuIndexBatteryInfo, PowerSettingsSubmenuIndexReboot, PowerSettingsSubmenuIndexOff, + PowerSettingsSubmenuShutdownIdle }; static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) { @@ -34,6 +35,12 @@ void power_settings_scene_start_on_enter(void* context) { PowerSettingsSubmenuIndexOff, power_settings_scene_start_submenu_callback, app); + submenu_add_item( + submenu, + "Shutdown on Idle", + PowerSettingsSubmenuShutdownIdle, + power_settings_scene_start_submenu_callback, + app); submenu_set_selected_item( submenu, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart)); @@ -51,6 +58,8 @@ bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneReboot); } else if(event.event == PowerSettingsSubmenuIndexOff) { scene_manager_next_scene(app->scene_manager, PowerSettingsAppScenePowerOff); + }else if(event.event == PowerSettingsSubmenuShutdownIdle){ + scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneShutdownIdle); } scene_manager_set_scene_state(app->scene_manager, PowerSettingsAppSceneStart, event.event); consumed = true; diff --git a/applications/power/power_settings_filename.h b/applications/power/power_settings_filename.h new file mode 100644 index 000000000..6a3be534c --- /dev/null +++ b/applications/power/power_settings_filename.h @@ -0,0 +1,3 @@ +#pragma once + +#define POWER_SETTINGS_FILE_NAME ".power.settings" \ No newline at end of file