Merge branch 'heartrate-measurements-in-background' into v1.15.3
This commit is contained in:
commit
6e57b178e8
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -581,6 +582,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
|
|||
case Apps::SettingWakeUp:
|
||||
currentScreen = std::make_unique<Screens::SettingWakeUp>(settingsController);
|
||||
break;
|
||||
case Apps::SettingHeartRate:
|
||||
currentScreen = std::make_unique<Screens::SettingHeartRate>(settingsController);
|
||||
break;
|
||||
case Apps::SettingDisplay:
|
||||
currentScreen = std::make_unique<Screens::SettingDisplay>(settingsController);
|
||||
break;
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace Pinetime {
|
|||
SettingWatchFace,
|
||||
SettingTimeFormat,
|
||||
SettingWeatherFormat,
|
||||
SettingHeartRate,
|
||||
SettingDisplay,
|
||||
SettingWakeUp,
|
||||
SettingSteps,
|
||||
|
|
75
src/displayapp/screens/settings/SettingHeartRate.cpp
Normal file
75
src/displayapp/screens/settings/SettingHeartRate.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include "displayapp/screens/settings/SettingHeartRate.h"
|
||||
#include <lvgl/lvgl.h>
|
||||
#include "displayapp/screens/Styles.h"
|
||||
#include "displayapp/screens/Screen.h"
|
||||
#include "displayapp/screens/Symbols.h"
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Pinetime::Applications::Screens;
|
||||
|
||||
namespace {
|
||||
void event_handler(lv_obj_t* obj, lv_event_t event) {
|
||||
auto* screen = static_cast<SettingHeartRate*>(obj->user_data);
|
||||
screen->UpdateSelected(obj, event);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr std::array<Option, 8> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
src/displayapp/screens/settings/SettingHeartRate.h
Normal file
47
src/displayapp/screens/settings/SettingHeartRate.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <lvgl/lvgl.h>
|
||||
|
||||
#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<Option, 8> 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()];
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,15 +38,16 @@ 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::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},
|
||||
|
|
|
@ -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) {
|
||||
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)) {
|
||||
while (true) {
|
||||
TickType_t delay = CurrentTaskDelay(state, ppg.deltaTms);
|
||||
Messages msg;
|
||||
|
||||
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,182 @@ 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
|
@ -3,6 +3,9 @@
|
|||
#include <task.h>
|
||||
#include <queue.h>
|
||||
#include <components/heartrate/Ppg.h>
|
||||
#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
|
||||
};
|
||||
|
||||
explicit HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller);
|
||||
enum class States {
|
||||
ScreenOnAndStopped,
|
||||
ScreenOnAndMeasuring,
|
||||
ScreenOffAndStopped,
|
||||
ScreenOffAndWaiting,
|
||||
ScreenOffAndMeasuring
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue