Compare commits
39 commits
Author | SHA1 | Date | |
---|---|---|---|
D. Scott Boggs | cfd1ac4567 | ||
D. Scott Boggs | 6a9d13fe77 | ||
d689e5e874 | |||
D. Scott Boggs | 8abe9d428b | ||
D. Scott Boggs | b7cf42156c | ||
D. Scott Boggs | 7d8e58d863 | ||
D. Scott Boggs | fd15fd238d | ||
a9a36793ad | |||
7df39994ab | |||
9501d36060 | |||
b846547f2f | |||
71b31c78fb | |||
0978964b7d | |||
cedca795e2 | |||
78af44eafe | |||
e6f0a89202 | |||
616926345e | |||
6a0276f164 | |||
7cf4f6e1ec | |||
ffc5f96d9a | |||
3b432cd310 | |||
d78f26201b | |||
4ed4d2cfcd | |||
50d88bbe84 | |||
520e50901a | |||
04ed068ff9 | |||
69578a679a | |||
eeaf5374d4 | |||
f94c074064 | |||
a2edd931ec | |||
d376a856b7 | |||
be1a519098 | |||
27ee1eb2c8 | |||
5dbe1f77b5 | |||
7ae790bcdb | |||
a5db54af27 | |||
0370e3cd65 | |||
58c507ee45 | |||
f7b1111e05 |
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
|
@ -66,5 +66,8 @@
|
||||||
"streambuf": "cpp",
|
"streambuf": "cpp",
|
||||||
"cinttypes": "cpp",
|
"cinttypes": "cpp",
|
||||||
"typeinfo": "cpp"
|
"typeinfo": "cpp"
|
||||||
}
|
},
|
||||||
|
"cSpell.words": [
|
||||||
|
"Pinetime"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release")
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release")
|
||||||
|
|
||||||
project(pinetime VERSION 1.14.0 LANGUAGES C CXX ASM)
|
project(pinetime VERSION 1.15.1 LANGUAGES C CXX ASM)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 99)
|
set(CMAKE_C_STANDARD 99)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
10
default.nix
Normal file
10
default.nix
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
(import
|
||||||
|
(
|
||||||
|
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
|
||||||
|
fetchTarball {
|
||||||
|
url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{ src = ./.; }
|
||||||
|
).defaultNix
|
42
flake.lock
Normal file
42
flake.lock
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-compat": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1696426674,
|
||||||
|
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||||
|
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||||
|
"revCount": 57,
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.0.1/018afb31-abd1-7bff-a5e4-cff7e18efb7a/source.tar.gz"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1725634671,
|
||||||
|
"narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
114
flake.nix
Normal file
114
flake.nix
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
{
|
||||||
|
description = "A very basic flake";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||||
|
flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, ... }@inputs:
|
||||||
|
let
|
||||||
|
forAllSystems = function:
|
||||||
|
inputs.nixpkgs.lib.genAttrs [
|
||||||
|
"x86_64-linux"
|
||||||
|
"aarch64-linux"
|
||||||
|
]
|
||||||
|
(system: function (import inputs.nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
config.allowUnfree = true;
|
||||||
|
}));
|
||||||
|
in
|
||||||
|
{
|
||||||
|
packages = forAllSystems (pkgs:
|
||||||
|
let
|
||||||
|
infinitime-nrf5-sdk = pkgs.nrf5-sdk.overrideAttrs (old: {
|
||||||
|
version = "15.3.0";
|
||||||
|
src = pkgs.fetchzip {
|
||||||
|
url = "https://nsscprodmedia.blob.core.windows.net/prod/software-and-other-downloads/sdks/nrf5/binaries/nrf5sdk153059ac345.zip";
|
||||||
|
sha256 = "sha256-pfmhbpgVv5x2ju489XcivguwpnofHbgVA7bFUJRTj08=";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in
|
||||||
|
with pkgs; {
|
||||||
|
default = stdenv.mkDerivation rec {
|
||||||
|
name = "infinitime";
|
||||||
|
|
||||||
|
src = fetchFromGitea {
|
||||||
|
domain = "git.techwork.zone";
|
||||||
|
owner = "scott";
|
||||||
|
repo = "InfiniTime";
|
||||||
|
rev = "1.15.1";
|
||||||
|
hash = "sha256-9cy7qYRZrg7qZZwQzYeMIZivGLZ5uGUoTyPgHEvdnZ8=";
|
||||||
|
fetchSubmodules = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
cmake
|
||||||
|
nodePackages.lv_font_conv
|
||||||
|
python3
|
||||||
|
python3.pkgs.cbor
|
||||||
|
python3.pkgs.click
|
||||||
|
python3.pkgs.cryptography
|
||||||
|
python3.pkgs.intelhex
|
||||||
|
python3.pkgs.pillow
|
||||||
|
adafruit-nrfutil
|
||||||
|
patch
|
||||||
|
git
|
||||||
|
];
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
# /usr/bin/env is not available in the build sandbox
|
||||||
|
substituteInPlace src/displayapp/fonts/generate.py --replace "'/usr/bin/env', 'patch'" "'patch'"
|
||||||
|
substituteInPlace tools/mcuboot/imgtool.py --replace "/usr/bin/env python3" "${python3}/bin/python3"
|
||||||
|
'';
|
||||||
|
|
||||||
|
cmakeFlags = [
|
||||||
|
''-DARM_NONE_EABI_TOOLCHAIN_PATH=${gcc-arm-embedded-10}''
|
||||||
|
''-DNRF5_SDK_PATH=${infinitime-nrf5-sdk}/share/nRF5_SDK''
|
||||||
|
''-DBUILD_DFU=1''
|
||||||
|
''-DBUILD_RESOURCES=1''
|
||||||
|
''-DCMAKE_SOURCE_DIR=${src}''
|
||||||
|
];
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
SOURCES_DIR=${src} BUILD_DIR=. OUTPUT_DIR=$out ./post_build.sh
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
devShells = forAllSystems (pkgs:
|
||||||
|
let
|
||||||
|
infinitime-nrf5-sdk = pkgs.nrf5-sdk.overrideAttrs (old: {
|
||||||
|
version = "15.3.0";
|
||||||
|
src = pkgs.fetchzip {
|
||||||
|
url = "https://nsscprodmedia.blob.core.windows.net/prod/software-and-other-downloads/sdks/nrf5/binaries/nrf5sdk153059ac345.zip";
|
||||||
|
sha256 = "sha256-pfmhbpgVv5x2ju489XcivguwpnofHbgVA7bFUJRTj08=";
|
||||||
|
};
|
||||||
|
});
|
||||||
|
in
|
||||||
|
{
|
||||||
|
default =
|
||||||
|
pkgs.buildFHSUserEnv {
|
||||||
|
name = "infinitime-devenv";
|
||||||
|
# build tools
|
||||||
|
targetPkgs = pkgs: (with pkgs; [
|
||||||
|
cmake
|
||||||
|
nodePackages.lv_font_conv
|
||||||
|
python3
|
||||||
|
python3.pkgs.cbor
|
||||||
|
python3.pkgs.click
|
||||||
|
python3.pkgs.cryptography
|
||||||
|
python3.pkgs.intelhex
|
||||||
|
adafruit-nrfutil
|
||||||
|
|
||||||
|
(pkgs.writeShellScriptBin "cmake_infinitime" ''
|
||||||
|
cmake -DARM_NONE_EABI_TOOLCHAIN_PATH="${pkgs.gcc-arm-embedded-10}" \
|
||||||
|
-DNRF5_SDK_PATH="${infinitime-nrf5-sdk}/share/nRF5_SDK" \
|
||||||
|
"$@"
|
||||||
|
'')
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
10
shell.nix
Normal file
10
shell.nix
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
(import
|
||||||
|
(
|
||||||
|
let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in
|
||||||
|
fetchTarball {
|
||||||
|
url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz";
|
||||||
|
sha256 = lock.nodes.flake-compat.locked.narHash;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{ src = ./.; }
|
||||||
|
).shellNix
|
|
@ -411,6 +411,7 @@ list(APPEND SOURCE_FILES
|
||||||
displayapp/screens/settings/SettingWeatherFormat.cpp
|
displayapp/screens/settings/SettingWeatherFormat.cpp
|
||||||
displayapp/screens/settings/SettingWakeUp.cpp
|
displayapp/screens/settings/SettingWakeUp.cpp
|
||||||
displayapp/screens/settings/SettingDisplay.cpp
|
displayapp/screens/settings/SettingDisplay.cpp
|
||||||
|
displayapp/screens/settings/SettingHeartRate.cpp
|
||||||
displayapp/screens/settings/SettingSteps.cpp
|
displayapp/screens/settings/SettingSteps.cpp
|
||||||
displayapp/screens/settings/SettingSetDateTime.cpp
|
displayapp/screens/settings/SettingSetDateTime.cpp
|
||||||
displayapp/screens/settings/SettingSetDate.cpp
|
displayapp/screens/settings/SettingSetDate.cpp
|
||||||
|
|
|
@ -8,13 +8,11 @@ Settings::Settings(Pinetime::Controllers::FS& fs) : fs {fs} {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::Init() {
|
void Settings::Init() {
|
||||||
|
|
||||||
// Load default settings from Flash
|
// Load default settings from Flash
|
||||||
LoadSettingsFromFile();
|
LoadSettingsFromFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::SaveSettings() {
|
void Settings::SaveSettings() {
|
||||||
|
|
||||||
// verify if is necessary to save
|
// verify if is necessary to save
|
||||||
if (settingsChanged) {
|
if (settingsChanged) {
|
||||||
SaveSettingsToFile();
|
SaveSettingsToFile();
|
||||||
|
|
|
@ -50,6 +50,17 @@ namespace Pinetime {
|
||||||
int colorIndex = 0;
|
int colorIndex = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class HeartRateBackgroundMeasurementInterval : uint8_t {
|
||||||
|
Off,
|
||||||
|
Continuous,
|
||||||
|
TenSeconds,
|
||||||
|
ThirtySeconds,
|
||||||
|
OneMinute,
|
||||||
|
FiveMinutes,
|
||||||
|
TenMinutes,
|
||||||
|
ThirtyMinutes,
|
||||||
|
};
|
||||||
|
|
||||||
Settings(Pinetime::Controllers::FS& fs);
|
Settings(Pinetime::Controllers::FS& fs);
|
||||||
|
|
||||||
Settings(const Settings&) = delete;
|
Settings(const Settings&) = delete;
|
||||||
|
@ -298,10 +309,21 @@ namespace Pinetime {
|
||||||
return bleRadioEnabled;
|
return bleRadioEnabled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
HeartRateBackgroundMeasurementInterval GetHeartRateBackgroundMeasurementInterval() const {
|
||||||
|
return settings.heartRateBackgroundMeasurementInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHeartRateBackgroundMeasurementInterval(HeartRateBackgroundMeasurementInterval newHeartRateBackgroundMeasurementInterval) {
|
||||||
|
if (newHeartRateBackgroundMeasurementInterval != settings.heartRateBackgroundMeasurementInterval) {
|
||||||
|
settingsChanged = true;
|
||||||
|
}
|
||||||
|
settings.heartRateBackgroundMeasurementInterval = newHeartRateBackgroundMeasurementInterval;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Pinetime::Controllers::FS& fs;
|
Pinetime::Controllers::FS& fs;
|
||||||
|
|
||||||
static constexpr uint32_t settingsVersion = 0x0008;
|
static constexpr uint32_t settingsVersion = 0x0009;
|
||||||
|
|
||||||
struct SettingsData {
|
struct SettingsData {
|
||||||
uint32_t version = settingsVersion;
|
uint32_t version = settingsVersion;
|
||||||
|
@ -325,6 +347,8 @@ namespace Pinetime {
|
||||||
uint16_t shakeWakeThreshold = 150;
|
uint16_t shakeWakeThreshold = 150;
|
||||||
|
|
||||||
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium;
|
||||||
|
|
||||||
|
HeartRateBackgroundMeasurementInterval heartRateBackgroundMeasurementInterval = HeartRateBackgroundMeasurementInterval::Off;
|
||||||
};
|
};
|
||||||
|
|
||||||
SettingsData settings;
|
SettingsData settings;
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "displayapp/screens/settings/SettingSteps.h"
|
#include "displayapp/screens/settings/SettingSteps.h"
|
||||||
#include "displayapp/screens/settings/SettingSetDateTime.h"
|
#include "displayapp/screens/settings/SettingSetDateTime.h"
|
||||||
#include "displayapp/screens/settings/SettingChimes.h"
|
#include "displayapp/screens/settings/SettingChimes.h"
|
||||||
|
#include "displayapp/screens/settings/SettingHeartRate.h"
|
||||||
#include "displayapp/screens/settings/SettingShakeThreshold.h"
|
#include "displayapp/screens/settings/SettingShakeThreshold.h"
|
||||||
#include "displayapp/screens/settings/SettingBluetooth.h"
|
#include "displayapp/screens/settings/SettingBluetooth.h"
|
||||||
|
|
||||||
|
@ -333,7 +334,7 @@ void DisplayApp::Refresh() {
|
||||||
} else {
|
} else {
|
||||||
LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up);
|
LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up);
|
||||||
}
|
}
|
||||||
motorController.RunForDuration(35);
|
motorController.StartRinging();
|
||||||
break;
|
break;
|
||||||
case Messages::AlarmTriggered:
|
case Messages::AlarmTriggered:
|
||||||
if (currentApp == Apps::Alarm) {
|
if (currentApp == Apps::Alarm) {
|
||||||
|
@ -564,6 +565,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
|
||||||
case Apps::SettingWakeUp:
|
case Apps::SettingWakeUp:
|
||||||
currentScreen = std::make_unique<Screens::SettingWakeUp>(settingsController);
|
currentScreen = std::make_unique<Screens::SettingWakeUp>(settingsController);
|
||||||
break;
|
break;
|
||||||
|
case Apps::SettingHeartRate:
|
||||||
|
currentScreen = std::make_unique<Screens::SettingHeartRate>(settingsController);
|
||||||
|
break;
|
||||||
case Apps::SettingDisplay:
|
case Apps::SettingDisplay:
|
||||||
currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
|
currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace Pinetime {
|
||||||
SettingWatchFace,
|
SettingWatchFace,
|
||||||
SettingTimeFormat,
|
SettingTimeFormat,
|
||||||
SettingWeatherFormat,
|
SettingWeatherFormat,
|
||||||
|
SettingHeartRate,
|
||||||
SettingDisplay,
|
SettingDisplay,
|
||||||
SettingWakeUp,
|
SettingWakeUp,
|
||||||
SettingSteps,
|
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::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()];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,15 +38,16 @@ namespace Pinetime {
|
||||||
{Symbols::home, "Watch face", Apps::SettingWatchFace},
|
{Symbols::home, "Watch face", Apps::SettingWatchFace},
|
||||||
|
|
||||||
{Symbols::shoe, "Steps", Apps::SettingSteps},
|
{Symbols::shoe, "Steps", Apps::SettingSteps},
|
||||||
|
{Symbols::heartBeat, "Heartrate", Apps::SettingHeartRate},
|
||||||
{Symbols::clock, "Date&Time", Apps::SettingSetDateTime},
|
{Symbols::clock, "Date&Time", Apps::SettingSetDateTime},
|
||||||
{Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat},
|
{Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat},
|
||||||
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
|
|
||||||
|
|
||||||
|
{Symbols::batteryHalf, "Battery", Apps::BatteryInfo},
|
||||||
{Symbols::clock, "Chimes", Apps::SettingChimes},
|
{Symbols::clock, "Chimes", Apps::SettingChimes},
|
||||||
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
|
{Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold},
|
||||||
{Symbols::check, "Firmware", Apps::FirmwareValidation},
|
{Symbols::check, "Firmware", Apps::FirmwareValidation},
|
||||||
{Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth},
|
|
||||||
|
|
||||||
|
{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},
|
||||||
|
|
|
@ -5,8 +5,23 @@
|
||||||
|
|
||||||
using namespace Pinetime::Applications;
|
using namespace Pinetime::Applications;
|
||||||
|
|
||||||
HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller)
|
TickType_t CurrentTaskDelay(HeartRateTask::States state, TickType_t ppgDeltaTms) {
|
||||||
: heartRateSensor {heartRateSensor}, controller {controller} {
|
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() {
|
void HeartRateTask::Start() {
|
||||||
|
@ -25,77 +40,40 @@ void HeartRateTask::Process(void* instance) {
|
||||||
|
|
||||||
void HeartRateTask::Work() {
|
void HeartRateTask::Work() {
|
||||||
int lastBpm = 0;
|
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) {
|
switch (msg) {
|
||||||
case Messages::GoToSleep:
|
case Messages::GoToSleep:
|
||||||
StopMeasurement();
|
HandleGoToSleep();
|
||||||
state = States::Idle;
|
|
||||||
break;
|
break;
|
||||||
case Messages::WakeUp:
|
case Messages::WakeUp:
|
||||||
state = States::Running;
|
HandleWakeUp();
|
||||||
if (measurementStarted) {
|
|
||||||
lastBpm = 0;
|
|
||||||
StartMeasurement();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Messages::StartMeasurement:
|
case Messages::StartMeasurement:
|
||||||
if (measurementStarted) {
|
HandleStartMeasurement(&lastBpm);
|
||||||
break;
|
|
||||||
}
|
|
||||||
lastBpm = 0;
|
|
||||||
StartMeasurement();
|
|
||||||
measurementStarted = true;
|
|
||||||
break;
|
break;
|
||||||
case Messages::StopMeasurement:
|
case Messages::StopMeasurement:
|
||||||
if (!measurementStarted) {
|
HandleStopMeasurement();
|
||||||
break;
|
|
||||||
}
|
|
||||||
StopMeasurement();
|
|
||||||
measurementStarted = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (measurementStarted) {
|
switch (state) {
|
||||||
int8_t ambient = ppg.Preprocess(heartRateSensor.ReadHrs(), heartRateSensor.ReadAls());
|
case States::ScreenOffAndWaiting:
|
||||||
int bpm = ppg.HeartRate();
|
HandleBackgroundWaiting();
|
||||||
|
break;
|
||||||
// If ambient light detected or a reset requested (bpm < 0)
|
case States::ScreenOffAndMeasuring:
|
||||||
if (ambient > 0) {
|
case States::ScreenOnAndMeasuring:
|
||||||
// Reset all DAQ buffers
|
HandleSensorData(&lastBpm);
|
||||||
ppg.Reset(true);
|
break;
|
||||||
// Force state to NotEnoughData (below)
|
case States::ScreenOffAndStopped:
|
||||||
lastBpm = 0;
|
case States::ScreenOnAndStopped:
|
||||||
bpm = 0;
|
// nothing to do -> ignore
|
||||||
} else if (bpm < 0) {
|
break;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,6 +88,7 @@ void HeartRateTask::StartMeasurement() {
|
||||||
heartRateSensor.Enable();
|
heartRateSensor.Enable();
|
||||||
ppg.Reset(true);
|
ppg.Reset(true);
|
||||||
vTaskDelay(100);
|
vTaskDelay(100);
|
||||||
|
measurementStart = xTaskGetTickCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeartRateTask::StopMeasurement() {
|
void HeartRateTask::StopMeasurement() {
|
||||||
|
@ -117,3 +96,165 @@ void HeartRateTask::StopMeasurement() {
|
||||||
ppg.Reset(true);
|
ppg.Reset(true);
|
||||||
vTaskDelay(100);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#include <task.h>
|
#include <task.h>
|
||||||
#include <queue.h>
|
#include <queue.h>
|
||||||
#include <components/heartrate/Ppg.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 Pinetime {
|
||||||
namespace Drivers {
|
namespace Drivers {
|
||||||
|
@ -16,10 +19,24 @@ namespace Pinetime {
|
||||||
namespace Applications {
|
namespace Applications {
|
||||||
class HeartRateTask {
|
class HeartRateTask {
|
||||||
public:
|
public:
|
||||||
enum class Messages : uint8_t { GoToSleep, WakeUp, StartMeasurement, StopMeasurement };
|
enum class Messages : uint8_t {
|
||||||
enum class States { Idle, Running };
|
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 Start();
|
||||||
void Work();
|
void Work();
|
||||||
void PushMessage(Messages msg);
|
void PushMessage(Messages msg);
|
||||||
|
@ -28,14 +45,29 @@ namespace Pinetime {
|
||||||
static void Process(void* instance);
|
static void Process(void* instance);
|
||||||
void StartMeasurement();
|
void StartMeasurement();
|
||||||
void StopMeasurement();
|
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;
|
TaskHandle_t taskHandle;
|
||||||
QueueHandle_t messageQueue;
|
QueueHandle_t messageQueue;
|
||||||
States state = States::Running;
|
States state = States::ScreenOnAndStopped;
|
||||||
Drivers::Hrs3300& heartRateSensor;
|
Drivers::Hrs3300& heartRateSensor;
|
||||||
Controllers::HeartRateController& controller;
|
Controllers::HeartRateController& controller;
|
||||||
|
Controllers::Settings& settings;
|
||||||
Controllers::Ppg ppg;
|
Controllers::Ppg ppg;
|
||||||
bool measurementStarted = false;
|
TickType_t backgroundWaitingStart = 0;
|
||||||
|
TickType_t measurementStart = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,13 +93,13 @@ TimerHandle_t debounceChargeTimer;
|
||||||
Pinetime::Controllers::Battery batteryController;
|
Pinetime::Controllers::Battery batteryController;
|
||||||
Pinetime::Controllers::Ble bleController;
|
Pinetime::Controllers::Ble bleController;
|
||||||
|
|
||||||
Pinetime::Controllers::HeartRateController heartRateController;
|
|
||||||
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController);
|
|
||||||
|
|
||||||
Pinetime::Controllers::FS fs {spiNorFlash};
|
Pinetime::Controllers::FS fs {spiNorFlash};
|
||||||
Pinetime::Controllers::Settings settingsController {fs};
|
Pinetime::Controllers::Settings settingsController {fs};
|
||||||
Pinetime::Controllers::MotorController motorController {};
|
Pinetime::Controllers::MotorController motorController {};
|
||||||
|
|
||||||
|
Pinetime::Controllers::HeartRateController heartRateController;
|
||||||
|
Pinetime::Applications::HeartRateTask heartRateApp(heartRateSensor, heartRateController, settingsController);
|
||||||
|
|
||||||
Pinetime::Controllers::DateTime dateTimeController {settingsController};
|
Pinetime::Controllers::DateTime dateTimeController {settingsController};
|
||||||
Pinetime::Drivers::Watchdog watchdog;
|
Pinetime::Drivers::Watchdog watchdog;
|
||||||
Pinetime::Controllers::NotificationManager notificationManager;
|
Pinetime::Controllers::NotificationManager notificationManager;
|
||||||
|
|
Loading…
Reference in a new issue