diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d4facf1..dc3b6176 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -411,7 +411,6 @@ 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 49073e1a..1ae00a2d 100644 --- a/src/components/settings/Settings.cpp +++ b/src/components/settings/Settings.cpp @@ -8,11 +8,13 @@ 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 3597e7b6..602de3a5 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -50,17 +50,6 @@ 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; @@ -309,21 +298,10 @@ 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 = 0x0009; + static constexpr uint32_t settingsVersion = 0x0008; struct SettingsData { uint32_t version = settingsVersion; @@ -347,8 +325,6 @@ 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 3f8abc55..79519621 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -47,7 +47,6 @@ #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" @@ -565,9 +564,6 @@ 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(this, settingsController); break; diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index a74ca7a8..2104a267 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -35,7 +35,6 @@ 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 deleted file mode 100644 index fdba9af1..00000000 --- a/src/displayapp/screens/settings/SettingHeartRate.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#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 deleted file mode 100644 index 3cb08907..00000000 --- a/src/displayapp/screens/settings/SettingHeartRate.h +++ /dev/null @@ -1,47 +0,0 @@ -#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::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/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index 4f1082ad..a21b4ccd 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -38,16 +38,15 @@ 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}, + {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}, diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 0c082a5d..9d82d11e 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -5,23 +5,8 @@ using namespace Pinetime::Applications; -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} { +HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller) + : heartRateSensor {heartRateSensor}, controller {controller} { } void HeartRateTask::Start() { @@ -40,40 +25,77 @@ 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) == pdTRUE) { + if (xQueueReceive(messageQueue, &msg, delay)) { switch (msg) { case Messages::GoToSleep: - HandleGoToSleep(); + StopMeasurement(); + state = States::Idle; break; case Messages::WakeUp: - HandleWakeUp(); + state = States::Running; + if (measurementStarted) { + lastBpm = 0; + StartMeasurement(); + } break; case Messages::StartMeasurement: - HandleStartMeasurement(&lastBpm); + if (measurementStarted) { + break; + } + lastBpm = 0; + StartMeasurement(); + measurementStarted = true; break; case Messages::StopMeasurement: - HandleStopMeasurement(); + if (!measurementStarted) { + break; + } + StopMeasurement(); + measurementStarted = false; break; } } - 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; + 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); + } } } } @@ -88,7 +110,6 @@ void HeartRateTask::StartMeasurement() { heartRateSensor.Enable(); ppg.Reset(true); vTaskDelay(100); - measurementStart = xTaskGetTickCount(); } void HeartRateTask::StopMeasurement() { @@ -96,165 +117,3 @@ void HeartRateTask::StopMeasurement() { ppg.Reset(true); vTaskDelay(100); } - -void HeartRateTask::StartWaiting() { - StopMeasurement(); - backgroundWaitingStart = xTaskGetTickCount(); -} - -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; - } - - TickType_t ticksSinceWaitingStart = xTaskGetTickCount() - backgroundWaitingStart; - if (ticksSinceWaitingStart >= GetHeartRateBackgroundMeasurementIntervalInTicks()) { - state = States::ScreenOffAndMeasuring; - StartMeasurement(); - } -} - -void HeartRateTask::HandleSensorData(int* lastBpm) { - 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); - } else if (bpm < 0) { - // Reset all DAQ buffers except HRS buffer - ppg.Reset(false); - // Set HR to zero and update - 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, 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) { - state = States::ScreenOffAndWaiting; - StartWaiting(); - } -} - -TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() { - int ms; - switch (settings.GetHeartRateBackgroundMeasurementInterval()) { - case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds: - ms = 10 * 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; -} diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index f7d7e38b..5bbfb9fb 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -3,9 +3,6 @@ #include #include #include -#include "components/settings/Settings.h" - -#define DURATION_UNTIL_BACKGROUND_MEASUREMENT_IS_STOPPED pdMS_TO_TICKS(30 * 1000) namespace Pinetime { namespace Drivers { @@ -19,24 +16,10 @@ namespace Pinetime { namespace Applications { class HeartRateTask { public: - enum class Messages : uint8_t { - GoToSleep, - WakeUp, - StartMeasurement, - StopMeasurement - }; + enum class Messages : uint8_t { GoToSleep, WakeUp, StartMeasurement, StopMeasurement }; + enum class States { Idle, Running }; - enum class States { - ScreenOnAndStopped, - ScreenOnAndMeasuring, - ScreenOffAndStopped, - ScreenOffAndWaiting, - ScreenOffAndMeasuring - }; - - explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, - Controllers::HeartRateController& controller, - Controllers::Settings& settings); + explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller); void Start(); void Work(); void PushMessage(Messages msg); @@ -45,29 +28,14 @@ namespace Pinetime { static void Process(void* instance); void StartMeasurement(); void StopMeasurement(); - void StartWaiting(); - - void HandleGoToSleep(); - void HandleWakeUp(); - void HandleStartMeasurement(int* lastBpm); - void HandleStopMeasurement(); - - void HandleBackgroundWaiting(); - void HandleSensorData(int* lastBpm); - - TickType_t GetHeartRateBackgroundMeasurementIntervalInTicks(); - bool IsContinuousModeActivated(); - bool IsBackgroundMeasurementActivated(); TaskHandle_t taskHandle; QueueHandle_t messageQueue; - States state = States::ScreenOnAndStopped; + States state = States::Running; Drivers::Hrs3300& heartRateSensor; Controllers::HeartRateController& controller; - Controllers::Settings& settings; Controllers::Ppg ppg; - TickType_t backgroundWaitingStart = 0; - TickType_t measurementStart = 0; + bool measurementStarted = false; }; } diff --git a/src/main.cpp b/src/main.cpp index 9db1abf0..ab50fa74 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;