From a5feb1ffd541aaad1bcf9dfb2824c6e60e4c5f0d Mon Sep 17 00:00:00 2001 From: Patric Gruber Date: Fri, 31 Mar 2023 10:00:56 +0200 Subject: [PATCH] add heart rate measurments in the background increase task delay when waiting in the background to 10s remove background start timestamp reset on sleep rebase on main stop background after 30s of no data from the heart rate sensor properly format using clang-format add settings screen to choose heartrate measurement background use different style for the heartrate settings and fix issues with settings file use enum instead of uint32_t for heartrater interval setting add heart rate measurments in the background rebase on main stop background after 30s of no data from the heart rate sensor properly format using clang-format add settings screen to choose heartrate measurement background fix rebase mistakes bump settings version, fix types use pdMS_TO_TICKS correctly, format using clang-format fix DisplayApp.cpp fix issues after rebase on main fix bug where settings open pair pin screen fix settings screen refactor heartrate task (switch cases, comments with explanation) reduce RAM size use switch case keep measuring when transitioning to background Co-authored-by: Simon Effenberg use switch case remove unnecessary file use better state names integrate code review use interval as interval, instead of wait time --- src/CMakeLists.txt | 1 + src/components/settings/Settings.cpp | 2 - src/components/settings/Settings.h | 26 +- src/displayapp/DisplayApp.cpp | 4 + src/displayapp/apps/Apps.h.in | 1 + .../screens/settings/SettingHeartRate.cpp | 75 +++++ .../screens/settings/SettingHeartRate.h | 47 +++ src/displayapp/screens/settings/Settings.h | 15 +- src/heartratetask/HeartRateTask.cpp | 276 ++++++++++++++---- src/heartratetask/HeartRateTask.h | 44 ++- src/main.cpp | 6 +- 11 files changed, 418 insertions(+), 79 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 e2b69b8b02..2abb56a47a 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.cpp b/src/components/settings/Settings.cpp index 1ae00a2dbc..49073e1a1d 100644 --- a/src/components/settings/Settings.cpp +++ b/src/components/settings/Settings.cpp @@ -8,13 +8,11 @@ Settings::Settings(Pinetime::Controllers::FS& fs) : fs {fs} { } void Settings::Init() { - // Load default settings from Flash LoadSettingsFromFile(); } void Settings::SaveSettings() { - // verify if is necessary to save if (settingsChanged) { SaveSettingsToFile(); diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 602de3a585..1a384d32b2 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, + FifteenSeconds, + ThirtySeconds, + OneMinute, + FiveMinutes, + TenMinutes, + ThirtyMinutes, + }; + Settings(Pinetime::Controllers::FS& fs); Settings(const Settings&) = delete; @@ -298,10 +309,21 @@ namespace Pinetime { return bleRadioEnabled; }; + HeartRateBackgroundMeasurementInterval GetHeartRateBackgroundMeasurementInterval() const { + return settings.heartRateBackgroundMeasurementInterval; + } + + void SetHeartRateBackgroundMeasurementInterval(HeartRateBackgroundMeasurementInterval newHeartRateBackgroundMeasurementInterval) { + if (newHeartRateBackgroundMeasurementInterval != settings.heartRateBackgroundMeasurementInterval) { + settingsChanged = true; + } + settings.heartRateBackgroundMeasurementInterval = newHeartRateBackgroundMeasurementInterval; + } + private: Pinetime::Controllers::FS& fs; - static constexpr uint32_t settingsVersion = 0x0008; + static constexpr uint32_t settingsVersion = 0x0009; struct SettingsData { uint32_t version = settingsVersion; @@ -325,6 +347,8 @@ namespace Pinetime { uint16_t shakeWakeThreshold = 150; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; + + HeartRateBackgroundMeasurementInterval heartRateBackgroundMeasurementInterval = HeartRateBackgroundMeasurementInterval::Off; }; SettingsData settings; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index b1594f197c..0a520ac49d 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" @@ -603,6 +604,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(settingsController); + break; case Apps::SettingDisplay: currentScreen = std::make_unique(settingsController); break; diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267c0..a74ca7a805 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/SettingHeartRate.cpp b/src/displayapp/screens/settings/SettingHeartRate.cpp new file mode 100644 index 0000000000..fdba9af15d --- /dev/null +++ b/src/displayapp/screens/settings/SettingHeartRate.cpp @@ -0,0 +1,75 @@ +#include "displayapp/screens/settings/SettingHeartRate.h" +#include +#include "displayapp/screens/Styles.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" +#include +#include + +using namespace Pinetime::Applications::Screens; + +namespace { + 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 SettingHeartRate::options; + +SettingHeartRate::SettingHeartRate(Pinetime::Controllers::Settings& settingsController) : 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, 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); + + 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_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); + + 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); + } + } +} + +SettingHeartRate::~SettingHeartRate() { + lv_obj_clean(lv_scr_act()); + settingsController.SaveSettings(); +} + +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); + } + } + } +} diff --git a/src/displayapp/screens/settings/SettingHeartRate.h b/src/displayapp/screens/settings/SettingHeartRate.h new file mode 100644 index 0000000000..88b477103c --- /dev/null +++ b/src/displayapp/screens/settings/SettingHeartRate.h @@ -0,0 +1,47 @@ +#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 { + + struct Option { + const Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval interval; + const char* name; + }; + + class SettingHeartRate : public Screen { + public: + SettingHeartRate(Pinetime::Controllers::Settings& settings); + ~SettingHeartRate() override; + + void UpdateSelected(lv_obj_t* object, lv_event_t event); + + private: + Pinetime::Controllers::Settings& settingsController; + + static constexpr std::array options = {{ + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off, " Off"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous, "Cont"}, + {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FifteenSeconds, " 15s"}, + {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/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 3722c2be39..7053f0261a 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -38,22 +38,19 @@ namespace Pinetime { {Symbols::home, "Watch face", Apps::SettingWatchFace}, {Symbols::shoe, "Steps", Apps::SettingSteps}, - {Symbols::clock, "Date & Time", Apps::SettingSetDateTime}, + {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::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::none, "None", Apps::None}, - + {Symbols::none, "None", Apps::None}, + {Symbols::none, "None", Apps::None}, }}; ScreenList screens; }; diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 8a5a871b41..e38d6fa5e9 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -5,8 +5,23 @@ using namespace Pinetime::Applications; -HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller) - : heartRateSensor {heartRateSensor}, controller {controller} { +TickType_t CurrentTaskDelay(HeartRateTask::States state, TickType_t ppgDeltaTms) { + switch (state) { + case HeartRateTask::States::ScreenOnAndMeasuring: + case HeartRateTask::States::ScreenOffAndMeasuring: + return ppgDeltaTms; + case HeartRateTask::States::ScreenOffAndWaiting: + return pdMS_TO_TICKS(1000); + default: + return portMAX_DELAY; + } +} + + +HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, + Controllers::HeartRateController& controller, + Controllers::Settings& settings) + : heartRateSensor {heartRateSensor}, controller {controller}, settings {settings} { } void HeartRateTask::Start() { @@ -25,78 +40,40 @@ void HeartRateTask::Process(void* instance) { void HeartRateTask::Work() { int lastBpm = 0; + while (true) { + TickType_t delay = CurrentTaskDelay(state, ppg.deltaTms); Messages msg; - uint32_t delay; - if (state == States::Running) { - if (measurementStarted) { - delay = ppg.deltaTms; - } else { - delay = 100; - } - } else { - delay = portMAX_DELAY; - } - if (xQueueReceive(messageQueue, &msg, delay)) { + if (xQueueReceive(messageQueue, &msg, delay) == pdTRUE) { switch (msg) { case Messages::GoToSleep: - StopMeasurement(); - state = States::Idle; + HandleGoToSleep(); break; case Messages::WakeUp: - state = States::Running; - if (measurementStarted) { - lastBpm = 0; - StartMeasurement(); - } + HandleWakeUp(); break; case Messages::StartMeasurement: - if (measurementStarted) { - break; - } - lastBpm = 0; - StartMeasurement(); - measurementStarted = true; + HandleStartMeasurement(&lastBpm); break; case Messages::StopMeasurement: - if (!measurementStarted) { - break; - } - StopMeasurement(); - measurementStarted = false; + HandleStopMeasurement(); break; } } - if (measurementStarted) { - auto sensorData = heartRateSensor.ReadHrsAls(); - int8_t ambient = ppg.Preprocess(sensorData.hrs, sensorData.als); - 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); - } + switch (state) { + case States::ScreenOffAndWaiting: + HandleBackgroundWaiting(); + break; + case States::ScreenOffAndMeasuring: + case States::ScreenOnAndMeasuring: + HandleSensorData(&lastBpm); + break; + case States::ScreenOffAndStopped: + case States::ScreenOnAndStopped: + // nothing to do -> ignore + break; } } } @@ -111,6 +88,7 @@ void HeartRateTask::StartMeasurement() { heartRateSensor.Enable(); ppg.Reset(true); vTaskDelay(100); + measurementStart = xTaskGetTickCount(); } void HeartRateTask::StopMeasurement() { @@ -118,3 +96,183 @@ void HeartRateTask::StopMeasurement() { ppg.Reset(true); vTaskDelay(100); } + +void HeartRateTask::HandleGoToSleep() { + switch (state) { + case States::ScreenOnAndStopped: + state = States::ScreenOffAndStopped; + break; + case States::ScreenOnAndMeasuring: + state = States::ScreenOffAndMeasuring; + break; + case States::ScreenOffAndStopped: + case States::ScreenOffAndWaiting: + case States::ScreenOffAndMeasuring: + // shouldn't happen -> ignore + break; + } +} + +void HeartRateTask::HandleWakeUp() { + switch (state) { + case States::ScreenOffAndStopped: + state = States::ScreenOnAndStopped; + break; + case States::ScreenOffAndMeasuring: + state = States::ScreenOnAndMeasuring; + break; + case States::ScreenOffAndWaiting: + state = States::ScreenOnAndMeasuring; + StartMeasurement(); + break; + case States::ScreenOnAndStopped: + case States::ScreenOnAndMeasuring: + // shouldn't happen -> ignore + break; + } +} + +void HeartRateTask::HandleStartMeasurement(int* lastBpm) { + switch (state) { + case States::ScreenOffAndStopped: + case States::ScreenOnAndStopped: + state = States::ScreenOnAndMeasuring; + *lastBpm = 0; + StartMeasurement(); + break; + case States::ScreenOnAndMeasuring: + case States::ScreenOffAndMeasuring: + case States::ScreenOffAndWaiting: + // shouldn't happen -> ignore + break; + } +} + +void HeartRateTask::HandleStopMeasurement() { + switch (state) { + case States::ScreenOnAndMeasuring: + state = States::ScreenOnAndStopped; + StopMeasurement(); + break; + case States::ScreenOffAndMeasuring: + case States::ScreenOffAndWaiting: + state = States::ScreenOffAndStopped; + StopMeasurement(); + break; + case States::ScreenOnAndStopped: + case States::ScreenOffAndStopped: + // shouldn't happen -> ignore + break; + } +} + +void HeartRateTask::HandleBackgroundWaiting() { + if (!IsBackgroundMeasurementActivated()) { + return; + } + + if (ShouldStartBackgroundMeasuring()) { + state = States::ScreenOffAndMeasuring; + StartMeasurement(); + } +} + +void HeartRateTask::HandleSensorData(int* lastBpm) { + auto sensorData = heartRateSensor.ReadHrsAls(); + int8_t ambient = ppg.Preprocess(sensorData.hrs, sensorData.als); + int bpm = ppg.HeartRate(); + + // If ambient light detected or a reset requested (bpm < 0) + if (ambient > 0) { + // Reset all DAQ buffers + ppg.Reset(true); + } else if (bpm < 0) { + // Reset all DAQ buffers except HRS buffer + ppg.Reset(false); + // Set HR to zero and update + 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; + } + + // 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; + StopMeasurement(); + } + +} + +TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { + int ms; + switch (settings.GetHeartRateBackgroundMeasurementInterval()) { + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FifteenSeconds: + ms = 15 * 1000; + break; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds: + ms = 30 * 1000; + break; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute: + ms = 60 * 1000; + break; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes: + ms = 5 * 60 * 1000; + break; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenMinutes: + ms = 10 * 60 * 1000; + break; + case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtyMinutes: + ms = 30 * 60 * 1000; + break; + default: + ms = 0; + break; + } + return pdMS_TO_TICKS(ms); +} + +bool HeartRateTask::IsContinuousModeActivated() { + return settings.GetHeartRateBackgroundMeasurementInterval() == + Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous; +} + +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 5bbfb9fb3e..53d4d5bc86 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -3,6 +3,9 @@ #include #include #include +#include "components/settings/Settings.h" + +#define DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED pdMS_TO_TICKS(30 * 1000) namespace Pinetime { namespace Drivers { @@ -16,10 +19,24 @@ namespace Pinetime { namespace Applications { class HeartRateTask { public: - enum class Messages : uint8_t { GoToSleep, WakeUp, StartMeasurement, StopMeasurement }; - enum class States { Idle, Running }; + enum class Messages : uint8_t { + GoToSleep, + WakeUp, + StartMeasurement, + StopMeasurement + }; + + enum class States { + ScreenOnAndStopped, + ScreenOnAndMeasuring, + ScreenOffAndStopped, + ScreenOffAndWaiting, + ScreenOffAndMeasuring + }; - 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); @@ -29,13 +46,30 @@ namespace Pinetime { void StartMeasurement(); void StopMeasurement(); + void HandleGoToSleep(); + void HandleWakeUp(); + void HandleStartMeasurement(int* lastBpm); + void HandleStopMeasurement(); + + void HandleBackgroundWaiting(); + void HandleSensorData(int* lastBpm); + + TickType_t GetHeartRateBackgroundMeasurementIntervalInTicks(); + bool IsContinuousModeActivated(); + bool IsBackgroundMeasurementActivated(); + + TickType_t GetTicksSinceLastMeasurementStarted(); + bool ShoudStopTryingToGetData(); + bool ShouldStartBackgroundMeasuring(); + TaskHandle_t taskHandle; QueueHandle_t messageQueue; - States state = States::Running; + States state = States::ScreenOnAndStopped; Drivers::Hrs3300& heartRateSensor; Controllers::HeartRateController& controller; + Controllers::Settings& settings; Controllers::Ppg ppg; - bool measurementStarted = false; + TickType_t measurementStart = 0; }; } diff --git a/src/main.cpp b/src/main.cpp index 24f13caddd..9f412c5b87 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;