From f7b1111e05c3e5b6652507d2964366cb3cc8739c Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 31 Mar 2023 10:00:56 +0200 Subject: [PATCH 01/32] add heart rate measurments in the background --- src/heartratetask/HeartRateTask.cpp | 136 ++++++++++++++++++---------- src/heartratetask/HeartRateTask.h | 11 ++- 2 files changed, 95 insertions(+), 52 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 9d82d11e..0159f938 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -24,78 +24,59 @@ void HeartRateTask::Process(void* instance) { } void HeartRateTask::Work() { - int lastBpm = 0; - while (true) { - Messages msg; - uint32_t delay; - if (state == States::Running) { - if (measurementStarted) { - delay = ppg.deltaTms; - } else { - delay = 100; - } - } else { - delay = portMAX_DELAY; - } + lastBpm = 0; - if (xQueueReceive(messageQueue, &msg, delay)) { + while (true) { + auto delay = CurrentTaskDelay(); + Messages msg; + + if (xQueueReceive(messageQueue, &msg, delay) == pdTRUE) { switch (msg) { case Messages::GoToSleep: - StopMeasurement(); - state = States::Idle; + if (state == States::Running) { + state = States::Idle; + } else if (state == States::Measuring) { + state = States::BackgroundWaiting; + backgroundMeasurementWaitingStart = xTaskGetTickCount(); + StopMeasurement(); + } break; case Messages::WakeUp: - state = States::Running; - if (measurementStarted) { - lastBpm = 0; + if (state == States::Idle) { + state = States::Running; + } else if (state == States::BackgroundMeasuring) { + state = States::Measuring; + } else if (state == States::BackgroundWaiting) { + state = States::Measuring; StartMeasurement(); } break; case Messages::StartMeasurement: - if (measurementStarted) { + if (state == States::Measuring || state == States::BackgroundMeasuring) { break; } + state = States::Measuring; lastBpm = 0; StartMeasurement(); - measurementStarted = true; break; case Messages::StopMeasurement: - if (!measurementStarted) { + if (state == States::Running || state == States::Idle) { break; } + if (state == States::Measuring) { + state = States::Running; + } else if (state == States::BackgroundMeasuring) { + state = States::Idle; + } StopMeasurement(); - measurementStarted = false; break; } } - if (measurementStarted) { - int8_t ambient = ppg.Preprocess(heartRateSensor.ReadHrs(), heartRateSensor.ReadAls()); - int bpm = ppg.HeartRate(); - - // If ambient light detected or a reset requested (bpm < 0) - if (ambient > 0) { - // Reset all DAQ buffers - ppg.Reset(true); - // Force state to NotEnoughData (below) - lastBpm = 0; - bpm = 0; - } else if (bpm < 0) { - // Reset all DAQ buffers except HRS buffer - ppg.Reset(false); - // Set HR to zero and update - bpm = 0; - controller.Update(Controllers::HeartRateController::States::Running, bpm); - } - - if (lastBpm == 0 && bpm == 0) { - controller.Update(Controllers::HeartRateController::States::NotEnoughData, bpm); - } - - if (bpm != 0) { - lastBpm = bpm; - controller.Update(Controllers::HeartRateController::States::Running, lastBpm); - } + if (state == States::BackgroundWaiting) { + HandleBackgroundWaiting(); + } else if (state == States::BackgroundMeasuring || state == States::Measuring) { + HandleSensorData(); } } } @@ -117,3 +98,58 @@ void HeartRateTask::StopMeasurement() { ppg.Reset(true); vTaskDelay(100); } + +void HeartRateTask::HandleBackgroundWaiting() { + if (xTaskGetTickCount() - backgroundMeasurementWaitingStart >= DURATION_BETWEEN_BACKGROUND_MEASUREMENTS) { + state = States::BackgroundMeasuring; + StartMeasurement(); + } +} + +void HeartRateTask::HandleSensorData() { + int8_t ambient = ppg.Preprocess(heartRateSensor.ReadHrs(), heartRateSensor.ReadAls()); + int bpm = ppg.HeartRate(); + + // If ambient light detected or a reset requested (bpm < 0) + if (ambient > 0) { + // Reset all DAQ buffers + ppg.Reset(true); + // Force state to NotEnoughData (below) + lastBpm = 0; + bpm = 0; + } else if (bpm < 0) { + // Reset all DAQ buffers except HRS buffer + ppg.Reset(false); + // Set HR to zero and update + bpm = 0; + controller.Update(Controllers::HeartRateController::States::Running, bpm); + } + + if (lastBpm == 0 && bpm == 0) { + controller.Update(Controllers::HeartRateController::States::NotEnoughData, bpm); + } + + if (bpm != 0) { + lastBpm = bpm; + controller.Update(Controllers::HeartRateController::States::Running, lastBpm); + if (state == States::BackgroundMeasuring) { + StopMeasurement(); + state = States::BackgroundWaiting; + backgroundMeasurementWaitingStart = xTaskGetTickCount(); + } + } +} + +int HeartRateTask::CurrentTaskDelay() { + switch (state) { + case States::Measuring: + case States::BackgroundMeasuring: + return ppg.deltaTms; + case States::Running: + return 100; + case States::BackgroundWaiting: + return 500; + default: + return portMAX_DELAY; + } +} \ No newline at end of file diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 5bbfb9fb..ab058227 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -4,6 +4,8 @@ #include #include +#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 Minutes assuming 1 Hz + namespace Pinetime { namespace Drivers { class Hrs3300; @@ -17,7 +19,7 @@ namespace Pinetime { class HeartRateTask { public: enum class Messages : uint8_t { GoToSleep, WakeUp, StartMeasurement, StopMeasurement }; - enum class States { Idle, Running }; + enum class States { Idle, Running, Measuring, BackgroundWaiting, BackgroundMeasuring }; explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller); void Start(); @@ -29,13 +31,18 @@ namespace Pinetime { void StartMeasurement(); void StopMeasurement(); + void HandleBackgroundWaiting(); + void HandleSensorData(); + int CurrentTaskDelay(); + TaskHandle_t taskHandle; QueueHandle_t messageQueue; States state = States::Running; Drivers::Hrs3300& heartRateSensor; Controllers::HeartRateController& controller; Controllers::Ppg ppg; - bool measurementStarted = false; + int lastBpm = 0; + TickType_t backgroundMeasurementWaitingStart; }; } From 58c507ee45ab08445e06030a6e29dc83641a6ddf Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 31 Mar 2023 10:25:36 +0200 Subject: [PATCH 02/32] increase task delay when waiting in the background to 10s --- src/heartratetask/HeartRateTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 0159f938..f332fadf 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -148,7 +148,7 @@ int HeartRateTask::CurrentTaskDelay() { case States::Running: return 100; case States::BackgroundWaiting: - return 500; + return 10000; default: return portMAX_DELAY; } From 0370e3cd65fd77e9dd5289fa5484fcebd477fcf7 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Mon, 3 Apr 2023 21:29:17 +0200 Subject: [PATCH 03/32] remove background start timestamp reset on sleep --- src/heartratetask/HeartRateTask.cpp | 1 - src/heartratetask/HeartRateTask.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index f332fadf..f48045d8 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -37,7 +37,6 @@ void HeartRateTask::Work() { state = States::Idle; } else if (state == States::Measuring) { state = States::BackgroundWaiting; - backgroundMeasurementWaitingStart = xTaskGetTickCount(); StopMeasurement(); } break; diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index ab058227..61151af2 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -42,7 +42,7 @@ namespace Pinetime { Controllers::HeartRateController& controller; Controllers::Ppg ppg; int lastBpm = 0; - TickType_t backgroundMeasurementWaitingStart; + TickType_t backgroundMeasurementWaitingStart = 0; }; } From a5db54af2793a472f7e315d3580d1ee2c597a4f2 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 11 May 2023 23:47:31 +0200 Subject: [PATCH 04/32] rebase on main --- src/heartratetask/HeartRateTask.cpp | 16 ++++++---------- src/heartratetask/HeartRateTask.h | 3 +-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index f48045d8..a010cd44 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -24,7 +24,7 @@ void HeartRateTask::Process(void* instance) { } void HeartRateTask::Work() { - lastBpm = 0; + int lastBpm = 0; while (true) { auto delay = CurrentTaskDelay(); @@ -75,7 +75,7 @@ void HeartRateTask::Work() { if (state == States::BackgroundWaiting) { HandleBackgroundWaiting(); } else if (state == States::BackgroundMeasuring || state == States::Measuring) { - HandleSensorData(); + HandleSensorData(&lastBpm); } } } @@ -105,7 +105,7 @@ void HeartRateTask::HandleBackgroundWaiting() { } } -void HeartRateTask::HandleSensorData() { +void HeartRateTask::HandleSensorData(int* lastBpm) { int8_t ambient = ppg.Preprocess(heartRateSensor.ReadHrs(), heartRateSensor.ReadAls()); int bpm = ppg.HeartRate(); @@ -113,24 +113,20 @@ void HeartRateTask::HandleSensorData() { if (ambient > 0) { // Reset all DAQ buffers ppg.Reset(true); - // Force state to NotEnoughData (below) - lastBpm = 0; - bpm = 0; } else if (bpm < 0) { // Reset all DAQ buffers except HRS buffer ppg.Reset(false); // Set HR to zero and update bpm = 0; - controller.Update(Controllers::HeartRateController::States::Running, bpm); } - if (lastBpm == 0 && bpm == 0) { + if (*lastBpm == 0 && bpm == 0) { controller.Update(Controllers::HeartRateController::States::NotEnoughData, bpm); } if (bpm != 0) { - lastBpm = bpm; - controller.Update(Controllers::HeartRateController::States::Running, lastBpm); + *lastBpm = bpm; + controller.Update(Controllers::HeartRateController::States::Running, bpm); if (state == States::BackgroundMeasuring) { StopMeasurement(); state = States::BackgroundWaiting; diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 61151af2..d27f68e7 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -32,7 +32,7 @@ namespace Pinetime { void StopMeasurement(); void HandleBackgroundWaiting(); - void HandleSensorData(); + void HandleSensorData(int* lastBpm); int CurrentTaskDelay(); TaskHandle_t taskHandle; @@ -41,7 +41,6 @@ namespace Pinetime { Drivers::Hrs3300& heartRateSensor; Controllers::HeartRateController& controller; Controllers::Ppg ppg; - int lastBpm = 0; TickType_t backgroundMeasurementWaitingStart = 0; }; From 7ae790bcdb40c8f849f047f5138b8b091177471d Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 25 May 2023 23:41:26 +0200 Subject: [PATCH 05/32] stop background after 30s of no data from the heart rate sensor --- src/heartratetask/HeartRateTask.cpp | 17 +++++++++++++---- src/heartratetask/HeartRateTask.h | 7 +++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index a010cd44..1184ba1e 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -37,7 +37,7 @@ void HeartRateTask::Work() { state = States::Idle; } else if (state == States::Measuring) { state = States::BackgroundWaiting; - StopMeasurement(); + StartWaiting(); } break; case Messages::WakeUp: @@ -90,6 +90,7 @@ void HeartRateTask::StartMeasurement() { heartRateSensor.Enable(); ppg.Reset(true); vTaskDelay(100); + measurementStart = xTaskGetTickCount(); } void HeartRateTask::StopMeasurement() { @@ -98,8 +99,13 @@ void HeartRateTask::StopMeasurement() { vTaskDelay(100); } +void HeartRateTask::StartWaiting() { + StopMeasurement(); + backgroundWaitingStart = xTaskGetTickCount(); +} + void HeartRateTask::HandleBackgroundWaiting() { - if (xTaskGetTickCount() - backgroundMeasurementWaitingStart >= DURATION_BETWEEN_BACKGROUND_MEASUREMENTS) { + if (xTaskGetTickCount() - backgroundWaitingStart >= DURATION_BETWEEN_BACKGROUND_MEASUREMENTS) { state = States::BackgroundMeasuring; StartMeasurement(); } @@ -128,11 +134,14 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { *lastBpm = bpm; controller.Update(Controllers::HeartRateController::States::Running, bpm); if (state == States::BackgroundMeasuring) { - StopMeasurement(); state = States::BackgroundWaiting; - backgroundMeasurementWaitingStart = xTaskGetTickCount(); + StartWaiting(); } } + if (bpm == 0 && state == States::BackgroundMeasuring && xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { + state = States::BackgroundWaiting; + StartWaiting(); + } } int HeartRateTask::CurrentTaskDelay() { diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index d27f68e7..620dcf24 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -4,7 +4,8 @@ #include #include -#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 Minutes assuming 1 Hz +#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz +#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz namespace Pinetime { namespace Drivers { @@ -30,6 +31,7 @@ namespace Pinetime { static void Process(void* instance); void StartMeasurement(); void StopMeasurement(); + void StartWaiting(); void HandleBackgroundWaiting(); void HandleSensorData(int* lastBpm); @@ -41,7 +43,8 @@ namespace Pinetime { Drivers::Hrs3300& heartRateSensor; Controllers::HeartRateController& controller; Controllers::Ppg ppg; - TickType_t backgroundMeasurementWaitingStart = 0; + TickType_t backgroundWaitingStart = 0; + TickType_t measurementStart = 0; }; } From 5dbe1f77b53fff25765b7cf75f92e79cb8dbc40b Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 7 Jul 2023 23:20:41 +0200 Subject: [PATCH 06/32] properly format using clang-format --- src/heartratetask/HeartRateTask.cpp | 29 +++++++++++++++-------------- src/heartratetask/HeartRateTask.h | 4 ++-- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 1184ba1e..25437c42 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -100,8 +100,8 @@ void HeartRateTask::StopMeasurement() { } void HeartRateTask::StartWaiting() { - StopMeasurement(); - backgroundWaitingStart = xTaskGetTickCount(); + StopMeasurement(); + backgroundWaitingStart = xTaskGetTickCount(); } void HeartRateTask::HandleBackgroundWaiting() { @@ -138,22 +138,23 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { StartWaiting(); } } - if (bpm == 0 && state == States::BackgroundMeasuring && xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { + if (bpm == 0 && state == States::BackgroundMeasuring && + xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { state = States::BackgroundWaiting; StartWaiting(); } } int HeartRateTask::CurrentTaskDelay() { - switch (state) { - case States::Measuring: - case States::BackgroundMeasuring: - return ppg.deltaTms; - case States::Running: - return 100; - case States::BackgroundWaiting: - return 10000; - default: - return portMAX_DELAY; - } + switch (state) { + case States::Measuring: + case States::BackgroundMeasuring: + return ppg.deltaTms; + case States::Running: + return 100; + case States::BackgroundWaiting: + return 10000; + default: + return portMAX_DELAY; + } } \ No newline at end of file diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 620dcf24..d087d517 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -4,8 +4,8 @@ #include #include -#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz -#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz +#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz +#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz namespace Pinetime { namespace Drivers { From 27ee1eb2c85b70280c1f31b316ae99dc7825adb8 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 25 Aug 2023 02:10:45 +0200 Subject: [PATCH 07/32] add settings screen to choose heartrate measurement background --- src/CMakeLists.txt | 1 + src/components/settings/Settings.h | 13 +++ src/displayapp/DisplayApp.cpp | 4 + .../screens/settings/SettingHeartRate.cpp | 85 +++++++++++++++++++ .../screens/settings/SettingHeartRate.h | 42 +++++++++ src/displayapp/screens/settings/Settings.h | 8 +- src/heartratetask/HeartRateTask.cpp | 13 ++- src/heartratetask/HeartRateTask.h | 9 +- src/main.cpp | 6 +- 9 files changed, 169 insertions(+), 12 deletions(-) create mode 100644 src/displayapp/screens/settings/SettingHeartRate.cpp create mode 100644 src/displayapp/screens/settings/SettingHeartRate.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd8ece62..ca373119 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -411,6 +411,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingWeatherFormat.cpp displayapp/screens/settings/SettingWakeUp.cpp displayapp/screens/settings/SettingDisplay.cpp + displayapp/screens/settings/SettingHeartRate.cpp displayapp/screens/settings/SettingSteps.cpp displayapp/screens/settings/SettingSetDateTime.cpp displayapp/screens/settings/SettingSetDate.cpp diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 06312077..77c1ca1a 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -283,6 +283,17 @@ namespace Pinetime { return bleRadioEnabled; }; + uint32_t GetHeartRateBackgroundMeasurementInterval() const { + return settings.heartRateBackgroundMeasurementInterval; + } + + void SetHeartRateBackgroundMeasurementInterval(uint32_t newHeartRateBackgroundMeasurementInterval) { + if (newHeartRateBackgroundMeasurementInterval != settings.heartRateBackgroundMeasurementInterval) { + settingsChanged = true; + } + settings.heartRateBackgroundMeasurementInterval = newHeartRateBackgroundMeasurementInterval; + } + private: Pinetime::Controllers::FS& fs; @@ -308,6 +319,8 @@ namespace Pinetime { uint16_t shakeWakeThreshold = 150; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; + + uint32_t heartRateBackgroundMeasurementInterval = 0; }; SettingsData settings; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 3fd34b3a..94975db8 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -47,6 +47,7 @@ #include "displayapp/screens/settings/SettingSteps.h" #include "displayapp/screens/settings/SettingSetDateTime.h" #include "displayapp/screens/settings/SettingChimes.h" +#include "displayapp/screens/settings/SettingHeartRate.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" @@ -506,6 +507,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio case Apps::SettingWakeUp: currentScreen = std::make_unique(settingsController); break; + case Apps::SettingHeartRate: + currentScreen = std::make_unique(this, settingsController); + break; case Apps::SettingDisplay: currentScreen = std::make_unique(this, settingsController); break; diff --git a/src/displayapp/screens/settings/SettingHeartRate.cpp b/src/displayapp/screens/settings/SettingHeartRate.cpp new file mode 100644 index 00000000..8460e260 --- /dev/null +++ b/src/displayapp/screens/settings/SettingHeartRate.cpp @@ -0,0 +1,85 @@ +#include "displayapp/screens/settings/SettingHeartRate.h" +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" +#include +#include + +using namespace Pinetime::Applications::Screens; + +constexpr const char* SettingHeartRate::title; +constexpr const char* SettingHeartRate::symbol; + +namespace { + constexpr std::array intervalOptions = {{ + 0, + 30 * 1000, + 60 * 1000, + 5 * 60 * 1000, + 10 * 60 * 1000, + 30 * 60 * 1000, + }}; + + constexpr std::array options = {{ + {"Off", true}, + {"30s", true}, + {"1 min", true}, + {"5 min", true}, + {"10 min", true}, + {"30 min", true}, + {"", false}, + {"", false}, + }}; + + uint32_t GetDefaultOption(uint32_t currentInterval) { + for (size_t i = 0; i < intervalOptions.size(); i++) { + if (intervalOptions[i] == currentInterval) { + return i; + } + } + return 0; + } +} + +auto SettingHeartRate::CreateScreenList() const { + std::array()>, nScreens> screens; + for (size_t i = 0; i < screens.size(); i++) { + screens[i] = [this, i]() -> std::unique_ptr { + return CreateScreen(i); + }; + } + return screens; +} + +SettingHeartRate::SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settings) + : app {app}, settings {settings}, screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} { +} + +SettingHeartRate::~SettingHeartRate() { + lv_obj_clean(lv_scr_act()); +} + +bool SettingHeartRate::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + return screens.OnTouchEvent(event); +} + +std::unique_ptr SettingHeartRate::CreateScreen(unsigned int screenNum) const { + std::array optionsOnThisScreen; + for (int i = 0; i < optionsPerScreen; i++) { + optionsOnThisScreen[i] = options[screenNum * optionsPerScreen + i]; + } + + return std::make_unique( + screenNum, + nScreens, + title, + symbol, + GetDefaultOption(settings.GetHeartRateBackgroundMeasurementInterval()), + [&settings = settings](uint32_t index) { + settings.SetHeartRateBackgroundMeasurementInterval(intervalOptions[index]); + settings.SaveSettings(); + }, + optionsOnThisScreen); +} \ No newline at end of file diff --git a/src/displayapp/screens/settings/SettingHeartRate.h b/src/displayapp/screens/settings/SettingHeartRate.h new file mode 100644 index 00000000..6b4ba581 --- /dev/null +++ b/src/displayapp/screens/settings/SettingHeartRate.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#include "components/settings/Settings.h" +#include "displayapp/screens/ScreenList.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/screens/CheckboxList.h" + +namespace Pinetime { + + namespace Applications { + namespace Screens { + + class SettingHeartRate : public Screen { + public: + SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settings); + ~SettingHeartRate() override; + + bool OnTouchEvent(TouchEvents event) override; + + private: + DisplayApp* app; + + auto CreateScreenList() const; + std::unique_ptr CreateScreen(unsigned int screenNum) const; + + Pinetime::Controllers::Settings& settings; + + static constexpr const char* title = "Backg. Interval"; + static constexpr const char* symbol = Symbols::heartBeat; + + static constexpr int optionsPerScreen = 4; + static constexpr int nScreens = 2; + + ScreenList screens; + }; + } + } +} diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index a21b4ccd..0098b304 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -38,6 +38,7 @@ namespace Pinetime { {Symbols::home, "Watch face", Apps::SettingWatchFace}, {Symbols::shoe, "Steps", Apps::SettingSteps}, + {Symbols::heartBeat, "Heartrate", Apps::SettingHeartRate}, {Symbols::clock, "Date&Time", Apps::SettingSetDateTime}, {Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat}, {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, @@ -49,9 +50,10 @@ namespace Pinetime { {Symbols::list, "About", Apps::SysInfo}, - // {Symbols::none, "None", Apps::None}, - // {Symbols::none, "None", Apps::None}, - // {Symbols::none, "None", Apps::None}, + {Symbols::none, "None", Apps::None}, + {Symbols::none, "None", Apps::None}, + {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, }}; diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 25437c42..e833dfe0 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -5,8 +5,10 @@ using namespace Pinetime::Applications; -HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller) - : heartRateSensor {heartRateSensor}, controller {controller} { +HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, + Controllers::HeartRateController& controller, + Controllers::Settings& settings) + : heartRateSensor {heartRateSensor}, controller {controller}, settings {settings} { } void HeartRateTask::Start() { @@ -105,7 +107,12 @@ void HeartRateTask::StartWaiting() { } void HeartRateTask::HandleBackgroundWaiting() { - if (xTaskGetTickCount() - backgroundWaitingStart >= DURATION_BETWEEN_BACKGROUND_MEASUREMENTS) { + if (settings.GetHeartRateBackgroundMeasurementInterval() == 0) { + // stay waiting + return; + } + + if (xTaskGetTickCount() - backgroundWaitingStart >= settings.GetHeartRateBackgroundMeasurementInterval()) { state = States::BackgroundMeasuring; StartMeasurement(); } diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index d087d517..80b6abc8 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -3,9 +3,9 @@ #include #include #include +#include "components/settings/Settings.h" -#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz -#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz +#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz namespace Pinetime { namespace Drivers { @@ -22,7 +22,9 @@ namespace Pinetime { enum class Messages : uint8_t { GoToSleep, WakeUp, StartMeasurement, StopMeasurement }; enum class States { Idle, Running, Measuring, BackgroundWaiting, BackgroundMeasuring }; - explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller); + explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, + Controllers::HeartRateController& controller, + Controllers::Settings& settings); void Start(); void Work(); void PushMessage(Messages msg); @@ -42,6 +44,7 @@ namespace Pinetime { States state = States::Running; Drivers::Hrs3300& heartRateSensor; Controllers::HeartRateController& controller; + Controllers::Settings& settings; Controllers::Ppg ppg; TickType_t backgroundWaitingStart = 0; TickType_t measurementStart = 0; diff --git a/src/main.cpp b/src/main.cpp index ee6a6d3d..6a957336 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,13 +93,13 @@ TimerHandle_t debounceChargeTimer; Pinetime::Controllers::Battery batteryController; Pinetime::Controllers::Ble bleController; -Pinetime::Controllers::HeartRateController heartRateController; -Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController); - Pinetime::Controllers::FS fs {spiNorFlash}; Pinetime::Controllers::Settings settingsController {fs}; Pinetime::Controllers::MotorController motorController {}; +Pinetime::Controllers::HeartRateController heartRateController; +Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController, settingsController); + Pinetime::Controllers::DateTime dateTimeController {settingsController}; Pinetime::Drivers::Watchdog watchdog; Pinetime::Controllers::NotificationManager notificationManager; From be1a5190982aec62d66f3341019cab3d69381fb8 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 25 Aug 2023 13:06:18 +0200 Subject: [PATCH 08/32] use different style for the heartrate settings and fix issues with settings file --- src/components/settings/Settings.cpp | 1 - src/components/settings/Settings.h | 1 + .../screens/settings/SettingHeartRate.cpp | 115 ++++++++---------- .../screens/settings/SettingHeartRate.h | 30 +++-- src/heartratetask/HeartRateTask.cpp | 2 +- 5 files changed, 73 insertions(+), 76 deletions(-) diff --git a/src/components/settings/Settings.cpp b/src/components/settings/Settings.cpp index 1ae00a2d..05ab23d4 100644 --- a/src/components/settings/Settings.cpp +++ b/src/components/settings/Settings.cpp @@ -8,7 +8,6 @@ Settings::Settings(Pinetime::Controllers::FS& fs) : fs {fs} { } void Settings::Init() { - // Load default settings from Flash LoadSettingsFromFile(); } diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 77c1ca1a..53ab75a2 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -320,6 +320,7 @@ namespace Pinetime { Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; + // The interval for measuring the heart rate when the screen is off (in seconds) uint32_t heartRateBackgroundMeasurementInterval = 0; }; diff --git a/src/displayapp/screens/settings/SettingHeartRate.cpp b/src/displayapp/screens/settings/SettingHeartRate.cpp index 8460e260..99f4a463 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.cpp +++ b/src/displayapp/screens/settings/SettingHeartRate.cpp @@ -9,77 +9,68 @@ using namespace Pinetime::Applications::Screens; -constexpr const char* SettingHeartRate::title; -constexpr const char* SettingHeartRate::symbol; - namespace { - constexpr std::array intervalOptions = {{ - 0, - 30 * 1000, - 60 * 1000, - 5 * 60 * 1000, - 10 * 60 * 1000, - 30 * 60 * 1000, - }}; + void event_handler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->UpdateSelected(obj, event); + } +} - constexpr std::array options = {{ - {"Off", true}, - {"30s", true}, - {"1 min", true}, - {"5 min", true}, - {"10 min", true}, - {"30 min", true}, - {"", false}, - {"", false}, - }}; +constexpr std::array SettingHeartRate::options; - uint32_t GetDefaultOption(uint32_t currentInterval) { - for (size_t i = 0; i < intervalOptions.size(); i++) { - if (intervalOptions[i] == currentInterval) { - return i; - } +SettingHeartRate::SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) + : app {app}, settingsController {settingsController} { + + 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); + lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); + lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); + lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + + lv_obj_set_pos(container1, 10, 60); + lv_obj_set_width(container1, LV_HOR_RES - 20); + lv_obj_set_height(container1, LV_VER_RES - 50); + lv_cont_set_layout(container1, LV_LAYOUT_PRETTY_TOP); + + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, "Backg. Interval"); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 15); + + lv_obj_t* icon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_label_set_text_static(icon, Symbols::heartBeat); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + for (unsigned int i = 0; i < options.size(); i++) { + cbOption[i] = lv_checkbox_create(container1, nullptr); + lv_checkbox_set_text(cbOption[i], options[i].name); + cbOption[i]->user_data = this; + lv_obj_set_event_cb(cbOption[i], event_handler); + SetRadioButtonStyle(cbOption[i]); + + if (settingsController.GetHeartRateBackgroundMeasurementInterval() == options[i].interval) { + lv_checkbox_set_checked(cbOption[i], true); } - return 0; } } -auto SettingHeartRate::CreateScreenList() const { - std::array()>, nScreens> screens; - for (size_t i = 0; i < screens.size(); i++) { - screens[i] = [this, i]() -> std::unique_ptr { - return CreateScreen(i); - }; - } - return screens; -} - -SettingHeartRate::SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settings) - : app {app}, settings {settings}, screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} { -} - SettingHeartRate::~SettingHeartRate() { lv_obj_clean(lv_scr_act()); + settingsController.SaveSettings(); } -bool SettingHeartRate::OnTouchEvent(Pinetime::Applications::TouchEvents event) { - return screens.OnTouchEvent(event); -} - -std::unique_ptr SettingHeartRate::CreateScreen(unsigned int screenNum) const { - std::array optionsOnThisScreen; - for (int i = 0; i < optionsPerScreen; i++) { - optionsOnThisScreen[i] = options[screenNum * optionsPerScreen + i]; +void SettingHeartRate::UpdateSelected(lv_obj_t* object, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + for (unsigned int i = 0; i < options.size(); i++) { + if (object == cbOption[i]) { + lv_checkbox_set_checked(cbOption[i], true); + settingsController.SetHeartRateBackgroundMeasurementInterval(options[i].interval); + } else { + lv_checkbox_set_checked(cbOption[i], false); + } + } } - - return std::make_unique( - screenNum, - nScreens, - title, - symbol, - GetDefaultOption(settings.GetHeartRateBackgroundMeasurementInterval()), - [&settings = settings](uint32_t index) { - settings.SetHeartRateBackgroundMeasurementInterval(intervalOptions[index]); - settings.SaveSettings(); - }, - optionsOnThisScreen); -} \ No newline at end of file +} diff --git a/src/displayapp/screens/settings/SettingHeartRate.h b/src/displayapp/screens/settings/SettingHeartRate.h index 6b4ba581..28605bac 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.h +++ b/src/displayapp/screens/settings/SettingHeartRate.h @@ -14,28 +14,34 @@ namespace Pinetime { namespace Applications { namespace Screens { + struct Option { + const uint32_t interval; + const char* name; + }; + class SettingHeartRate : public Screen { public: SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settings); ~SettingHeartRate() override; - bool OnTouchEvent(TouchEvents event) override; + void UpdateSelected(lv_obj_t* object, lv_event_t event); private: DisplayApp* app; + Pinetime::Controllers::Settings& settingsController; - auto CreateScreenList() const; - std::unique_ptr CreateScreen(unsigned int screenNum) const; + static constexpr std::array options = {{ + {0, "Off"}, + {10, "10s"}, + {30, "30s"}, + {60, " 1m"}, + {5 * 60, " 5m"}, + {10 * 60, "10m"}, + {30 * 60, "30m"}, + {60 * 60, " 1h"}, + }}; - Pinetime::Controllers::Settings& settings; - - static constexpr const char* title = "Backg. Interval"; - static constexpr const char* symbol = Symbols::heartBeat; - - static constexpr int optionsPerScreen = 4; - static constexpr int nScreens = 2; - - ScreenList screens; + lv_obj_t* cbOption[options.size()]; }; } } diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index e833dfe0..531cdf5e 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -112,7 +112,7 @@ void HeartRateTask::HandleBackgroundWaiting() { return; } - if (xTaskGetTickCount() - backgroundWaitingStart >= settings.GetHeartRateBackgroundMeasurementInterval()) { + if (xTaskGetTickCount() - backgroundWaitingStart >= settings.GetHeartRateBackgroundMeasurementInterval() * 1000) { state = States::BackgroundMeasuring; StartMeasurement(); } From d376a856b7323217e40349a16750805a18771f5d Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Sat, 26 Aug 2023 20:35:39 +0200 Subject: [PATCH 09/32] use enum instead of uint32_t for heartrater interval setting --- src/components/settings/Settings.h | 18 ++++++-- .../screens/settings/SettingHeartRate.cpp | 3 +- .../screens/settings/SettingHeartRate.h | 18 ++++---- src/heartratetask/HeartRateTask.cpp | 43 ++++++++++++++++--- src/heartratetask/HeartRateTask.h | 4 ++ 5 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 53ab75a2..94fde265 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -50,6 +50,17 @@ namespace Pinetime { int colorIndex = 0; }; + enum class HeartRateBackgroundMeasurementInterval : uint8_t { + Off, + Continuous, + TenSeconds, + ThirtySeconds, + OneMinute, + FiveMinutes, + TenMinutes, + ThirtyMinutes, + }; + Settings(Pinetime::Controllers::FS& fs); Settings(const Settings&) = delete; @@ -283,11 +294,11 @@ namespace Pinetime { return bleRadioEnabled; }; - uint32_t GetHeartRateBackgroundMeasurementInterval() const { + HeartRateBackgroundMeasurementInterval GetHeartRateBackgroundMeasurementInterval() const { return settings.heartRateBackgroundMeasurementInterval; } - void SetHeartRateBackgroundMeasurementInterval(uint32_t newHeartRateBackgroundMeasurementInterval) { + void SetHeartRateBackgroundMeasurementInterval(HeartRateBackgroundMeasurementInterval newHeartRateBackgroundMeasurementInterval) { if (newHeartRateBackgroundMeasurementInterval != settings.heartRateBackgroundMeasurementInterval) { settingsChanged = true; } @@ -320,8 +331,7 @@ namespace Pinetime { Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; - // The interval for measuring the heart rate when the screen is off (in seconds) - uint32_t heartRateBackgroundMeasurementInterval = 0; + HeartRateBackgroundMeasurementInterval heartRateBackgroundMeasurementInterval = HeartRateBackgroundMeasurementInterval::Off; }; SettingsData settings; diff --git a/src/displayapp/screens/settings/SettingHeartRate.cpp b/src/displayapp/screens/settings/SettingHeartRate.cpp index 99f4a463..d3da19b2 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.cpp +++ b/src/displayapp/screens/settings/SettingHeartRate.cpp @@ -24,7 +24,7 @@ SettingHeartRate::SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pine 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); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); + lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); @@ -35,6 +35,7 @@ SettingHeartRate::SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pine lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Backg. Interval"); + lv_label_set_text(title, "Backg. Interval"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 15); diff --git a/src/displayapp/screens/settings/SettingHeartRate.h b/src/displayapp/screens/settings/SettingHeartRate.h index 28605bac..40eff744 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.h +++ b/src/displayapp/screens/settings/SettingHeartRate.h @@ -15,7 +15,7 @@ namespace Pinetime { namespace Screens { struct Option { - const uint32_t interval; + const Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval interval; const char* name; }; @@ -31,14 +31,14 @@ namespace Pinetime { Pinetime::Controllers::Settings& settingsController; static constexpr std::array options = {{ - {0, "Off"}, - {10, "10s"}, - {30, "30s"}, - {60, " 1m"}, - {5 * 60, " 5m"}, - {10 * 60, "10m"}, - {30 * 60, "30m"}, - {60 * 60, " 1h"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off, " Off"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous, "Cont"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds, " 10s"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds, " 30s"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute, " 1m"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes, " 5m"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenMinutes, " 10m"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtyMinutes, " 30m"}, }}; lv_obj_t* cbOption[options.size()]; diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 531cdf5e..56439e93 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -107,12 +107,12 @@ void HeartRateTask::StartWaiting() { } void HeartRateTask::HandleBackgroundWaiting() { - if (settings.GetHeartRateBackgroundMeasurementInterval() == 0) { - // stay waiting + if (!IsBackgroundMeasurementActivated()) { return; } - if (xTaskGetTickCount() - backgroundWaitingStart >= settings.GetHeartRateBackgroundMeasurementInterval() * 1000) { + TickType_t ticksSinceWaitingStart = xTaskGetTickCount() - backgroundWaitingStart; + if (ticksSinceWaitingStart >= GetHeartRateBackgroundMeasurementIntervalInTicks()) { state = States::BackgroundMeasuring; StartMeasurement(); } @@ -140,13 +140,17 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { if (bpm != 0) { *lastBpm = bpm; controller.Update(Controllers::HeartRateController::States::Running, bpm); + if (state == States::Measuring || IsContinuosModeActivated()) { + return; + } if (state == States::BackgroundMeasuring) { state = States::BackgroundWaiting; StartWaiting(); } } - if (bpm == 0 && state == States::BackgroundMeasuring && - xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { + TickType_t ticksSinceMeasurementStart = xTaskGetTickCount() - measurementStart; + if (bpm == 0 && state == States::BackgroundMeasuring && !IsContinuosModeActivated() && + ticksSinceMeasurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { state = States::BackgroundWaiting; StartWaiting(); } @@ -164,4 +168,33 @@ int HeartRateTask::CurrentTaskDelay() { default: return portMAX_DELAY; } +} + +uint32_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { + switch (settings.GetHeartRateBackgroundMeasurementInterval()) { + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds: + return 10 * 1000; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds: + return 30 * 1000; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute: + return 60 * 1000; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes: + return 5 * 60 * 1000; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenMinutes: + return 10 * 60 * 1000; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtyMinutes: + return 30 * 60 * 1000; + default: + return 0; + } +} + +bool HeartRateTask::IsContinuosModeActivated() { + return settings.GetHeartRateBackgroundMeasurementInterval() == + Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous; +} + +bool HeartRateTask::IsBackgroundMeasurementActivated() { + return settings.GetHeartRateBackgroundMeasurementInterval() != + Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off; } \ No newline at end of file diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 80b6abc8..0361c2ec 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -39,6 +39,10 @@ namespace Pinetime { void HandleSensorData(int* lastBpm); int CurrentTaskDelay(); + uint32_t GetHeartRateBackgroundMeasurementIntervalInTicks(); + bool IsContinuosModeActivated(); + bool IsBackgroundMeasurementActivated(); + TaskHandle_t taskHandle; QueueHandle_t messageQueue; States state = States::Running; From a2edd931ecdd020abb2d84025ba7e4765c01456e Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 31 Mar 2023 10:00:56 +0200 Subject: [PATCH 10/32] add heart rate measurments in the background --- src/heartratetask/HeartRateTask.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 0361c2ec..29f593ee 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -7,6 +7,8 @@ #define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz +#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 Minutes assuming 1 Hz + namespace Pinetime { namespace Drivers { class Hrs3300; @@ -43,6 +45,10 @@ namespace Pinetime { bool IsContinuosModeActivated(); bool IsBackgroundMeasurementActivated(); + void HandleBackgroundWaiting(); + void HandleSensorData(); + int CurrentTaskDelay(); + TaskHandle_t taskHandle; QueueHandle_t messageQueue; States state = States::Running; From f94c0740648a6770dd087e270c54eb9f0e9edc79 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 11 May 2023 23:47:31 +0200 Subject: [PATCH 11/32] rebase on main --- src/heartratetask/HeartRateTask.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 29f593ee..e08d29d0 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -46,7 +46,7 @@ namespace Pinetime { bool IsBackgroundMeasurementActivated(); void HandleBackgroundWaiting(); - void HandleSensorData(); + void HandleSensorData(int* lastBpm); int CurrentTaskDelay(); TaskHandle_t taskHandle; From eeaf5374d4d1cfe427c4aa7e883c8d830bb29967 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 25 May 2023 23:41:26 +0200 Subject: [PATCH 12/32] stop background after 30s of no data from the heart rate sensor --- src/heartratetask/HeartRateTask.cpp | 4 ++++ src/heartratetask/HeartRateTask.h | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 56439e93..3ee04be9 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -154,6 +154,10 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { state = States::BackgroundWaiting; StartWaiting(); } + if (bpm == 0 && state == States::BackgroundMeasuring && xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { + state = States::BackgroundWaiting; + StartWaiting(); + } } int HeartRateTask::CurrentTaskDelay() { diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index e08d29d0..85ccb601 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -7,7 +7,8 @@ #define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz -#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 Minutes assuming 1 Hz +#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz +#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz namespace Pinetime { namespace Drivers { From 69578a679aabedc2a66634b850f4396cfb4ab8dc Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 7 Jul 2023 23:20:41 +0200 Subject: [PATCH 13/32] properly format using clang-format --- src/heartratetask/HeartRateTask.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 85ccb601..36754856 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -7,8 +7,8 @@ #define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz -#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz -#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz +#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz +#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz namespace Pinetime { namespace Drivers { From 04ed068ff958f0107544bdd63442705e2930c85f Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 25 Aug 2023 02:10:45 +0200 Subject: [PATCH 14/32] add settings screen to choose heartrate measurement background --- src/heartratetask/HeartRateTask.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 36754856..9dea9e79 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -7,9 +7,6 @@ #define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz -#define DURATION_BETWEEN_BACKGROUND_MEASUREMENTS 5 * 60 * 1000 // 5 minutes assuming 1 Hz -#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz - namespace Pinetime { namespace Drivers { class Hrs3300; From 520e50901a770039db32b110a8db7167db82cdc9 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 1 Dec 2023 14:18:09 +0100 Subject: [PATCH 15/32] fix rebase mistakes --- src/heartratetask/HeartRateTask.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 9dea9e79..0361c2ec 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -43,10 +43,6 @@ namespace Pinetime { bool IsContinuosModeActivated(); bool IsBackgroundMeasurementActivated(); - void HandleBackgroundWaiting(); - void HandleSensorData(int* lastBpm); - int CurrentTaskDelay(); - TaskHandle_t taskHandle; QueueHandle_t messageQueue; States state = States::Running; From 50d88bbe8481ece1da697d4564e29f96233547c3 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 1 Dec 2023 17:15:24 +0100 Subject: [PATCH 16/32] bump settings version, fix types --- .../screens/settings/SettingHeartRate.cpp | 5 ++-- .../screens/settings/SettingHeartRate.h | 3 +-- src/heartratetask/HeartRateTask.cpp | 24 +++++++++---------- src/heartratetask/HeartRateTask.h | 6 ++--- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/displayapp/screens/settings/SettingHeartRate.cpp b/src/displayapp/screens/settings/SettingHeartRate.cpp index d3da19b2..7d8206cd 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.cpp +++ b/src/displayapp/screens/settings/SettingHeartRate.cpp @@ -1,6 +1,5 @@ #include "displayapp/screens/settings/SettingHeartRate.h" #include -#include "displayapp/DisplayApp.h" #include "displayapp/screens/Styles.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" @@ -18,8 +17,8 @@ namespace { constexpr std::array SettingHeartRate::options; -SettingHeartRate::SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : app {app}, settingsController {settingsController} { +SettingHeartRate::SettingHeartRate(Pinetime::Controllers::Settings& settingsController) + : settingsController {settingsController} { lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); diff --git a/src/displayapp/screens/settings/SettingHeartRate.h b/src/displayapp/screens/settings/SettingHeartRate.h index 40eff744..3cb08907 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.h +++ b/src/displayapp/screens/settings/SettingHeartRate.h @@ -21,13 +21,12 @@ namespace Pinetime { class SettingHeartRate : public Screen { public: - SettingHeartRate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settings); + SettingHeartRate(Pinetime::Controllers::Settings& settings); ~SettingHeartRate() override; void UpdateSelected(lv_obj_t* object, lv_event_t event); private: - DisplayApp* app; Pinetime::Controllers::Settings& settingsController; static constexpr std::array options = {{ diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 3ee04be9..1d1f7952 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -29,7 +29,7 @@ void HeartRateTask::Work() { int lastBpm = 0; while (true) { - auto delay = CurrentTaskDelay(); + TickType_t delay = CurrentTaskDelay(); Messages msg; if (xQueueReceive(messageQueue, &msg, delay) == pdTRUE) { @@ -160,34 +160,34 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { } } -int HeartRateTask::CurrentTaskDelay() { +TickType_t HeartRateTask::CurrentTaskDelay() { switch (state) { case States::Measuring: case States::BackgroundMeasuring: return ppg.deltaTms; case States::Running: - return 100; + return 100 * pdMS_TO_TICKS; case States::BackgroundWaiting: - return 10000; + return 10000 * pdMS_TO_TICKS; default: return portMAX_DELAY; } } -uint32_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { +TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { switch (settings.GetHeartRateBackgroundMeasurementInterval()) { case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds: - return 10 * 1000; + return 10 * pdMS_TO_TICKS; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds: - return 30 * 1000; + return 30 * pdMS_TO_TICKS; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute: - return 60 * 1000; + return 60 * pdMS_TO_TICKS; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes: - return 5 * 60 * 1000; + return 5 * 60 * pdMS_TO_TICKS; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenMinutes: - return 10 * 60 * 1000; + return 10 * 60 * pdMS_TO_TICKS; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtyMinutes: - return 30 * 60 * 1000; + return 30 * 60 * pdMS_TO_TICKS; default: return 0; } @@ -201,4 +201,4 @@ bool HeartRateTask::IsContinuosModeActivated() { bool HeartRateTask::IsBackgroundMeasurementActivated() { return settings.GetHeartRateBackgroundMeasurementInterval() != Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off; -} \ No newline at end of file +} diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 0361c2ec..5321363b 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -5,7 +5,7 @@ #include #include "components/settings/Settings.h" -#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * 1000 // 30 seconds assuming 1 Hz +#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * pdMS_TO_TICKS namespace Pinetime { namespace Drivers { @@ -37,9 +37,9 @@ namespace Pinetime { void HandleBackgroundWaiting(); void HandleSensorData(int* lastBpm); - int CurrentTaskDelay(); + TickType_t CurrentTaskDelay(); - uint32_t GetHeartRateBackgroundMeasurementIntervalInTicks(); + TickType_t GetHeartRateBackgroundMeasurementIntervalInTicks(); bool IsContinuosModeActivated(); bool IsBackgroundMeasurementActivated(); From 4ed4d2cfcdae1fba9553de7a370eec9a1a1c7611 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 1 Dec 2023 17:22:28 +0100 Subject: [PATCH 17/32] use pdMS_TO_TICKS correctly, format using clang-format --- .../screens/settings/SettingHeartRate.cpp | 3 +-- src/heartratetask/HeartRateTask.cpp | 19 ++++++++++--------- src/heartratetask/HeartRateTask.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/displayapp/screens/settings/SettingHeartRate.cpp b/src/displayapp/screens/settings/SettingHeartRate.cpp index 7d8206cd..fdba9af1 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.cpp +++ b/src/displayapp/screens/settings/SettingHeartRate.cpp @@ -17,8 +17,7 @@ namespace { constexpr std::array SettingHeartRate::options; -SettingHeartRate::SettingHeartRate(Pinetime::Controllers::Settings& settingsController) - : settingsController {settingsController} { +SettingHeartRate::SettingHeartRate(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} { lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 1d1f7952..a3baa7d2 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -154,7 +154,8 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { state = States::BackgroundWaiting; StartWaiting(); } - if (bpm == 0 && state == States::BackgroundMeasuring && xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { + if (bpm == 0 && state == States::BackgroundMeasuring && + xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { state = States::BackgroundWaiting; StartWaiting(); } @@ -166,9 +167,9 @@ TickType_t HeartRateTask::CurrentTaskDelay() { case States::BackgroundMeasuring: return ppg.deltaTms; case States::Running: - return 100 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(100); case States::BackgroundWaiting: - return 10000 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(10000); default: return portMAX_DELAY; } @@ -177,17 +178,17 @@ TickType_t HeartRateTask::CurrentTaskDelay() { TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { switch (settings.GetHeartRateBackgroundMeasurementInterval()) { case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds: - return 10 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(10 * 1000); case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds: - return 30 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(30 * 1000); case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute: - return 60 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(60 * 1000); case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes: - return 5 * 60 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(5 * 60 * 1000); case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenMinutes: - return 10 * 60 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(10 * 60 * 1000); case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtyMinutes: - return 30 * 60 * pdMS_TO_TICKS; + return pdMS_TO_TICKS(30 * 60 * 1000); default: return 0; } diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 5321363b..47b86d60 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -5,7 +5,7 @@ #include #include "components/settings/Settings.h" -#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED 30 * pdMS_TO_TICKS +#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED pdMS_TO_TICKS(30 * 1000) namespace Pinetime { namespace Drivers { From d78f26201b44b857f6dbf404016f2c04863063f1 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Mon, 11 Dec 2023 12:18:16 +0100 Subject: [PATCH 18/32] fix DisplayApp.cpp --- src/displayapp/DisplayApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 94975db8..6ccd4fdd 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -508,7 +508,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio currentScreen = std::make_unique(settingsController); break; case Apps::SettingHeartRate: - currentScreen = std::make_unique(this, settingsController); + currentScreen = std::make_unique(settingsController); break; case Apps::SettingDisplay: currentScreen = std::make_unique(this, settingsController); From 3b432cd3106669c6e36a167c5d9392f9cfd2cc2c Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Tue, 2 Jan 2024 16:07:35 +0100 Subject: [PATCH 19/32] fix issues after rebase on main --- src/displayapp/apps/Apps.h.in | 1 + src/displayapp/screens/settings/Settings.h | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267..a74ca7a8 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -35,6 +35,7 @@ namespace Pinetime { SettingWatchFace, SettingTimeFormat, SettingWeatherFormat, + SettingHeartRate, SettingDisplay, SettingWakeUp, SettingSteps, diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 0098b304..d4e2a2d7 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -41,16 +41,14 @@ namespace Pinetime { {Symbols::heartBeat, "Heartrate", Apps::SettingHeartRate}, {Symbols::clock, "Date&Time", Apps::SettingSetDateTime}, {Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat}, - {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, + {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, {Symbols::clock, "Chimes", Apps::SettingChimes}, {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold}, {Symbols::check, "Firmware", Apps::FirmwareValidation}, + {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, - {Symbols::list, "About", Apps::SysInfo}, - - {Symbols::none, "None", Apps::None}, {Symbols::none, "None", Apps::None}, {Symbols::none, "None", Apps::None}, From ffc5f96d9a9ccd7448c1ae200e66aee0b1d6c228 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 11 Apr 2024 00:01:10 +0200 Subject: [PATCH 20/32] bump settings version --- src/components/settings/Settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 94fde265..6f7f7369 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -308,7 +308,7 @@ namespace Pinetime { private: Pinetime::Controllers::FS& fs; - static constexpr uint32_t settingsVersion = 0x0007; + static constexpr uint32_t settingsVersion = 0x0008; struct SettingsData { uint32_t version = settingsVersion; From 7cf4f6e1ece28be8dcb60a1d71300da982bac08b Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 11 Apr 2024 00:35:11 +0200 Subject: [PATCH 21/32] fix bug where settings open pair pin screen --- src/displayapp/screens/settings/Settings.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index d4e2a2d7..fbe89b53 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -48,11 +48,7 @@ namespace Pinetime { {Symbols::check, "Firmware", Apps::FirmwareValidation}, {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, - {Symbols::list, "About", Apps::SysInfo}, - {Symbols::none, "None", Apps::None}, - {Symbols::none, "None", Apps::None}, - - // {Symbols::none, "None", Apps::None}, + {Symbols::list, "About", Apps::SysInfo} }}; ScreenList screens; From 6a0276f164547a1f256ec8f6d4f1a95e83a56b56 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 11 Jul 2024 14:55:17 +0200 Subject: [PATCH 22/32] fix settings screen --- src/displayapp/screens/settings/Settings.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index fbe89b53..4f1082ad 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -48,7 +48,12 @@ namespace Pinetime { {Symbols::check, "Firmware", Apps::FirmwareValidation}, {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, - {Symbols::list, "About", Apps::SysInfo} + {Symbols::list, "About", Apps::SysInfo}, + + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, }}; ScreenList screens; From 616926345ea98f494df256f85dde199b0cf48423 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 11 Jul 2024 14:56:06 +0200 Subject: [PATCH 23/32] refactor heartrate task (switch cases, comments with explanation) --- src/heartratetask/HeartRateTask.cpp | 135 +++++++++++++++++++--------- src/heartratetask/HeartRateTask.h | 33 ++++++- 2 files changed, 122 insertions(+), 46 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index a3baa7d2..ba34c074 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -26,7 +26,7 @@ void HeartRateTask::Process(void* instance) { } void HeartRateTask::Work() { - int lastBpm = 0; + lastBpm = 0; while (true) { TickType_t delay = CurrentTaskDelay(); @@ -35,41 +35,16 @@ void HeartRateTask::Work() { if (xQueueReceive(messageQueue, &msg, delay) == pdTRUE) { switch (msg) { case Messages::GoToSleep: - if (state == States::Running) { - state = States::Idle; - } else if (state == States::Measuring) { - state = States::BackgroundWaiting; - StartWaiting(); - } + HandleGoToSleep(); break; case Messages::WakeUp: - if (state == States::Idle) { - state = States::Running; - } else if (state == States::BackgroundMeasuring) { - state = States::Measuring; - } else if (state == States::BackgroundWaiting) { - state = States::Measuring; - StartMeasurement(); - } + HandleWakeUp(); break; case Messages::StartMeasurement: - if (state == States::Measuring || state == States::BackgroundMeasuring) { - break; - } - state = States::Measuring; - lastBpm = 0; - StartMeasurement(); + HandleStartMeasurement(); break; case Messages::StopMeasurement: - if (state == States::Running || state == States::Idle) { - break; - } - if (state == States::Measuring) { - state = States::Running; - } else if (state == States::BackgroundMeasuring) { - state = States::Idle; - } - StopMeasurement(); + HandleStopMeasurement(); break; } } @@ -106,6 +81,76 @@ void HeartRateTask::StartWaiting() { backgroundWaitingStart = xTaskGetTickCount(); } +void HeartRateTask::HandleGoToSleep() { + switch (state) { + case States::Running: + state = States::Idle; + break; + case States::Measuring: + state = States::BackgroundWaiting; + StartWaiting(); + break; + case States::Idle: + case States::BackgroundWaiting: + case States::BackgroundMeasuring: + // shouldn't happen -> ignore + break; + } +} + +void HeartRateTask::HandleWakeUp() { + switch (state) { + case States::Idle: + state = States::Running; + break; + case States::BackgroundMeasuring: + state = States::Measuring; + break; + case States::BackgroundWaiting: + state = States::Measuring; + StartMeasurement(); + break; + case States::Running: + case States::Measuring: + // shouldn't happen -> ignore + break; + } +} + +void HeartRateTask::HandleStartMeasurement() { + switch (state) { + case States::Idle: + case States::Running: + state = States::Measuring; + lastBpm = 0; + StartMeasurement(); + break; + case States::Measuring: + case States::BackgroundMeasuring: + case States::BackgroundWaiting: + // shouldn't happen -> ignore + break; + } +} + +void HeartRateTask::HandleStopMeasurement() { + switch (state) { + case States::Measuring: + state = States::Running; + StopMeasurement(); + break; + case States::BackgroundMeasuring: + case States::BackgroundWaiting: + state = States::Idle; + StopMeasurement(); + break; + case States::Running: + case States::Idle: + // shouldn't happen -> ignore + break; + } +} + void HeartRateTask::HandleBackgroundWaiting() { if (!IsBackgroundMeasurementActivated()) { return; @@ -150,12 +195,7 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { } TickType_t ticksSinceMeasurementStart = xTaskGetTickCount() - measurementStart; if (bpm == 0 && state == States::BackgroundMeasuring && !IsContinuosModeActivated() && - ticksSinceMeasurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { - state = States::BackgroundWaiting; - StartWaiting(); - } - if (bpm == 0 && state == States::BackgroundMeasuring && - xTaskGetTickCount() - measurementStart >= DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED) { + ticksSinceMeasurementStart >= DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED) { state = States::BackgroundWaiting; StartWaiting(); } @@ -176,22 +216,31 @@ TickType_t HeartRateTask::CurrentTaskDelay() { } TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { + int ms; switch (settings.GetHeartRateBackgroundMeasurementInterval()) { case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds: - return pdMS_TO_TICKS(10 * 1000); + ms = 10 * 1000; + break; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds: - return pdMS_TO_TICKS(30 * 1000); + ms = 30 * 1000; + break; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute: - return pdMS_TO_TICKS(60 * 1000); + ms = 60 * 1000; + break; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes: - return pdMS_TO_TICKS(5 * 60 * 1000); + ms = 5 * 60 * 1000; + break; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenMinutes: - return pdMS_TO_TICKS(10 * 60 * 1000); + ms = 10 * 60 * 1000; + break; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtyMinutes: - return pdMS_TO_TICKS(30 * 60 * 1000); + ms = 30 * 60 * 1000; + break; default: - return 0; + ms = 0; + break; } + return pdMS_TO_TICKS(ms); } bool HeartRateTask::IsContinuosModeActivated() { diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 47b86d60..a8fa8b60 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -5,7 +5,7 @@ #include #include "components/settings/Settings.h" -#define DURATION_UNTIL_BACKGROUND_MEASURMENT_IS_STOPPED pdMS_TO_TICKS(30 * 1000) +#define DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED pdMS_TO_TICKS(30 * 1000) namespace Pinetime { namespace Drivers { @@ -19,8 +19,29 @@ namespace Pinetime { namespace Applications { class HeartRateTask { public: - enum class Messages : uint8_t { GoToSleep, WakeUp, StartMeasurement, StopMeasurement }; - enum class States { Idle, Running, Measuring, BackgroundWaiting, BackgroundMeasuring }; + enum class Messages : uint8_t { + // Screen gets turned off + GoToSleep, + // Screen gets turned on + WakeUp, + // Start button pressed + StartMeasurement, + // Stop button pressed + StopMeasurement + }; + + enum class States { + // Screen turned off, heartrate not measured + Idle, + // Screen turned on, heartrate app open, heartrate not measured + Running, + // Screen turned on, heartrate app open, heartrate actively measured + Measuring, + // Screen turned off, heartrate task is waiting until the next measurement should be started + BackgroundWaiting, + // Screen turned off, heartrate actively measured + BackgroundMeasuring + }; explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller, @@ -35,6 +56,11 @@ namespace Pinetime { void StopMeasurement(); void StartWaiting(); + void HandleGoToSleep(); + void HandleWakeUp(); + void HandleStartMeasurement(); + void HandleStopMeasurement(); + void HandleBackgroundWaiting(); void HandleSensorData(int* lastBpm); TickType_t CurrentTaskDelay(); @@ -52,6 +78,7 @@ namespace Pinetime { Controllers::Ppg ppg; TickType_t backgroundWaitingStart = 0; TickType_t measurementStart = 0; + int lastBpm = 0; }; } From e6f0a8920229ed438d0c1fee71c4ca4188dde7b6 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Thu, 11 Jul 2024 15:53:18 +0200 Subject: [PATCH 24/32] reduce RAM size --- src/heartratetask/HeartRateTask.cpp | 39 +++++++++++++++-------------- src/heartratetask/HeartRateTask.h | 4 +-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index ba34c074..2ed60742 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -5,6 +5,21 @@ using namespace Pinetime::Applications; +TickType_t CurrentTaskDelay(HeartRateTask::States state, TickType_t ppgDeltaTms) { + switch (state) { + case HeartRateTask::States::Measuring: + case HeartRateTask::States::BackgroundMeasuring: + return ppgDeltaTms; + case HeartRateTask::States::Running: + return pdMS_TO_TICKS(100); + case HeartRateTask::States::BackgroundWaiting: + return pdMS_TO_TICKS(10000); + default: + return portMAX_DELAY; + } +} + + HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller, Controllers::Settings& settings) @@ -26,10 +41,10 @@ void HeartRateTask::Process(void* instance) { } void HeartRateTask::Work() { - lastBpm = 0; + int lastBpm = 0; while (true) { - TickType_t delay = CurrentTaskDelay(); + TickType_t delay = CurrentTaskDelay(state, ppg.deltaTms); Messages msg; if (xQueueReceive(messageQueue, &msg, delay) == pdTRUE) { @@ -41,7 +56,7 @@ void HeartRateTask::Work() { HandleWakeUp(); break; case Messages::StartMeasurement: - HandleStartMeasurement(); + HandleStartMeasurement(&lastBpm); break; case Messages::StopMeasurement: HandleStopMeasurement(); @@ -117,12 +132,12 @@ void HeartRateTask::HandleWakeUp() { } } -void HeartRateTask::HandleStartMeasurement() { +void HeartRateTask::HandleStartMeasurement(int* lastBpm) { switch (state) { case States::Idle: case States::Running: state = States::Measuring; - lastBpm = 0; + *lastBpm = 0; StartMeasurement(); break; case States::Measuring: @@ -201,20 +216,6 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { } } -TickType_t HeartRateTask::CurrentTaskDelay() { - switch (state) { - case States::Measuring: - case States::BackgroundMeasuring: - return ppg.deltaTms; - case States::Running: - return pdMS_TO_TICKS(100); - case States::BackgroundWaiting: - return pdMS_TO_TICKS(10000); - default: - return portMAX_DELAY; - } -} - TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { int ms; switch (settings.GetHeartRateBackgroundMeasurementInterval()) { diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index a8fa8b60..2b273061 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -58,12 +58,11 @@ namespace Pinetime { void HandleGoToSleep(); void HandleWakeUp(); - void HandleStartMeasurement(); + void HandleStartMeasurement(int* lastBpm); void HandleStopMeasurement(); void HandleBackgroundWaiting(); void HandleSensorData(int* lastBpm); - TickType_t CurrentTaskDelay(); TickType_t GetHeartRateBackgroundMeasurementIntervalInTicks(); bool IsContinuosModeActivated(); @@ -78,7 +77,6 @@ namespace Pinetime { Controllers::Ppg ppg; TickType_t backgroundWaitingStart = 0; TickType_t measurementStart = 0; - int lastBpm = 0; }; } From 78af44eafe1c52bf962176ff47d0271272b7858a Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Wed, 17 Jul 2024 20:18:31 +0200 Subject: [PATCH 25/32] keep measuring when transitioning to background Co-authored-by: Simon Effenberg --- src/heartratetask/HeartRateTask.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 2ed60742..f79ff6cc 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -102,8 +102,7 @@ void HeartRateTask::HandleGoToSleep() { state = States::Idle; break; case States::Measuring: - state = States::BackgroundWaiting; - StartWaiting(); + state = States::BackgroundMeasuring; break; case States::Idle: case States::BackgroundWaiting: From cedca795e283e56827006af589115c49ef9757de Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Sat, 31 Aug 2024 00:39:13 +0200 Subject: [PATCH 26/32] use switch case --- heartrate_statemachine_extended_ascii.txt | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 heartrate_statemachine_extended_ascii.txt diff --git a/heartrate_statemachine_extended_ascii.txt b/heartrate_statemachine_extended_ascii.txt new file mode 100644 index 00000000..1c5ad7ae --- /dev/null +++ b/heartrate_statemachine_extended_ascii.txt @@ -0,0 +1,25 @@ + *** Hearrate task state machine *** + + + GoToSleep StopMeasurement + ┌───────────────┐ ┌─────────────────────────────┐ + ▼ │ ▼ │ + ┌──────┐ ┌──┴──────┐ ┌─────┴─────┐ + │ │ WakeUp │ │ StartMeasurement │ │ + │ Idle ├───────►│ Running ├─────────────────►│ Measuring │ + │ │ │ │ │ │ + └──────┘ └─────────┘ └─────┬─────┘ + ▲ ▲ │ + │ StopMeasurement │ │ + ├──────────────────────────────────┐ │ │ GoToSleep + │ │ WakeUp │ │ + │ ┌────────────────────────────┼─────────┤ │ + │ │ │ │ ▼ + ┌──┴─────┴──────────┐ ┌┴─────────┴──────────┐ + │ │ measured │ │ + │ BackgroundWaiting │◄───────────────┤ BackgroundMeasuring │ + │ │ │ │ + └┬─────────────────┬┘ └─────────────────────┘ + │ ▲ │ ▲ + └────────┘ └────────────────────────────┘ +wait time < interval wait time >= interval From 71b31c78fbe5393705f1cf27423e36aed07a5be4 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Sat, 31 Aug 2024 00:40:58 +0200 Subject: [PATCH 27/32] use switch case --- src/heartratetask/HeartRateTask.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index f79ff6cc..fc28bb6e 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -64,10 +64,18 @@ void HeartRateTask::Work() { } } - if (state == States::BackgroundWaiting) { - HandleBackgroundWaiting(); - } else if (state == States::BackgroundMeasuring || state == States::Measuring) { - HandleSensorData(&lastBpm); + switch (state) { + case States::BackgroundWaiting: + HandleBackgroundWaiting(); + break; + case States::BackgroundMeasuring: + case States::Measuring: + HandleSensorData(&lastBpm); + break; + case States::Idle: + case States::Running: + // nothing to do -> ignore + break; } } } From b846547f2fabe5653cdc15795e963f0a7f66c4ea Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Sat, 31 Aug 2024 00:42:51 +0200 Subject: [PATCH 28/32] remove unnecessary file --- heartrate_statemachine_extended_ascii.txt | 25 ----------------------- 1 file changed, 25 deletions(-) delete mode 100644 heartrate_statemachine_extended_ascii.txt diff --git a/heartrate_statemachine_extended_ascii.txt b/heartrate_statemachine_extended_ascii.txt deleted file mode 100644 index 1c5ad7ae..00000000 --- a/heartrate_statemachine_extended_ascii.txt +++ /dev/null @@ -1,25 +0,0 @@ - *** Hearrate task state machine *** - - - GoToSleep StopMeasurement - ┌───────────────┐ ┌─────────────────────────────┐ - ▼ │ ▼ │ - ┌──────┐ ┌──┴──────┐ ┌─────┴─────┐ - │ │ WakeUp │ │ StartMeasurement │ │ - │ Idle ├───────►│ Running ├─────────────────►│ Measuring │ - │ │ │ │ │ │ - └──────┘ └─────────┘ └─────┬─────┘ - ▲ ▲ │ - │ StopMeasurement │ │ - ├──────────────────────────────────┐ │ │ GoToSleep - │ │ WakeUp │ │ - │ ┌────────────────────────────┼─────────┤ │ - │ │ │ │ ▼ - ┌──┴─────┴──────────┐ ┌┴─────────┴──────────┐ - │ │ measured │ │ - │ BackgroundWaiting │◄───────────────┤ BackgroundMeasuring │ - │ │ │ │ - └┬─────────────────┬┘ └─────────────────────┘ - │ ▲ │ ▲ - └────────┘ └────────────────────────────┘ -wait time < interval wait time >= interval From 9501d3606094dcb8550e72787b20bc2685316513 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Sat, 31 Aug 2024 00:54:05 +0200 Subject: [PATCH 29/32] use better state names --- src/heartratetask/HeartRateTask.cpp | 86 ++++++++++++++--------------- src/heartratetask/HeartRateTask.h | 21 ++----- 2 files changed, 49 insertions(+), 58 deletions(-) diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index fc28bb6e..b19f6fcd 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -7,12 +7,12 @@ using namespace Pinetime::Applications; TickType_t CurrentTaskDelay(HeartRateTask::States state, TickType_t ppgDeltaTms) { switch (state) { - case HeartRateTask::States::Measuring: - case HeartRateTask::States::BackgroundMeasuring: + case HeartRateTask::States::ScreenOnAndMeasuring: + case HeartRateTask::States::ScreenOffAndMeasuring: return ppgDeltaTms; - case HeartRateTask::States::Running: + case HeartRateTask::States::ScreenOnAndStopped: return pdMS_TO_TICKS(100); - case HeartRateTask::States::BackgroundWaiting: + case HeartRateTask::States::ScreenOffAndWaiting: return pdMS_TO_TICKS(10000); default: return portMAX_DELAY; @@ -65,15 +65,15 @@ void HeartRateTask::Work() { } switch (state) { - case States::BackgroundWaiting: + case States::ScreenOffAndWaiting: HandleBackgroundWaiting(); break; - case States::BackgroundMeasuring: - case States::Measuring: + case States::ScreenOffAndMeasuring: + case States::ScreenOnAndMeasuring: HandleSensorData(&lastBpm); break; - case States::Idle: - case States::Running: + case States::ScreenOffAndStopped: + case States::ScreenOnAndStopped: // nothing to do -> ignore break; } @@ -106,15 +106,15 @@ void HeartRateTask::StartWaiting() { void HeartRateTask::HandleGoToSleep() { switch (state) { - case States::Running: - state = States::Idle; + case States::ScreenOnAndStopped: + state = States::ScreenOffAndStopped; break; - case States::Measuring: - state = States::BackgroundMeasuring; + case States::ScreenOnAndMeasuring: + state = States::ScreenOffAndMeasuring; break; - case States::Idle: - case States::BackgroundWaiting: - case States::BackgroundMeasuring: + case States::ScreenOffAndStopped: + case States::ScreenOffAndWaiting: + case States::ScreenOffAndMeasuring: // shouldn't happen -> ignore break; } @@ -122,18 +122,18 @@ void HeartRateTask::HandleGoToSleep() { void HeartRateTask::HandleWakeUp() { switch (state) { - case States::Idle: - state = States::Running; + case States::ScreenOffAndStopped: + state = States::ScreenOnAndStopped; break; - case States::BackgroundMeasuring: - state = States::Measuring; + case States::ScreenOffAndMeasuring: + state = States::ScreenOnAndMeasuring; break; - case States::BackgroundWaiting: - state = States::Measuring; + case States::ScreenOffAndWaiting: + state = States::ScreenOnAndMeasuring; StartMeasurement(); break; - case States::Running: - case States::Measuring: + case States::ScreenOnAndStopped: + case States::ScreenOnAndMeasuring: // shouldn't happen -> ignore break; } @@ -141,15 +141,15 @@ void HeartRateTask::HandleWakeUp() { void HeartRateTask::HandleStartMeasurement(int* lastBpm) { switch (state) { - case States::Idle: - case States::Running: - state = States::Measuring; + case States::ScreenOffAndStopped: + case States::ScreenOnAndStopped: + state = States::ScreenOnAndMeasuring; *lastBpm = 0; StartMeasurement(); break; - case States::Measuring: - case States::BackgroundMeasuring: - case States::BackgroundWaiting: + case States::ScreenOnAndMeasuring: + case States::ScreenOffAndMeasuring: + case States::ScreenOffAndWaiting: // shouldn't happen -> ignore break; } @@ -157,17 +157,17 @@ void HeartRateTask::HandleStartMeasurement(int* lastBpm) { void HeartRateTask::HandleStopMeasurement() { switch (state) { - case States::Measuring: - state = States::Running; + case States::ScreenOnAndMeasuring: + state = States::ScreenOnAndStopped; StopMeasurement(); break; - case States::BackgroundMeasuring: - case States::BackgroundWaiting: - state = States::Idle; + case States::ScreenOffAndMeasuring: + case States::ScreenOffAndWaiting: + state = States::ScreenOffAndStopped; StopMeasurement(); break; - case States::Running: - case States::Idle: + case States::ScreenOnAndStopped: + case States::ScreenOffAndStopped: // shouldn't happen -> ignore break; } @@ -180,7 +180,7 @@ void HeartRateTask::HandleBackgroundWaiting() { TickType_t ticksSinceWaitingStart = xTaskGetTickCount() - backgroundWaitingStart; if (ticksSinceWaitingStart >= GetHeartRateBackgroundMeasurementIntervalInTicks()) { - state = States::BackgroundMeasuring; + state = States::ScreenOffAndMeasuring; StartMeasurement(); } } @@ -207,18 +207,18 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { if (bpm != 0) { *lastBpm = bpm; controller.Update(Controllers::HeartRateController::States::Running, bpm); - if (state == States::Measuring || IsContinuosModeActivated()) { + if (state == States::ScreenOnAndMeasuring || IsContinuosModeActivated()) { return; } - if (state == States::BackgroundMeasuring) { - state = States::BackgroundWaiting; + if (state == States::ScreenOffAndMeasuring) { + state = States::ScreenOffAndWaiting; StartWaiting(); } } TickType_t ticksSinceMeasurementStart = xTaskGetTickCount() - measurementStart; - if (bpm == 0 && state == States::BackgroundMeasuring && !IsContinuosModeActivated() && + if (bpm == 0 && state == States::ScreenOffAndMeasuring && !IsContinuosModeActivated() && ticksSinceMeasurementStart >= DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED) { - state = States::BackgroundWaiting; + state = States::ScreenOffAndWaiting; StartWaiting(); } } diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 2b273061..511e34f3 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -20,27 +20,18 @@ namespace Pinetime { class HeartRateTask { public: enum class Messages : uint8_t { - // Screen gets turned off GoToSleep, - // Screen gets turned on WakeUp, - // Start button pressed StartMeasurement, - // Stop button pressed StopMeasurement }; enum class States { - // Screen turned off, heartrate not measured - Idle, - // Screen turned on, heartrate app open, heartrate not measured - Running, - // Screen turned on, heartrate app open, heartrate actively measured - Measuring, - // Screen turned off, heartrate task is waiting until the next measurement should be started - BackgroundWaiting, - // Screen turned off, heartrate actively measured - BackgroundMeasuring + ScreenOnAndStopped, + ScreenOnAndMeasuring, + ScreenOffAndStopped, + ScreenOffAndWaiting, + ScreenOffAndMeasuring }; explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, @@ -70,7 +61,7 @@ namespace Pinetime { TaskHandle_t taskHandle; QueueHandle_t messageQueue; - States state = States::Running; + States state = States::ScreenOnAndStopped; Drivers::Hrs3300& heartRateSensor; Controllers::HeartRateController& controller; Controllers::Settings& settings; From 7df39994abbccdb19385c22ba75b731d29bc696d Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Sat, 31 Aug 2024 20:49:19 +0200 Subject: [PATCH 30/32] integrate code review --- src/components/settings/Settings.cpp | 1 - src/heartratetask/HeartRateTask.cpp | 10 ++++------ src/heartratetask/HeartRateTask.h | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/settings/Settings.cpp b/src/components/settings/Settings.cpp index 05ab23d4..49073e1a 100644 --- a/src/components/settings/Settings.cpp +++ b/src/components/settings/Settings.cpp @@ -13,7 +13,6 @@ void Settings::Init() { } void Settings::SaveSettings() { - // verify if is necessary to save if (settingsChanged) { SaveSettingsToFile(); diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index b19f6fcd..0c082a5d 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -10,10 +10,8 @@ TickType_t CurrentTaskDelay(HeartRateTask::States state, TickType_t ppgDeltaTms) case HeartRateTask::States::ScreenOnAndMeasuring: case HeartRateTask::States::ScreenOffAndMeasuring: return ppgDeltaTms; - case HeartRateTask::States::ScreenOnAndStopped: - return pdMS_TO_TICKS(100); case HeartRateTask::States::ScreenOffAndWaiting: - return pdMS_TO_TICKS(10000); + return pdMS_TO_TICKS(1000); default: return portMAX_DELAY; } @@ -207,7 +205,7 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { if (bpm != 0) { *lastBpm = bpm; controller.Update(Controllers::HeartRateController::States::Running, bpm); - if (state == States::ScreenOnAndMeasuring || IsContinuosModeActivated()) { + if (state == States::ScreenOnAndMeasuring || IsContinuousModeActivated()) { return; } if (state == States::ScreenOffAndMeasuring) { @@ -216,7 +214,7 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { } } TickType_t ticksSinceMeasurementStart = xTaskGetTickCount() - measurementStart; - if (bpm == 0 && state == States::ScreenOffAndMeasuring && !IsContinuosModeActivated() && + if (bpm == 0 && state == States::ScreenOffAndMeasuring && !IsContinuousModeActivated() && ticksSinceMeasurementStart >= DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED) { state = States::ScreenOffAndWaiting; StartWaiting(); @@ -251,7 +249,7 @@ TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { return pdMS_TO_TICKS(ms); } -bool HeartRateTask::IsContinuosModeActivated() { +bool HeartRateTask::IsContinuousModeActivated() { return settings.GetHeartRateBackgroundMeasurementInterval() == Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous; } diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 511e34f3..f7d7e38b 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -56,7 +56,7 @@ namespace Pinetime { void HandleSensorData(int* lastBpm); TickType_t GetHeartRateBackgroundMeasurementIntervalInTicks(); - bool IsContinuosModeActivated(); + bool IsContinuousModeActivated(); bool IsBackgroundMeasurementActivated(); TaskHandle_t taskHandle; From 462ea11bd43e87fca39ec76bd90d63d53b469032 Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Sun, 22 Sep 2024 20:55:45 +0200 Subject: [PATCH 31/32] use interval as interval, instead of wait time --- src/components/settings/Settings.h | 2 +- .../screens/settings/SettingHeartRate.h | 2 +- src/heartratetask/HeartRateTask.cpp | 59 ++++++++++++------- src/heartratetask/HeartRateTask.h | 6 +- 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 6f7f7369..c86415cd 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -53,7 +53,7 @@ namespace Pinetime { enum class HeartRateBackgroundMeasurementInterval : uint8_t { Off, Continuous, - TenSeconds, + FifteenSeconds, ThirtySeconds, OneMinute, FiveMinutes, diff --git a/src/displayapp/screens/settings/SettingHeartRate.h b/src/displayapp/screens/settings/SettingHeartRate.h index 3cb08907..88b47710 100644 --- a/src/displayapp/screens/settings/SettingHeartRate.h +++ b/src/displayapp/screens/settings/SettingHeartRate.h @@ -32,7 +32,7 @@ namespace Pinetime { static constexpr std::array options = {{ {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off, " Off"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous, "Cont"}, - {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds, " 10s"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FifteenSeconds, " 15s"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds, " 30s"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute, " 1m"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes, " 5m"}, diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 0c082a5d..e82cf0ff 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -97,11 +97,6 @@ void HeartRateTask::StopMeasurement() { vTaskDelay(100); } -void HeartRateTask::StartWaiting() { - StopMeasurement(); - backgroundWaitingStart = xTaskGetTickCount(); -} - void HeartRateTask::HandleGoToSleep() { switch (state) { case States::ScreenOnAndStopped: @@ -176,8 +171,7 @@ void HeartRateTask::HandleBackgroundWaiting() { return; } - TickType_t ticksSinceWaitingStart = xTaskGetTickCount() - backgroundWaitingStart; - if (ticksSinceWaitingStart >= GetHeartRateBackgroundMeasurementIntervalInTicks()) { + if (ShouldStartBackgroundMeasuring()) { state = States::ScreenOffAndMeasuring; StartMeasurement(); } @@ -198,34 +192,45 @@ void HeartRateTask::HandleSensorData(int* lastBpm) { bpm = 0; } - if (*lastBpm == 0 && bpm == 0) { + bool notEnoughData = *lastBpm == 0 && bpm == 0; + if (notEnoughData) { controller.Update(Controllers::HeartRateController::States::NotEnoughData, bpm); } if (bpm != 0) { *lastBpm = bpm; controller.Update(Controllers::HeartRateController::States::Running, bpm); - if (state == States::ScreenOnAndMeasuring || IsContinuousModeActivated()) { - return; - } - if (state == States::ScreenOffAndMeasuring) { - state = States::ScreenOffAndWaiting; - StartWaiting(); - } } - TickType_t ticksSinceMeasurementStart = xTaskGetTickCount() - measurementStart; - if (bpm == 0 && state == States::ScreenOffAndMeasuring && !IsContinuousModeActivated() && - ticksSinceMeasurementStart >= DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED) { + + if (state == States::ScreenOnAndMeasuring || IsContinuousModeActivated()) { + return; + } + + // state == States::ScreenOffAndMeasuring + // (because state != ScreenOnAndMeasuring and the only state that enables measuring is ScreenOffAndMeasuring) + // !IsContinuousModeActivated() + + if (ShouldStartBackgroundMeasuring()) { + // This doesn't change the state but resets the measurment timer, which basically starts the next measurment without resetting the sensor. + // This is basically a fall back to continuous mode, when measurments take too long. + measurementStart = xTaskGetTickCount(); + return; + } + + bool noDataWithinTimeLimit = bpm == 0 && ShoudStopTryingToGetData(); + bool dataWithinTimeLimit = bpm != 0; + if (dataWithinTimeLimit || noDataWithinTimeLimit) { state = States::ScreenOffAndWaiting; - StartWaiting(); + StopMeasurement(); } + } TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { int ms; switch (settings.GetHeartRateBackgroundMeasurementInterval()) { - case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds: - ms = 10 * 1000; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FifteenSeconds: + ms = 15 * 1000; break; case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds: ms = 30 * 1000; @@ -258,3 +263,15 @@ bool HeartRateTask::IsBackgroundMeasurementActivated() { return settings.GetHeartRateBackgroundMeasurementInterval() != Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off; } + +TickType_t HeartRateTask::GetTicksSinceLastMeasurementStarted() { + return xTaskGetTickCount() - measurementStart; +} + +bool HeartRateTask::ShoudStopTryingToGetData() { + return GetTicksSinceLastMeasurementStarted() >= DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED; +} + +bool HeartRateTask::ShouldStartBackgroundMeasuring() { + return GetTicksSinceLastMeasurementStarted() >= GetHeartRateBackgroundMeasurementIntervalInTicks(); +} \ No newline at end of file diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index f7d7e38b..53d4d5bc 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -45,7 +45,6 @@ namespace Pinetime { static void Process(void* instance); void StartMeasurement(); void StopMeasurement(); - void StartWaiting(); void HandleGoToSleep(); void HandleWakeUp(); @@ -59,6 +58,10 @@ namespace Pinetime { bool IsContinuousModeActivated(); bool IsBackgroundMeasurementActivated(); + TickType_t GetTicksSinceLastMeasurementStarted(); + bool ShoudStopTryingToGetData(); + bool ShouldStartBackgroundMeasuring(); + TaskHandle_t taskHandle; QueueHandle_t messageQueue; States state = States::ScreenOnAndStopped; @@ -66,7 +69,6 @@ namespace Pinetime { Controllers::HeartRateController& controller; Controllers::Settings& settings; Controllers::Ppg ppg; - TickType_t backgroundWaitingStart = 0; TickType_t measurementStart = 0; }; From a2a2b6a64dd622b63874aca9672cb657c26d143b Mon Sep 17 00:00:00 2001 From: "D. Scott Boggs" Date: Sun, 15 Sep 2024 08:43:08 -0400 Subject: [PATCH 32/32] bump settings version --- src/components/settings/Settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index c86415cd..64a5f192 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -308,7 +308,7 @@ namespace Pinetime { private: Pinetime::Controllers::FS& fs; - static constexpr uint32_t settingsVersion = 0x0008; + static constexpr uint32_t settingsVersion = 0x0009; struct SettingsData { uint32_t version = settingsVersion;