From 202673aed1186a5b17d0feaee61352cc4b32decd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=82=E3=81=8F?= Date: Mon, 19 Apr 2021 19:26:25 +0300 Subject: [PATCH] [FL-1151] Power: Low Battery power off routine (#418) --- applications/power/power.c | 75 +++++++++++++++++--------------- applications/power/power_cli.c | 36 +++++++++++++++ applications/power/power_cli.h | 5 +++ applications/power/power_views.c | 20 +++++++++ applications/power/power_views.h | 9 +++- 5 files changed, 109 insertions(+), 36 deletions(-) create mode 100644 applications/power/power_cli.c create mode 100644 applications/power/power_cli.h diff --git a/applications/power/power.c b/applications/power/power.c index ce28b2e56..565367192 100644 --- a/applications/power/power.c +++ b/applications/power/power.c @@ -1,4 +1,5 @@ #include "power.h" +#include "power_cli.h" #include "power_views.h" #include @@ -13,12 +14,14 @@ #include #include #include -#include #include +#define POWER_OFF_TIMEOUT 30 + struct Power { ViewDispatcher* view_dispatcher; View* info_view; + View* off_view; Icon* usb_icon; ViewPort* usb_view_port; @@ -97,6 +100,7 @@ Power* power_alloc() { power->menu_vm = furi_record_open("menu"); power->cli = furi_record_open("cli"); + power_cli_init(power->cli); power->menu = menu_item_alloc_menu("Power", NULL); menu_item_subitem_add( @@ -119,6 +123,11 @@ Power* power_alloc() { view_set_previous_callback(power->info_view, power_info_back_callback); view_dispatcher_add_view(power->view_dispatcher, PowerViewInfo, power->info_view); + power->off_view = view_alloc(); + view_allocate_model(power->off_view, ViewModelTypeLockFree, sizeof(PowerOffModel)); + view_set_draw_callback(power->off_view, power_off_draw_callback); + view_dispatcher_add_view(power->view_dispatcher, PowerViewOff, power->off_view); + power->dialog = dialog_alloc(); dialog_set_context(power->dialog, power); view_dispatcher_add_view( @@ -142,44 +151,10 @@ void power_free(Power* power) { free(power); } -void power_cli_poweroff(string_t args, void* context) { - api_hal_power_off(); -} - -void power_cli_reset(string_t args, void* context) { - NVIC_SystemReset(); -} - -void power_cli_dfu(string_t args, void* context) { - api_hal_boot_set_mode(ApiHalBootModeDFU); - NVIC_SystemReset(); -} - -void power_cli_test(string_t args, void* context) { - api_hal_power_dump_state(); -} - -void power_cli_otg_on(string_t args, void* context) { - api_hal_power_enable_otg(); -} - -void power_cli_otg_off(string_t args, void* context) { - api_hal_power_disable_otg(); -} - int32_t power_task(void* p) { (void)p; Power* power = power_alloc(); - if(power->cli) { - cli_add_command(power->cli, "poweroff", power_cli_poweroff, power); - cli_add_command(power->cli, "reset", power_cli_reset, power); - cli_add_command(power->cli, "dfu", power_cli_dfu, power); - cli_add_command(power->cli, "power_test", power_cli_test, power); - cli_add_command(power->cli, "power_otg_on", power_cli_otg_on, power); - cli_add_command(power->cli, "power_otg_off", power_cli_otg_off, power); - } - Gui* gui = furi_record_open("gui"); gui_add_view_port(gui, power->usb_view_port, GuiLayerStatusBarLeft); gui_add_view_port(gui, power->battery_view_port, GuiLayerStatusBarRight); @@ -191,6 +166,8 @@ int32_t power_task(void* p) { furi_record_create("power", power); while(1) { + bool battery_low = false; + with_view_model( power->info_view, (PowerInfoModel * model) { model->charge = api_hal_power_get_pct(); @@ -207,11 +184,39 @@ int32_t power_task(void* p) { model->temperature_gauge = api_hal_power_get_battery_temperature(ApiHalPowerICFuelGauge); + if(model->voltage_gauge < 3.3f && model->voltage_vbus < 4.0f) { + battery_low = true; + } + + return true; + }); + + with_view_model( + power->off_view, (PowerOffModel * model) { + if(battery_low) { + if(model->poweroff_tick == 0) { + model->poweroff_tick = + osKernelGetTickCount() + osKernelGetTickFreq() * POWER_OFF_TIMEOUT; + } else { + if(osKernelGetTickCount() > model->poweroff_tick) { + api_hal_power_off(); + } + } + } else { + model->poweroff_tick = 0; + } + + if(model->battery_low != battery_low) { + model->battery_low = battery_low; + view_dispatcher_switch_to_view( + power->view_dispatcher, battery_low ? PowerViewOff : VIEW_NONE); + } return true; }); view_port_update(power->battery_view_port); view_port_enabled_set(power->usb_view_port, api_hal_power_is_charging()); + osDelay(1024); } diff --git a/applications/power/power_cli.c b/applications/power/power_cli.c new file mode 100644 index 000000000..f33a7d616 --- /dev/null +++ b/applications/power/power_cli.c @@ -0,0 +1,36 @@ +#include "power_cli.h" +#include + +void power_cli_poweroff(string_t args, void* context) { + api_hal_power_off(); +} + +void power_cli_reset(string_t args, void* context) { + NVIC_SystemReset(); +} + +void power_cli_dfu(string_t args, void* context) { + api_hal_boot_set_mode(ApiHalBootModeDFU); + NVIC_SystemReset(); +} + +void power_cli_test(string_t args, void* context) { + api_hal_power_dump_state(); +} + +void power_cli_otg_on(string_t args, void* context) { + api_hal_power_enable_otg(); +} + +void power_cli_otg_off(string_t args, void* context) { + api_hal_power_disable_otg(); +} + +void power_cli_init(Cli* cli) { + cli_add_command(cli, "poweroff", power_cli_poweroff, NULL); + cli_add_command(cli, "reset", power_cli_reset, NULL); + cli_add_command(cli, "dfu", power_cli_dfu, NULL); + cli_add_command(cli, "power_test", power_cli_test, NULL); + cli_add_command(cli, "power_otg_on", power_cli_otg_on, NULL); + cli_add_command(cli, "power_otg_off", power_cli_otg_off, NULL); +} diff --git a/applications/power/power_cli.h b/applications/power/power_cli.h new file mode 100644 index 000000000..ca4e6bcba --- /dev/null +++ b/applications/power/power_cli.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void power_cli_init(Cli* cli); \ No newline at end of file diff --git a/applications/power/power_views.c b/applications/power/power_views.c index 382abaeed..6508026cd 100644 --- a/applications/power/power_views.c +++ b/applications/power/power_views.c @@ -76,6 +76,7 @@ static void draw_battery(Canvas* canvas, PowerInfoModel* data, int x, int y) { }; void power_info_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); PowerInfoModel* data = context; canvas_clear(canvas); @@ -102,3 +103,22 @@ void power_info_draw_callback(Canvas* canvas, void* context) { draw_stat(canvas, 72, 42, I_Voltage_16x16, voltage); draw_stat(canvas, 104, 42, I_Health_16x16, health); } + +void power_off_draw_callback(Canvas* canvas, void* context) { + furi_assert(context); + PowerOffModel* model = context; + + canvas_set_color(canvas, ColorBlack); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 2, 15, "!!! Low Battery !!!"); + + char buffer[64]; + canvas_set_font(canvas, FontSecondary); + canvas_draw_str(canvas, 5, 30, "Connect to charger"); + snprintf( + buffer, + 64, + "Or poweroff in %lds", + (model->poweroff_tick - osKernelGetTickCount()) / osKernelGetTickFreq()); + canvas_draw_str(canvas, 5, 42, buffer); +} diff --git a/applications/power/power_views.h b/applications/power/power_views.h index 044f7308d..c7ea27f26 100644 --- a/applications/power/power_views.h +++ b/applications/power/power_views.h @@ -6,7 +6,7 @@ #include #include -typedef enum { PowerViewInfo, PowerViewDialog } PowerView; +typedef enum { PowerViewInfo, PowerViewDialog, PowerViewOff } PowerView; typedef struct { float current_charger; @@ -26,4 +26,11 @@ typedef struct { uint8_t health; } PowerInfoModel; +typedef struct { + uint32_t poweroff_tick; + bool battery_low; +} PowerOffModel; + void power_info_draw_callback(Canvas* canvas, void* context); + +void power_off_draw_callback(Canvas* canvas, void* context);