mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge Power service refactor, rework power settings
- Merge OFW power service refactor stuff - Move charge cap variable to service - Mirror settings usage of desktop and bt services for power settings - Proper power settings struct, no more weird settings pubsub - Load power settings on SD insert - Set shutdown on idle time in main power settings menu, not in submenu - Update battery icon visibility in power tick event - Remove unused power functions (power_trigger_ui_update(), power_set_battery_icon_enabled())
This commit is contained in:
@@ -28,8 +28,6 @@ static void momentum_app_scene_interface_statusbar_battery_icon_changed(Variable
|
||||
variable_item_set_current_value_text(item, battery_icon_names[index]);
|
||||
momentum_settings.battery_icon = index;
|
||||
app->save_settings = true;
|
||||
power_set_battery_icon_enabled(furi_record_open(RECORD_POWER), index != BatteryIconOff);
|
||||
furi_record_close(RECORD_POWER);
|
||||
}
|
||||
|
||||
static void momentum_app_scene_interface_statusbar_statusbar_clock_changed(VariableItem* item) {
|
||||
|
||||
@@ -4,17 +4,18 @@
|
||||
#include <furi_hal.h>
|
||||
#include <momentum/momentum.h>
|
||||
|
||||
#include <update_util/update_operation.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#define TAG "Power"
|
||||
|
||||
#define POWER_OFF_TIMEOUT 90
|
||||
#define POWER_OFF_TIMEOUT_S (90U)
|
||||
#define POWER_POLL_PERIOD_MS (1000UL)
|
||||
|
||||
void power_set_battery_icon_enabled(Power* power, bool is_enabled) {
|
||||
furi_assert(power);
|
||||
#define POWER_VBUS_LOW_THRESHOLD (4.0f)
|
||||
#define POWER_HEALTH_LOW_THRESHOLD (70U)
|
||||
|
||||
view_port_enabled_set(power->battery_view_port, is_enabled);
|
||||
}
|
||||
|
||||
void power_draw_battery_callback(Canvas* canvas, void* context) {
|
||||
static void power_draw_battery_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
Power* power = context;
|
||||
BatteryIcon battery_icon = momentum_settings.battery_icon;
|
||||
@@ -237,6 +238,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) {
|
||||
}
|
||||
canvas_set_bitmap_mode(canvas, false);
|
||||
}
|
||||
|
||||
} else {
|
||||
canvas_draw_box(canvas, 8, 3, 8, 2);
|
||||
}
|
||||
@@ -246,12 +248,12 @@ static ViewPort* power_battery_view_port_alloc(Power* power) {
|
||||
ViewPort* battery_view_port = view_port_alloc();
|
||||
view_port_set_width(battery_view_port, icon_get_width(&I_Battery_25x8));
|
||||
view_port_draw_callback_set(battery_view_port, power_draw_battery_callback, power);
|
||||
gui_add_view_port(power->gui, battery_view_port, GuiLayerStatusBarRight);
|
||||
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));
|
||||
furi_timer_start(
|
||||
power->auto_shutdown_timer, furi_ms_to_ticks(power->settings.shutdown_idle_delay_ms));
|
||||
}
|
||||
|
||||
static void power_stop_auto_shutdown_timer(Power* power) {
|
||||
@@ -271,7 +273,7 @@ static void power_auto_shutdown_callback(const void* value, void* context) {
|
||||
}
|
||||
|
||||
static void power_auto_shutdown_arm(Power* power) {
|
||||
if(power->shutdown_idle_delay_ms) {
|
||||
if(power->settings.shutdown_idle_delay_ms) {
|
||||
if(power->input_events_subscription == NULL) {
|
||||
power->input_events_subscription = furi_pubsub_subscribe(
|
||||
power->input_events_pubsub, power_auto_shutdown_callback, power);
|
||||
@@ -302,14 +304,31 @@ static void power_loader_callback(const void* message, void* context) {
|
||||
const LoaderEvent* event = message;
|
||||
|
||||
if(event->type == LoaderEventTypeApplicationBeforeLoad) {
|
||||
power->app_running = true;
|
||||
power_auto_shutdown_inhibit(power);
|
||||
} else if(
|
||||
event->type == LoaderEventTypeApplicationLoadFailed ||
|
||||
event->type == LoaderEventTypeApplicationStopped) {
|
||||
power->app_running = false;
|
||||
power_auto_shutdown_arm(power);
|
||||
}
|
||||
}
|
||||
|
||||
static void power_storage_callback(const void* message, void* context) {
|
||||
furi_assert(context);
|
||||
Power* power = context;
|
||||
const StorageEvent* event = message;
|
||||
|
||||
if(event->type == StorageEventTypeCardMount) {
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeReloadSettings,
|
||||
};
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
}
|
||||
}
|
||||
|
||||
static void power_auto_shutdown_timer_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Power* power = context;
|
||||
@@ -317,121 +336,66 @@ static void power_auto_shutdown_timer_callback(void* context) {
|
||||
power_off(power);
|
||||
}
|
||||
|
||||
static void power_shutdown_time_changed_callback(const void* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
Power* power = context;
|
||||
power->shutdown_idle_delay_ms = *(uint32_t*)event;
|
||||
if(power->shutdown_idle_delay_ms) {
|
||||
static void power_apply_settings(Power* power) {
|
||||
if(power->settings.shutdown_idle_delay_ms && !power->app_running) {
|
||||
power_auto_shutdown_arm(power);
|
||||
} else if(power_is_running_auto_shutdown_timer(power)) {
|
||||
power_auto_shutdown_inhibit(power);
|
||||
}
|
||||
}
|
||||
|
||||
Power* power_alloc(void) {
|
||||
Power* power = malloc(sizeof(Power));
|
||||
static bool power_update_info(Power* power) {
|
||||
const PowerInfo info = {
|
||||
.is_charging = furi_hal_power_is_charging(),
|
||||
.gauge_is_ok = furi_hal_power_gauge_is_ok(),
|
||||
.is_shutdown_requested = furi_hal_power_is_shutdown_requested(),
|
||||
.charge = furi_hal_power_get_pct(),
|
||||
.health = furi_hal_power_get_bat_health_pct(),
|
||||
.capacity_remaining = furi_hal_power_get_battery_remaining_capacity(),
|
||||
.capacity_full = furi_hal_power_get_battery_full_capacity(),
|
||||
.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger),
|
||||
.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge),
|
||||
.voltage_battery_charge_limit = furi_hal_power_get_battery_charge_voltage_limit(),
|
||||
.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger),
|
||||
.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge),
|
||||
.voltage_vbus = furi_hal_power_get_usb_voltage(),
|
||||
.temperature_charger = furi_hal_power_get_battery_temperature(FuriHalPowerICCharger),
|
||||
.temperature_gauge = furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge),
|
||||
};
|
||||
|
||||
// Records
|
||||
power->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
power->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// Pubsub
|
||||
power->event_pubsub = furi_pubsub_alloc();
|
||||
power->settings_events = furi_pubsub_alloc();
|
||||
power->loader = furi_record_open(RECORD_LOADER);
|
||||
power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS);
|
||||
power->input_events_subscription = NULL;
|
||||
power->ascii_events_pubsub = furi_record_open(RECORD_ASCII_EVENTS);
|
||||
power->ascii_events_subscription = NULL;
|
||||
power->app_start_stop_subscription =
|
||||
furi_pubsub_subscribe(loader_get_pubsub(power->loader), power_loader_callback, power);
|
||||
power->settings_events_subscription =
|
||||
furi_pubsub_subscribe(power->settings_events, power_shutdown_time_changed_callback, power);
|
||||
|
||||
// State initialization
|
||||
power->state = PowerStateNotCharging;
|
||||
power->battery_low = false;
|
||||
power->power_off_timeout = POWER_OFF_TIMEOUT;
|
||||
power->api_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
|
||||
// Gui
|
||||
power->view_dispatcher = view_dispatcher_alloc();
|
||||
power->power_off = power_off_alloc();
|
||||
view_dispatcher_add_view(
|
||||
power->view_dispatcher, PowerViewOff, power_off_get_view(power->power_off));
|
||||
power->power_unplug_usb = power_unplug_usb_alloc();
|
||||
view_dispatcher_add_view(
|
||||
power->view_dispatcher,
|
||||
PowerViewUnplugUsb,
|
||||
power_unplug_usb_get_view(power->power_unplug_usb));
|
||||
view_dispatcher_attach_to_gui(power->view_dispatcher, power->gui, ViewDispatcherTypeDesktop);
|
||||
|
||||
// Battery view port
|
||||
power->battery_view_port = power_battery_view_port_alloc(power);
|
||||
power_set_battery_icon_enabled(power, momentum_settings.battery_icon != BatteryIconOff);
|
||||
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;
|
||||
const bool need_refresh = (power->info.charge != info.charge) ||
|
||||
(power->info.is_charging != info.is_charging);
|
||||
power->info = info;
|
||||
return need_refresh;
|
||||
}
|
||||
|
||||
static void power_check_charging_state(Power* power) {
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
if(furi_hal_power_is_charging()) {
|
||||
if((power->info.charge == 100) || (furi_hal_power_is_charging_done())) {
|
||||
if(power->state != PowerStateCharged) {
|
||||
notification_internal_message(power->notification, &sequence_charged);
|
||||
notification_internal_message(notification, &sequence_charged);
|
||||
power->state = PowerStateCharged;
|
||||
power->event.type = PowerEventTypeFullyCharged;
|
||||
furi_pubsub_publish(power->event_pubsub, &power->event);
|
||||
}
|
||||
} else {
|
||||
if(power->state != PowerStateCharging) {
|
||||
notification_internal_message(power->notification, &sequence_charging);
|
||||
power->state = PowerStateCharging;
|
||||
power->event.type = PowerEventTypeStartCharging;
|
||||
furi_pubsub_publish(power->event_pubsub, &power->event);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(power->state != PowerStateNotCharging) {
|
||||
notification_internal_message(power->notification, &sequence_not_charging);
|
||||
power->state = PowerStateNotCharging;
|
||||
power->event.type = PowerEventTypeStopCharging;
|
||||
|
||||
} else if(power->state != PowerStateCharging) {
|
||||
notification_internal_message(notification, &sequence_charging);
|
||||
power->state = PowerStateCharging;
|
||||
power->event.type = PowerEventTypeStartCharging;
|
||||
furi_pubsub_publish(power->event_pubsub, &power->event);
|
||||
}
|
||||
|
||||
} else if(power->state != PowerStateNotCharging) {
|
||||
notification_internal_message(notification, &sequence_not_charging);
|
||||
power->state = PowerStateNotCharging;
|
||||
power->event.type = PowerEventTypeStopCharging;
|
||||
furi_pubsub_publish(power->event_pubsub, &power->event);
|
||||
}
|
||||
}
|
||||
|
||||
static bool power_update_info(Power* power) {
|
||||
PowerInfo info;
|
||||
|
||||
info.is_charging = furi_hal_power_is_charging();
|
||||
info.gauge_is_ok = furi_hal_power_gauge_is_ok();
|
||||
info.is_shutdown_requested = furi_hal_power_is_shutdown_requested();
|
||||
info.charge = furi_hal_power_get_pct();
|
||||
info.health = furi_hal_power_get_bat_health_pct();
|
||||
info.capacity_remaining = furi_hal_power_get_battery_remaining_capacity();
|
||||
info.capacity_full = furi_hal_power_get_battery_full_capacity();
|
||||
info.current_charger = furi_hal_power_get_battery_current(FuriHalPowerICCharger);
|
||||
info.current_gauge = furi_hal_power_get_battery_current(FuriHalPowerICFuelGauge);
|
||||
info.voltage_battery_charge_limit = furi_hal_power_get_battery_charge_voltage_limit();
|
||||
info.voltage_charger = furi_hal_power_get_battery_voltage(FuriHalPowerICCharger);
|
||||
info.voltage_gauge = furi_hal_power_get_battery_voltage(FuriHalPowerICFuelGauge);
|
||||
info.voltage_vbus = furi_hal_power_get_usb_voltage();
|
||||
info.temperature_charger = furi_hal_power_get_battery_temperature(FuriHalPowerICCharger);
|
||||
info.temperature_gauge = furi_hal_power_get_battery_temperature(FuriHalPowerICFuelGauge);
|
||||
|
||||
furi_mutex_acquire(power->api_mtx, FuriWaitForever);
|
||||
bool need_refresh = power->info.charge != info.charge;
|
||||
need_refresh |= power->info.is_charging != info.is_charging;
|
||||
power->info = info;
|
||||
furi_mutex_release(power->api_mtx);
|
||||
|
||||
return need_refresh;
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
}
|
||||
|
||||
static void power_check_low_battery(Power* power) {
|
||||
@@ -440,40 +404,41 @@ static void power_check_low_battery(Power* power) {
|
||||
}
|
||||
|
||||
// Check battery charge and vbus voltage
|
||||
if((power->info.is_shutdown_requested) && (power->info.voltage_vbus < 4.0f) &&
|
||||
power->show_low_bat_level_message) {
|
||||
if((power->info.is_shutdown_requested) &&
|
||||
(power->info.voltage_vbus < POWER_VBUS_LOW_THRESHOLD) && power->show_battery_low_warning) {
|
||||
if(!power->battery_low) {
|
||||
view_dispatcher_send_to_front(power->view_dispatcher);
|
||||
view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewOff);
|
||||
view_holder_send_to_front(power->view_holder);
|
||||
view_holder_set_view(power->view_holder, power_off_get_view(power->view_power_off));
|
||||
}
|
||||
power->battery_low = true;
|
||||
} else {
|
||||
if(power->battery_low) {
|
||||
view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE);
|
||||
power->power_off_timeout = POWER_OFF_TIMEOUT;
|
||||
// view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE);
|
||||
view_holder_set_view(power->view_holder, NULL);
|
||||
power->power_off_timeout = POWER_OFF_TIMEOUT_S;
|
||||
}
|
||||
power->battery_low = false;
|
||||
}
|
||||
// If battery low, update view and switch off power after timeout
|
||||
if(power->battery_low) {
|
||||
PowerOffResponse response = power_off_get_response(power->power_off);
|
||||
PowerOffResponse response = power_off_get_response(power->view_power_off);
|
||||
if(response == PowerOffResponseDefault) {
|
||||
if(power->power_off_timeout) {
|
||||
power_off_set_time_left(power->power_off, power->power_off_timeout--);
|
||||
power_off_set_time_left(power->view_power_off, power->power_off_timeout--);
|
||||
} else {
|
||||
power_off(power);
|
||||
}
|
||||
} else if(response == PowerOffResponseOk) {
|
||||
power_off(power);
|
||||
} else if(response == PowerOffResponseHide) {
|
||||
view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE);
|
||||
view_holder_set_view(power->view_holder, NULL);
|
||||
if(power->power_off_timeout) {
|
||||
power_off_set_time_left(power->power_off, power->power_off_timeout--);
|
||||
power_off_set_time_left(power->view_power_off, power->power_off_timeout--);
|
||||
} else {
|
||||
power_off(power);
|
||||
}
|
||||
} else if(response == PowerOffResponseCancel) {
|
||||
view_dispatcher_switch_to_view(power->view_dispatcher, VIEW_NONE);
|
||||
view_holder_set_view(power->view_holder, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -490,20 +455,172 @@ static void power_check_battery_level_change(Power* power) {
|
||||
static void power_check_charge_cap(Power* power) {
|
||||
uint32_t cap = momentum_settings.charge_cap;
|
||||
if(power->info.charge >= cap && cap < 100) {
|
||||
if(!power->info.is_charge_capped) { // Suppress charging if charge reaches custom cap
|
||||
power->info.is_charge_capped = true;
|
||||
if(!power->is_charge_capped) { // Suppress charging if charge reaches custom cap
|
||||
power->is_charge_capped = true;
|
||||
furi_hal_power_suppress_charge_enter();
|
||||
}
|
||||
} else {
|
||||
if(power->info.is_charge_capped) { // Start charging again if charge below custom cap
|
||||
power->info.is_charge_capped = false;
|
||||
if(power->is_charge_capped) { // Start charging again if charge below custom cap
|
||||
power->is_charge_capped = false;
|
||||
furi_hal_power_suppress_charge_exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void power_trigger_ui_update(Power* power) {
|
||||
view_port_update(power->battery_view_port);
|
||||
static void power_handle_shutdown(Power* power) {
|
||||
furi_hal_power_off();
|
||||
// Notify user if USB is plugged
|
||||
view_holder_send_to_front(power->view_holder);
|
||||
view_holder_set_view(
|
||||
power->view_holder, power_unplug_usb_get_view(power->view_power_unplug_usb));
|
||||
furi_delay_ms(100);
|
||||
furi_halt("Disconnect USB for safe shutdown");
|
||||
}
|
||||
|
||||
static void power_handle_reboot(PowerBootMode mode) {
|
||||
if(mode == PowerBootModeNormal) {
|
||||
update_operation_disarm();
|
||||
} else if(mode == PowerBootModeDfu) {
|
||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeDfu);
|
||||
} else if(mode == PowerBootModeUpdateStart) {
|
||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePreUpdate);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
|
||||
furi_hal_power_reset();
|
||||
}
|
||||
|
||||
static bool power_message_callback(FuriEventLoopObject* object, void* context) {
|
||||
furi_assert(context);
|
||||
Power* power = context;
|
||||
|
||||
furi_assert(object == power->message_queue);
|
||||
|
||||
PowerMessage msg;
|
||||
furi_check(furi_message_queue_get(power->message_queue, &msg, 0) == FuriStatusOk);
|
||||
|
||||
switch(msg.type) {
|
||||
case PowerMessageTypeShutdown:
|
||||
power_handle_shutdown(power);
|
||||
break;
|
||||
case PowerMessageTypeReboot:
|
||||
power_handle_reboot(msg.boot_mode);
|
||||
break;
|
||||
case PowerMessageTypeGetInfo:
|
||||
*msg.power_info = power->info;
|
||||
break;
|
||||
case PowerMessageTypeIsBatteryHealthy:
|
||||
*msg.bool_param = power->info.health > POWER_HEALTH_LOW_THRESHOLD;
|
||||
break;
|
||||
case PowerMessageTypeShowBatteryLowWarning:
|
||||
power->show_battery_low_warning = *msg.bool_param;
|
||||
break;
|
||||
case PowerMessageTypeGetSettings:
|
||||
furi_assert(msg.lock);
|
||||
*msg.settings = power->settings;
|
||||
break;
|
||||
case PowerMessageTypeSetSettings:
|
||||
furi_assert(msg.lock);
|
||||
power->settings = *msg.csettings;
|
||||
power_apply_settings(power);
|
||||
power_settings_save(&power->settings);
|
||||
break;
|
||||
case PowerMessageTypeReloadSettings:
|
||||
power_settings_load(&power->settings);
|
||||
power_apply_settings(power);
|
||||
break;
|
||||
default:
|
||||
furi_crash();
|
||||
}
|
||||
|
||||
if(msg.lock) {
|
||||
api_lock_unlock(msg.lock);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void power_tick_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Power* power = context;
|
||||
|
||||
// Update data from gauge and charger
|
||||
const bool need_refresh = power_update_info(power);
|
||||
// Check low battery level
|
||||
power_check_low_battery(power);
|
||||
// Check and notify about charging state
|
||||
power_check_charging_state(power);
|
||||
// Check and notify about battery level change
|
||||
power_check_battery_level_change(power);
|
||||
// Check charge cap, compare with user setting and (un)suppress charging
|
||||
power_check_charge_cap(power);
|
||||
// Update battery view port
|
||||
view_port_enabled_set(
|
||||
power->battery_view_port, momentum_settings.battery_icon != BatteryIconOff);
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
static void power_init_settings(Power* power) {
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
furi_pubsub_subscribe(storage_get_pubsub(storage), power_storage_callback, power);
|
||||
|
||||
if(storage_sd_status(storage) != FSE_OK) {
|
||||
FURI_LOG_D(TAG, "SD Card not ready, skipping settings");
|
||||
return;
|
||||
}
|
||||
|
||||
power_settings_load(&power->settings);
|
||||
power_apply_settings(power);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static Power* power_alloc(void) {
|
||||
Power* power = malloc(sizeof(Power));
|
||||
// Pubsub
|
||||
power->event_pubsub = furi_pubsub_alloc();
|
||||
// State initialization
|
||||
power->power_off_timeout = POWER_OFF_TIMEOUT_S;
|
||||
power->show_battery_low_warning = true;
|
||||
// Gui
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// Auto shutdown on idle
|
||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||
furi_pubsub_subscribe(loader_get_pubsub(loader), power_loader_callback, power);
|
||||
power->input_events_pubsub = furi_record_open(RECORD_INPUT_EVENTS);
|
||||
power->ascii_events_pubsub = furi_record_open(RECORD_ASCII_EVENTS);
|
||||
power->auto_shutdown_timer =
|
||||
furi_timer_alloc(power_auto_shutdown_timer_callback, FuriTimerTypeOnce, power);
|
||||
power->app_running = loader_is_locked(loader);
|
||||
|
||||
power->view_holder = view_holder_alloc();
|
||||
power->view_power_off = power_off_alloc();
|
||||
power->view_power_unplug_usb = power_unplug_usb_alloc();
|
||||
|
||||
view_holder_attach_to_gui(power->view_holder, gui);
|
||||
// Battery view port
|
||||
power->battery_view_port = power_battery_view_port_alloc(power);
|
||||
gui_add_view_port(gui, power->battery_view_port, GuiLayerStatusBarRight);
|
||||
// Event loop
|
||||
power->event_loop = furi_event_loop_alloc();
|
||||
power->message_queue = furi_message_queue_alloc(4, sizeof(PowerMessage));
|
||||
|
||||
furi_event_loop_subscribe_message_queue(
|
||||
power->event_loop,
|
||||
power->message_queue,
|
||||
FuriEventLoopEventIn,
|
||||
power_message_callback,
|
||||
power);
|
||||
furi_event_loop_tick_set(power->event_loop, 1000, power_tick_callback, power);
|
||||
|
||||
return power;
|
||||
}
|
||||
|
||||
int32_t power_srv(void* p) {
|
||||
@@ -517,44 +634,11 @@ int32_t power_srv(void* p) {
|
||||
}
|
||||
|
||||
Power* power = power_alloc();
|
||||
if(!LOAD_POWER_SETTINGS(&power->shutdown_idle_delay_ms)) {
|
||||
power->shutdown_idle_delay_ms = 0;
|
||||
}
|
||||
power_auto_shutdown_arm(power);
|
||||
power_init_settings(power);
|
||||
power_update_info(power);
|
||||
power->info.is_charge_capped = false; // default false
|
||||
|
||||
furi_record_create(RECORD_POWER, power);
|
||||
|
||||
while(1) {
|
||||
// Update data from gauge and charger
|
||||
bool need_refresh = power_update_info(power);
|
||||
|
||||
// Check low battery level
|
||||
power_check_low_battery(power);
|
||||
|
||||
// Check and notify about charging state
|
||||
power_check_charging_state(power);
|
||||
|
||||
// Check and notify about battery level change
|
||||
power_check_battery_level_change(power);
|
||||
|
||||
// Check charge cap, compare with user setting and suppress/unsuppress charging
|
||||
power_check_charge_cap(power);
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
furi_delay_ms(1000);
|
||||
}
|
||||
|
||||
furi_crash("That was unexpected");
|
||||
furi_event_loop_run(power->event_loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -56,8 +56,6 @@ typedef struct {
|
||||
|
||||
uint8_t charge;
|
||||
uint8_t health;
|
||||
|
||||
bool is_charge_capped;
|
||||
} PowerInfo;
|
||||
|
||||
/** Power off device
|
||||
@@ -85,14 +83,6 @@ void power_get_info(Power* power, PowerInfo* info);
|
||||
*/
|
||||
FuriPubSub* power_get_pubsub(Power* power);
|
||||
|
||||
/** Get power settings events pubsub handler
|
||||
*
|
||||
* @param power Power instance
|
||||
*
|
||||
* @return FuriPubSub instance
|
||||
*/
|
||||
FuriPubSub* power_get_settings_events_pubsub(Power* power);
|
||||
|
||||
/** Check battery health
|
||||
*
|
||||
* @return true if battery is healthy
|
||||
@@ -106,19 +96,6 @@ bool power_is_battery_healthy(Power* power);
|
||||
*/
|
||||
void power_enable_low_battery_level_notification(Power* power, bool enable);
|
||||
|
||||
/** Trigger UI update for changing battery layout
|
||||
*
|
||||
* @param power Power instance
|
||||
*/
|
||||
void power_trigger_ui_update(Power* power);
|
||||
|
||||
/** Enable or disable battery icon
|
||||
*
|
||||
* @param power Power instance
|
||||
* @param is_enabled Show battery or not
|
||||
*/
|
||||
void power_set_battery_icon_enabled(Power* power, bool is_enabled);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,41 +1,39 @@
|
||||
#include "power_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <update_util/update_operation.h>
|
||||
|
||||
void power_off(Power* power) {
|
||||
furi_check(power);
|
||||
|
||||
furi_hal_power_off();
|
||||
// Notify user if USB is plugged
|
||||
view_dispatcher_send_to_front(power->view_dispatcher);
|
||||
view_dispatcher_switch_to_view(power->view_dispatcher, PowerViewUnplugUsb);
|
||||
furi_delay_ms(100);
|
||||
furi_halt("Disconnect USB for safe shutdown");
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeShutdown,
|
||||
};
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
}
|
||||
|
||||
void power_reboot(PowerBootMode mode) {
|
||||
if(mode == PowerBootModeNormal) {
|
||||
update_operation_disarm();
|
||||
} else if(mode == PowerBootModeDfu) {
|
||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModeDfu);
|
||||
} else if(mode == PowerBootModeUpdateStart) {
|
||||
furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePreUpdate);
|
||||
} else {
|
||||
furi_crash();
|
||||
}
|
||||
void power_reboot(Power* power, PowerBootMode mode) {
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeReboot,
|
||||
.boot_mode = mode,
|
||||
};
|
||||
|
||||
furi_hal_power_reset();
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
}
|
||||
|
||||
void power_get_info(Power* power, PowerInfo* info) {
|
||||
furi_check(power);
|
||||
furi_check(info);
|
||||
|
||||
furi_mutex_acquire(power->api_mtx, FuriWaitForever);
|
||||
memcpy(info, &power->info, sizeof(power->info));
|
||||
furi_mutex_release(power->api_mtx);
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeGetInfo,
|
||||
.power_info = info,
|
||||
.lock = api_lock_alloc_locked(),
|
||||
};
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
api_lock_wait_unlock_and_free(msg.lock);
|
||||
}
|
||||
|
||||
FuriPubSub* power_get_pubsub(Power* power) {
|
||||
@@ -43,23 +41,66 @@ FuriPubSub* power_get_pubsub(Power* power) {
|
||||
return power->event_pubsub;
|
||||
}
|
||||
|
||||
FuriPubSub* power_get_settings_events_pubsub(Power* power) {
|
||||
furi_assert(power);
|
||||
return power->settings_events;
|
||||
}
|
||||
|
||||
bool power_is_battery_healthy(Power* power) {
|
||||
furi_check(power);
|
||||
bool is_healthy = false;
|
||||
furi_mutex_acquire(power->api_mtx, FuriWaitForever);
|
||||
is_healthy = power->info.health > POWER_BATTERY_HEALTHY_LEVEL;
|
||||
furi_mutex_release(power->api_mtx);
|
||||
return is_healthy;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeIsBatteryHealthy,
|
||||
.lock = api_lock_alloc_locked(),
|
||||
.bool_param = &ret,
|
||||
};
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
api_lock_wait_unlock_and_free(msg.lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void power_enable_low_battery_level_notification(Power* power, bool enable) {
|
||||
furi_check(power);
|
||||
furi_mutex_acquire(power->api_mtx, FuriWaitForever);
|
||||
power->show_low_bat_level_message = enable;
|
||||
furi_mutex_release(power->api_mtx);
|
||||
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeShowBatteryLowWarning,
|
||||
.bool_param = &enable,
|
||||
};
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Private API for the Settings app
|
||||
*/
|
||||
|
||||
void power_get_settings(Power* power, PowerSettings* settings) {
|
||||
furi_assert(power);
|
||||
furi_assert(settings);
|
||||
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeGetSettings,
|
||||
.settings = settings,
|
||||
.lock = api_lock_alloc_locked(),
|
||||
};
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
api_lock_wait_unlock_and_free(msg.lock);
|
||||
}
|
||||
|
||||
void power_set_settings(Power* power, const PowerSettings* settings) {
|
||||
furi_assert(power);
|
||||
furi_assert(settings);
|
||||
|
||||
PowerMessage msg = {
|
||||
.type = PowerMessageTypeSetSettings,
|
||||
.csettings = settings,
|
||||
.lock = api_lock_alloc_locked(),
|
||||
};
|
||||
|
||||
furi_check(
|
||||
furi_message_queue_put(power->message_queue, &msg, FuriWaitForever) == FuriStatusOk);
|
||||
api_lock_wait_unlock_and_free(msg.lock);
|
||||
}
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include <loader/loader.h>
|
||||
|
||||
#include "views/power_off.h"
|
||||
#include <power/power_settings.h>
|
||||
#include "views/power_unplug_usb.h"
|
||||
|
||||
#include <power/power_settings.h>
|
||||
|
||||
typedef enum {
|
||||
PowerStateNotCharging,
|
||||
PowerStateCharging,
|
||||
@@ -38,16 +39,14 @@ struct Power {
|
||||
uint8_t battery_level;
|
||||
uint8_t power_off_timeout;
|
||||
|
||||
FuriPubSub* settings_events;
|
||||
FuriPubSub* input_events_pubsub;
|
||||
FuriPubSubSubscription* input_events_subscription;
|
||||
FuriPubSub* ascii_events_pubsub;
|
||||
FuriPubSubSubscription* input_events_subscription;
|
||||
FuriPubSubSubscription* ascii_events_subscription;
|
||||
FuriPubSubSubscription* app_start_stop_subscription;
|
||||
FuriPubSubSubscription* settings_events_subscription;
|
||||
uint32_t shutdown_idle_delay_ms;
|
||||
FuriTimer* auto_shutdown_timer;
|
||||
Loader* loader;
|
||||
PowerSettings settings;
|
||||
bool is_charge_capped;
|
||||
bool app_running;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@@ -61,6 +60,10 @@ typedef enum {
|
||||
PowerMessageTypeGetInfo,
|
||||
PowerMessageTypeIsBatteryHealthy,
|
||||
PowerMessageTypeShowBatteryLowWarning,
|
||||
|
||||
PowerMessageTypeGetSettings,
|
||||
PowerMessageTypeSetSettings,
|
||||
PowerMessageTypeReloadSettings,
|
||||
} PowerMessageType;
|
||||
|
||||
typedef struct {
|
||||
@@ -69,6 +72,9 @@ typedef struct {
|
||||
PowerBootMode boot_mode;
|
||||
PowerInfo* power_info;
|
||||
bool* bool_param;
|
||||
|
||||
PowerSettings* settings;
|
||||
const PowerSettings* csettings;
|
||||
};
|
||||
FuriApiLock lock;
|
||||
} PowerMessage;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "power.h"
|
||||
#include "../power_settings.h"
|
||||
|
||||
void power_get_settings(Power* power, PowerSettings* settings);
|
||||
|
||||
void power_set_settings(Power* power, const PowerSettings* settings);
|
||||
@@ -1,12 +1,42 @@
|
||||
#include "power_settings.h"
|
||||
#include "power_settings_filename.h"
|
||||
|
||||
bool SAVE_POWER_SETTINGS(uint32_t* x) {
|
||||
return saved_struct_save(
|
||||
POWER_SETTINGS_PATH, x, sizeof(uint32_t), POWER_SETTINGS_MAGIC, POWER_SETTINGS_VER);
|
||||
#include <saved_struct.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define TAG "PowerSettings"
|
||||
|
||||
#define POWER_SETTINGS_VER (1)
|
||||
#define POWER_SETTINGS_MAGIC (0x21)
|
||||
|
||||
void power_settings_load(PowerSettings* settings) {
|
||||
furi_assert(settings);
|
||||
|
||||
const bool success = saved_struct_load(
|
||||
POWER_SETTINGS_PATH,
|
||||
settings,
|
||||
sizeof(PowerSettings),
|
||||
POWER_SETTINGS_MAGIC,
|
||||
POWER_SETTINGS_VER);
|
||||
|
||||
if(!success) {
|
||||
FURI_LOG_W(TAG, "Failed to load file, using defaults");
|
||||
memset(settings, 0, sizeof(PowerSettings));
|
||||
// power_settings_save(settings);
|
||||
}
|
||||
}
|
||||
|
||||
bool LOAD_POWER_SETTINGS(uint32_t* x) {
|
||||
return saved_struct_load(
|
||||
POWER_SETTINGS_PATH, x, sizeof(uint32_t), POWER_SETTINGS_MAGIC, POWER_SETTINGS_VER);
|
||||
void power_settings_save(const PowerSettings* settings) {
|
||||
furi_assert(settings);
|
||||
|
||||
const bool success = saved_struct_save(
|
||||
POWER_SETTINGS_PATH,
|
||||
settings,
|
||||
sizeof(PowerSettings),
|
||||
POWER_SETTINGS_MAGIC,
|
||||
POWER_SETTINGS_VER);
|
||||
|
||||
if(!success) {
|
||||
FURI_LOG_E(TAG, "Failed to save file");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
#include <toolbox/saved_struct.h>
|
||||
#include <storage/storage.h>
|
||||
#pragma once
|
||||
|
||||
#define POWER_SETTINGS_VER (1)
|
||||
#include <stdint.h>
|
||||
|
||||
#define POWER_SETTINGS_MAGIC (0x21)
|
||||
typedef struct {
|
||||
uint32_t shutdown_idle_delay_ms;
|
||||
} PowerSettings;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool SAVE_POWER_SETTINGS(uint32_t* x);
|
||||
|
||||
bool LOAD_POWER_SETTINGS(uint32_t* x);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
void power_settings_load(PowerSettings* settings);
|
||||
void power_settings_save(const PowerSettings* settings);
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
// Instead of copying the file, can (ab)use the preprocessor to insert the source code here
|
||||
// Then, we still use the Header from original code as if nothing happened
|
||||
|
||||
// LOAD_POWER_SETTINGS(), SAVE_POWER_SETTINGS()
|
||||
#include <applications/services/power/power_settings.c>
|
||||
// power_get_settings(), power_set_settings()
|
||||
#include <applications/services/power/power_service/power_api.c>
|
||||
@@ -28,9 +28,6 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene, ViewDispatcherT
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->power = furi_record_open(RECORD_POWER);
|
||||
|
||||
//PubSub
|
||||
app->settings_events = power_get_settings_events_pubsub(app->power);
|
||||
|
||||
// View dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&power_settings_scene_handlers, app);
|
||||
@@ -64,6 +61,8 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene, ViewDispatcherT
|
||||
PowerSettingsAppViewVariableItemList,
|
||||
variable_item_list_get_view(app->variable_item_list));
|
||||
|
||||
power_get_settings(app->power, &app->settings);
|
||||
|
||||
// Set first scene
|
||||
scene_manager_next_scene(app->scene_manager, first_scene);
|
||||
return app;
|
||||
@@ -71,6 +70,7 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene, ViewDispatcherT
|
||||
|
||||
void power_settings_app_free(PowerSettingsApp* app) {
|
||||
furi_assert(app);
|
||||
power_set_settings(app->power, &app->settings);
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo);
|
||||
battery_info_free(app->battery_info);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <furi.h>
|
||||
#include <power/power_service/power.h>
|
||||
#include <power/power_service/power_settings_api_i.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
@@ -13,21 +14,21 @@
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
|
||||
#include <power/power_settings.h>
|
||||
#include "scenes/power_settings_scene.h"
|
||||
|
||||
typedef struct {
|
||||
PowerSettings settings;
|
||||
|
||||
Power* power;
|
||||
Gui* gui;
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
BatteryInfo* battery_info;
|
||||
Submenu* submenu;
|
||||
VariableItemList* variable_item_list;
|
||||
DialogEx* dialog;
|
||||
PowerInfo info;
|
||||
VariableItemList* variable_item_list;
|
||||
uint32_t shutdown_idle_delay_ms;
|
||||
FuriPubSub* settings_events;
|
||||
|
||||
bool about_battery;
|
||||
} PowerSettingsApp;
|
||||
|
||||
|
||||
@@ -3,4 +3,3 @@ ADD_SCENE(power_settings, battery_info, BatteryInfo)
|
||||
ADD_SCENE(power_settings, reboot, Reboot)
|
||||
ADD_SCENE(power_settings, reboot_confirm, RebootConfirm)
|
||||
ADD_SCENE(power_settings, power_off, PowerOff)
|
||||
ADD_SCENE(power_settings, shutdown_idle, ShutdownIdle)
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
#include "../power_settings_app.h"
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
#define SHUTDOWN_IDLE_DELAY_COUNT 9
|
||||
#define SCENE_EVENT_SELECT_SHUTDOWN_IDLE_DELAY 0
|
||||
|
||||
const char* const shutdown_idle_delay_text[SHUTDOWN_IDLE_DELAY_COUNT] =
|
||||
{"OFF", "15min", "30min", "1h", "2h", "6h", "12h", "24h", "48h"};
|
||||
|
||||
const uint32_t shutdown_idle_delay_value[SHUTDOWN_IDLE_DELAY_COUNT] =
|
||||
{0, 900000, 1800000, 3600000, 7200000, 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) {
|
||||
if(event.event == SCENE_EVENT_SELECT_SHUTDOWN_IDLE_DELAY) {
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void power_settings_scene_shutdown_idle_on_exit(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
SAVE_POWER_SETTINGS(&app->shutdown_idle_delay_ms);
|
||||
furi_pubsub_publish(app->settings_events, &app->shutdown_idle_delay_ms);
|
||||
variable_item_list_reset(app->variable_item_list);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "../power_settings_app.h"
|
||||
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
enum PowerSettingsSubmenuIndex {
|
||||
PowerSettingsSubmenuIndexBatteryInfo,
|
||||
PowerSettingsSubmenuIndexReboot,
|
||||
@@ -7,6 +9,29 @@ enum PowerSettingsSubmenuIndex {
|
||||
PowerSettingsSubmenuShutdownIdle
|
||||
};
|
||||
|
||||
#define SHUTDOWN_IDLE_DELAY_COUNT 9
|
||||
const char* const shutdown_idle_delay_text[SHUTDOWN_IDLE_DELAY_COUNT] = {
|
||||
"OFF",
|
||||
"15min",
|
||||
"30min",
|
||||
"1h",
|
||||
"2h",
|
||||
"6h",
|
||||
"12h",
|
||||
"24h",
|
||||
"48h",
|
||||
};
|
||||
const uint32_t shutdown_idle_delay_value[SHUTDOWN_IDLE_DELAY_COUNT] =
|
||||
{0, 900000, 1800000, 3600000, 7200000, 21600000, 43200000, 86400000, 172800000};
|
||||
|
||||
static void power_settings_scene_start_auto_lock_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->settings.shutdown_idle_delay_ms = shutdown_idle_delay_value[index];
|
||||
}
|
||||
|
||||
static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
PowerSettingsApp* app = context;
|
||||
@@ -15,34 +40,36 @@ static void power_settings_scene_start_submenu_callback(void* context, uint32_t
|
||||
|
||||
void power_settings_scene_start_on_enter(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
VariableItemList* variable_item_list = app->variable_item_list;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Battery Info",
|
||||
PowerSettingsSubmenuIndexBatteryInfo,
|
||||
power_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Reboot",
|
||||
PowerSettingsSubmenuIndexReboot,
|
||||
power_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Power OFF",
|
||||
PowerSettingsSubmenuIndexOff,
|
||||
power_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
|
||||
variable_item_list_add(variable_item_list, "Battery Info", 1, NULL, NULL);
|
||||
|
||||
variable_item_list_add(variable_item_list, "Reboot", 1, NULL, NULL);
|
||||
|
||||
variable_item_list_add(variable_item_list, "Power OFF", 1, NULL, NULL);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Shutdown on Idle",
|
||||
PowerSettingsSubmenuShutdownIdle,
|
||||
power_settings_scene_start_submenu_callback,
|
||||
SHUTDOWN_IDLE_DELAY_COUNT,
|
||||
power_settings_scene_start_auto_lock_delay_changed,
|
||||
app);
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart));
|
||||
value_index = value_index_uint32(
|
||||
app->settings.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]);
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
variable_item_list,
|
||||
scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart));
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list, power_settings_scene_start_submenu_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
|
||||
}
|
||||
@@ -59,7 +86,6 @@ bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event)
|
||||
} 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;
|
||||
|
||||
@@ -2996,12 +2996,9 @@ Function,-,pow10f,float,float
|
||||
Function,+,power_enable_low_battery_level_notification,void,"Power*, _Bool"
|
||||
Function,+,power_get_info,void,"Power*, PowerInfo*"
|
||||
Function,+,power_get_pubsub,FuriPubSub*,Power*
|
||||
Function,+,power_get_settings_events_pubsub,FuriPubSub*,Power*
|
||||
Function,+,power_is_battery_healthy,_Bool,Power*
|
||||
Function,+,power_off,void,Power*
|
||||
Function,+,power_reboot,void,"Power*, PowerBootMode"
|
||||
Function,+,power_set_battery_icon_enabled,void,"Power*, _Bool"
|
||||
Function,-,power_trigger_ui_update,void,Power*
|
||||
Function,+,powf,float,"float, float"
|
||||
Function,-,powl,long double,"long double, long double"
|
||||
Function,+,pretty_format_bytes_hex_canonical,void,"FuriString*, size_t, const char*, const uint8_t*, size_t"
|
||||
|
||||
|
Reference in New Issue
Block a user