From 99e26bdd4cbafcdeec815ce6435f1830f1d74816 Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Wed, 7 Jul 2021 15:47:47 +0300 Subject: [PATCH 1/5] LVGL use system tick --- src/FreeRTOSConfig.h | 2 +- src/displayapp/screens/BatteryInfo.cpp | 38 ++----------------- src/displayapp/screens/BatteryInfo.h | 3 -- src/displayapp/screens/Tile.cpp | 2 +- .../screens/settings/QuickSettings.cpp | 2 +- src/libs/lv_conf.h | 8 ++-- src/main.cpp | 7 ---- 7 files changed, 11 insertions(+), 51 deletions(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 07c152dc..adbbc8f0 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -77,7 +77,7 @@ #define configENABLE_BACKWARD_COMPATIBILITY 1 /* Hook function related definitions. */ -#define configUSE_IDLE_HOOK 1 +#define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCHECK_FOR_STACK_OVERFLOW 0 #define configUSE_MALLOC_FAILED_HOOK 0 diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index 87c8b4bb..5ea0b6ff 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -9,11 +9,6 @@ static void lv_update_task(struct _lv_task_t* task) { user_data->UpdateScreen(); } -static void lv_anim_task(struct _lv_task_t* task) { - auto user_data = static_cast(task->user_data); - user_data->UpdateAnim(); -} - BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Battery& batteryController) : Screen(app), batteryController {batteryController} { @@ -24,12 +19,12 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont lv_obj_set_size(charging_bar, 200, 15); lv_bar_set_range(charging_bar, 0, 100); lv_obj_align(charging_bar, nullptr, LV_ALIGN_CENTER, 0, 10); - lv_bar_set_anim_time(charging_bar, 2000); + lv_bar_set_anim_time(charging_bar, 1000); lv_obj_set_style_local_radius(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, lv_color_hex(0x222222)); lv_obj_set_style_local_bg_opa(charging_bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, LV_OPA_100); lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, lv_color_hex(0xFF0000)); - lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_OFF); + lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON); status = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(status, "Reading Battery status"); @@ -58,40 +53,15 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont lv_obj_set_pos(backgroundLabel, 0, 0); lv_label_set_text_static(backgroundLabel, ""); - taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_LOW, this); - taskAnim = lv_task_create(lv_anim_task, 1000, LV_TASK_PRIO_LOW, this); + taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_LOW, this); UpdateScreen(); } BatteryInfo::~BatteryInfo() { lv_task_del(taskUpdate); - lv_task_del(taskAnim); lv_obj_clean(lv_scr_act()); } -void BatteryInfo::UpdateAnim() { - batteryPercent = batteryController.PercentRemaining(); - - if (batteryPercent >= 0) { - if (batteryController.IsCharging() and batteryPercent < 100) { - animation += 1; - if (animation >= 100) { - animation = 0; - } - - } else { - if (animation > batteryPercent) { - animation--; - } - if (animation < batteryPercent) { - animation++; - } - } - - lv_bar_set_value(charging_bar, animation, LV_ANIM_OFF); - } -} - void BatteryInfo::UpdateScreen() { batteryController.Update(); @@ -123,9 +93,9 @@ void BatteryInfo::UpdateScreen() { lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10); + lv_bar_set_value(charging_bar, batteryPercent, LV_ANIM_ON); } bool BatteryInfo::Refresh() { - return running; } diff --git a/src/displayapp/screens/BatteryInfo.h b/src/displayapp/screens/BatteryInfo.h index 346dc571..32115938 100644 --- a/src/displayapp/screens/BatteryInfo.h +++ b/src/displayapp/screens/BatteryInfo.h @@ -22,7 +22,6 @@ namespace Pinetime { bool Refresh() override; void UpdateScreen(); - void UpdateAnim(); private: Pinetime::Controllers::Battery& batteryController; @@ -33,9 +32,7 @@ namespace Pinetime { lv_obj_t* status; lv_task_t* taskUpdate; - lv_task_t* taskAnim; - int8_t animation = 0; int8_t batteryPercent = -1; uint16_t batteryVoltage = 0; }; diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index ec36af38..3eb127cc 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -107,7 +107,7 @@ Tile::Tile(uint8_t screenID, lv_obj_set_pos(backgroundLabel, 0, 0); lv_label_set_text_static(backgroundLabel, ""); - taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this); + taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this); } Tile::~Tile() { diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index 5db7468c..acc2a27a 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -110,7 +110,7 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app, lv_obj_set_pos(backgroundLabel, 0, 0); lv_label_set_text_static(backgroundLabel, ""); - taskUpdate = lv_task_create(lv_update_task, 500000, LV_TASK_PRIO_MID, this); + taskUpdate = lv_task_create(lv_update_task, 5000, LV_TASK_PRIO_MID, this); } QuickSettings::~QuickSettings() { diff --git a/src/libs/lv_conf.h b/src/libs/lv_conf.h index a03a4833..37824bbd 100644 --- a/src/libs/lv_conf.h +++ b/src/libs/lv_conf.h @@ -293,10 +293,10 @@ typedef void* lv_img_decoder_user_data_t; /* 1: use a custom tick source. * It removes the need to manually update the tick with `lv_tick_inc`) */ -#define LV_TICK_CUSTOM 0 +#define LV_TICK_CUSTOM 1 #if LV_TICK_CUSTOM == 1 -#define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ -#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ +#define LV_TICK_CUSTOM_INCLUDE "FreeRTOS.h" /*Header for the system time function*/ +#define LV_TICK_CUSTOM_SYS_TIME_EXPR (xTaskGetTickCount()) /*Expression evaluating to current system time in ms*/ #endif /*LV_TICK_CUSTOM*/ typedef void* lv_disp_drv_user_data_t; /*Type of user data in the display driver*/ @@ -759,4 +759,4 @@ typedef void* lv_obj_user_data_t; /*--END OF LV_CONF_H--*/ -#endif /*LV_CONF_H*/ \ No newline at end of file +#endif /*LV_CONF_H*/ diff --git a/src/main.cpp b/src/main.cpp index 5832a78f..ebdf0175 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -175,13 +175,6 @@ void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } -extern "C" { -void vApplicationIdleHook(void) { - if (!isFactory) - lv_tick_inc(1); -} -} - void DebounceTimerChargeCallback(TimerHandle_t xTimer) { xTimerStop(xTimer, 0); systemTask.PushMessage(Pinetime::System::Messages::OnChargingEvent); From e21f6a7f414d1f832e8fddfeaab3b9de05aa3459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sun, 11 Jul 2021 16:55:06 +0200 Subject: [PATCH 2/5] Notify battery level every 10 minutes when connected to a BLE host. Refactor battery percent : only use uint8_t to store the battery % remaining. --- src/components/battery/BatteryController.cpp | 13 +--- src/components/battery/BatteryController.h | 18 +++-- .../ble/BatteryInformationService.cpp | 8 ++- .../ble/BatteryInformationService.h | 2 +- src/components/ble/NimbleController.cpp | 6 ++ src/components/ble/NimbleController.h | 3 +- src/displayapp/screens/BatteryIcon.cpp | 3 +- src/displayapp/screens/BatteryIcon.h | 2 +- src/displayapp/screens/BatteryInfo.cpp | 66 ++++++++----------- src/displayapp/screens/BatteryInfo.h | 2 +- src/displayapp/screens/PineTimeStyle.h | 2 +- src/displayapp/screens/SystemInfo.cpp | 2 +- src/displayapp/screens/WatchFaceAnalog.cpp | 1 - src/displayapp/screens/WatchFaceAnalog.h | 2 +- src/displayapp/screens/WatchFaceDigital.h | 2 +- src/systemtask/SystemTask.cpp | 5 ++ src/systemtask/SystemTask.h | 2 + 17 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index 76ad8cb3..fa476ea3 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -1,9 +1,7 @@ #include "BatteryController.h" #include #include -#include #include -#include using namespace Pinetime::Controllers; @@ -18,7 +16,6 @@ void Battery::Init() { } void Battery::Update() { - isCharging = !nrf_gpio_pin_read(chargingPin); isPowerPresent = !nrf_gpio_pin_read(powerPresentPin); @@ -33,13 +30,13 @@ void Battery::Update() { nrfx_saadc_sample(); } -void Battery::adcCallbackStatic(nrfx_saadc_evt_t const* event) { +void Battery::AdcCallbackStatic(nrfx_saadc_evt_t const* event) { instance->SaadcEventHandler(event); } void Battery::SaadcInit() { nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG; - APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic)); + APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, AdcCallbackStatic)); nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED, @@ -55,7 +52,6 @@ void Battery::SaadcInit() { } void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { - const uint16_t battery_max = 4180; // maximum voltage of battery ( max charging voltage is 4.21 ) const uint16_t battery_min = 3200; // minimum voltage of battery before shutdown ( depends on the battery ) @@ -69,13 +65,10 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { // reference_voltage is 0.6V // p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024 voltage = p_event->data.done.p_buffer[0] * 6000 / 1024; - percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min); - percentRemaining = std::max(percentRemaining, 0); percentRemaining = std::min(percentRemaining, 100); - - percentRemainingBuffer.insert(percentRemaining); + percentRemainingBuffer.Insert(percentRemaining); samples++; if (samples > percentRemainingSamples) { diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 26e24938..1333ad0e 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -19,7 +19,7 @@ namespace Pinetime { insert member function overwrites the next data to the current HEAD and moves the HEAD to the newly inserted value. */ - void insert(const int num) { + void Insert(const uint8_t num) { head %= cap; arr[head++] = num; if (sz != cap) { @@ -27,13 +27,13 @@ namespace Pinetime { } } - int GetAverage() const { + uint8_t GetAverage() const { int sum = std::accumulate(arr.begin(), arr.end(), 0); - return (sum / sz); + return static_cast(sum / sz); } private: - std::array arr; /**< internal array used to store the values*/ + std::array arr; /**< internal array used to store the values*/ uint8_t sz; /**< The current size of the array.*/ uint8_t cap; /**< Total capacity of the CircBuffer.*/ uint8_t head; /**< The current head of the CircBuffer*/ @@ -46,8 +46,11 @@ namespace Pinetime { void Init(); void Update(); - int PercentRemaining() const { - return percentRemainingBuffer.GetAverage(); + uint8_t PercentRemaining() const { + auto avg = percentRemainingBuffer.GetAverage(); + avg = std::min(avg, static_cast(100)); + avg = std::max(avg, static_cast(0)); + return avg; } uint16_t Voltage() const { @@ -57,6 +60,7 @@ namespace Pinetime { bool IsCharging() const { return isCharging; } + bool IsPowerPresent() const { return isPowerPresent; } @@ -80,7 +84,7 @@ namespace Pinetime { void SaadcInit(); void SaadcEventHandler(nrfx_saadc_evt_t const* p_event); - static void adcCallbackStatic(nrfx_saadc_evt_t const* event); + static void AdcCallbackStatic(nrfx_saadc_evt_t const* event); bool isReading = false; uint8_t samples = 0; diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp index 10a78d67..7f176904 100644 --- a/src/components/ble/BatteryInformationService.cpp +++ b/src/components/ble/BatteryInformationService.cpp @@ -17,7 +17,7 @@ BatteryInformationService::BatteryInformationService(Controllers::Battery& batte characteristicDefinition {{.uuid = (ble_uuid_t*) &batteryLevelUuid, .access_cb = BatteryInformationServiceCallback, .arg = this, - .flags = BLE_GATT_CHR_F_READ, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY, .val_handle = &batteryLevelHandle}, {0}}, serviceDefinition { @@ -48,4 +48,8 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } return 0; -} \ No newline at end of file +} +void BatteryInformationService::NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level) { + auto* om = ble_hs_mbuf_from_flat(&level, 1); + ble_gattc_notify_custom(connectionHandle, batteryLevelHandle, om); +} diff --git a/src/components/ble/BatteryInformationService.h b/src/components/ble/BatteryInformationService.h index 7d060909..1303fd6c 100644 --- a/src/components/ble/BatteryInformationService.h +++ b/src/components/ble/BatteryInformationService.h @@ -17,7 +17,7 @@ namespace Pinetime { void Init(); int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); - + void NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level); private: Controllers::Battery& batteryController; static constexpr uint16_t batteryInformationServiceId {0x180F}; diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 2c1d0f99..5eb227bf 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -235,3 +235,9 @@ void NimbleController::StartDiscovery() { uint16_t NimbleController::connHandle() { return connectionHandle; } + +void NimbleController::NotifyBatteryLevel(uint8_t level) { + if(connectionHandle != BLE_HS_CONN_HANDLE_NONE) { + batteryInformationService.NotifyBatteryLevel(connectionHandle, level); + } +} diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 5dd01e42..0cfe983c 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -70,6 +70,7 @@ namespace Pinetime { }; uint16_t connHandle(); + void NotifyBatteryLevel(uint8_t level); private: static constexpr const char* deviceName = "InfiniTime"; @@ -92,7 +93,7 @@ namespace Pinetime { HeartRateService heartRateService; uint8_t addrType; // 1 = Random, 0 = PUBLIC - uint16_t connectionHandle = 0; + uint16_t connectionHandle = BLE_HS_CONN_HANDLE_NONE; ble_uuid128_t dfuServiceUuid { .u {.type = BLE_UUID_TYPE_128}, diff --git a/src/displayapp/screens/BatteryIcon.cpp b/src/displayapp/screens/BatteryIcon.cpp index 6b54a305..bb6626a5 100644 --- a/src/displayapp/screens/BatteryIcon.cpp +++ b/src/displayapp/screens/BatteryIcon.cpp @@ -1,9 +1,10 @@ +#include #include "BatteryIcon.h" #include "Symbols.h" using namespace Pinetime::Applications::Screens; -const char* BatteryIcon::GetBatteryIcon(int batteryPercent) { +const char* BatteryIcon::GetBatteryIcon(uint8_t batteryPercent) { if (batteryPercent > 90) return Symbols::batteryFull; if (batteryPercent > 75) diff --git a/src/displayapp/screens/BatteryIcon.h b/src/displayapp/screens/BatteryIcon.h index 9c192ff7..b370b331 100644 --- a/src/displayapp/screens/BatteryIcon.h +++ b/src/displayapp/screens/BatteryIcon.h @@ -6,7 +6,7 @@ namespace Pinetime { class BatteryIcon { public: static const char* GetUnknownIcon(); - static const char* GetBatteryIcon(int batteryPercent); + static const char* GetBatteryIcon(uint8_t batteryPercent); static const char* GetPlugIcon(bool isCharging); }; } diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index 87c8b4bb..2af024e7 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -38,11 +38,7 @@ BatteryInfo::BatteryInfo(Pinetime::Applications::DisplayApp* app, Pinetime::Cont percent = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(percent, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - if (batteryPercent >= 0) { - lv_label_set_text_fmt(percent, "%02i%%", batteryPercent); - } else { - lv_label_set_text(percent, "--%"); - } + lv_label_set_text_fmt(percent, "%02i%%", batteryPercent); lv_label_set_align(percent, LV_LABEL_ALIGN_LEFT); lv_obj_align(percent, nullptr, LV_ALIGN_CENTER, 0, -60); @@ -72,24 +68,22 @@ BatteryInfo::~BatteryInfo() { void BatteryInfo::UpdateAnim() { batteryPercent = batteryController.PercentRemaining(); - if (batteryPercent >= 0) { - if (batteryController.IsCharging() and batteryPercent < 100) { - animation += 1; - if (animation >= 100) { - animation = 0; - } - - } else { - if (animation > batteryPercent) { - animation--; - } - if (animation < batteryPercent) { - animation++; - } + if (batteryController.IsCharging() and batteryPercent < 100) { + animation += 1; + if (animation >= 100) { + animation = 0; } - lv_bar_set_value(charging_bar, animation, LV_ANIM_OFF); + } else { + if (animation > batteryPercent) { + animation--; + } + if (animation < batteryPercent) { + animation++; + } } + + lv_bar_set_value(charging_bar, animation, LV_ANIM_OFF); } void BatteryInfo::UpdateScreen() { @@ -99,28 +93,22 @@ void BatteryInfo::UpdateScreen() { batteryPercent = batteryController.PercentRemaining(); batteryVoltage = batteryController.Voltage(); - if (batteryPercent >= 0) { - if (batteryController.IsCharging() and batteryPercent < 100) { - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED); - lv_label_set_text_static(status, "Battery charging"); - } else if (batteryPercent == 100) { - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE); - lv_label_set_text_static(status, "Battery is fully charged"); - } else if (batteryPercent < 10) { - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW); - lv_label_set_text_static(status, "Battery is low"); - } else { - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN); - lv_label_set_text_static(status, "Battery discharging"); - } - - lv_label_set_text_fmt(percent, "%02i%%", batteryPercent); - + if (batteryController.IsCharging() and batteryPercent < 100) { + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_label_set_text_static(status, "Battery charging"); + } else if (batteryPercent == 100) { + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE); + lv_label_set_text_static(status, "Battery is fully charged"); + } else if (batteryPercent < 10) { + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW); + lv_label_set_text_static(status, "Battery is low"); } else { - lv_label_set_text_static(status, "Reading Battery status"); - lv_label_set_text(percent, "--%"); + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_GREEN); + lv_label_set_text_static(status, "Battery discharging"); } + lv_label_set_text_fmt(percent, "%02i%%", batteryPercent); + lv_obj_align(status, charging_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 20); lv_label_set_text_fmt(voltage, "%1i.%02i volts", batteryVoltage / 1000, batteryVoltage % 1000 / 10); } diff --git a/src/displayapp/screens/BatteryInfo.h b/src/displayapp/screens/BatteryInfo.h index 346dc571..da85c6dd 100644 --- a/src/displayapp/screens/BatteryInfo.h +++ b/src/displayapp/screens/BatteryInfo.h @@ -36,7 +36,7 @@ namespace Pinetime { lv_task_t* taskAnim; int8_t animation = 0; - int8_t batteryPercent = -1; + uint8_t batteryPercent = 0; uint16_t batteryVoltage = 0; }; } diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h index 70794cc5..3b4ded1e 100644 --- a/src/displayapp/screens/PineTimeStyle.h +++ b/src/displayapp/screens/PineTimeStyle.h @@ -42,7 +42,7 @@ namespace Pinetime { Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; uint8_t currentDay = 0; - DirtyValue batteryPercentRemaining {}; + DirtyValue batteryPercentRemaining {}; DirtyValue bleState {}; DirtyValue> currentDateTime {}; DirtyValue motionSensorOk {}; diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index 5ae3a595..f5bf0cc9 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -103,7 +103,7 @@ std::unique_ptr SystemInfo::CreateScreen1() { } std::unique_ptr SystemInfo::CreateScreen2() { - auto batteryPercent = static_cast(batteryController.PercentRemaining()); + auto batteryPercent = batteryController.PercentRemaining(); auto resetReason = [this]() { switch (watchdog.ResetReason()) { case Drivers::Watchdog::ResetReasons::Watchdog: diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 0051408c..b0eb65bc 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -165,7 +165,6 @@ void WatchFaceAnalog::UpdateClock() { } bool WatchFaceAnalog::Refresh() { - batteryPercentRemaining = batteryController.PercentRemaining(); if (batteryPercentRemaining.IsUpdated()) { auto batteryPercent = batteryPercentRemaining.Get(); diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index 96225558..ac7f0ac5 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -48,7 +48,7 @@ namespace Pinetime { Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; uint8_t currentDay = 0; - DirtyValue batteryPercentRemaining {0}; + DirtyValue batteryPercentRemaining {0}; DirtyValue> currentDateTime; DirtyValue notificationState {false}; diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 246efc95..76c8d3dc 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -45,7 +45,7 @@ namespace Pinetime { Pinetime::Controllers::DateTime::Days currentDayOfWeek = Pinetime::Controllers::DateTime::Days::Unknown; uint8_t currentDay = 0; - DirtyValue batteryPercentRemaining {}; + DirtyValue batteryPercentRemaining {}; DirtyValue bleState {}; DirtyValue> currentDateTime {}; DirtyValue motionSensorOk {}; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 17e78230..eb29638a 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -330,6 +330,11 @@ void SystemTask::Work() { } } + if (xTaskGetTickCount() - batteryNotificationTick > batteryNotificationPeriod) { + nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining()); + batteryNotificationTick = xTaskGetTickCount(); + } + monitor.Process(); uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); dateTimeController.UpdateTime(systick_counter); diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index bfb97264..f8cf6370 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -135,6 +135,8 @@ namespace Pinetime { void GoToRunning(); void UpdateMotion(); bool stepCounterMustBeReset = false; + static constexpr TickType_t batteryNotificationPeriod = 1000 * 60 * 10; // 1 tick ~= 1ms. 1ms * 60 * 10 = 10 minutes + TickType_t batteryNotificationTick = 0; #if configUSE_TRACE_FACILITY == 1 SystemMonitor monitor; From a5616b0bc8ea385c3c70ae700498c8abe07f647b Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Tue, 13 Jul 2021 21:42:59 +0300 Subject: [PATCH 3/5] Adjust displayapp delay to compensate time spent (#482) --- src/displayapp/DisplayApp.cpp | 11 +++++++++-- src/displayapp/DisplayApp.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 04ebd2d3..6d66afe5 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -114,6 +114,7 @@ uint32_t count = 0; bool toggle = true; void DisplayApp::Refresh() { TickType_t queueTimeout; + TickType_t delta; switch (state) { case States::Idle: IdleState(); @@ -121,7 +122,11 @@ void DisplayApp::Refresh() { break; case States::Running: RunningState(); - queueTimeout = 20; + delta = xTaskGetTickCount() - lastWakeTime; + if (delta > 20) { + delta = 20; + } + queueTimeout = 20 - delta; break; default: queueTimeout = portMAX_DELAY; @@ -129,7 +134,9 @@ void DisplayApp::Refresh() { } Messages msg; - if (xQueueReceive(msgQueue, &msg, queueTimeout)) { + bool messageReceived = xQueueReceive(msgQueue, &msg, queueTimeout); + lastWakeTime = xTaskGetTickCount(); + if (messageReceived) { switch (msg) { case Messages::GoToSleep: brightnessController.Backup(); diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 73a7cc36..f4573ab7 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -114,6 +114,7 @@ namespace Pinetime { Apps nextApp = Apps::None; DisplayApp::FullRefreshDirections nextDirection; + TickType_t lastWakeTime; }; } } From 7133287b76dae9d97a88bed5c5ca1976e507826d Mon Sep 17 00:00:00 2001 From: Riku Isokoski Date: Wed, 14 Jul 2021 21:35:21 +0300 Subject: [PATCH 4/5] Set correct refresh times for lvgl (#488) --- src/displayapp/DisplayApp.cpp | 8 +++++--- src/libs/lv_conf.h | 5 ++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 6d66afe5..071af0c8 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -43,6 +43,8 @@ #include "displayapp/screens/settings/SettingDisplay.h" #include "displayapp/screens/settings/SettingSteps.h" +#include "libs/lv_conf.h" + using namespace Pinetime::Applications; using namespace Pinetime::Applications::Display; @@ -123,10 +125,10 @@ void DisplayApp::Refresh() { case States::Running: RunningState(); delta = xTaskGetTickCount() - lastWakeTime; - if (delta > 20) { - delta = 20; + if (delta > LV_DISP_DEF_REFR_PERIOD) { + delta = LV_DISP_DEF_REFR_PERIOD; } - queueTimeout = 20 - delta; + queueTimeout = LV_DISP_DEF_REFR_PERIOD - delta; break; default: queueTimeout = portMAX_DELAY; diff --git a/src/libs/lv_conf.h b/src/libs/lv_conf.h index 65263daa..18fc3fa2 100644 --- a/src/libs/lv_conf.h +++ b/src/libs/lv_conf.h @@ -42,7 +42,7 @@ /* Default display refresh period. * Can be changed in the display driver (`lv_disp_drv_t`).*/ -#define LV_DISP_DEF_REFR_PERIOD 30 /*[ms]*/ +#define LV_DISP_DEF_REFR_PERIOD 20 /*[ms]*/ /* Dot Per Inch: used to initialize default sizes. * E.g. a button with width = LV_DPI / 2 -> half inch wide @@ -112,7 +112,7 @@ typedef int16_t lv_coord_t; * Can be changed in the Input device driver (`lv_indev_drv_t`)*/ /* Input device read period in milliseconds */ -#define LV_INDEV_DEF_READ_PERIOD 30 +#define LV_INDEV_DEF_READ_PERIOD 20 /* Drag threshold in pixels */ #define LV_INDEV_DEF_DRAG_LIMIT 10 @@ -128,7 +128,6 @@ typedef int16_t lv_coord_t; * Time between `LV_EVENT_LONG_PRESSED_REPEAT */ #define LV_INDEV_DEF_LONG_PRESS_REP_TIME 100 - /* Gesture threshold in pixels */ #define LV_INDEV_DEF_GESTURE_LIMIT 50 From 57b339707861c5688f5d432f1506a99df6bb0fce Mon Sep 17 00:00:00 2001 From: Kozova1 <30871100+Kozova1@users.noreply.github.com> Date: Wed, 14 Jul 2021 21:51:51 +0300 Subject: [PATCH 5/5] Multiple wakeup sources (#290) * Allow multiple wakeup modes at the same time. This commit adds multiple wakeup modes support. It does so by storing them as a uint8_t bitfield enum. It changes the following functions: Since multiple modes can be on now, older version would not cut it: WakeUpMode getWakeupMode() -> std::bitset<3> getWakeUpModes() Where each bit corresponds to a WakeUpMode We still need a way to check whether a specific wakeup mode is on, so: bool isWakeUpModeOn(const WakeUpMode mode) This function was changed to work correctly with the new implementation. setWakeUpMode(WakeupMode mode, bool enable) Previously, systemtask would exit SystemTask::OnTouchEvent() if the wake up mode was None or RaiseWrist, to prevent waking up when a touch was received. However, after enabling using multiple WakeUpModes, this caused a bug where when RaiseWrist was checked with SingleTap or DoubleTap, the tap detection wouldn't work. This commit fixes that bug. Next commit will update the settings WakeUpMode select UI to reflect these changes. Signed-off-by: Kozova1 * Updated UI to reflect multiple WakeUp sources being available. Signed-off-by: Kozova1 --- src/components/settings/Settings.h | 39 +++++++++--- .../screens/settings/SettingWakeUp.cpp | 60 +++++++++---------- .../screens/settings/SettingWakeUp.h | 5 ++ src/systemtask/SystemTask.cpp | 18 +++--- 4 files changed, 73 insertions(+), 49 deletions(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 577455eb..93d6d217 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include "components/datetime/DateTimeController.h" #include "components/brightness/BrightnessController.h" #include "components/fs/FS.h" @@ -11,7 +12,11 @@ namespace Pinetime { public: enum class ClockType : uint8_t { H24, H12 }; enum class Vibration : uint8_t { ON, OFF }; - enum class WakeUpMode : uint8_t { None, SingleTap, DoubleTap, RaiseWrist }; + enum class WakeUpMode : uint8_t { + SingleTap = 0, + DoubleTap = 1, + RaiseWrist = 2, + }; Settings(Pinetime::Controllers::FS& fs); @@ -72,15 +77,33 @@ namespace Pinetime { return settings.screenTimeOut; }; - void setWakeUpMode(WakeUpMode wakeUp) { - if (wakeUp != settings.wakeUpMode) { + void setWakeUpMode(WakeUpMode wakeUp, bool enabled) { + if (!isWakeUpModeOn(wakeUp)) { settingsChanged = true; } - settings.wakeUpMode = wakeUp; + settings.wakeUpMode.set(static_cast(wakeUp), enabled); + // Handle special behavior + if (enabled) { + switch (wakeUp) { + case WakeUpMode::SingleTap: + settings.wakeUpMode.set(static_cast(WakeUpMode::DoubleTap), false); + break; + case WakeUpMode::DoubleTap: + settings.wakeUpMode.set(static_cast(WakeUpMode::SingleTap), false); + break; + case WakeUpMode::RaiseWrist: + break; + } + } }; - WakeUpMode getWakeUpMode() const { + + std::bitset<3> getWakeUpModes() const { return settings.wakeUpMode; - }; + } + + bool isWakeUpModeOn(const WakeUpMode mode) const { + return getWakeUpModes()[static_cast(mode)]; + } void SetBrightness(Controllers::BrightnessController::Levels level) { if (level != settings.brightLevel) { @@ -116,7 +139,7 @@ namespace Pinetime { uint8_t clockFace = 0; - WakeUpMode wakeUpMode = WakeUpMode::None; + std::bitset<3> wakeUpMode {0}; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; }; @@ -131,4 +154,4 @@ namespace Pinetime { void SaveSettingsToFile(); }; } -} \ No newline at end of file +} diff --git a/src/displayapp/screens/settings/SettingWakeUp.cpp b/src/displayapp/screens/settings/SettingWakeUp.cpp index 89f0c098..0e080353 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.cpp +++ b/src/displayapp/screens/settings/SettingWakeUp.cpp @@ -16,7 +16,7 @@ namespace { SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) : Screen(app), settingsController {settingsController} { - + ignoringEvents = false; lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); @@ -42,18 +42,10 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime:: optionsTotal = 0; cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text_static(cbOption[optionsTotal], " None"); - cbOption[optionsTotal]->user_data = this; - lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::None) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); - } - optionsTotal++; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); lv_checkbox_set_text_static(cbOption[optionsTotal], " Single Tap"); cbOption[optionsTotal]->user_data = this; lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::SingleTap) { + if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) { lv_checkbox_set_checked(cbOption[optionsTotal], true); } optionsTotal++; @@ -61,7 +53,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime:: lv_checkbox_set_text_static(cbOption[optionsTotal], " Double Tap"); cbOption[optionsTotal]->user_data = this; lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) { + if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { lv_checkbox_set_checked(cbOption[optionsTotal], true); } optionsTotal++; @@ -69,7 +61,7 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime:: lv_checkbox_set_text_static(cbOption[optionsTotal], " Raise Wrist"); cbOption[optionsTotal]->user_data = this; lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) { + if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) { lv_checkbox_set_checked(cbOption[optionsTotal], true); } optionsTotal++; @@ -85,27 +77,31 @@ bool SettingWakeUp::Refresh() { } void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - for (int i = 0; i < optionsTotal; i++) { - if (object == cbOption[i]) { - lv_checkbox_set_checked(cbOption[i], true); + using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode; + if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) { + ignoringEvents = true; - if (i == 0) { - settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::None); - }; - if (i == 1) { - settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::SingleTap); - }; - if (i == 2) { - settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap); - }; - if (i == 3) { - settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist); - }; - - } else { - lv_checkbox_set_checked(cbOption[i], false); + // Find the index of the checkbox that triggered the event + int index = 0; + for (; index < optionsTotal; ++index) { + if (cbOption[index] == object) { + break; } } + + // Toggle needed wakeup mode + auto mode = static_cast(index); + auto currentState = settingsController.isWakeUpModeOn(mode); + settingsController.setWakeUpMode(mode, !currentState); + + // Update checkbox according to current wakeup modes. + // This is needed because we can have extra logic when setting or unsetting wakeup modes, + // for example, when setting SingleTap, DoubleTap is unset and vice versa. + auto modes = settingsController.getWakeUpModes(); + for (int i = 0; i < optionsTotal; ++i) { + lv_checkbox_set_checked(cbOption[i], modes[i]); + } + + ignoringEvents = false; } -} \ No newline at end of file +} diff --git a/src/displayapp/screens/settings/SettingWakeUp.h b/src/displayapp/screens/settings/SettingWakeUp.h index 8b33eb06..248dd9ac 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.h +++ b/src/displayapp/screens/settings/SettingWakeUp.h @@ -22,6 +22,11 @@ namespace Pinetime { Controllers::Settings& settingsController; uint8_t optionsTotal; lv_obj_t* cbOption[4]; + // When UpdateSelected is called, it uses lv_checkbox_set_checked, + // which can cause extra events to be fired, + // which might trigger UpdateSelected again, causing a loop. + // This variable is used as a mutex to prevent that. + bool ignoringEvents; }; } } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index eb29638a..d8b965b1 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -211,7 +211,7 @@ void SystemTask::Work() { twiMaster.Wakeup(); // Double Tap needs the touch screen to be in normal mode - if (settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) { + if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { touchPanel.Wakeup(); } @@ -232,9 +232,9 @@ void SystemTask::Work() { auto touchInfo = touchPanel.GetTouchInfo(); twiMaster.Sleep(); if (touchInfo.isTouch and ((touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::DoubleTap and - settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) or + settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) or (touchInfo.gesture == Pinetime::Drivers::Cst816S::Gestures::SingleTap and - settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::SingleTap))) { + settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)))) { GoToRunning(); } } break; @@ -296,7 +296,7 @@ void SystemTask::Work() { spi.Sleep(); // Double Tap needs the touch screen to be in normal mode - if (settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::DoubleTap) { + if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { touchPanel.Sleep(); } twiMaster.Sleep(); @@ -348,7 +348,7 @@ void SystemTask::UpdateMotion() { if (isGoingToSleep or isWakingUp) return; - if (isSleeping && settingsController.getWakeUpMode() != Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) + if (isSleeping && !settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) return; if (isSleeping) @@ -399,10 +399,10 @@ void SystemTask::OnTouchEvent() { PushMessage(Messages::OnTouchEvent); displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent); } else if (!isWakingUp) { - if (settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::None or - settingsController.getWakeUpMode() == Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) - return; - PushMessage(Messages::TouchWakeUp); + if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap) or + settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { + PushMessage(Messages::TouchWakeUp); + } } }