Compare commits

..

8 commits

Author SHA1 Message Date
D. Scott Boggs cfd1ac4567 Add spell-check exception
Some checks failed
CI / build-firmware (push) Has been cancelled
CI / build-simulator (push) Has been cancelled
CI / get-base-ref-size (push) Has been cancelled
CI / Compare build size (push) Has been cancelled
2024-10-19 06:21:18 -04:00
D. Scott Boggs 6a9d13fe77 Bump version to 1.15.1
Some checks failed
CI / build-firmware (push) Has been cancelled
CI / build-simulator (push) Has been cancelled
CI / get-base-ref-size (push) Has been cancelled
CI / Compare build size (push) Has been cancelled
2024-09-15 12:00:38 -04:00
Davis Mosenkovs d689e5e874 Improve timer vibration
Some checks are pending
CI / build-firmware (push) Waiting to run
CI / build-simulator (push) Waiting to run
CI / get-base-ref-size (push) Waiting to run
CI / Compare build size (push) Blocked by required conditions
2024-09-15 11:57:35 -04:00
D. Scott Boggs 8abe9d428b Update flake for v1.15.0 2024-09-15 11:57:10 -04:00
D. Scott Boggs b7cf42156c bump version
Some checks are pending
CI / build-firmware (push) Waiting to run
CI / build-simulator (push) Waiting to run
CI / get-base-ref-size (push) Waiting to run
CI / Compare build size (push) Blocked by required conditions
2024-09-15 09:30:15 -04:00
D. Scott Boggs 7d8e58d863 Merge branch 'heartrate-measurements-in-background'
Some checks are pending
CI / build-firmware (push) Waiting to run
CI / build-simulator (push) Waiting to run
CI / get-base-ref-size (push) Waiting to run
CI / Compare build size (push) Blocked by required conditions
2024-09-15 09:07:20 -04:00
D. Scott Boggs fd15fd238d bump settings version 2024-09-15 08:43:08 -04:00
Dom Rodriguez a9a36793ad
feat: Introduce Flake for development and builds
Some checks are pending
CI / build-firmware (push) Waiting to run
CI / build-simulator (push) Waiting to run
CI / get-base-ref-size (push) Waiting to run
CI / Compare build size (push) Blocked by required conditions
This PR introduces a Nix flake, allowing for InfiniTime to be built as a
Flake, including a FHS development environment.

It's derived from #1850 and
c57c57f3c6.

We also introduce `flake-compat`, allowing for non-Flake Nix mahcines to
use the project as-is, both for building (`default.nix`), and
development (`shell.nix`).

Additionally, we introduce `.envrc`, meaning that with `direnv`, the Nix
Flake is activated automatically.

Fixes #1850.

Signed-off-by: Dom Rodriguez <shymega@shymega.org.uk>
2024-09-14 14:27:43 +01:00
47 changed files with 299 additions and 437 deletions

3
.gitmodules vendored
View file

@ -4,6 +4,9 @@
[submodule "src/libs/littlefs"] [submodule "src/libs/littlefs"]
path = src/libs/littlefs path = src/libs/littlefs
url = https://github.com/littlefs-project/littlefs.git url = https://github.com/littlefs-project/littlefs.git
[submodule "src/libs/QCBOR"]
path = src/libs/QCBOR
url = https://github.com/laurencelundblade/QCBOR.git
[submodule "src/libs/arduinoFFT"] [submodule "src/libs/arduinoFFT"]
path = src/libs/arduinoFFT path = src/libs/arduinoFFT
url = https://github.com/kosme/arduinoFFT.git url = https://github.com/kosme/arduinoFFT.git

View file

@ -66,5 +66,8 @@
"streambuf": "cpp", "streambuf": "cpp",
"cinttypes": "cpp", "cinttypes": "cpp",
"typeinfo": "cpp" "typeinfo": "cpp"
} },
"cSpell.words": [
"Pinetime"
]
} }

View file

@ -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.15.3 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)

View file

@ -16,11 +16,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1728492678, "lastModified": 1725634671,
"narHash": "sha256-9UTxR8eukdg+XZeHgxW5hQA9fIKHsKCdOIUycTryeVw=", "narHash": "sha256-v3rIhsJBOMLR8e/RNWxr828tB+WywYIoajrZKFM+0Gg=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "5633bcff0c6162b9e4b5f1264264611e950c8ec7", "rev": "574d1eac1c200690e27b8eb4e24887f8df7ac27c",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -32,26 +32,28 @@
with pkgs; { with pkgs; {
default = stdenv.mkDerivation rec { default = stdenv.mkDerivation rec {
name = "infinitime"; name = "infinitime";
version = "1.14.1";
src = fetchFromGitHub { src = fetchFromGitea {
owner = "InfiniTimeOrg"; domain = "git.techwork.zone";
owner = "scott";
repo = "InfiniTime"; repo = "InfiniTime";
rev = "refs/tags/${version}"; rev = "1.15.1";
hash = "sha256-IrsN+9LgEjgfoRR6H7FhsdLMK+GLxc41IBnSbdpwv/E="; hash = "sha256-9cy7qYRZrg7qZZwQzYeMIZivGLZ5uGUoTyPgHEvdnZ8=";
fetchSubmodules = true; fetchSubmodules = true;
}; };
nativeBuildInputs = [ nativeBuildInputs = [
adafruit-nrfutil cmake
nodePackages.lv_font_conv nodePackages.lv_font_conv
patch
python3 python3
python3.pkgs.cbor python3.pkgs.cbor
python3.pkgs.click python3.pkgs.click
python3.pkgs.cryptography python3.pkgs.cryptography
python3.pkgs.intelhex python3.pkgs.intelhex
python3.pkgs.pillow python3.pkgs.pillow
adafruit-nrfutil
patch
git
]; ];
postPatch = '' postPatch = ''
@ -84,17 +86,27 @@
}; };
}); });
in in
with pkgs; { {
default = default =
mkShell { pkgs.buildFHSUserEnv {
packages = [ name = "infinitime-devenv";
(writeShellScriptBin "cmake_infinitime" '' # build tools
${cmake}/bin/cmake -DARM_NONE_EABI_TOOLCHAIN_PATH="${gcc-arm-embedded-10}" \ 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" \ -DNRF5_SDK_PATH="${infinitime-nrf5-sdk}/share/nRF5_SDK" \
"$@" "$@"
'') '')
ninja ]);
] ++ self.packages.${pkgs.system}.default.nativeBuildInputs;
}; };
}); });
}; };

View file

@ -479,7 +479,6 @@ list(APPEND SOURCE_FILES
systemtask/SystemTask.cpp systemtask/SystemTask.cpp
systemtask/SystemMonitor.cpp systemtask/SystemMonitor.cpp
systemtask/WakeLock.cpp
drivers/TwiMaster.cpp drivers/TwiMaster.cpp
heartratetask/HeartRateTask.cpp heartratetask/HeartRateTask.cpp
@ -544,7 +543,6 @@ list(APPEND RECOVERY_SOURCE_FILES
systemtask/SystemTask.cpp systemtask/SystemTask.cpp
systemtask/SystemMonitor.cpp systemtask/SystemMonitor.cpp
systemtask/WakeLock.cpp
drivers/TwiMaster.cpp drivers/TwiMaster.cpp
components/rle/RleDecoder.cpp components/rle/RleDecoder.cpp
components/heartrate/HeartRateController.cpp components/heartrate/HeartRateController.cpp
@ -663,7 +661,6 @@ set(INCLUDE_FILES
displayapp/InfiniTimeTheme.h displayapp/InfiniTimeTheme.h
systemtask/SystemTask.h systemtask/SystemTask.h
systemtask/SystemMonitor.h systemtask/SystemMonitor.h
systemtask/WakeLock.h
displayapp/screens/Symbols.h displayapp/screens/Symbols.h
drivers/TwiMaster.h drivers/TwiMaster.h
heartratetask/HeartRateTask.h heartratetask/HeartRateTask.h

View file

@ -19,13 +19,11 @@
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
#include "task.h" #include "task.h"
#include <chrono> #include <chrono>
#include <libraries/log/nrf_log.h>
using namespace Pinetime::Controllers; using namespace Pinetime::Controllers;
using namespace std::chrono_literals; using namespace std::chrono_literals;
AlarmController::AlarmController(Controllers::DateTime& dateTimeController, Controllers::FS& fs) AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : dateTimeController {dateTimeController} {
: dateTimeController {dateTimeController}, fs {fs} {
} }
namespace { namespace {
@ -38,28 +36,11 @@ namespace {
void AlarmController::Init(System::SystemTask* systemTask) { void AlarmController::Init(System::SystemTask* systemTask) {
this->systemTask = systemTask; this->systemTask = systemTask;
alarmTimer = xTimerCreate("Alarm", 1, pdFALSE, this, SetOffAlarm); alarmTimer = xTimerCreate("Alarm", 1, pdFALSE, this, SetOffAlarm);
LoadSettingsFromFile();
if (alarm.isEnabled) {
NRF_LOG_INFO("[AlarmController] Loaded alarm was enabled, scheduling");
ScheduleAlarm();
}
}
void AlarmController::SaveAlarm() {
// verify if it is necessary to save
if (alarmChanged) {
SaveSettingsToFile();
}
alarmChanged = false;
} }
void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) { void AlarmController::SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin) {
if (alarm.hours == alarmHr && alarm.minutes == alarmMin) { hours = alarmHr;
return; minutes = alarmMin;
}
alarm.hours = alarmHr;
alarm.minutes = alarmMin;
alarmChanged = true;
} }
void AlarmController::ScheduleAlarm() { void AlarmController::ScheduleAlarm() {
@ -72,19 +53,18 @@ void AlarmController::ScheduleAlarm() {
tm* tmAlarmTime = std::localtime(&ttAlarmTime); tm* tmAlarmTime = std::localtime(&ttAlarmTime);
// If the time being set has already passed today,the alarm should be set for tomorrow // If the time being set has already passed today,the alarm should be set for tomorrow
if (alarm.hours < dateTimeController.Hours() || if (hours < dateTimeController.Hours() || (hours == dateTimeController.Hours() && minutes <= dateTimeController.Minutes())) {
(alarm.hours == dateTimeController.Hours() && alarm.minutes <= dateTimeController.Minutes())) {
tmAlarmTime->tm_mday += 1; tmAlarmTime->tm_mday += 1;
// tm_wday doesn't update automatically // tm_wday doesn't update automatically
tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7; tmAlarmTime->tm_wday = (tmAlarmTime->tm_wday + 1) % 7;
} }
tmAlarmTime->tm_hour = alarm.hours; tmAlarmTime->tm_hour = hours;
tmAlarmTime->tm_min = alarm.minutes; tmAlarmTime->tm_min = minutes;
tmAlarmTime->tm_sec = 0; tmAlarmTime->tm_sec = 0;
// if alarm is in weekday-only mode, make sure it shifts to the next weekday // if alarm is in weekday-only mode, make sure it shifts to the next weekday
if (alarm.recurrence == RecurType::Weekdays) { if (recurrence == RecurType::Weekdays) {
if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day if (tmAlarmTime->tm_wday == 0) { // Sunday, shift 1 day
tmAlarmTime->tm_mday += 1; tmAlarmTime->tm_mday += 1;
} else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days } else if (tmAlarmTime->tm_wday == 6) { // Saturday, shift 2 days
@ -99,10 +79,7 @@ void AlarmController::ScheduleAlarm() {
xTimerChangePeriod(alarmTimer, secondsToAlarm * configTICK_RATE_HZ, 0); xTimerChangePeriod(alarmTimer, secondsToAlarm * configTICK_RATE_HZ, 0);
xTimerStart(alarmTimer, 0); xTimerStart(alarmTimer, 0);
if (!alarm.isEnabled) { state = AlarmState::Set;
alarm.isEnabled = true;
alarmChanged = true;
}
} }
uint32_t AlarmController::SecondsToAlarm() const { uint32_t AlarmController::SecondsToAlarm() const {
@ -111,72 +88,20 @@ uint32_t AlarmController::SecondsToAlarm() const {
void AlarmController::DisableAlarm() { void AlarmController::DisableAlarm() {
xTimerStop(alarmTimer, 0); xTimerStop(alarmTimer, 0);
isAlerting = false; state = AlarmState::Not_Set;
if (alarm.isEnabled) {
alarm.isEnabled = false;
alarmChanged = true;
}
} }
void AlarmController::SetOffAlarmNow() { void AlarmController::SetOffAlarmNow() {
isAlerting = true; state = AlarmState::Alerting;
systemTask->PushMessage(System::Messages::SetOffAlarm); systemTask->PushMessage(System::Messages::SetOffAlarm);
} }
void AlarmController::StopAlerting() { void AlarmController::StopAlerting() {
isAlerting = false; // Alarm state is off unless this is a recurring alarm
// Disable alarm unless it is recurring if (recurrence == RecurType::None) {
if (alarm.recurrence == RecurType::None) { state = AlarmState::Not_Set;
alarm.isEnabled = false;
alarmChanged = true;
} else { } else {
// set next instance // set next instance
ScheduleAlarm(); ScheduleAlarm();
} }
} }
void AlarmController::SetRecurrence(RecurType recurrence) {
if (alarm.recurrence != recurrence) {
alarm.recurrence = recurrence;
alarmChanged = true;
}
}
void AlarmController::LoadSettingsFromFile() {
lfs_file_t alarmFile;
AlarmSettings alarmBuffer;
if (fs.FileOpen(&alarmFile, "/.system/alarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) {
NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file");
return;
}
fs.FileRead(&alarmFile, reinterpret_cast<uint8_t*>(&alarmBuffer), sizeof(alarmBuffer));
fs.FileClose(&alarmFile);
if (alarmBuffer.version != alarmFormatVersion) {
NRF_LOG_WARNING("[AlarmController] Loaded alarm settings has version %u instead of %u, discarding",
alarmBuffer.version,
alarmFormatVersion);
return;
}
alarm = alarmBuffer;
NRF_LOG_INFO("[AlarmController] Loaded alarm settings from file");
}
void AlarmController::SaveSettingsToFile() const {
lfs_dir systemDir;
if (fs.DirOpen("/.system", &systemDir) != LFS_ERR_OK) {
fs.DirCreate("/.system");
}
fs.DirClose(&systemDir);
lfs_file_t alarmFile;
if (fs.FileOpen(&alarmFile, "/.system/alarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) {
NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file for saving");
return;
}
fs.FileWrite(&alarmFile, reinterpret_cast<const uint8_t*>(&alarm), sizeof(alarm));
fs.FileClose(&alarmFile);
NRF_LOG_INFO("[AlarmController] Saved alarm settings with format version %u to file", alarm.version);
}

View file

@ -30,65 +30,47 @@ namespace Pinetime {
namespace Controllers { namespace Controllers {
class AlarmController { class AlarmController {
public: public:
AlarmController(Controllers::DateTime& dateTimeController, Controllers::FS& fs); AlarmController(Controllers::DateTime& dateTimeController);
void Init(System::SystemTask* systemTask); void Init(System::SystemTask* systemTask);
void SaveAlarm();
void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin); void SetAlarmTime(uint8_t alarmHr, uint8_t alarmMin);
void ScheduleAlarm(); void ScheduleAlarm();
void DisableAlarm(); void DisableAlarm();
void SetOffAlarmNow(); void SetOffAlarmNow();
uint32_t SecondsToAlarm() const; uint32_t SecondsToAlarm() const;
void StopAlerting(); void StopAlerting();
enum class AlarmState { Not_Set, Set, Alerting };
enum class RecurType { None, Daily, Weekdays }; enum class RecurType { None, Daily, Weekdays };
uint8_t Hours() const { uint8_t Hours() const {
return alarm.hours; return hours;
} }
uint8_t Minutes() const { uint8_t Minutes() const {
return alarm.minutes; return minutes;
} }
bool IsAlerting() const { AlarmState State() const {
return isAlerting; return state;
}
bool IsEnabled() const {
return alarm.isEnabled;
} }
RecurType Recurrence() const { RecurType Recurrence() const {
return alarm.recurrence; return recurrence;
} }
void SetRecurrence(RecurType recurrence); void SetRecurrence(RecurType recurType) {
recurrence = recurType;
}
private: private:
// Versions 255 is reserved for now, so the version field can be made
// bigger, should it ever be needed.
static constexpr uint8_t alarmFormatVersion = 1;
struct AlarmSettings {
uint8_t version = alarmFormatVersion;
uint8_t hours = 7;
uint8_t minutes = 0;
RecurType recurrence = RecurType::None;
bool isEnabled = false;
};
bool isAlerting = false;
bool alarmChanged = false;
Controllers::DateTime& dateTimeController; Controllers::DateTime& dateTimeController;
Controllers::FS& fs;
System::SystemTask* systemTask = nullptr; System::SystemTask* systemTask = nullptr;
TimerHandle_t alarmTimer; TimerHandle_t alarmTimer;
AlarmSettings alarm; uint8_t hours = 7;
uint8_t minutes = 0;
std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime; std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> alarmTime;
AlarmState state = AlarmState::Not_Set;
void LoadSettingsFromFile(); RecurType recurrence = RecurType::None;
void SaveSettingsToFile() const;
}; };
} }
} }

View file

@ -124,11 +124,9 @@ int DfuService::WritePacketHandler(uint16_t connectionHandle, os_mbuf* om) {
bootloaderSize, bootloaderSize,
applicationSize); applicationSize);
// Wait until SystemTask has disabled sleeping // wait until SystemTask has finished waking up all devices
// This isn't quite correct, as we don't actually know while (systemTask.IsSleeping()) {
// if BleFirmwareUpdateStarted has been received yet vTaskDelay(50); // 50ms
while (!systemTask.IsSleepDisabled()) {
vTaskDelay(pdMS_TO_TICKS(5));
} }
dfuImage.Erase(); dfuImage.Erase();

View file

@ -18,8 +18,6 @@
#include "components/ble/MusicService.h" #include "components/ble/MusicService.h"
#include "components/ble/NimbleController.h" #include "components/ble/NimbleController.h"
#include <cstring> #include <cstring>
#include <FreeRTOS.h>
#include <task.h>
namespace { namespace {
// 0000yyxx-78fc-48fe-8e23-433b3a1942d0 // 0000yyxx-78fc-48fe-8e23-433b3a1942d0

View file

@ -25,7 +25,6 @@
#include <host/ble_uuid.h> #include <host/ble_uuid.h>
#undef max #undef max
#undef min #undef min
#include <FreeRTOS.h>
namespace Pinetime { namespace Pinetime {
namespace Controllers { namespace Controllers {

View file

@ -454,15 +454,9 @@ void NimbleController::PersistBond(struct ble_gap_conn_desc& desc) {
/* Wakeup Spi and SpiNorFlash before accessing the file system /* Wakeup Spi and SpiNorFlash before accessing the file system
* This should be fixed in the FS driver * This should be fixed in the FS driver
*/ */
systemTask.PushMessage(Pinetime::System::Messages::GoToRunning);
systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
vTaskDelay(10);
// This isn't quite correct
// SystemTask could receive EnableSleeping right after passing this check
// We need some guarantee that the SystemTask has processed the above message
// before we can continue
while (!systemTask.IsSleepDisabled()) {
vTaskDelay(pdMS_TO_TICKS(5));
}
lfs_file_t file_p; lfs_file_t file_p;

View file

@ -142,7 +142,7 @@ Ppg::Ppg() {
spectrum.fill(0.0f); spectrum.fill(0.0f);
} }
int8_t Ppg::Preprocess(uint16_t hrs, uint16_t als) { int8_t Ppg::Preprocess(uint32_t hrs, uint32_t als) {
if (dataIndex < dataLength) { if (dataIndex < dataLength) {
dataHRS[dataIndex++] = hrs; dataHRS[dataIndex++] = hrs;
} }

View file

@ -14,7 +14,7 @@ namespace Pinetime {
class Ppg { class Ppg {
public: public:
Ppg(); Ppg();
int8_t Preprocess(uint16_t hrs, uint16_t als); int8_t Preprocess(uint32_t hrs, uint32_t als);
int HeartRate(); int HeartRate();
void Reset(bool resetDaqBuffer); void Reset(bool resetDaqBuffer);
static constexpr int deltaTms = 100; static constexpr int deltaTms = 100;

View file

@ -53,7 +53,7 @@ namespace Pinetime {
enum class HeartRateBackgroundMeasurementInterval : uint8_t { enum class HeartRateBackgroundMeasurementInterval : uint8_t {
Off, Off,
Continuous, Continuous,
FifteenSeconds, TenSeconds,
ThirtySeconds, ThirtySeconds,
OneMinute, OneMinute,
FiveMinutes, FiveMinutes,

View file

@ -256,20 +256,9 @@ void DisplayApp::Refresh() {
isDimmed = true; isDimmed = true;
brightnessController.Set(Controllers::BrightnessController::Levels::Low); brightnessController.Set(Controllers::BrightnessController::Levels::Low);
} }
if (IsPastSleepTime() && uxQueueMessagesWaiting(msgQueue) == 0) { if (IsPastSleepTime()) {
PushMessageToSystemTask(System::Messages::GoToSleep); systemTask->PushMessage(System::Messages::GoToSleep);
// Can't set state to Idle here, something may send state = States::Idle;
// DisableSleeping before this GoToSleep arrives
// Instead we check we have no messages queued before sending GoToSleep
// This works as the SystemTask is higher priority than DisplayApp
// As soon as we send GoToSleep, SystemTask pre-empts DisplayApp
// Whenever DisplayApp is running again, it is guaranteed that
// SystemTask has handled the message
// If it responded, we will have a GoToSleep waiting in the queue
// By checking that there are no messages in the queue, we avoid
// resending GoToSleep when we already have a response
// SystemTask is resilient to duplicate messages, this is an
// optimisation to reduce pressure on the message queues
} }
} else if (isDimmed) { } else if (isDimmed) {
isDimmed = false; isDimmed = false;
@ -285,9 +274,6 @@ void DisplayApp::Refresh() {
if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) { if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) {
switch (msg) { switch (msg) {
case Messages::GoToSleep: case Messages::GoToSleep:
if (state != States::Running) {
break;
}
while (brightnessController.Level() != Controllers::BrightnessController::Levels::Low) { while (brightnessController.Level() != Controllers::BrightnessController::Levels::Low) {
brightnessController.Lower(); brightnessController.Lower();
vTaskDelay(100); vTaskDelay(100);
@ -322,9 +308,6 @@ void DisplayApp::Refresh() {
lv_disp_trig_activity(nullptr); lv_disp_trig_activity(nullptr);
break; break;
case Messages::GoToRunning: case Messages::GoToRunning:
if (state == States::Running) {
break;
}
if (settingsController.GetAlwaysOnDisplay()) { if (settingsController.GetAlwaysOnDisplay()) {
lcd.LowPowerOff(); lcd.LowPowerOff();
} else { } else {
@ -586,7 +569,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
currentScreen = std::make_unique<Screens::SettingHeartRate>(settingsController); currentScreen = std::make_unique<Screens::SettingHeartRate>(settingsController);
break; break;
case Apps::SettingDisplay: case Apps::SettingDisplay:
currentScreen = std::make_unique<Screens::SettingDisplay>(settingsController); currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController);
break; break;
case Apps::SettingSteps: case Apps::SettingSteps:
currentScreen = std::make_unique<Screens::SettingSteps>(settingsController); currentScreen = std::make_unique<Screens::SettingSteps>(settingsController);

View file

@ -48,7 +48,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
Controllers::Settings::ClockType clockType, Controllers::Settings::ClockType clockType,
System::SystemTask& systemTask, System::SystemTask& systemTask,
Controllers::MotorController& motorController) Controllers::MotorController& motorController)
: alarmController {alarmController}, wakeLock(systemTask), motorController {motorController} { : alarmController {alarmController}, systemTask {systemTask}, motorController {motorController} {
hourCounter.Create(); hourCounter.Create();
lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
@ -117,7 +117,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
UpdateAlarmTime(); UpdateAlarmTime();
if (alarmController.IsAlerting()) { if (alarmController.State() == Controllers::AlarmController::AlarmState::Alerting) {
SetAlerting(); SetAlerting();
} else { } else {
SetSwitchState(LV_ANIM_OFF); SetSwitchState(LV_ANIM_OFF);
@ -125,15 +125,14 @@ Alarm::Alarm(Controllers::AlarmController& alarmController,
} }
Alarm::~Alarm() { Alarm::~Alarm() {
if (alarmController.IsAlerting()) { if (alarmController.State() == AlarmController::AlarmState::Alerting) {
StopAlerting(); StopAlerting();
} }
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
alarmController.SaveAlarm();
} }
void Alarm::DisableAlarm() { void Alarm::DisableAlarm() {
if (alarmController.IsEnabled()) { if (alarmController.State() == AlarmController::AlarmState::Set) {
alarmController.DisableAlarm(); alarmController.DisableAlarm();
lv_switch_off(enableSwitch, LV_ANIM_ON); lv_switch_off(enableSwitch, LV_ANIM_ON);
} }
@ -173,7 +172,7 @@ bool Alarm::OnButtonPushed() {
HideInfo(); HideInfo();
return true; return true;
} }
if (alarmController.IsAlerting()) { if (alarmController.State() == AlarmController::AlarmState::Alerting) {
StopAlerting(); StopAlerting();
return true; return true;
} }
@ -182,7 +181,7 @@ bool Alarm::OnButtonPushed() {
bool Alarm::OnTouchEvent(Pinetime::Applications::TouchEvents event) { bool Alarm::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
// Don't allow closing the screen by swiping while the alarm is alerting // Don't allow closing the screen by swiping while the alarm is alerting
return alarmController.IsAlerting() && event == TouchEvents::SwipeDown; return alarmController.State() == AlarmController::AlarmState::Alerting && event == TouchEvents::SwipeDown;
} }
void Alarm::OnValueChanged() { void Alarm::OnValueChanged() {
@ -206,7 +205,7 @@ void Alarm::SetAlerting() {
lv_obj_set_hidden(btnStop, false); lv_obj_set_hidden(btnStop, false);
taskStopAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); taskStopAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this);
motorController.StartRinging(); motorController.StartRinging();
wakeLock.Lock(); systemTask.PushMessage(System::Messages::DisableSleeping);
} }
void Alarm::StopAlerting() { void Alarm::StopAlerting() {
@ -217,16 +216,21 @@ void Alarm::StopAlerting() {
lv_task_del(taskStopAlarm); lv_task_del(taskStopAlarm);
taskStopAlarm = nullptr; taskStopAlarm = nullptr;
} }
wakeLock.Release(); systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_set_hidden(enableSwitch, false); lv_obj_set_hidden(enableSwitch, false);
lv_obj_set_hidden(btnStop, true); lv_obj_set_hidden(btnStop, true);
} }
void Alarm::SetSwitchState(lv_anim_enable_t anim) { void Alarm::SetSwitchState(lv_anim_enable_t anim) {
if (alarmController.IsEnabled()) { switch (alarmController.State()) {
case AlarmController::AlarmState::Set:
lv_switch_on(enableSwitch, anim); lv_switch_on(enableSwitch, anim);
} else { break;
case AlarmController::AlarmState::Not_Set:
lv_switch_off(enableSwitch, anim); lv_switch_off(enableSwitch, anim);
break;
default:
break;
} }
} }
@ -243,7 +247,7 @@ void Alarm::ShowInfo() {
txtMessage = lv_label_create(btnMessage, nullptr); txtMessage = lv_label_create(btnMessage, nullptr);
lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY); lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY);
if (alarmController.IsEnabled()) { if (alarmController.State() == AlarmController::AlarmState::Set) {
auto timeToAlarm = alarmController.SecondsToAlarm(); auto timeToAlarm = alarmController.SecondsToAlarm();
auto daysToAlarm = timeToAlarm / 86400; auto daysToAlarm = timeToAlarm / 86400;

View file

@ -22,7 +22,6 @@
#include "displayapp/screens/Screen.h" #include "displayapp/screens/Screen.h"
#include "displayapp/widgets/Counter.h" #include "displayapp/widgets/Counter.h"
#include "displayapp/Controllers.h" #include "displayapp/Controllers.h"
#include "systemtask/WakeLock.h"
#include "Symbols.h" #include "Symbols.h"
namespace Pinetime { namespace Pinetime {
@ -44,7 +43,7 @@ namespace Pinetime {
private: private:
Controllers::AlarmController& alarmController; Controllers::AlarmController& alarmController;
System::WakeLock wakeLock; System::SystemTask& systemTask;
Controllers::MotorController& motorController; Controllers::MotorController& motorController;
lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch; lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch;

View file

@ -15,7 +15,7 @@ namespace {
} }
FlashLight::FlashLight(System::SystemTask& systemTask, Controllers::BrightnessController& brightnessController) FlashLight::FlashLight(System::SystemTask& systemTask, Controllers::BrightnessController& brightnessController)
: wakeLock(systemTask), brightnessController {brightnessController} { : systemTask {systemTask}, brightnessController {brightnessController} {
previousBrightnessLevel = brightnessController.Level(); previousBrightnessLevel = brightnessController.Level();
brightnessController.Set(Controllers::BrightnessController::Levels::Low); brightnessController.Set(Controllers::BrightnessController::Levels::Low);
@ -47,13 +47,14 @@ FlashLight::FlashLight(System::SystemTask& systemTask, Controllers::BrightnessCo
backgroundAction->user_data = this; backgroundAction->user_data = this;
lv_obj_set_event_cb(backgroundAction, EventHandler); lv_obj_set_event_cb(backgroundAction, EventHandler);
wakeLock.Lock(); systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
} }
FlashLight::~FlashLight() { FlashLight::~FlashLight() {
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK);
brightnessController.Set(previousBrightnessLevel); brightnessController.Set(previousBrightnessLevel);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
} }
void FlashLight::SetColors() { void FlashLight::SetColors() {

View file

@ -3,7 +3,6 @@
#include "displayapp/screens/Screen.h" #include "displayapp/screens/Screen.h"
#include "components/brightness/BrightnessController.h" #include "components/brightness/BrightnessController.h"
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
#include "systemtask/WakeLock.h"
#include <cstdint> #include <cstdint>
#include <lvgl/lvgl.h> #include <lvgl/lvgl.h>
@ -24,7 +23,7 @@ namespace Pinetime {
void SetIndicators(); void SetIndicators();
void SetColors(); void SetColors();
Pinetime::System::WakeLock wakeLock; Pinetime::System::SystemTask& systemTask;
Controllers::BrightnessController& brightnessController; Controllers::BrightnessController& brightnessController;
Controllers::BrightnessController::Levels brightnessLevel = Controllers::BrightnessController::Levels::High; Controllers::BrightnessController::Levels brightnessLevel = Controllers::BrightnessController::Levels::High;

View file

@ -29,7 +29,7 @@ namespace {
} }
HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, System::SystemTask& systemTask) HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, System::SystemTask& systemTask)
: heartRateController {heartRateController}, wakeLock(systemTask) { : heartRateController {heartRateController}, systemTask {systemTask} {
bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; bool isHrRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
label_hr = lv_label_create(lv_scr_act(), nullptr); label_hr = lv_label_create(lv_scr_act(), nullptr);
@ -63,7 +63,7 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst
label_startStop = lv_label_create(btn_startStop, nullptr); label_startStop = lv_label_create(btn_startStop, nullptr);
UpdateStartStopButton(isHrRunning); UpdateStartStopButton(isHrRunning);
if (isHrRunning) { if (isHrRunning) {
wakeLock.Lock(); systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
} }
taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this);
@ -72,6 +72,7 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst
HeartRate::~HeartRate() { HeartRate::~HeartRate() {
lv_task_del(taskRefresh); lv_task_del(taskRefresh);
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
} }
void HeartRate::Refresh() { void HeartRate::Refresh() {
@ -100,12 +101,12 @@ void HeartRate::OnStartStopEvent(lv_event_t event) {
if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) { if (heartRateController.State() == Controllers::HeartRateController::States::Stopped) {
heartRateController.Start(); heartRateController.Start();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped); UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
wakeLock.Lock(); systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight);
} else { } else {
heartRateController.Stop(); heartRateController.Stop();
UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped); UpdateStartStopButton(heartRateController.State() != Controllers::HeartRateController::States::Stopped);
wakeLock.Release(); systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray);
} }
} }

View file

@ -4,7 +4,6 @@
#include <chrono> #include <chrono>
#include "displayapp/screens/Screen.h" #include "displayapp/screens/Screen.h"
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
#include "systemtask/WakeLock.h"
#include "Symbols.h" #include "Symbols.h"
#include <lvgl/src/lv_core/lv_style.h> #include <lvgl/src/lv_core/lv_style.h>
#include <lvgl/src/lv_core/lv_obj.h> #include <lvgl/src/lv_core/lv_obj.h>
@ -28,7 +27,7 @@ namespace Pinetime {
private: private:
Controllers::HeartRateController& heartRateController; Controllers::HeartRateController& heartRateController;
Pinetime::System::WakeLock wakeLock; Pinetime::System::SystemTask& systemTask;
void UpdateStartStopButton(bool isRunning); void UpdateStartStopButton(bool isRunning);
lv_obj_t* label_hr; lv_obj_t* label_hr;
lv_obj_t* label_bpm; lv_obj_t* label_bpm;

View file

@ -22,7 +22,7 @@ namespace {
} }
Metronome::Metronome(Controllers::MotorController& motorController, System::SystemTask& systemTask) Metronome::Metronome(Controllers::MotorController& motorController, System::SystemTask& systemTask)
: motorController {motorController}, wakeLock(systemTask) { : motorController {motorController}, systemTask {systemTask} {
bpmArc = lv_arc_create(lv_scr_act(), nullptr); bpmArc = lv_arc_create(lv_scr_act(), nullptr);
bpmArc->user_data = this; bpmArc->user_data = this;
@ -72,6 +72,7 @@ Metronome::Metronome(Controllers::MotorController& motorController, System::Syst
Metronome::~Metronome() { Metronome::~Metronome() {
lv_task_del(taskRefresh); lv_task_del(taskRefresh);
systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
@ -127,12 +128,12 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) {
metronomeStarted = !metronomeStarted; metronomeStarted = !metronomeStarted;
if (metronomeStarted) { if (metronomeStarted) {
lv_label_set_text_static(lblPlayPause, Symbols::pause); lv_label_set_text_static(lblPlayPause, Symbols::pause);
wakeLock.Lock(); systemTask.PushMessage(System::Messages::DisableSleeping);
startTime = xTaskGetTickCount(); startTime = xTaskGetTickCount();
counter = 1; counter = 1;
} else { } else {
lv_label_set_text_static(lblPlayPause, Symbols::play); lv_label_set_text_static(lblPlayPause, Symbols::play);
wakeLock.Release(); systemTask.PushMessage(System::Messages::EnableSleeping);
} }
} }
break; break;

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
#include "systemtask/WakeLock.h"
#include "components/motor/MotorController.h" #include "components/motor/MotorController.h"
#include "displayapp/screens/Screen.h" #include "displayapp/screens/Screen.h"
#include "Symbols.h" #include "Symbols.h"
@ -22,7 +21,7 @@ namespace Pinetime {
TickType_t startTime = 0; TickType_t startTime = 0;
TickType_t tappedTime = 0; TickType_t tappedTime = 0;
Controllers::MotorController& motorController; Controllers::MotorController& motorController;
System::WakeLock wakeLock; System::SystemTask& systemTask;
int16_t bpm = 120; int16_t bpm = 120;
uint8_t bpb = 4; uint8_t bpb = 4;
uint8_t counter = 1; uint8_t counter = 1;

View file

@ -20,7 +20,7 @@ Notifications::Notifications(DisplayApp* app,
notificationManager {notificationManager}, notificationManager {notificationManager},
alertNotificationService {alertNotificationService}, alertNotificationService {alertNotificationService},
motorController {motorController}, motorController {motorController},
wakeLock(systemTask), systemTask {systemTask},
mode {mode} { mode {mode} {
notificationManager.ClearNewNotificationFlag(); notificationManager.ClearNewNotificationFlag();
@ -40,7 +40,7 @@ Notifications::Notifications(DisplayApp* app,
validDisplay = false; validDisplay = false;
} }
if (mode == Modes::Preview) { if (mode == Modes::Preview) {
wakeLock.Lock(); systemTask.PushMessage(System::Messages::DisableSleeping);
if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) { if (notification.category == Controllers::NotificationManager::Categories::IncomingCall) {
motorController.StartRinging(); motorController.StartRinging();
} else { } else {
@ -65,6 +65,7 @@ Notifications::~Notifications() {
lv_task_del(taskRefresh); lv_task_del(taskRefresh);
// make sure we stop any vibrations before exiting // make sure we stop any vibrations before exiting
motorController.StopRinging(); motorController.StopRinging();
systemTask.PushMessage(System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
@ -81,6 +82,7 @@ void Notifications::Refresh() {
} else if (mode == Modes::Preview && dismissingNotification) { } else if (mode == Modes::Preview && dismissingNotification) {
running = false; running = false;
currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
} else if (dismissingNotification) { } else if (dismissingNotification) {
dismissingNotification = false; dismissingNotification = false;
@ -111,15 +113,15 @@ void Notifications::Refresh() {
alertNotificationService, alertNotificationService,
motorController); motorController);
} else { } else {
running = false; currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController);
} }
} }
running = running && currentItem->IsRunning(); running = currentItem->IsRunning() && running;
} }
void Notifications::OnPreviewInteraction() { void Notifications::OnPreviewInteraction() {
wakeLock.Release(); systemTask.PushMessage(System::Messages::EnableSleeping);
motorController.StopRinging(); motorController.StopRinging();
if (timeoutLine != nullptr) { if (timeoutLine != nullptr) {
lv_obj_del(timeoutLine); lv_obj_del(timeoutLine);
@ -171,9 +173,7 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
} else if (nextMessage.valid) { } else if (nextMessage.valid) {
currentId = nextMessage.id; currentId = nextMessage.id;
} else { } else {
// don't update id, notification manager will try to fetch // don't update id, won't be found be refresh and try to load latest message or no message box
// but not find it. Refresh will try to load latest message
// or dismiss to watchface
} }
DismissToBlack(); DismissToBlack();
return true; return true;

View file

@ -8,7 +8,6 @@
#include "components/ble/NotificationManager.h" #include "components/ble/NotificationManager.h"
#include "components/motor/MotorController.h" #include "components/motor/MotorController.h"
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
#include "systemtask/WakeLock.h"
namespace Pinetime { namespace Pinetime {
namespace Controllers { namespace Controllers {
@ -74,7 +73,7 @@ namespace Pinetime {
Pinetime::Controllers::NotificationManager& notificationManager; Pinetime::Controllers::NotificationManager& notificationManager;
Pinetime::Controllers::AlertNotificationService& alertNotificationService; Pinetime::Controllers::AlertNotificationService& alertNotificationService;
Pinetime::Controllers::MotorController& motorController; Pinetime::Controllers::MotorController& motorController;
System::WakeLock wakeLock; System::SystemTask& systemTask;
Modes mode = Modes::Normal; Modes mode = Modes::Normal;
std::unique_ptr<NotificationItem> currentItem; std::unique_ptr<NotificationItem> currentItem;
Pinetime::Controllers::NotificationManager::Notification::Id currentId; Pinetime::Controllers::NotificationManager::Notification::Id currentId;

View file

@ -34,7 +34,7 @@ namespace {
constexpr TickType_t blinkInterval = pdMS_TO_TICKS(1000); constexpr TickType_t blinkInterval = pdMS_TO_TICKS(1000);
} }
StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) { StopWatch::StopWatch(System::SystemTask& systemTask) : systemTask {systemTask} {
static constexpr uint8_t btnWidth = 115; static constexpr uint8_t btnWidth = 115;
static constexpr uint8_t btnHeight = 80; static constexpr uint8_t btnHeight = 80;
btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); btnPlayPause = lv_btn_create(lv_scr_act(), nullptr);
@ -79,6 +79,7 @@ StopWatch::StopWatch(System::SystemTask& systemTask) : wakeLock(systemTask) {
StopWatch::~StopWatch() { StopWatch::~StopWatch() {
lv_task_del(taskRefresh); lv_task_del(taskRefresh);
systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
lv_obj_clean(lv_scr_act()); lv_obj_clean(lv_scr_act());
} }
@ -134,7 +135,7 @@ void StopWatch::Start() {
SetInterfaceRunning(); SetInterfaceRunning();
startTime = xTaskGetTickCount(); startTime = xTaskGetTickCount();
currentState = States::Running; currentState = States::Running;
wakeLock.Lock(); systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping);
} }
void StopWatch::Pause() { void StopWatch::Pause() {
@ -144,7 +145,7 @@ void StopWatch::Pause() {
oldTimeElapsed = laps[lapsDone]; oldTimeElapsed = laps[lapsDone];
blinkTime = xTaskGetTickCount() + blinkInterval; blinkTime = xTaskGetTickCount() + blinkInterval;
currentState = States::Halted; currentState = States::Halted;
wakeLock.Release(); systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping);
} }
void StopWatch::Refresh() { void StopWatch::Refresh() {

View file

@ -7,7 +7,6 @@
#include "portmacro_cmsis.h" #include "portmacro_cmsis.h"
#include "systemtask/SystemTask.h" #include "systemtask/SystemTask.h"
#include "systemtask/WakeLock.h"
#include "displayapp/apps/Apps.h" #include "displayapp/apps/Apps.h"
#include "displayapp/Controllers.h" #include "displayapp/Controllers.h"
#include "Symbols.h" #include "Symbols.h"
@ -44,7 +43,7 @@ namespace Pinetime {
void Start(); void Start();
void Pause(); void Pause();
Pinetime::System::WakeLock wakeLock; Pinetime::System::SystemTask& systemTask;
States currentState = States::Init; States currentState = States::Init;
TickType_t startTime; TickType_t startTime;
TickType_t oldTimeElapsed = 0; TickType_t oldTimeElapsed = 0;

View file

@ -40,7 +40,8 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::MotionController& motionController,
const Pinetime::Drivers::Cst816S& touchPanel, const Pinetime::Drivers::Cst816S& touchPanel,
const Pinetime::Drivers::SpiNorFlash& spiNorFlash) const Pinetime::Drivers::SpiNorFlash& spiNorFlash)
: dateTimeController {dateTimeController}, : app {app},
dateTimeController {dateTimeController},
batteryController {batteryController}, batteryController {batteryController},
brightnessController {brightnessController}, brightnessController {brightnessController},
bleController {bleController}, bleController {bleController},

View file

@ -35,6 +35,7 @@ namespace Pinetime {
bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(TouchEvents event) override;
private: private:
DisplayApp* app;
Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::DateTime& dateTimeController;
const Pinetime::Controllers::Battery& batteryController; const Pinetime::Controllers::Battery& batteryController;
Pinetime::Controllers::BrightnessController& brightnessController; Pinetime::Controllers::BrightnessController& brightnessController;

View file

@ -24,7 +24,8 @@ namespace {
constexpr std::array<uint16_t, 6> SettingDisplay::options; constexpr std::array<uint16_t, 6> SettingDisplay::options;
SettingDisplay::SettingDisplay(Pinetime::Controllers::Settings& settingsController) : settingsController {settingsController} { SettingDisplay::SettingDisplay(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController)
: app {app}, settingsController {settingsController} {
lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr);

View file

@ -14,13 +14,14 @@ namespace Pinetime {
class SettingDisplay : public Screen { class SettingDisplay : public Screen {
public: public:
SettingDisplay(Pinetime::Controllers::Settings& settingsController); SettingDisplay(DisplayApp* app, Pinetime::Controllers::Settings& settingsController);
~SettingDisplay() override; ~SettingDisplay() override;
void UpdateSelected(lv_obj_t* object, lv_event_t event); void UpdateSelected(lv_obj_t* object, lv_event_t event);
void ToggleAlwaysOn(); void ToggleAlwaysOn();
private: private:
DisplayApp* app;
static constexpr std::array<uint16_t, 6> options = {5000, 7000, 10000, 15000, 20000, 30000}; static constexpr std::array<uint16_t, 6> options = {5000, 7000, 10000, 15000, 20000, 30000};
Controllers::Settings& settingsController; Controllers::Settings& settingsController;

View file

@ -32,7 +32,7 @@ namespace Pinetime {
static constexpr std::array<Option, 8> options = {{ static constexpr std::array<Option, 8> options = {{
{Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off, " Off"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off, " Off"},
{Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous, "Cont"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Continuous, "Cont"},
{Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FifteenSeconds, " 15s"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds, " 10s"},
{Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds, " 30s"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds, " 30s"},
{Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute, " 1m"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::OneMinute, " 1m"},
{Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes, " 5m"}, {Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FiveMinutes, " 5m"},

View file

@ -15,7 +15,8 @@ bool SettingSetDateTime::OnTouchEvent(Pinetime::Applications::TouchEvents event)
SettingSetDateTime::SettingSetDateTime(Pinetime::Applications::DisplayApp* app, SettingSetDateTime::SettingSetDateTime(Pinetime::Applications::DisplayApp* app,
Pinetime::Controllers::DateTime& dateTimeController, Pinetime::Controllers::DateTime& dateTimeController,
Pinetime::Controllers::Settings& settingsController) Pinetime::Controllers::Settings& settingsController)
: dateTimeController {dateTimeController}, : app {app},
dateTimeController {dateTimeController},
settingsController {settingsController}, settingsController {settingsController},
screens {app, screens {app,
0, 0,

View file

@ -20,6 +20,7 @@ namespace Pinetime {
void Quit(); void Quit();
private: private:
DisplayApp* app;
Controllers::DateTime& dateTimeController; Controllers::DateTime& dateTimeController;
Controllers::Settings& settingsController; Controllers::Settings& settingsController;

View file

@ -54,7 +54,8 @@ SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app,
std::array<Screens::SettingWatchFace::Item, UserWatchFaceTypes::Count>&& watchfaceItems, std::array<Screens::SettingWatchFace::Item, UserWatchFaceTypes::Count>&& watchfaceItems,
Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::Settings& settingsController,
Pinetime::Controllers::FS& filesystem) Pinetime::Controllers::FS& filesystem)
: watchfaceItems {std::move(watchfaceItems)}, : app {app},
watchfaceItems {std::move(watchfaceItems)},
settingsController {settingsController}, settingsController {settingsController},
filesystem {filesystem}, filesystem {filesystem},
screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} { screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} {

View file

@ -34,6 +34,7 @@ namespace Pinetime {
bool OnTouchEvent(TouchEvents event) override; bool OnTouchEvent(TouchEvents event) override;
private: private:
DisplayApp* app;
auto CreateScreenList() const; auto CreateScreenList() const;
std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const; std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const;

View file

@ -6,7 +6,6 @@
#include "drivers/Hrs3300.h" #include "drivers/Hrs3300.h"
#include <algorithm> #include <algorithm>
#include <iterator>
#include <nrf_gpio.h> #include <nrf_gpio.h>
#include <FreeRTOS.h> #include <FreeRTOS.h>
@ -68,37 +67,40 @@ void Hrs3300::Disable() {
WriteRegister(static_cast<uint8_t>(Registers::PDriver), 0); WriteRegister(static_cast<uint8_t>(Registers::PDriver), 0);
} }
Hrs3300::PackedHrsAls Hrs3300::ReadHrsAls() { uint32_t Hrs3300::ReadHrs() {
constexpr Registers dataRegisters[] = auto m = ReadRegister(static_cast<uint8_t>(Registers::C0DataM));
{Registers::C1dataM, Registers::C0DataM, Registers::C0DataH, Registers::C1dataH, Registers::C1dataL, Registers::C0dataL}; auto h = ReadRegister(static_cast<uint8_t>(Registers::C0DataH));
// Calculate smallest register address auto l = ReadRegister(static_cast<uint8_t>(Registers::C0dataL));
constexpr uint8_t baseOffset = static_cast<uint8_t>(*std::min_element(std::begin(dataRegisters), std::end(dataRegisters))); return ((l & 0x30) << 12) | (m << 8) | ((h & 0x0f) << 4) | (l & 0x0f);
// Calculate largest address to determine length of read needed
// Add one to largest relative index to find the length
constexpr uint8_t length = static_cast<uint8_t>(*std::max_element(std::begin(dataRegisters), std::end(dataRegisters))) - baseOffset + 1;
Hrs3300::PackedHrsAls res;
uint8_t buf[length];
auto ret = twiMaster.Read(twiAddress, baseOffset, buf, length);
if (ret != TwiMaster::ErrorCodes::NoError) {
NRF_LOG_INFO("READ ERROR");
} }
// hrs
uint8_t m = static_cast<uint8_t>(Registers::C0DataM) - baseOffset;
uint8_t h = static_cast<uint8_t>(Registers::C0DataH) - baseOffset;
uint8_t l = static_cast<uint8_t>(Registers::C0dataL) - baseOffset;
// There are two extra bits (17 and 18) but they are not read here
// as resolutions >16bit aren't practically useful (too slow) and
// all hrs values throughout InfiniTime are 16bit
res.hrs = (buf[m] << 8) | ((buf[h] & 0x0f) << 4) | (buf[l] & 0x0f);
// als uint32_t Hrs3300::ReadAls() {
m = static_cast<uint8_t>(Registers::C1dataM) - baseOffset; auto m = ReadRegister(static_cast<uint8_t>(Registers::C1dataM));
h = static_cast<uint8_t>(Registers::C1dataH) - baseOffset; auto h = ReadRegister(static_cast<uint8_t>(Registers::C1dataH));
l = static_cast<uint8_t>(Registers::C1dataL) - baseOffset; auto l = ReadRegister(static_cast<uint8_t>(Registers::C1dataL));
res.als = ((buf[h] & 0x3f) << 11) | (buf[m] << 3) | (buf[l] & 0x07); return ((h & 0x3f) << 11) | (m << 3) | (l & 0x07);
}
return res; void Hrs3300::SetGain(uint8_t gain) {
constexpr uint8_t maxGain = 64U;
gain = std::min(gain, maxGain);
uint8_t hgain = 0;
while ((1 << hgain) < gain) {
++hgain;
}
WriteRegister(static_cast<uint8_t>(Registers::Hgain), hgain << 2);
}
void Hrs3300::SetDrive(uint8_t drive) {
auto en = ReadRegister(static_cast<uint8_t>(Registers::Enable));
auto pd = ReadRegister(static_cast<uint8_t>(Registers::PDriver));
en = (en & 0xf7) | ((drive & 2) << 2);
pd = (pd & 0xbf) | ((drive & 1) << 6);
WriteRegister(static_cast<uint8_t>(Registers::Enable), en);
WriteRegister(static_cast<uint8_t>(Registers::PDriver), pd);
} }
void Hrs3300::WriteRegister(uint8_t reg, uint8_t data) { void Hrs3300::WriteRegister(uint8_t reg, uint8_t data) {

View file

@ -21,11 +21,6 @@ namespace Pinetime {
Hgain = 0x17 Hgain = 0x17
}; };
struct PackedHrsAls {
uint16_t hrs;
uint16_t als;
};
Hrs3300(TwiMaster& twiMaster, uint8_t twiAddress); Hrs3300(TwiMaster& twiMaster, uint8_t twiAddress);
Hrs3300(const Hrs3300&) = delete; Hrs3300(const Hrs3300&) = delete;
Hrs3300& operator=(const Hrs3300&) = delete; Hrs3300& operator=(const Hrs3300&) = delete;
@ -35,7 +30,10 @@ namespace Pinetime {
void Init(); void Init();
void Enable(); void Enable();
void Disable(); void Disable();
PackedHrsAls ReadHrsAls(); uint32_t ReadHrs();
uint32_t ReadAls();
void SetGain(uint8_t gain);
void SetDrive(uint8_t drive);
private: private:
TwiMaster& twiMaster; TwiMaster& twiMaster;

View file

@ -97,6 +97,11 @@ void HeartRateTask::StopMeasurement() {
vTaskDelay(100); vTaskDelay(100);
} }
void HeartRateTask::StartWaiting() {
StopMeasurement();
backgroundWaitingStart = xTaskGetTickCount();
}
void HeartRateTask::HandleGoToSleep() { void HeartRateTask::HandleGoToSleep() {
switch (state) { switch (state) {
case States::ScreenOnAndStopped: case States::ScreenOnAndStopped:
@ -171,7 +176,8 @@ void HeartRateTask::HandleBackgroundWaiting() {
return; return;
} }
if (ShouldStartBackgroundMeasuring()) { TickType_t ticksSinceWaitingStart = xTaskGetTickCount() - backgroundWaitingStart;
if (ticksSinceWaitingStart >= GetHeartRateBackgroundMeasurementIntervalInTicks()) {
state = States::ScreenOffAndMeasuring; state = States::ScreenOffAndMeasuring;
StartMeasurement(); StartMeasurement();
} }
@ -192,45 +198,34 @@ void HeartRateTask::HandleSensorData(int* lastBpm) {
bpm = 0; bpm = 0;
} }
bool notEnoughData = *lastBpm == 0 && bpm == 0; if (*lastBpm == 0 && bpm == 0) {
if (notEnoughData) {
controller.Update(Controllers::HeartRateController::States::NotEnoughData, bpm); controller.Update(Controllers::HeartRateController::States::NotEnoughData, bpm);
} }
if (bpm != 0) { if (bpm != 0) {
*lastBpm = bpm; *lastBpm = bpm;
controller.Update(Controllers::HeartRateController::States::Running, bpm); controller.Update(Controllers::HeartRateController::States::Running, bpm);
}
if (state == States::ScreenOnAndMeasuring || IsContinuousModeActivated()) { if (state == States::ScreenOnAndMeasuring || IsContinuousModeActivated()) {
return; return;
} }
if (state == States::ScreenOffAndMeasuring) {
// 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; state = States::ScreenOffAndWaiting;
StopMeasurement(); 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() { TickType_t HeartRateTask::GetHeartRateBackgroundMeasurementIntervalInTicks() {
int ms; int ms;
switch (settings.GetHeartRateBackgroundMeasurementInterval()) { switch (settings.GetHeartRateBackgroundMeasurementInterval()) {
case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::FifteenSeconds: case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::TenSeconds:
ms = 15 * 1000; ms = 10 * 1000;
break; break;
case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds: case Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::ThirtySeconds:
ms = 30 * 1000; ms = 30 * 1000;
@ -263,15 +258,3 @@ bool HeartRateTask::IsBackgroundMeasurementActivated() {
return settings.GetHeartRateBackgroundMeasurementInterval() != return settings.GetHeartRateBackgroundMeasurementInterval() !=
Pinetime::Controllers::Settings::HeartRateBackgroundMeasurementInterval::Off; 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();
}

View file

@ -45,6 +45,7 @@ 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 HandleGoToSleep();
void HandleWakeUp(); void HandleWakeUp();
@ -58,10 +59,6 @@ namespace Pinetime {
bool IsContinuousModeActivated(); bool IsContinuousModeActivated();
bool IsBackgroundMeasurementActivated(); bool IsBackgroundMeasurementActivated();
TickType_t GetTicksSinceLastMeasurementStarted();
bool ShoudStopTryingToGetData();
bool ShouldStartBackgroundMeasuring();
TaskHandle_t taskHandle; TaskHandle_t taskHandle;
QueueHandle_t messageQueue; QueueHandle_t messageQueue;
States state = States::ScreenOnAndStopped; States state = States::ScreenOnAndStopped;
@ -69,6 +66,7 @@ namespace Pinetime {
Controllers::HeartRateController& controller; Controllers::HeartRateController& controller;
Controllers::Settings& settings; Controllers::Settings& settings;
Controllers::Ppg ppg; Controllers::Ppg ppg;
TickType_t backgroundWaitingStart = 0;
TickType_t measurementStart = 0; TickType_t measurementStart = 0;
}; };

1
src/libs/QCBOR Submodule

@ -0,0 +1 @@
Subproject commit 56b17bf9f74096774944bcac0829adcd887d391e

View file

@ -104,7 +104,7 @@ Pinetime::Controllers::DateTime dateTimeController {settingsController};
Pinetime::Drivers::Watchdog watchdog; Pinetime::Drivers::Watchdog watchdog;
Pinetime::Controllers::NotificationManager notificationManager; Pinetime::Controllers::NotificationManager notificationManager;
Pinetime::Controllers::MotionController motionController; Pinetime::Controllers::MotionController motionController;
Pinetime::Controllers::AlarmController alarmController {dateTimeController, fs}; Pinetime::Controllers::AlarmController alarmController {dateTimeController};
Pinetime::Controllers::TouchHandler touchHandler; Pinetime::Controllers::TouchHandler touchHandler;
Pinetime::Controllers::ButtonHandler buttonHandler; Pinetime::Controllers::ButtonHandler buttonHandler;
Pinetime::Controllers::BrightnessController brightnessController {}; Pinetime::Controllers::BrightnessController brightnessController {};

View file

@ -189,14 +189,36 @@ void SystemTask::Work() {
if (xQueueReceive(systemTasksMsgQueue, &msg, 100) == pdTRUE) { if (xQueueReceive(systemTasksMsgQueue, &msg, 100) == pdTRUE) {
switch (msg) { switch (msg) {
case Messages::EnableSleeping: case Messages::EnableSleeping:
wakeLocksHeld--; // Make sure that exiting an app doesn't enable sleeping,
// if the exiting was caused by a firmware update
if (!bleController.IsFirmwareUpdating()) {
doNotGoToSleep = false;
}
break; break;
case Messages::DisableSleeping: case Messages::DisableSleeping:
GoToRunning(); doNotGoToSleep = true;
wakeLocksHeld++;
break; break;
case Messages::GoToRunning: case Messages::GoToRunning:
GoToRunning(); // SPI doesn't go to sleep for always on mode
if (!settingsController.GetAlwaysOnDisplay()) {
spi.Wakeup();
}
// Double Tap needs the touch screen to be in normal mode
if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
touchPanel.Wakeup();
}
spiNorFlash.Wakeup();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning);
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp);
if (bleController.IsRadioEnabled() && !bleController.IsConnected()) {
nimbleController.RestartFastAdv();
}
state = SystemTaskState::Running;
break; break;
case Messages::TouchWakeUp: { case Messages::TouchWakeUp: {
if (touchHandler.ProcessTouchInfo(touchPanel.GetTouchInfo())) { if (touchHandler.ProcessTouchInfo(touchPanel.GetTouchInfo())) {
@ -213,23 +235,31 @@ void SystemTask::Work() {
break; break;
} }
case Messages::GoToSleep: case Messages::GoToSleep:
GoToSleep(); if (doNotGoToSleep) {
break;
}
state = SystemTaskState::GoingToSleep; // Already set in PushMessage()
NRF_LOG_INFO("[systemtask] Going to sleep");
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToSleep);
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::GoToSleep);
break; break;
case Messages::OnNewTime: case Messages::OnNewTime:
if (alarmController.IsEnabled()) { if (alarmController.State() == Controllers::AlarmController::AlarmState::Set) {
alarmController.ScheduleAlarm(); alarmController.ScheduleAlarm();
} }
break; break;
case Messages::OnNewNotification: case Messages::OnNewNotification:
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) { if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) {
if (IsSleeping()) { if (state == SystemTaskState::Sleeping) {
GoToRunning(); GoToRunning();
} }
displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification); displayApp.PushMessage(Pinetime::Applications::Display::Messages::NewNotification);
} }
break; break;
case Messages::SetOffAlarm: case Messages::SetOffAlarm:
if (state == SystemTaskState::Sleeping) {
GoToRunning(); GoToRunning();
}
displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered); displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered);
break; break;
case Messages::BleConnected: case Messages::BleConnected:
@ -238,25 +268,29 @@ void SystemTask::Work() {
bleDiscoveryTimer = 5; bleDiscoveryTimer = 5;
break; break;
case Messages::BleFirmwareUpdateStarted: case Messages::BleFirmwareUpdateStarted:
doNotGoToSleep = true;
if (state == SystemTaskState::Sleeping) {
GoToRunning(); GoToRunning();
wakeLocksHeld++; }
displayApp.PushMessage(Pinetime::Applications::Display::Messages::BleFirmwareUpdateStarted); displayApp.PushMessage(Pinetime::Applications::Display::Messages::BleFirmwareUpdateStarted);
break; break;
case Messages::BleFirmwareUpdateFinished: case Messages::BleFirmwareUpdateFinished:
if (bleController.State() == Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated) { if (bleController.State() == Pinetime::Controllers::Ble::FirmwareUpdateStates::Validated) {
NVIC_SystemReset(); NVIC_SystemReset();
} }
wakeLocksHeld--; doNotGoToSleep = false;
break; break;
case Messages::StartFileTransfer: case Messages::StartFileTransfer:
NRF_LOG_INFO("[systemtask] FS Started"); NRF_LOG_INFO("[systemtask] FS Started");
doNotGoToSleep = true;
if (state == SystemTaskState::Sleeping) {
GoToRunning(); GoToRunning();
wakeLocksHeld++; }
// TODO add intent of fs access icon or something // TODO add intent of fs access icon or something
break; break;
case Messages::StopFileTransfer: case Messages::StopFileTransfer:
NRF_LOG_INFO("[systemtask] FS Stopped"); NRF_LOG_INFO("[systemtask] FS Stopped");
wakeLocksHeld--; doNotGoToSleep = false;
// TODO add intent of fs access icon or something // TODO add intent of fs access icon or something
break; break;
case Messages::OnTouchEvent: case Messages::OnTouchEvent:
@ -284,13 +318,6 @@ void SystemTask::Work() {
HandleButtonAction(action); HandleButtonAction(action);
} break; } break;
case Messages::OnDisplayTaskSleeping: case Messages::OnDisplayTaskSleeping:
// The state was set to GoingToSleep when GoToSleep() was called
// If the state is no longer GoingToSleep, we have since transitioned back to Running
// In this case absorb the OnDisplayTaskSleeping
// as DisplayApp is about to receive GoToRunning
if (state != SystemTaskState::GoingToSleep) {
break;
}
if (BootloaderVersion::IsValid()) { if (BootloaderVersion::IsValid()) {
// First versions of the bootloader do not expose their version and cannot initialize the SPI NOR FLASH // First versions of the bootloader do not expose their version and cannot initialize the SPI NOR FLASH
// if it's in sleep mode. Avoid bricked device by disabling sleep mode on these versions. // if it's in sleep mode. Avoid bricked device by disabling sleep mode on these versions.
@ -317,23 +344,39 @@ void SystemTask::Work() {
case Messages::OnNewHour: case Messages::OnNewHour:
using Pinetime::Controllers::AlarmController; using Pinetime::Controllers::AlarmController;
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && !alarmController.IsAlerting()) { settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours &&
alarmController.State() != AlarmController::AlarmState::Alerting) {
// if sleeping, we can't send a chime to displayApp yet (SPI flash switched off)
// request running first and repush the chime message
if (state == SystemTaskState::Sleeping) {
GoToRunning(); GoToRunning();
PushMessage(msg);
} else {
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime); displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
} }
}
break; break;
case Messages::OnNewHalfHour: case Messages::OnNewHalfHour:
using Pinetime::Controllers::AlarmController; using Pinetime::Controllers::AlarmController;
if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep &&
settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && !alarmController.IsAlerting()) { settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours &&
alarmController.State() != AlarmController::AlarmState::Alerting) {
// if sleeping, we can't send a chime to displayApp yet (SPI flash switched off)
// request running first and repush the chime message
if (state == SystemTaskState::Sleeping) {
GoToRunning(); GoToRunning();
PushMessage(msg);
} else {
displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime); displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime);
} }
}
break; break;
case Messages::OnChargingEvent: case Messages::OnChargingEvent:
batteryController.ReadPowerState(); batteryController.ReadPowerState();
GoToRunning();
displayApp.PushMessage(Applications::Display::Messages::OnChargingEvent); displayApp.PushMessage(Applications::Display::Messages::OnChargingEvent);
if (state == SystemTaskState::Sleeping) {
GoToRunning();
}
break; break;
case Messages::MeasureBatteryTimerExpired: case Messages::MeasureBatteryTimerExpired:
batteryController.MeasureVoltage(); batteryController.MeasureVoltage();
@ -342,7 +385,9 @@ void SystemTask::Work() {
nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining()); nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining());
break; break;
case Messages::OnPairing: case Messages::OnPairing:
if (state == SystemTaskState::Sleeping) {
GoToRunning(); GoToRunning();
}
displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowPairingKey); displayApp.PushMessage(Pinetime::Applications::Display::Messages::ShowPairingKey);
break; break;
case Messages::BleRadioEnableToggle: case Messages::BleRadioEnableToggle:
@ -377,48 +422,12 @@ void SystemTask::Work() {
#pragma clang diagnostic pop #pragma clang diagnostic pop
} }
void SystemTask::GoToRunning() {
if (state == SystemTaskState::Running) {
return;
}
// SPI doesn't go to sleep for always on mode
if (!settingsController.GetAlwaysOnDisplay()) {
spi.Wakeup();
}
// Double Tap needs the touch screen to be in normal mode
if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
touchPanel.Wakeup();
}
spiNorFlash.Wakeup();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToRunning);
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::WakeUp);
if (bleController.IsRadioEnabled() && !bleController.IsConnected()) {
nimbleController.RestartFastAdv();
}
state = SystemTaskState::Running;
};
void SystemTask::GoToSleep() {
if (IsSleeping()) {
return;
}
if (IsSleepDisabled()) {
return;
}
NRF_LOG_INFO("[systemtask] Going to sleep");
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToSleep);
heartRateApp.PushMessage(Pinetime::Applications::HeartRateTask::Messages::GoToSleep);
state = SystemTaskState::GoingToSleep;
};
void SystemTask::UpdateMotion() { void SystemTask::UpdateMotion() {
if (IsSleeping() && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) || if (state == SystemTaskState::GoingToSleep || state == SystemTaskState::WakingUp) {
return;
}
if (state == SystemTaskState::Sleeping && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) ||
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) || settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) ||
motionController.GetService()->IsMotionNotificationSubscribed())) { motionController.GetService()->IsMotionNotificationSubscribed())) {
return; return;
@ -443,7 +452,7 @@ void SystemTask::UpdateMotion() {
} }
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::LowerWrist) && state == SystemTaskState::Running && if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::LowerWrist) && state == SystemTaskState::Running &&
motionController.ShouldLowerSleep()) { motionController.ShouldLowerSleep()) {
GoToSleep(); PushMessage(Messages::GoToSleep);
} }
} }
@ -459,7 +468,7 @@ void SystemTask::HandleButtonAction(Controllers::ButtonActions action) {
switch (action) { switch (action) {
case Actions::Click: case Actions::Click:
// If the first action after fast wakeup is a click, it should be ignored. // If the first action after fast wakeup is a click, it should be ignored.
if (!fastWakeUpDone) { if (!fastWakeUpDone && state != SystemTaskState::GoingToSleep) {
displayApp.PushMessage(Applications::Display::Messages::ButtonPushed); displayApp.PushMessage(Applications::Display::Messages::ButtonPushed);
} }
break; break;
@ -479,10 +488,17 @@ void SystemTask::HandleButtonAction(Controllers::ButtonActions action) {
fastWakeUpDone = false; fastWakeUpDone = false;
} }
void SystemTask::GoToRunning() {
if (state == SystemTaskState::Sleeping) {
state = SystemTaskState::WakingUp;
PushMessage(Messages::GoToRunning);
}
}
void SystemTask::OnTouchEvent() { void SystemTask::OnTouchEvent() {
if (state == SystemTaskState::Running) { if (state == SystemTaskState::Running) {
PushMessage(Messages::OnTouchEvent); PushMessage(Messages::OnTouchEvent);
} else { } else if (state == SystemTaskState::Sleeping) {
if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap) or if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap) or
settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) {
PushMessage(Messages::TouchWakeUp); PushMessage(Messages::TouchWakeUp);
@ -491,6 +507,10 @@ void SystemTask::OnTouchEvent() {
} }
void SystemTask::PushMessage(System::Messages msg) { void SystemTask::PushMessage(System::Messages msg) {
if (msg == Messages::GoToSleep && !doNotGoToSleep) {
state = SystemTaskState::GoingToSleep;
}
if (in_isr()) { if (in_isr()) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken); xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken);

View file

@ -52,7 +52,7 @@ namespace Pinetime {
namespace System { namespace System {
class SystemTask { class SystemTask {
public: public:
enum class SystemTaskState { Sleeping, Running, GoingToSleep }; enum class SystemTaskState { Sleeping, Running, GoingToSleep, WakingUp };
SystemTask(Drivers::SpiMaster& spi, SystemTask(Drivers::SpiMaster& spi,
Pinetime::Drivers::SpiNorFlash& spiNorFlash, Pinetime::Drivers::SpiNorFlash& spiNorFlash,
Drivers::TwiMaster& twiMaster, Drivers::TwiMaster& twiMaster,
@ -79,8 +79,11 @@ namespace Pinetime {
void OnTouchEvent(); void OnTouchEvent();
void OnIdle();
void OnDim();
bool IsSleepDisabled() { bool IsSleepDisabled() {
return wakeLocksHeld > 0; return doNotGoToSleep;
} }
Pinetime::Controllers::NimbleController& nimble() { Pinetime::Controllers::NimbleController& nimble() {
@ -88,7 +91,7 @@ namespace Pinetime {
}; };
bool IsSleeping() const { bool IsSleeping() const {
return state != SystemTaskState::Running; return state == SystemTaskState::Sleeping || state == SystemTaskState::WakingUp;
} }
private: private:
@ -124,14 +127,13 @@ namespace Pinetime {
bool isBleDiscoveryTimerRunning = false; bool isBleDiscoveryTimerRunning = false;
uint8_t bleDiscoveryTimer = 0; uint8_t bleDiscoveryTimer = 0;
TimerHandle_t measureBatteryTimer; TimerHandle_t measureBatteryTimer;
uint8_t wakeLocksHeld = 0; bool doNotGoToSleep = false;
SystemTaskState state = SystemTaskState::Running; SystemTaskState state = SystemTaskState::Running;
void HandleButtonAction(Controllers::ButtonActions action); void HandleButtonAction(Controllers::ButtonActions action);
bool fastWakeUpDone = false; bool fastWakeUpDone = false;
void GoToRunning(); void GoToRunning();
void GoToSleep();
void UpdateMotion(); void UpdateMotion();
bool stepCounterMustBeReset = false; bool stepCounterMustBeReset = false;
static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000); static constexpr TickType_t batteryMeasurementPeriod = pdMS_TO_TICKS(10 * 60 * 1000);

View file

@ -1,27 +0,0 @@
#include "systemtask/WakeLock.h"
using namespace Pinetime::System;
WakeLock::WakeLock(SystemTask& systemTask) : systemTask {systemTask} {
lockHeld = false;
}
WakeLock::~WakeLock() {
Release();
}
void WakeLock::Lock() {
if (lockHeld) {
return;
}
systemTask.PushMessage(Messages::DisableSleeping);
lockHeld = true;
}
void WakeLock::Release() {
if (!lockHeld) {
return;
}
systemTask.PushMessage(Messages::EnableSleeping);
lockHeld = false;
}

View file

@ -1,19 +0,0 @@
#pragma once
#include "systemtask/SystemTask.h"
namespace Pinetime {
namespace System {
class WakeLock {
public:
WakeLock(SystemTask& systemTask);
~WakeLock();
void Lock();
void Release();
private:
bool lockHeld;
SystemTask& systemTask;
};
}
}