From 07d2599005a126ee592a57f07e6ed11feff14b34 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 2 Oct 2024 15:27:11 -0500 Subject: [PATCH 001/191] Started working on SleepTracker --- src/displayapp/DisplayApp.cpp | 1 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 1 + src/displayapp/fonts/fonts.json | 2 +- src/displayapp/screens/SleepTracker.cpp | 21 +++++++++++++++++ src/displayapp/screens/SleepTracker.h | 30 +++++++++++++++++++++++++ src/displayapp/screens/Symbols.h | 1 + 7 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/displayapp/screens/SleepTracker.cpp create mode 100644 src/displayapp/screens/SleepTracker.h diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index b1594f197c..94737bb71c 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -30,6 +30,7 @@ #include "displayapp/screens/Weather.h" #include "displayapp/screens/PassKey.h" #include "displayapp/screens/Error.h" +#include "displayapp/screens/SleepTracker.h" #include "drivers/Cst816s.h" #include "drivers/St7789.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267c0..96b9564f35 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -22,6 +22,7 @@ namespace Pinetime { Paddle, Twos, HeartRate, + SleepTracker, Navigation, StopWatch, Metronome, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index d78587609e..33ead23165 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -16,6 +16,7 @@ else () set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") + set(USERAPP_TYPES "${USERAPP_TYPES}, Apps::SleepTracker") endif () if(DEFINED ENABLE_WATCHFACES) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 41c383c0d4..85e3269088 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743" + "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf236" } ], "bpp": 1, diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp new file mode 100644 index 0000000000..b4803be9e4 --- /dev/null +++ b/src/displayapp/screens/SleepTracker.cpp @@ -0,0 +1,21 @@ +#include "displayapp/screens/SleepTracker.h" + +using namespace Pinetime::Applications::Screens; + +SleepTracker::SleepTracker() { + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, "My test application"); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + + // Create the HR Data Task + +} + +SleepTracker::~SleepTracker() { + lv_obj_clean(lv_scr_act()); +} + +void SleepTracker::GetBPM() { + +} \ No newline at end of file diff --git a/src/displayapp/screens/SleepTracker.h b/src/displayapp/screens/SleepTracker.h new file mode 100644 index 0000000000..748d2cdec5 --- /dev/null +++ b/src/displayapp/screens/SleepTracker.h @@ -0,0 +1,30 @@ +#pragma once + +#include "displayapp/apps/Apps.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/Controllers.h" +#include "Symbols.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SleepTracker : public Screen { + public: + SleepTracker(); + ~SleepTracker() override; + + private: + void GetBPM(); + }; + } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::SleepTracker; + static constexpr const char* icon = Screens::Symbols::bed; + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::SleepTracker(); + } + }; + } +} \ No newline at end of file diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index bd958b285f..6bd5f0efe7 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -39,6 +39,7 @@ namespace Pinetime { static constexpr const char* eye = "\xEF\x81\xAE"; static constexpr const char* home = "\xEF\x80\x95"; static constexpr const char* sleep = "\xEE\xBD\x84"; + static constexpr const char* bed = "\xEF\x88\xB6"; // fontawesome_weathericons.c // static constexpr const char* sun = "\xEF\x86\x85"; From be0dca5c039e6c4d0bf481e5a78704b74263e341 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 3 Oct 2024 18:29:54 -0500 Subject: [PATCH 002/191] Began adding BPM data collection --- src/displayapp/screens/SleepTracker.cpp | 60 +++++++++++++++++++++++-- src/displayapp/screens/SleepTracker.h | 24 ++++++++-- 2 files changed, 78 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index b4803be9e4..64e0425148 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -1,21 +1,75 @@ #include "displayapp/screens/SleepTracker.h" +#include +#include +#include +#include + using namespace Pinetime::Applications::Screens; -SleepTracker::SleepTracker() { +namespace { + + void BpmDataCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + screen->GetBPM(); + } + +} + +SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, System::SystemTask& systemTask) + : heartRateController {heartRateController}, dateTimeController {dateTimeController}, wakeLock(systemTask) { + + wakeLock.Lock(); + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "My test application"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); - // Create the HR Data Task - + label_hr = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + + // Create the refresh task + mainRefreshTask = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); + hrRefreshTask = lv_task_create(BpmDataCallback, 3000, LV_TASK_PRIO_MID, this); } SleepTracker::~SleepTracker() { + wakeLock.Release(); + lv_obj_clean(lv_scr_act()); + lv_task_del(mainRefreshTask); + lv_task_del(hrRefreshTask); +} + +// This function is called periodically from the refresh task +void SleepTracker::Refresh() { + // Get the current heart rate } void SleepTracker::GetBPM() { + // Get the heart rate from the controller + prevBpm = bpm; + bpm = heartRateController.HeartRate(); + + if(prevBpm != 0) + rollingBpm = (rollingBpm + bpm) / 2; + else + rollingBpm = bpm; + + // Get the current time from DateTimeController + //auto now = dateTimeController.CurrentDateTime(); + int hours = dateTimeController.Hours(); + int minutes = dateTimeController.Minutes(); + int seconds = dateTimeController.Seconds(); + + // Log the BPM and current time + NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); + + // if (bpm == 0) { + // lv_label_set_text_static(label_hr, "---"); + // } else { + // lv_label_set_text_fmt(label_hr, "%03d", bpm); + // } } \ No newline at end of file diff --git a/src/displayapp/screens/SleepTracker.h b/src/displayapp/screens/SleepTracker.h index 748d2cdec5..ad387b5222 100644 --- a/src/displayapp/screens/SleepTracker.h +++ b/src/displayapp/screens/SleepTracker.h @@ -3,6 +3,8 @@ #include "displayapp/apps/Apps.h" #include "displayapp/screens/Screen.h" #include "displayapp/Controllers.h" +#include "systemtask/SystemTask.h" +#include "systemtask/WakeLock.h" #include "Symbols.h" namespace Pinetime { @@ -10,11 +12,27 @@ namespace Pinetime { namespace Screens { class SleepTracker : public Screen { public: - SleepTracker(); + SleepTracker(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, System::SystemTask& systemTask); ~SleepTracker() override; - private: + void Refresh() override; + void GetBPM(); + + + private: + Controllers::HeartRateController& heartRateController; + Controllers::DateTime& dateTimeController; + Pinetime::System::WakeLock wakeLock; + + int bpm = 0; + int prevBpm = 0; + int rollingBpm = 0; + + lv_obj_t* label_hr; + + lv_task_t* mainRefreshTask; + lv_task_t* hrRefreshTask; }; } @@ -23,7 +41,7 @@ namespace Pinetime { static constexpr Apps app = Apps::SleepTracker; static constexpr const char* icon = Screens::Symbols::bed; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::SleepTracker(); + return new Screens::SleepTracker(controllers.heartRateController, controllers.dateTimeController, *controllers.systemTask); } }; } From 6297c7e7ea5879ea14367cc01acca8e63e084038 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 3 Oct 2024 19:45:57 -0500 Subject: [PATCH 003/191] Started on data saving --- src/displayapp/screens/SleepTracker.cpp | 55 ++++++++++++++++++++++++- src/displayapp/screens/SleepTracker.h | 11 ++++- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index 64e0425148..15c231f3b0 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include using namespace Pinetime::Applications::Screens; @@ -16,8 +17,8 @@ namespace { } -SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, System::SystemTask& systemTask) - : heartRateController {heartRateController}, dateTimeController {dateTimeController}, wakeLock(systemTask) { +SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask) + : heartRateController {heartRateController}, dateTimeController {dateTimeController}, fsController {fsController}, wakeLock(systemTask) { wakeLock.Lock(); @@ -66,10 +67,60 @@ void SleepTracker::GetBPM() { // Log the BPM and current time NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); + // Write data to CSV + int motion = 0; // Placeholder for motion data + std::vector> data = {std::make_tuple(hours, minutes, seconds, rollingBpm, motion)}; + WriteDataCSV("SleepTracker_Data.csv", data); // if (bpm == 0) { // lv_label_set_text_static(label_hr, "---"); // } else { // lv_label_set_text_fmt(label_hr, "%03d", bpm); // } +} + +// File IO Stuff + +/* +* Write data to a CSV file +* Format: Time,BPM,Motion +*/ +void SleepTracker::WriteDataCSV(const char* fileName, const std::vector>& data) { + lfs_file_t file; + int err = fsController.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error opening file: %d", err); + return; + } + + // Check if the file is empty + // int fileSize = fsController.FileSeek(&file, 0); + // if (fileSize == 0) { + // // Write header if file is empty + // const char* header = "Time,BPM,Motion\n"; + // err = fsController.FileWrite(&file, reinterpret_cast(header), strlen(header)); + // if (err < 0) { + // // Handle error + // NRF_LOG_INFO("Error writing to file: %d", err); + // fsController.FileClose(&file); + // return; + // } + // } + + // Write data + for (const auto& entry : data) { + int hours, minutes, seconds, bpm, motion; + std::tie(hours, minutes, seconds, bpm, motion) = entry; + char buffer[64]; + int len = snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d,%d,%d\n", hours, minutes, seconds, bpm, motion); + int err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error writing to file: %d", err); + return; + } + } + + fsController.FileClose(&file); } \ No newline at end of file diff --git a/src/displayapp/screens/SleepTracker.h b/src/displayapp/screens/SleepTracker.h index ad387b5222..6f3bf2aba9 100644 --- a/src/displayapp/screens/SleepTracker.h +++ b/src/displayapp/screens/SleepTracker.h @@ -7,12 +7,14 @@ #include "systemtask/WakeLock.h" #include "Symbols.h" +#include + namespace Pinetime { namespace Applications { namespace Screens { class SleepTracker : public Screen { public: - SleepTracker(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, System::SystemTask& systemTask); + SleepTracker(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask); ~SleepTracker() override; void Refresh() override; @@ -23,8 +25,13 @@ namespace Pinetime { private: Controllers::HeartRateController& heartRateController; Controllers::DateTime& dateTimeController; + Controllers::FS& fsController; Pinetime::System::WakeLock wakeLock; + // For File IO + void WriteDataCSV(const char* fileName, const std::vector>& data); + std::vector> ReadDataCSV(const char* fileName); + int bpm = 0; int prevBpm = 0; int rollingBpm = 0; @@ -41,7 +48,7 @@ namespace Pinetime { static constexpr Apps app = Apps::SleepTracker; static constexpr const char* icon = Screens::Symbols::bed; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::SleepTracker(controllers.heartRateController, controllers.dateTimeController, *controllers.systemTask); + return new Screens::SleepTracker(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, *controllers.systemTask); } }; } From 0eadfe3b93612ffa5b1e83a56b92b5f999701eea Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 4 Oct 2024 13:43:39 -0500 Subject: [PATCH 004/191] Added basic data reading and clear data button --- src/displayapp/screens/SleepTracker.cpp | 87 ++++++++++++++++++++++++- src/displayapp/screens/SleepTracker.h | 2 + 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index 15c231f3b0..018dc30957 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -6,6 +6,8 @@ #include #include +#include + using namespace Pinetime::Applications::Screens; namespace { @@ -15,6 +17,14 @@ namespace { screen->GetBPM(); } + void ClearDataCallback(lv_obj_t* btn, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + // Clear data + auto* screen = static_cast(lv_obj_get_user_data(btn)); + screen->ClearDataCSV("SleepTracker_Data.csv"); + } + } + } SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask) @@ -23,7 +33,7 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController wakeLock.Lock(); lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "My test application"); + lv_label_set_text_static(title, "Sleep Tracker"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); @@ -33,6 +43,23 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController // Create the refresh task mainRefreshTask = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); hrRefreshTask = lv_task_create(BpmDataCallback, 3000, LV_TASK_PRIO_MID, this); + + // Create the clear data button + lv_obj_t* btn = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_event_cb(btn, ClearDataCallback); + lv_obj_set_user_data(btn, this); + lv_obj_align(btn, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -10); + + lv_obj_t* label = lv_label_create(btn, nullptr); + lv_label_set_text(label, "X"); + + std::vector> data = ReadDataCSV("SleepTracker_Data.csv"); + for (const auto& entry : data) { + int hours, minutes, seconds, bpm, motion; + std::tie(hours, minutes, seconds, bpm, motion) = entry; + NRF_LOG_INFO("Read data: %02d:%02d:%02d, %d, %d", hours, minutes, seconds, bpm, motion); + } + NRF_LOG_INFO("-------------------------------"); } SleepTracker::~SleepTracker() { @@ -123,4 +150,62 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::vector> SleepTracker::ReadDataCSV(const char* filename) { + lfs_file_t file; + int err = fsController.FileOpen(&file, filename, LFS_O_RDONLY); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error opening file: %d", err); + return {}; + } + + std::vector> data; + char buffer[128]; + int bytesRead; + + // Skip header + // bytesRead = fsController.FileRead(&file, reinterpret_cast(buffer), sizeof(buffer)); + // std::istringstream headerStream(buffer); + // std::string headerLine; + // std::getline(headerStream, headerLine); + + // Read data + while ((bytesRead = fsController.FileRead(&file, reinterpret_cast(buffer), sizeof(buffer))) > 0) { + std::istringstream dataStream(buffer); + std::string line; + while (std::getline(dataStream, line)) { + int hours, minutes, seconds, bpm, motion; + char colon1, colon2, comma1, comma2; + std::istringstream lineStream(line); + if (lineStream >> hours >> colon1 >> minutes >> colon2 >> seconds >> comma1 >> bpm >> comma2 >> motion) { + if (colon1 == ':' && colon2 == ':' && comma1 == ',' && comma2 == ',') { + data.emplace_back(hours, minutes, seconds, bpm, motion); + } else { + NRF_LOG_INFO("Parsing error: incorrect format in line: %s", line.c_str()); + } + } else { + NRF_LOG_INFO("Parsing error: failed to parse line: %s", line.c_str()); + } + } + } + + fsController.FileClose(&file); + return data; +} + +// Clear data in CSV +void SleepTracker::ClearDataCSV(const char* filename) { + lfs_file_t file; + int err = fsController.FileOpen(&file, filename, LFS_O_WRONLY | LFS_O_TRUNC); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error opening file: %d", err); + return; + } + + fsController.FileClose(&file); + NRF_LOG_INFO("CSV data cleared"); } \ No newline at end of file diff --git a/src/displayapp/screens/SleepTracker.h b/src/displayapp/screens/SleepTracker.h index 6f3bf2aba9..e2f75fb3fd 100644 --- a/src/displayapp/screens/SleepTracker.h +++ b/src/displayapp/screens/SleepTracker.h @@ -21,6 +21,8 @@ namespace Pinetime { void GetBPM(); + void ClearDataCSV(const char* filename); + private: Controllers::HeartRateController& heartRateController; From f1921eeff571bcf21ceb4443b01211fc7cba2116 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 4 Oct 2024 23:56:53 -0500 Subject: [PATCH 005/191] Added functions for sleeptracking time detection. (First night of testing) --- src/displayapp/screens/SleepTracker.cpp | 157 ++++++++++++++++++++++-- src/displayapp/screens/SleepTracker.h | 14 ++- 2 files changed, 163 insertions(+), 8 deletions(-) diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index 018dc30957..bcbf410ff6 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -25,12 +25,23 @@ namespace { } } + void GetSleepInfoCallback(lv_obj_t* btn, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + // Get sleep info + auto* screen = static_cast(lv_obj_get_user_data(btn)); + screen->GetSleepInfo(screen->ReadDataCSV("SleepTracker_Data.csv")); + } + } + } SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask) : heartRateController {heartRateController}, dateTimeController {dateTimeController}, fsController {fsController}, wakeLock(systemTask) { wakeLock.Lock(); + + static constexpr uint8_t btnWidth = 115; + static constexpr uint8_t btnHeight = 80; lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Sleep Tracker"); @@ -45,13 +56,24 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController hrRefreshTask = lv_task_create(BpmDataCallback, 3000, LV_TASK_PRIO_MID, this); // Create the clear data button - lv_obj_t* btn = lv_btn_create(lv_scr_act(), nullptr); - lv_obj_set_event_cb(btn, ClearDataCallback); - lv_obj_set_user_data(btn, this); - lv_obj_align(btn, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, -10); + lv_obj_t* btnClear = lv_btn_create(lv_scr_act(), nullptr); + btnClear->user_data = this; + lv_obj_set_event_cb(btnClear, ClearDataCallback); + lv_obj_set_size(btnClear, btnWidth, btnHeight); + lv_obj_align(btnClear, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_t* txtClear = lv_label_create(btnClear, nullptr); + lv_label_set_text(txtClear, "X"); + + // Create the get info button + lv_obj_t* btnInfo = lv_btn_create(lv_scr_act(), nullptr); + btnInfo->user_data = this; + lv_obj_set_event_cb(btnInfo, GetSleepInfoCallback); + lv_obj_set_size(btnInfo, btnWidth, btnHeight); + lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); + lv_label_set_text(txtInfo, "?"); + - lv_obj_t* label = lv_label_create(btn, nullptr); - lv_label_set_text(label, "X"); std::vector> data = ReadDataCSV("SleepTracker_Data.csv"); for (const auto& entry : data) { @@ -75,6 +97,127 @@ void SleepTracker::Refresh() { // Get the current heart rate } +// Convert time to minutes +double SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) { + return hours * 60 + minutes + seconds / 60.0; +} + +// Get the moving average of BPM Values +std::vector SleepTracker::MovingAverage(const std::vector& bpmData, int windowSize) { + std::vector smoothedBpm; + + int n = bpmData.size(); + + for (int i = 0; i < n - windowSize + 1; ++i) { + double sum = 0; + for (int j = 0; j < windowSize; ++j) { + sum += bpmData[i + j]; + } + smoothedBpm.push_back(sum / windowSize); + } + + return smoothedBpm; +} + +// Detect the sleep regions +std::vector> SleepTracker::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, double threshold) { + std::vector> sleep_regions; + double start_time = -1; + bool in_sleep = false; + + for (int i = 0; i < bpmData.size(); ++i) { + if (bpmData[i] < threshold) { + if (!in_sleep) { + start_time = time[i]; // Mark the start of sleep + in_sleep = true; + } + } else { + if (in_sleep) { + double end_time = time[i]; // Mark the end of sleep + sleep_regions.push_back({start_time, end_time}); + in_sleep = false; + } + } + } + + // In case the last region extends to the end of the data + if (in_sleep) { + sleep_regions.push_back({start_time, time.back()}); + } + + return sleep_regions; +} + +// Get Sleep Info +void SleepTracker::GetSleepInfo(std::vector> data) { + std::vector time; + std::vector bpm; + + // Extract the time (in minutes) and bpm from the data + for (const auto& entry : data) { + int hours, minutes, seconds, bpm_value, motion; + std::tie(hours, minutes, seconds, bpm_value, motion) = entry; + time.push_back(ConvertToMinutes(hours, minutes, seconds)); + bpm.push_back(bpm_value); + } + + // Compute the moving average with a window size of 5 (15 minutes smoothing, since each data point is 3 minutes) + std::vector smoothed_bpm = MovingAverage(bpm, 5); + + // Calculate a threshold as 80% of the average BPM + double average_bpm = std::accumulate(bpm.begin(), bpm.end(), 0.0) / bpm.size(); + double threshold = average_bpm * 0.8; + + // Detect multiple sleep regions + std::vector> sleep_regions = DetectSleepRegions(smoothed_bpm, time, threshold); + + // Output sleep regions + if (!sleep_regions.empty()) { + for (const auto& region : sleep_regions) { + NRF_LOG_INFO("Sleep detected from %.2f minutes to %.2f minutes.", region.first, region.second); + } + } else { + NRF_LOG_INFO("No significant sleep regions detected."); + } + + // Open the output file + lfs_file_t file; + int err = fsController.FileOpen(&file, "SleepTracker_SleepInfo.csv", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error opening file: %d", err); + return; + } + + // Write sleep regions to the file + if (!sleep_regions.empty()) { + for (const auto& region : sleep_regions) { + char buffer[64]; + int len = snprintf(buffer, sizeof(buffer), "Sleep detected from %.2f minutes to %.2f minutes.\n", region.first, region.second); + err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error writing to file: %d", err); + fsController.FileClose(&file); + return; + } + } + } else { + const char* noSleepMsg = "No significant sleep regions detected.\n"; + err = fsController.FileWrite(&file, reinterpret_cast(noSleepMsg), strlen(noSleepMsg)); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error writing to file: %d", err); + fsController.FileClose(&file); + return; + } + } + + // Close the file + fsController.FileClose(&file); + NRF_LOG_INFO("Sleep info written to SleepTracker_SleepInfo.csv"); +} + void SleepTracker::GetBPM() { // Get the heart rate from the controller prevBpm = bpm; @@ -96,7 +239,7 @@ void SleepTracker::GetBPM() { // Write data to CSV int motion = 0; // Placeholder for motion data - std::vector> data = {std::make_tuple(hours, minutes, seconds, rollingBpm, motion)}; + std::vector> data = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; WriteDataCSV("SleepTracker_Data.csv", data); // if (bpm == 0) { diff --git a/src/displayapp/screens/SleepTracker.h b/src/displayapp/screens/SleepTracker.h index e2f75fb3fd..76861833c8 100644 --- a/src/displayapp/screens/SleepTracker.h +++ b/src/displayapp/screens/SleepTracker.h @@ -8,6 +8,8 @@ #include "Symbols.h" #include +#include // for accumulate +#include // for abs namespace Pinetime { namespace Applications { @@ -23,6 +25,17 @@ namespace Pinetime { void ClearDataCSV(const char* filename); + // Data Processing functions + double ConvertToMinutes(int hours, int minutes, int seconds); + // Get the moving average of BPM Values + std::vector MovingAverage(const std::vector& bpm, int windowSize); + // Detect the sleep regions + std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, double threshold); + // Get the sleep info + void GetSleepInfo(std::vector> data); + + // Read IO + std::vector> ReadDataCSV(const char* fileName); private: Controllers::HeartRateController& heartRateController; @@ -32,7 +45,6 @@ namespace Pinetime { // For File IO void WriteDataCSV(const char* fileName, const std::vector>& data); - std::vector> ReadDataCSV(const char* fileName); int bpm = 0; int prevBpm = 0; From bbfb05a939567428c122909dbbc8d078f7b59145 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 5 Oct 2024 13:30:53 -0500 Subject: [PATCH 006/191] More changes tyo get the app on the watch --- src/CMakeLists.txt | 2 ++ src/FreeRTOSConfig.h | 2 +- src/displayapp/apps/CMakeLists.txt | 12 ++++++------ src/displayapp/screens/SleepTracker.cpp | 4 ++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a97a0158b..6701bd90fe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -395,6 +395,7 @@ list(APPEND SOURCE_FILES displayapp/screens/PassKey.cpp displayapp/screens/Error.cpp displayapp/screens/Alarm.cpp + displayapp/screens/SleepTracker.cpp displayapp/screens/Styles.cpp displayapp/screens/WeatherSymbols.cpp displayapp/Colors.cpp @@ -613,6 +614,7 @@ set(INCLUDE_FILES displayapp/screens/Timer.h displayapp/screens/Dice.h displayapp/screens/Alarm.h + displayapp/screens/SleepTracker.h displayapp/Colors.h displayapp/widgets/Counter.h displayapp/widgets/PageIndicator.h diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 67c33a34cc..930ec7644b 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,7 +62,7 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) -#define configTOTAL_HEAP_SIZE (1024 * 40) +#define configTOTAL_HEAP_SIZE (1024 * 35) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 33ead23165..9eb3cc8829 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -6,17 +6,17 @@ else () set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Timer") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Steps") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::HeartRate") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") + #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::SleepTracker") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") - set(USERAPP_TYPES "${USERAPP_TYPES}, Apps::SleepTracker") endif () if(DEFINED ENABLE_WATCHFACES) diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index bcbf410ff6..dbbff8f5dc 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -53,7 +53,7 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController // Create the refresh task mainRefreshTask = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); - hrRefreshTask = lv_task_create(BpmDataCallback, 3000, LV_TASK_PRIO_MID, this); + hrRefreshTask = lv_task_create(BpmDataCallback, 180000, LV_TASK_PRIO_MID, this); // Create the clear data button lv_obj_t* btnClear = lv_btn_create(lv_scr_act(), nullptr); @@ -125,7 +125,7 @@ std::vector> SleepTracker::DetectSleepRegions(const st double start_time = -1; bool in_sleep = false; - for (int i = 0; i < bpmData.size(); ++i) { + for (unsigned int i = 0; i < bpmData.size(); ++i) { if (bpmData[i] < threshold) { if (!in_sleep) { start_time = time[i]; // Mark the start of sleep From 3289107ef69d2dd8ef8eda776374776379074ed6 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 6 Oct 2024 09:19:40 -0500 Subject: [PATCH 007/191] trying to decrease flash and ram size --- src/CMakeLists.txt | 10 +- src/FreeRTOSConfig.h | 2 +- src/displayapp/DisplayApp.cpp | 4 +- src/displayapp/apps/Apps.h.in | 4 +- src/displayapp/apps/CMakeLists.txt | 2 +- src/displayapp/screens/SleepTracker.cpp | 148 ++++++++++-------------- src/displayapp/screens/SleepTracker.h | 14 +-- 7 files changed, 77 insertions(+), 107 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6701bd90fe..e8f4d0792a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -367,7 +367,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Screen.cpp displayapp/screens/Tile.cpp displayapp/screens/InfiniPaint.cpp - displayapp/screens/Paddle.cpp + #displayapp/screens/Paddle.cpp displayapp/screens/StopWatch.cpp displayapp/screens/BatteryIcon.cpp displayapp/screens/BleIcon.cpp @@ -376,7 +376,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Label.cpp displayapp/screens/FirmwareUpdate.cpp displayapp/screens/Music.cpp - displayapp/screens/Navigation.cpp + #displayapp/screens/Navigation.cpp displayapp/screens/Metronome.cpp displayapp/screens/Motion.cpp displayapp/screens/Weather.cpp @@ -456,7 +456,7 @@ list(APPEND SOURCE_FILES components/ble/AlertNotificationService.cpp components/ble/MusicService.cpp components/ble/SimpleWeatherService.cpp - components/ble/NavigationService.cpp + #components/ble/NavigationService.cpp components/ble/BatteryInformationService.cpp components/ble/FSService.cpp components/ble/ImmediateAlertService.cpp @@ -530,7 +530,7 @@ list(APPEND RECOVERY_SOURCE_FILES components/ble/FSService.cpp components/ble/ImmediateAlertService.cpp components/ble/ServiceDiscovery.cpp - components/ble/NavigationService.cpp + #components/ble/NavigationService.cpp components/ble/HeartRateService.cpp components/ble/MotionService.cpp components/firmwarevalidator/FirmwareValidator.cpp @@ -595,7 +595,7 @@ set(INCLUDE_FILES displayapp/screens/Tile.h displayapp/screens/InfiniPaint.h displayapp/screens/StopWatch.h - displayapp/screens/Paddle.h + #displayapp/screens/Paddle.h displayapp/screens/BatteryIcon.h displayapp/screens/BleIcon.h displayapp/screens/NotificationIcon.h diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 930ec7644b..c21629c199 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,7 +62,7 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) -#define configTOTAL_HEAP_SIZE (1024 * 35) +#define configTOTAL_HEAP_SIZE (1024 * 30) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 94737bb71c..3003c45b14 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -14,11 +14,11 @@ #include "displayapp/screens/FirmwareUpdate.h" #include "displayapp/screens/FirmwareValidation.h" #include "displayapp/screens/InfiniPaint.h" -#include "displayapp/screens/Paddle.h" +//#include "displayapp/screens/Paddle.h" #include "displayapp/screens/StopWatch.h" #include "displayapp/screens/Metronome.h" #include "displayapp/screens/Music.h" -#include "displayapp/screens/Navigation.h" +//#include "displayapp/screens/Navigation.h" #include "displayapp/screens/Notifications.h" #include "displayapp/screens/SystemInfo.h" #include "displayapp/screens/Tile.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 96b9564f35..b642aad846 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -19,11 +19,11 @@ namespace Pinetime { BatteryInfo, Music, Paint, - Paddle, + //Paddle, Twos, HeartRate, SleepTracker, - Navigation, + //Navigation, StopWatch, Metronome, Motion, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 9eb3cc8829..11bb0bb34f 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -23,7 +23,7 @@ if(DEFINED ENABLE_WATCHFACES) set(WATCHFACE_TYPES ${ENABLE_WATCHFACES} CACHE STRING "List of watch faces to build into the firmware") else() set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital") - set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog") + #set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PineTimeStyle") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat") diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index dbbff8f5dc..412db8275f 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -7,6 +7,7 @@ #include #include +#include using namespace Pinetime::Applications::Screens; @@ -19,7 +20,6 @@ namespace { void ClearDataCallback(lv_obj_t* btn, lv_event_t event) { if (event == LV_EVENT_CLICKED) { - // Clear data auto* screen = static_cast(lv_obj_get_user_data(btn)); screen->ClearDataCSV("SleepTracker_Data.csv"); } @@ -27,7 +27,6 @@ namespace { void GetSleepInfoCallback(lv_obj_t* btn, lv_event_t event) { if (event == LV_EVENT_CLICKED) { - // Get sleep info auto* screen = static_cast(lv_obj_get_user_data(btn)); screen->GetSleepInfo(screen->ReadDataCSV("SleepTracker_Data.csv")); } @@ -40,8 +39,8 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController wakeLock.Lock(); - static constexpr uint8_t btnWidth = 115; - static constexpr uint8_t btnHeight = 80; + constexpr uint8_t btnWidth = 115; + constexpr uint8_t btnHeight = 80; lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Sleep Tracker"); @@ -73,9 +72,7 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); lv_label_set_text(txtInfo, "?"); - - - std::vector> data = ReadDataCSV("SleepTracker_Data.csv"); + const auto data = ReadDataCSV("SleepTracker_Data.csv"); for (const auto& entry : data) { int hours, minutes, seconds, bpm, motion; std::tie(hours, minutes, seconds, bpm, motion) = entry; @@ -98,86 +95,85 @@ void SleepTracker::Refresh() { } // Convert time to minutes -double SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) { - return hours * 60 + minutes + seconds / 60.0; +float SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) const { + return hours * 60 + minutes + seconds / 60.0f; } // Get the moving average of BPM Values -std::vector SleepTracker::MovingAverage(const std::vector& bpmData, int windowSize) { - std::vector smoothedBpm; - - int n = bpmData.size(); +std::vector SleepTracker::MovingAverage(const std::vector& bpmData, int windowSize) const { + std::vector smoothedBpm; + const int n = bpmData.size(); - for (int i = 0; i < n - windowSize + 1; ++i) { - double sum = 0; - for (int j = 0; j < windowSize; ++j) { - sum += bpmData[i + j]; - } - smoothedBpm.push_back(sum / windowSize); + for (int i = 0; i < n - windowSize + 1; ++i) { + float sum = 0; + for (int j = 0; j < windowSize; ++j) { + sum += bpmData[i + j]; } + smoothedBpm.push_back(sum / windowSize); + } - return smoothedBpm; + return smoothedBpm; } // Detect the sleep regions -std::vector> SleepTracker::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, double threshold) { - std::vector> sleep_regions; - double start_time = -1; - bool in_sleep = false; +std::vector> SleepTracker::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const { + std::vector> sleep_regions; + float start_time = -1; + bool in_sleep = false; - for (unsigned int i = 0; i < bpmData.size(); ++i) { - if (bpmData[i] < threshold) { - if (!in_sleep) { - start_time = time[i]; // Mark the start of sleep - in_sleep = true; - } - } else { - if (in_sleep) { - double end_time = time[i]; // Mark the end of sleep - sleep_regions.push_back({start_time, end_time}); - in_sleep = false; - } - } + for (size_t i = 0; i < bpmData.size(); ++i) { + if (bpmData[i] < threshold) { + if (!in_sleep) { + start_time = time[i]; // Mark the start of sleep + in_sleep = true; + } + } else { + if (in_sleep) { + float end_time = time[i]; // Mark the end of sleep + sleep_regions.emplace_back(start_time, end_time); + in_sleep = false; + } } + } - // In case the last region extends to the end of the data - if (in_sleep) { - sleep_regions.push_back({start_time, time.back()}); - } + // In case the last region extends to the end of the data + if (in_sleep) { + sleep_regions.emplace_back(start_time, time.back()); + } - return sleep_regions; + return sleep_regions; } // Get Sleep Info -void SleepTracker::GetSleepInfo(std::vector> data) { - std::vector time; +void SleepTracker::GetSleepInfo(const std::vector>& data) const { + std::vector time; std::vector bpm; // Extract the time (in minutes) and bpm from the data for (const auto& entry : data) { - int hours, minutes, seconds, bpm_value, motion; - std::tie(hours, minutes, seconds, bpm_value, motion) = entry; - time.push_back(ConvertToMinutes(hours, minutes, seconds)); - bpm.push_back(bpm_value); + int hours, minutes, seconds, bpm_value, motion; + std::tie(hours, minutes, seconds, bpm_value, motion) = entry; + time.push_back(ConvertToMinutes(hours, minutes, seconds)); + bpm.push_back(bpm_value); } // Compute the moving average with a window size of 5 (15 minutes smoothing, since each data point is 3 minutes) - std::vector smoothed_bpm = MovingAverage(bpm, 5); + const auto smoothed_bpm = MovingAverage(bpm, 5); // Calculate a threshold as 80% of the average BPM - double average_bpm = std::accumulate(bpm.begin(), bpm.end(), 0.0) / bpm.size(); - double threshold = average_bpm * 0.8; + const float average_bpm = std::accumulate(bpm.begin(), bpm.end(), 0.0f) / bpm.size(); + const float threshold = average_bpm * 0.8f; // Detect multiple sleep regions - std::vector> sleep_regions = DetectSleepRegions(smoothed_bpm, time, threshold); + const auto sleep_regions = DetectSleepRegions(smoothed_bpm, time, threshold); // Output sleep regions if (!sleep_regions.empty()) { - for (const auto& region : sleep_regions) { - NRF_LOG_INFO("Sleep detected from %.2f minutes to %.2f minutes.", region.first, region.second); - } + for (const auto& region : sleep_regions) { + NRF_LOG_INFO("Sleep detected from %.2f minutes to %.2f minutes.", region.first, region.second); + } } else { - NRF_LOG_INFO("No significant sleep regions detected."); + NRF_LOG_INFO("No significant sleep regions detected."); } // Open the output file @@ -229,7 +225,6 @@ void SleepTracker::GetBPM() { rollingBpm = bpm; // Get the current time from DateTimeController - //auto now = dateTimeController.CurrentDateTime(); int hours = dateTimeController.Hours(); int minutes = dateTimeController.Minutes(); int seconds = dateTimeController.Seconds(); @@ -238,15 +233,9 @@ void SleepTracker::GetBPM() { NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); // Write data to CSV - int motion = 0; // Placeholder for motion data - std::vector> data = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; + const int motion = 0; // Placeholder for motion data + const std::vector> data = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; WriteDataCSV("SleepTracker_Data.csv", data); - - // if (bpm == 0) { - // lv_label_set_text_static(label_hr, "---"); - // } else { - // lv_label_set_text_fmt(label_hr, "%03d", bpm); - // } } // File IO Stuff @@ -255,7 +244,7 @@ void SleepTracker::GetBPM() { * Write data to a CSV file * Format: Time,BPM,Motion */ -void SleepTracker::WriteDataCSV(const char* fileName, const std::vector>& data) { +void SleepTracker::WriteDataCSV(const char* fileName, const std::vector>& data) const { lfs_file_t file; int err = fsController.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); if (err < 0) { @@ -264,30 +253,17 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::vector(header), strlen(header)); - // if (err < 0) { - // // Handle error - // NRF_LOG_INFO("Error writing to file: %d", err); - // fsController.FileClose(&file); - // return; - // } - // } - // Write data for (const auto& entry : data) { int hours, minutes, seconds, bpm, motion; std::tie(hours, minutes, seconds, bpm, motion) = entry; char buffer[64]; int len = snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d,%d,%d\n", hours, minutes, seconds, bpm, motion); - int err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); + err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); if (err < 0) { // Handle error NRF_LOG_INFO("Error writing to file: %d", err); + fsController.FileClose(&file); return; } } @@ -296,7 +272,7 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::vector> SleepTracker::ReadDataCSV(const char* filename) { +std::vector> SleepTracker::ReadDataCSV(const char* filename) const { lfs_file_t file; int err = fsController.FileOpen(&file, filename, LFS_O_RDONLY); if (err < 0) { @@ -309,12 +285,6 @@ std::vector> SleepTracker::ReadDataCSV(const char buffer[128]; int bytesRead; - // Skip header - // bytesRead = fsController.FileRead(&file, reinterpret_cast(buffer), sizeof(buffer)); - // std::istringstream headerStream(buffer); - // std::string headerLine; - // std::getline(headerStream, headerLine); - // Read data while ((bytesRead = fsController.FileRead(&file, reinterpret_cast(buffer), sizeof(buffer))) > 0) { std::istringstream dataStream(buffer); @@ -340,7 +310,7 @@ std::vector> SleepTracker::ReadDataCSV(const } // Clear data in CSV -void SleepTracker::ClearDataCSV(const char* filename) { +void SleepTracker::ClearDataCSV(const char* filename) const { lfs_file_t file; int err = fsController.FileOpen(&file, filename, LFS_O_WRONLY | LFS_O_TRUNC); if (err < 0) { diff --git a/src/displayapp/screens/SleepTracker.h b/src/displayapp/screens/SleepTracker.h index 76861833c8..c120fa1932 100644 --- a/src/displayapp/screens/SleepTracker.h +++ b/src/displayapp/screens/SleepTracker.h @@ -23,19 +23,19 @@ namespace Pinetime { void GetBPM(); - void ClearDataCSV(const char* filename); + void ClearDataCSV(const char* filename) const; // Data Processing functions - double ConvertToMinutes(int hours, int minutes, int seconds); + float ConvertToMinutes(int hours, int minutes, int seconds) const; // Get the moving average of BPM Values - std::vector MovingAverage(const std::vector& bpm, int windowSize); + std::vector MovingAverage(const std::vector& bpm, int windowSize) const; // Detect the sleep regions - std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, double threshold); + std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const; // Get the sleep info - void GetSleepInfo(std::vector> data); + void GetSleepInfo(const std::vector>& data) const; // Read IO - std::vector> ReadDataCSV(const char* fileName); + std::vector> ReadDataCSV(const char* fileName) const; private: Controllers::HeartRateController& heartRateController; @@ -44,7 +44,7 @@ namespace Pinetime { Pinetime::System::WakeLock wakeLock; // For File IO - void WriteDataCSV(const char* fileName, const std::vector>& data); + void WriteDataCSV(const char* fileName, const std::vector>& data) const; int bpm = 0; int prevBpm = 0; From 298d92ea0d6a4c133a52207ae15aaf0c21b1cec8 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 9 Oct 2024 12:36:05 -0500 Subject: [PATCH 008/191] Got rid of Nevigation & removed vectors and proccessing in SleepTracker --- src/FreeRTOSConfig.h | 2 +- src/components/ble/NimbleController.cpp | 2 +- src/components/ble/NimbleController.h | 10 +- src/displayapp/apps/CMakeLists.txt | 2 +- src/displayapp/screens/SleepTracker.cpp | 325 ++++++++++++------------ src/displayapp/screens/SleepTracker.h | 16 +- src/systemtask/SystemTask.cpp | 2 +- 7 files changed, 179 insertions(+), 180 deletions(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index c21629c199..67c33a34cc 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,7 +62,7 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) -#define configTOTAL_HEAP_SIZE (1024 * 30) +#define configTOTAL_HEAP_SIZE (1024 * 40) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 5059007ab9..046870c9aa 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -90,7 +90,7 @@ void NimbleController::Init() { currentTimeService.Init(); musicService.Init(); weatherService.Init(); - navService.Init(); + //navService.Init(); anService.Init(); dfuService.Init(); batteryInformationService.Init(); diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 597ef0cc34..0ea422ef31 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -18,7 +18,7 @@ #include "components/ble/HeartRateService.h" #include "components/ble/ImmediateAlertService.h" #include "components/ble/MusicService.h" -#include "components/ble/NavigationService.h" +//#include "components/ble/NavigationService.h" #include "components/ble/ServiceDiscovery.h" #include "components/ble/MotionService.h" #include "components/ble/SimpleWeatherService.h" @@ -59,9 +59,9 @@ namespace Pinetime { return musicService; }; - Pinetime::Controllers::NavigationService& navigation() { - return navService; - }; + // Pinetime::Controllers::NavigationService& navigation() { + // return navService; + // }; Pinetime::Controllers::AlertNotificationService& alertService() { return anService; @@ -100,7 +100,7 @@ namespace Pinetime { CurrentTimeService currentTimeService; MusicService musicService; SimpleWeatherService weatherService; - NavigationService navService; + //NavigationService navService; BatteryInformationService batteryInformationService; ImmediateAlertService immediateAlertService; HeartRateService heartRateService; diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 11bb0bb34f..9eb3cc8829 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -23,7 +23,7 @@ if(DEFINED ENABLE_WATCHFACES) set(WATCHFACE_TYPES ${ENABLE_WATCHFACES} CACHE STRING "List of watch faces to build into the firmware") else() set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital") - #set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Analog") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::PineTimeStyle") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal") set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat") diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index 412db8275f..925381dd18 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -25,12 +25,12 @@ namespace { } } - void GetSleepInfoCallback(lv_obj_t* btn, lv_event_t event) { - if (event == LV_EVENT_CLICKED) { - auto* screen = static_cast(lv_obj_get_user_data(btn)); - screen->GetSleepInfo(screen->ReadDataCSV("SleepTracker_Data.csv")); - } - } + // void GetSleepInfoCallback(lv_obj_t* btn, lv_event_t event) { + // if (event == LV_EVENT_CLICKED) { + // auto* screen = static_cast(lv_obj_get_user_data(btn)); + // screen->GetSleepInfo(screen->ReadDataCSV("SleepTracker_Data.csv")); + // } + // } } @@ -64,21 +64,21 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController lv_label_set_text(txtClear, "X"); // Create the get info button - lv_obj_t* btnInfo = lv_btn_create(lv_scr_act(), nullptr); - btnInfo->user_data = this; - lv_obj_set_event_cb(btnInfo, GetSleepInfoCallback); - lv_obj_set_size(btnInfo, btnWidth, btnHeight); - lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); - lv_label_set_text(txtInfo, "?"); - - const auto data = ReadDataCSV("SleepTracker_Data.csv"); - for (const auto& entry : data) { - int hours, minutes, seconds, bpm, motion; - std::tie(hours, minutes, seconds, bpm, motion) = entry; - NRF_LOG_INFO("Read data: %02d:%02d:%02d, %d, %d", hours, minutes, seconds, bpm, motion); - } - NRF_LOG_INFO("-------------------------------"); + // lv_obj_t* btnInfo = lv_btn_create(lv_scr_act(), nullptr); + // btnInfo->user_data = this; + // lv_obj_set_event_cb(btnInfo, GetSleepInfoCallback); + // lv_obj_set_size(btnInfo, btnWidth, btnHeight); + // lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + // lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); + // lv_label_set_text(txtInfo, "?"); + + // const auto data = ReadDataCSV("SleepTracker_Data.csv"); + // for (const auto& entry : data) { + // int hours, minutes, seconds, bpm, motion; + // std::tie(hours, minutes, seconds, bpm, motion) = entry; + // NRF_LOG_INFO("Read data: %02d:%02d:%02d, %d, %d", hours, minutes, seconds, bpm, motion); + // } + // NRF_LOG_INFO("-------------------------------"); } SleepTracker::~SleepTracker() { @@ -100,119 +100,119 @@ float SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) const } // Get the moving average of BPM Values -std::vector SleepTracker::MovingAverage(const std::vector& bpmData, int windowSize) const { - std::vector smoothedBpm; - const int n = bpmData.size(); +// std::vector SleepTracker::MovingAverage(const std::vector& bpmData, int windowSize) const { +// std::vector smoothedBpm; +// const int n = bpmData.size(); - for (int i = 0; i < n - windowSize + 1; ++i) { - float sum = 0; - for (int j = 0; j < windowSize; ++j) { - sum += bpmData[i + j]; - } - smoothedBpm.push_back(sum / windowSize); - } +// for (int i = 0; i < n - windowSize + 1; ++i) { +// float sum = 0; +// for (int j = 0; j < windowSize; ++j) { +// sum += bpmData[i + j]; +// } +// smoothedBpm.push_back(sum / windowSize); +// } - return smoothedBpm; -} +// return smoothedBpm; +// } // Detect the sleep regions -std::vector> SleepTracker::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const { - std::vector> sleep_regions; - float start_time = -1; - bool in_sleep = false; +// std::vector> SleepTracker::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const { +// std::vector> sleep_regions; +// float start_time = -1; +// bool in_sleep = false; - for (size_t i = 0; i < bpmData.size(); ++i) { - if (bpmData[i] < threshold) { - if (!in_sleep) { - start_time = time[i]; // Mark the start of sleep - in_sleep = true; - } - } else { - if (in_sleep) { - float end_time = time[i]; // Mark the end of sleep - sleep_regions.emplace_back(start_time, end_time); - in_sleep = false; - } - } - } +// for (size_t i = 0; i < bpmData.size(); ++i) { +// if (bpmData[i] < threshold) { +// if (!in_sleep) { +// start_time = time[i]; // Mark the start of sleep +// in_sleep = true; +// } +// } else { +// if (in_sleep) { +// float end_time = time[i]; // Mark the end of sleep +// sleep_regions.emplace_back(start_time, end_time); +// in_sleep = false; +// } +// } +// } - // In case the last region extends to the end of the data - if (in_sleep) { - sleep_regions.emplace_back(start_time, time.back()); - } +// // In case the last region extends to the end of the data +// if (in_sleep) { +// sleep_regions.emplace_back(start_time, time.back()); +// } - return sleep_regions; -} +// return sleep_regions; +// } -// Get Sleep Info -void SleepTracker::GetSleepInfo(const std::vector>& data) const { - std::vector time; - std::vector bpm; +// // Get Sleep Info +// void SleepTracker::GetSleepInfo(const std::vector>& data) const { +// std::vector time; +// std::vector bpm; - // Extract the time (in minutes) and bpm from the data - for (const auto& entry : data) { - int hours, minutes, seconds, bpm_value, motion; - std::tie(hours, minutes, seconds, bpm_value, motion) = entry; - time.push_back(ConvertToMinutes(hours, minutes, seconds)); - bpm.push_back(bpm_value); - } +// // Extract the time (in minutes) and bpm from the data +// for (const auto& entry : data) { +// int hours, minutes, seconds, bpm_value, motion; +// std::tie(hours, minutes, seconds, bpm_value, motion) = entry; +// time.push_back(ConvertToMinutes(hours, minutes, seconds)); +// bpm.push_back(bpm_value); +// } - // Compute the moving average with a window size of 5 (15 minutes smoothing, since each data point is 3 minutes) - const auto smoothed_bpm = MovingAverage(bpm, 5); +// // Compute the moving average with a window size of 5 (15 minutes smoothing, since each data point is 3 minutes) +// const auto smoothed_bpm = MovingAverage(bpm, 5); - // Calculate a threshold as 80% of the average BPM - const float average_bpm = std::accumulate(bpm.begin(), bpm.end(), 0.0f) / bpm.size(); - const float threshold = average_bpm * 0.8f; +// // Calculate a threshold as 80% of the average BPM +// const float average_bpm = std::accumulate(bpm.begin(), bpm.end(), 0.0f) / bpm.size(); +// const float threshold = average_bpm * 0.8f; - // Detect multiple sleep regions - const auto sleep_regions = DetectSleepRegions(smoothed_bpm, time, threshold); +// // Detect multiple sleep regions +// const auto sleep_regions = DetectSleepRegions(smoothed_bpm, time, threshold); - // Output sleep regions - if (!sleep_regions.empty()) { - for (const auto& region : sleep_regions) { - NRF_LOG_INFO("Sleep detected from %.2f minutes to %.2f minutes.", region.first, region.second); - } - } else { - NRF_LOG_INFO("No significant sleep regions detected."); - } - - // Open the output file - lfs_file_t file; - int err = fsController.FileOpen(&file, "SleepTracker_SleepInfo.csv", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error opening file: %d", err); - return; - } - - // Write sleep regions to the file - if (!sleep_regions.empty()) { - for (const auto& region : sleep_regions) { - char buffer[64]; - int len = snprintf(buffer, sizeof(buffer), "Sleep detected from %.2f minutes to %.2f minutes.\n", region.first, region.second); - err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error writing to file: %d", err); - fsController.FileClose(&file); - return; - } - } - } else { - const char* noSleepMsg = "No significant sleep regions detected.\n"; - err = fsController.FileWrite(&file, reinterpret_cast(noSleepMsg), strlen(noSleepMsg)); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error writing to file: %d", err); - fsController.FileClose(&file); - return; - } - } - - // Close the file - fsController.FileClose(&file); - NRF_LOG_INFO("Sleep info written to SleepTracker_SleepInfo.csv"); -} +// // Output sleep regions +// if (!sleep_regions.empty()) { +// for (const auto& region : sleep_regions) { +// NRF_LOG_INFO("Sleep detected from %.2f minutes to %.2f minutes.", region.first, region.second); +// } +// } else { +// NRF_LOG_INFO("No significant sleep regions detected."); +// } + +// // Open the output file +// lfs_file_t file; +// int err = fsController.FileOpen(&file, "SleepTracker_SleepInfo.csv", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC); +// if (err < 0) { +// // Handle error +// NRF_LOG_INFO("Error opening file: %d", err); +// return; +// } + +// // Write sleep regions to the file +// if (!sleep_regions.empty()) { +// for (const auto& region : sleep_regions) { +// char buffer[64]; +// int len = snprintf(buffer, sizeof(buffer), "Sleep detected from %.2f minutes to %.2f minutes.\n", region.first, region.second); +// err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); +// if (err < 0) { +// // Handle error +// NRF_LOG_INFO("Error writing to file: %d", err); +// fsController.FileClose(&file); +// return; +// } +// } +// } else { +// const char* noSleepMsg = "No significant sleep regions detected.\n"; +// err = fsController.FileWrite(&file, reinterpret_cast(noSleepMsg), strlen(noSleepMsg)); +// if (err < 0) { +// // Handle error +// NRF_LOG_INFO("Error writing to file: %d", err); +// fsController.FileClose(&file); +// return; +// } +// } + +// // Close the file +// fsController.FileClose(&file); +// NRF_LOG_INFO("Sleep info written to SleepTracker_SleepInfo.csv"); +// } void SleepTracker::GetBPM() { // Get the heart rate from the controller @@ -234,8 +234,8 @@ void SleepTracker::GetBPM() { // Write data to CSV const int motion = 0; // Placeholder for motion data - const std::vector> data = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; - WriteDataCSV("SleepTracker_Data.csv", data); + std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; + WriteDataCSV("SleepTracker_Data.csv", data, 1); } // File IO Stuff @@ -244,7 +244,7 @@ void SleepTracker::GetBPM() { * Write data to a CSV file * Format: Time,BPM,Motion */ -void SleepTracker::WriteDataCSV(const char* fileName, const std::vector>& data) const { +void SleepTracker::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { lfs_file_t file; int err = fsController.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); if (err < 0) { @@ -253,10 +253,9 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::vector(buffer), len); @@ -272,42 +271,42 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::vector> SleepTracker::ReadDataCSV(const char* filename) const { - lfs_file_t file; - int err = fsController.FileOpen(&file, filename, LFS_O_RDONLY); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error opening file: %d", err); - return {}; - } - - std::vector> data; - char buffer[128]; - int bytesRead; - - // Read data - while ((bytesRead = fsController.FileRead(&file, reinterpret_cast(buffer), sizeof(buffer))) > 0) { - std::istringstream dataStream(buffer); - std::string line; - while (std::getline(dataStream, line)) { - int hours, minutes, seconds, bpm, motion; - char colon1, colon2, comma1, comma2; - std::istringstream lineStream(line); - if (lineStream >> hours >> colon1 >> minutes >> colon2 >> seconds >> comma1 >> bpm >> comma2 >> motion) { - if (colon1 == ':' && colon2 == ':' && comma1 == ',' && comma2 == ',') { - data.emplace_back(hours, minutes, seconds, bpm, motion); - } else { - NRF_LOG_INFO("Parsing error: incorrect format in line: %s", line.c_str()); - } - } else { - NRF_LOG_INFO("Parsing error: failed to parse line: %s", line.c_str()); - } - } - } - - fsController.FileClose(&file); - return data; -} +// std::vector> SleepTracker::ReadDataCSV(const char* filename) const { +// lfs_file_t file; +// int err = fsController.FileOpen(&file, filename, LFS_O_RDONLY); +// if (err < 0) { +// // Handle error +// NRF_LOG_INFO("Error opening file: %d", err); +// return {}; +// } + +// std::vector> data; +// char buffer[128]; +// int bytesRead; + +// // Read data +// while ((bytesRead = fsController.FileRead(&file, reinterpret_cast(buffer), sizeof(buffer))) > 0) { +// std::istringstream dataStream(buffer); +// std::string line; +// while (std::getline(dataStream, line)) { +// int hours, minutes, seconds, bpm, motion; +// char colon1, colon2, comma1, comma2; +// std::istringstream lineStream(line); +// if (lineStream >> hours >> colon1 >> minutes >> colon2 >> seconds >> comma1 >> bpm >> comma2 >> motion) { +// if (colon1 == ':' && colon2 == ':' && comma1 == ',' && comma2 == ',') { +// data.emplace_back(hours, minutes, seconds, bpm, motion); +// } else { +// NRF_LOG_INFO("Parsing error: incorrect format in line: %s", line.c_str()); +// } +// } else { +// NRF_LOG_INFO("Parsing error: failed to parse line: %s", line.c_str()); +// } +// } +// } + +// fsController.FileClose(&file); +// return data; +// } // Clear data in CSV void SleepTracker::ClearDataCSV(const char* filename) const { diff --git a/src/displayapp/screens/SleepTracker.h b/src/displayapp/screens/SleepTracker.h index c120fa1932..11196fb3a4 100644 --- a/src/displayapp/screens/SleepTracker.h +++ b/src/displayapp/screens/SleepTracker.h @@ -7,9 +7,9 @@ #include "systemtask/WakeLock.h" #include "Symbols.h" -#include -#include // for accumulate -#include // for abs +//#include +//#include // for accumulate +//#include // for abs namespace Pinetime { namespace Applications { @@ -28,14 +28,14 @@ namespace Pinetime { // Data Processing functions float ConvertToMinutes(int hours, int minutes, int seconds) const; // Get the moving average of BPM Values - std::vector MovingAverage(const std::vector& bpm, int windowSize) const; + //std::vector MovingAverage(const std::vector& bpm, int windowSize) const; // Detect the sleep regions - std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const; + //std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const; // Get the sleep info - void GetSleepInfo(const std::vector>& data) const; + //void GetSleepInfo(const std::vector>& data) const; // Read IO - std::vector> ReadDataCSV(const char* fileName) const; + //std::vector> ReadDataCSV(const char* fileName) const; private: Controllers::HeartRateController& heartRateController; @@ -44,7 +44,7 @@ namespace Pinetime { Pinetime::System::WakeLock wakeLock; // For File IO - void WriteDataCSV(const char* fileName, const std::vector>& data) const; + void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; int bpm = 0; int prevBpm = 0; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index eb013d6d1a..fee1fbf1f6 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -140,7 +140,7 @@ void SystemTask::Work() { displayApp.Register(this); displayApp.Register(&nimbleController.weather()); displayApp.Register(&nimbleController.music()); - displayApp.Register(&nimbleController.navigation()); + //displayApp.Register(&nimbleController.navigation()); displayApp.Start(bootError); heartRateSensor.Init(); From 144e47673d630876eaf29a167a9cd151ad07e078 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 9 Oct 2024 13:46:07 -0500 Subject: [PATCH 009/191] Put Navigation back for Sim to work, decreased bpm log interval for debugging --- src/CMakeLists.txt | 8 ++++---- src/components/ble/NimbleController.cpp | 2 +- src/components/ble/NimbleController.h | 10 +++++----- src/displayapp/DisplayApp.cpp | 4 ++-- src/displayapp/apps/Apps.h.in | 4 ++-- src/displayapp/apps/CMakeLists.txt | 2 +- src/displayapp/screens/SleepTracker.cpp | 3 ++- src/systemtask/SystemTask.cpp | 2 +- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8f4d0792a..6254b8953b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -367,7 +367,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Screen.cpp displayapp/screens/Tile.cpp displayapp/screens/InfiniPaint.cpp - #displayapp/screens/Paddle.cpp + displayapp/screens/Paddle.cpp displayapp/screens/StopWatch.cpp displayapp/screens/BatteryIcon.cpp displayapp/screens/BleIcon.cpp @@ -376,7 +376,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Label.cpp displayapp/screens/FirmwareUpdate.cpp displayapp/screens/Music.cpp - #displayapp/screens/Navigation.cpp + displayapp/screens/Navigation.cpp displayapp/screens/Metronome.cpp displayapp/screens/Motion.cpp displayapp/screens/Weather.cpp @@ -456,7 +456,7 @@ list(APPEND SOURCE_FILES components/ble/AlertNotificationService.cpp components/ble/MusicService.cpp components/ble/SimpleWeatherService.cpp - #components/ble/NavigationService.cpp + components/ble/NavigationService.cpp components/ble/BatteryInformationService.cpp components/ble/FSService.cpp components/ble/ImmediateAlertService.cpp @@ -595,7 +595,7 @@ set(INCLUDE_FILES displayapp/screens/Tile.h displayapp/screens/InfiniPaint.h displayapp/screens/StopWatch.h - #displayapp/screens/Paddle.h + displayapp/screens/Paddle.h displayapp/screens/BatteryIcon.h displayapp/screens/BleIcon.h displayapp/screens/NotificationIcon.h diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 046870c9aa..5059007ab9 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -90,7 +90,7 @@ void NimbleController::Init() { currentTimeService.Init(); musicService.Init(); weatherService.Init(); - //navService.Init(); + navService.Init(); anService.Init(); dfuService.Init(); batteryInformationService.Init(); diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 0ea422ef31..597ef0cc34 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -18,7 +18,7 @@ #include "components/ble/HeartRateService.h" #include "components/ble/ImmediateAlertService.h" #include "components/ble/MusicService.h" -//#include "components/ble/NavigationService.h" +#include "components/ble/NavigationService.h" #include "components/ble/ServiceDiscovery.h" #include "components/ble/MotionService.h" #include "components/ble/SimpleWeatherService.h" @@ -59,9 +59,9 @@ namespace Pinetime { return musicService; }; - // Pinetime::Controllers::NavigationService& navigation() { - // return navService; - // }; + Pinetime::Controllers::NavigationService& navigation() { + return navService; + }; Pinetime::Controllers::AlertNotificationService& alertService() { return anService; @@ -100,7 +100,7 @@ namespace Pinetime { CurrentTimeService currentTimeService; MusicService musicService; SimpleWeatherService weatherService; - //NavigationService navService; + NavigationService navService; BatteryInformationService batteryInformationService; ImmediateAlertService immediateAlertService; HeartRateService heartRateService; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 3003c45b14..94737bb71c 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -14,11 +14,11 @@ #include "displayapp/screens/FirmwareUpdate.h" #include "displayapp/screens/FirmwareValidation.h" #include "displayapp/screens/InfiniPaint.h" -//#include "displayapp/screens/Paddle.h" +#include "displayapp/screens/Paddle.h" #include "displayapp/screens/StopWatch.h" #include "displayapp/screens/Metronome.h" #include "displayapp/screens/Music.h" -//#include "displayapp/screens/Navigation.h" +#include "displayapp/screens/Navigation.h" #include "displayapp/screens/Notifications.h" #include "displayapp/screens/SystemInfo.h" #include "displayapp/screens/Tile.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index b642aad846..96b9564f35 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -19,11 +19,11 @@ namespace Pinetime { BatteryInfo, Music, Paint, - //Paddle, + Paddle, Twos, HeartRate, SleepTracker, - //Navigation, + Navigation, StopWatch, Metronome, Motion, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 9eb3cc8829..79f3431e4d 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -12,7 +12,7 @@ else () set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") - #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::SleepTracker") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/SleepTracker.cpp index 925381dd18..bca330df47 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/SleepTracker.cpp @@ -52,7 +52,7 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController // Create the refresh task mainRefreshTask = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); - hrRefreshTask = lv_task_create(BpmDataCallback, 180000, LV_TASK_PRIO_MID, this); + hrRefreshTask = lv_task_create(BpmDataCallback, 3000, LV_TASK_PRIO_MID, this); // Create the clear data button lv_obj_t* btnClear = lv_btn_create(lv_scr_act(), nullptr); @@ -263,6 +263,7 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::tuple Date: Wed, 9 Oct 2024 20:45:04 -0400 Subject: [PATCH 010/191] Reenable user apps --- src/CMakeLists.txt | 2 +- src/displayapp/apps/CMakeLists.txt | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6254b8953b..6701bd90fe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -530,7 +530,7 @@ list(APPEND RECOVERY_SOURCE_FILES components/ble/FSService.cpp components/ble/ImmediateAlertService.cpp components/ble/ServiceDiscovery.cpp - #components/ble/NavigationService.cpp + components/ble/NavigationService.cpp components/ble/HeartRateService.cpp components/ble/MotionService.cpp components/firmwarevalidator/FirmwareValidator.cpp diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 79f3431e4d..17314db033 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -6,14 +6,14 @@ else () set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Timer") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Steps") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::HeartRate") - #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music") - #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint") - #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Music") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") - #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::SleepTracker") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") From 636f1f256112cf0aba90590e41613f5e1e35948c Mon Sep 17 00:00:00 2001 From: Liam Willey Date: Fri, 11 Oct 2024 00:18:07 -0400 Subject: [PATCH 011/191] Rename SleepTracker update button size --- src/CMakeLists.txt | 4 +-- src/displayapp/DisplayApp.cpp | 2 +- src/displayapp/apps/Apps.h.in | 2 +- src/displayapp/apps/CMakeLists.txt | 2 +- .../screens/{SleepTracker.cpp => Sleep.cpp} | 34 +++++++++---------- .../screens/{SleepTracker.h => Sleep.h} | 12 +++---- 6 files changed, 28 insertions(+), 28 deletions(-) rename src/displayapp/screens/{SleepTracker.cpp => Sleep.cpp} (87%) rename src/displayapp/screens/{SleepTracker.h => Sleep.h} (78%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6701bd90fe..2480518988 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -395,7 +395,7 @@ list(APPEND SOURCE_FILES displayapp/screens/PassKey.cpp displayapp/screens/Error.cpp displayapp/screens/Alarm.cpp - displayapp/screens/SleepTracker.cpp + displayapp/screens/Sleep.cpp displayapp/screens/Styles.cpp displayapp/screens/WeatherSymbols.cpp displayapp/Colors.cpp @@ -614,7 +614,7 @@ set(INCLUDE_FILES displayapp/screens/Timer.h displayapp/screens/Dice.h displayapp/screens/Alarm.h - displayapp/screens/SleepTracker.h + displayapp/screens/Sleep.h displayapp/Colors.h displayapp/widgets/Counter.h displayapp/widgets/PageIndicator.h diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 94737bb71c..5f507ce76a 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -30,7 +30,7 @@ #include "displayapp/screens/Weather.h" #include "displayapp/screens/PassKey.h" #include "displayapp/screens/Error.h" -#include "displayapp/screens/SleepTracker.h" +#include "displayapp/screens/Sleep.h" #include "drivers/Cst816s.h" #include "drivers/St7789.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 96b9564f35..499f43accb 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -22,7 +22,7 @@ namespace Pinetime { Paddle, Twos, HeartRate, - SleepTracker, + Sleep, Navigation, StopWatch, Metronome, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 17314db033..7d8879a4e8 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -14,7 +14,7 @@ else () set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::SleepTracker") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Sleep") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") endif () diff --git a/src/displayapp/screens/SleepTracker.cpp b/src/displayapp/screens/Sleep.cpp similarity index 87% rename from src/displayapp/screens/SleepTracker.cpp rename to src/displayapp/screens/Sleep.cpp index bca330df47..543f987235 100644 --- a/src/displayapp/screens/SleepTracker.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -1,4 +1,4 @@ -#include "displayapp/screens/SleepTracker.h" +#include "displayapp/screens/Sleep.h" #include #include @@ -14,33 +14,33 @@ using namespace Pinetime::Applications::Screens; namespace { void BpmDataCallback(lv_task_t* task) { - auto* screen = static_cast(task->user_data); + auto* screen = static_cast(task->user_data); screen->GetBPM(); } void ClearDataCallback(lv_obj_t* btn, lv_event_t event) { if (event == LV_EVENT_CLICKED) { - auto* screen = static_cast(lv_obj_get_user_data(btn)); - screen->ClearDataCSV("SleepTracker_Data.csv"); + auto* screen = static_cast(lv_obj_get_user_data(btn)); + screen->ClearDataCSV("Sleep_Data.csv"); } } // void GetSleepInfoCallback(lv_obj_t* btn, lv_event_t event) { // if (event == LV_EVENT_CLICKED) { - // auto* screen = static_cast(lv_obj_get_user_data(btn)); + // auto* screen = static_cast(lv_obj_get_user_data(btn)); // screen->GetSleepInfo(screen->ReadDataCSV("SleepTracker_Data.csv")); // } // } } -SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask) +Sleep::Sleep(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask) : heartRateController {heartRateController}, dateTimeController {dateTimeController}, fsController {fsController}, wakeLock(systemTask) { wakeLock.Lock(); constexpr uint8_t btnWidth = 115; - constexpr uint8_t btnHeight = 80; + constexpr uint8_t btnHeight = 45; lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Sleep Tracker"); @@ -81,7 +81,7 @@ SleepTracker::SleepTracker(Controllers::HeartRateController& heartRateController // NRF_LOG_INFO("-------------------------------"); } -SleepTracker::~SleepTracker() { +Sleep::~Sleep() { wakeLock.Release(); lv_obj_clean(lv_scr_act()); @@ -90,17 +90,17 @@ SleepTracker::~SleepTracker() { } // This function is called periodically from the refresh task -void SleepTracker::Refresh() { +void Sleep::Refresh() { // Get the current heart rate } // Convert time to minutes -float SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) const { +float Sleep::ConvertToMinutes(int hours, int minutes, int seconds) const { return hours * 60 + minutes + seconds / 60.0f; } // Get the moving average of BPM Values -// std::vector SleepTracker::MovingAverage(const std::vector& bpmData, int windowSize) const { +// std::vector Sleep::MovingAverage(const std::vector& bpmData, int windowSize) const { // std::vector smoothedBpm; // const int n = bpmData.size(); @@ -116,7 +116,7 @@ float SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) const // } // Detect the sleep regions -// std::vector> SleepTracker::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const { +// std::vector> Sleep::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const { // std::vector> sleep_regions; // float start_time = -1; // bool in_sleep = false; @@ -145,7 +145,7 @@ float SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) const // } // // Get Sleep Info -// void SleepTracker::GetSleepInfo(const std::vector>& data) const { +// void Sleep::GetSleepInfo(const std::vector>& data) const { // std::vector time; // std::vector bpm; @@ -214,7 +214,7 @@ float SleepTracker::ConvertToMinutes(int hours, int minutes, int seconds) const // NRF_LOG_INFO("Sleep info written to SleepTracker_SleepInfo.csv"); // } -void SleepTracker::GetBPM() { +void Sleep::GetBPM() { // Get the heart rate from the controller prevBpm = bpm; bpm = heartRateController.HeartRate(); @@ -244,7 +244,7 @@ void SleepTracker::GetBPM() { * Write data to a CSV file * Format: Time,BPM,Motion */ -void SleepTracker::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { +void Sleep::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { lfs_file_t file; int err = fsController.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); if (err < 0) { @@ -272,7 +272,7 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::tuple> SleepTracker::ReadDataCSV(const char* filename) const { +// std::vector> Sleep::ReadDataCSV(const char* filename) const { // lfs_file_t file; // int err = fsController.FileOpen(&file, filename, LFS_O_RDONLY); // if (err < 0) { @@ -310,7 +310,7 @@ void SleepTracker::WriteDataCSV(const char* fileName, const std::tuple - struct AppTraits { - static constexpr Apps app = Apps::SleepTracker; + struct AppTraits { + static constexpr Apps app = Apps::Sleep; static constexpr const char* icon = Screens::Symbols::bed; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::SleepTracker(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, *controllers.systemTask); + return new Screens::Sleep(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, *controllers.systemTask); } }; } From d8f024643b1b91c9f03d97f265c522ccdc5b2747 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 28 Oct 2024 01:58:22 -0500 Subject: [PATCH 012/191] Work on new Sleep Controller --- src/CMakeLists.txt | 3 + .../infinisleep/InfiniSleepController.cpp | 166 ++++++++++++++++++ .../infinisleep/InfiniSleepController.h | 78 ++++++++ src/main.cpp | 5 +- src/systemtask/Messages.h | 1 + src/systemtask/SystemTask.cpp | 10 +- src/systemtask/SystemTask.h | 5 +- 7 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 src/components/infinisleep/InfiniSleepController.cpp create mode 100644 src/components/infinisleep/InfiniSleepController.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2480518988..0e6f3ee54b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -468,6 +468,7 @@ list(APPEND SOURCE_FILES components/settings/Settings.cpp components/timer/Timer.cpp components/alarm/AlarmController.cpp + components/infinisleep/InfiniSleepController.cpp components/fs/FS.cpp drivers/Cst816s.cpp FreeRTOS/port.c @@ -537,6 +538,7 @@ list(APPEND RECOVERY_SOURCE_FILES components/settings/Settings.cpp components/timer/Timer.cpp components/alarm/AlarmController.cpp + components/infinisleep/InfiniSleepController.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -657,6 +659,7 @@ set(INCLUDE_FILES components/settings/Settings.h components/timer/Timer.h components/alarm/AlarmController.h + components/infinisleep/InfiniSleepController.h drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp new file mode 100644 index 0000000000..f9bedfbf36 --- /dev/null +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -0,0 +1,166 @@ +# include "components/infinisleep/InfiniSleepController.h" +#include "systemtask/SystemTask.h" +#include "task.h" +#include +#include + +using namespace Pinetime::Controllers; +using namespace std::chrono_literals; + +InfiniSleepController::InfiniSleepController(Controllers::DateTime& dateTimeController, Controllers::FS& fs) + : dateTimeController {dateTimeController}, fs {fs} { +} + +namespace { + void SetOffWakeAlarm(TimerHandle_t xTimer) { + auto* controller = static_cast(pvTimerGetTimerID(xTimer)); + controller->SetOffWakeAlarmNow(); + } +} + +void InfiniSleepController::Init(System::SystemTask* systemTask) { + this->systemTask = systemTask; + wakeAlarmTimer = xTimerCreate("WakeAlarm", 1, pdFALSE, this, SetOffWakeAlarm); + LoadSettingsFromFile(); + if (wakeAlarm.isEnabled) { + NRF_LOG_INFO("[InfiniSleepController] Loaded wake alarm was enabled, scheduling"); + ScheduleWakeAlarm(); + } +} + +void InfiniSleepController::SaveWakeAlarm() { + // verify is save needed + if (wakeAlarmChanged) { + SaveSettingsToFile(); + } + wakeAlarmChanged = false; +} + +void InfiniSleepController::SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin) { + if (wakeAlarm.hours == wakeAlarmHr && wakeAlarm.minutes == wakeAlarmMin) { + return; + } + wakeAlarm.hours = wakeAlarmHr; + wakeAlarm.minutes = wakeAlarmMin; + wakeAlarmChanged = true; +} + +void InfiniSleepController::ScheduleWakeAlarm() { + // Determine the next time the wake alarm needs to go off and set the timer + xTimerStop(wakeAlarmTimer, 0); + + auto now = dateTimeController.CurrentDateTime(); + wakeAlarmTime = now; + time_t ttWakeAlarmTime = std::chrono::system_clock::to_time_t(std::chrono::time_point_cast(wakeAlarmTime)); + tm* tmWakeAlarmTime = std::localtime(&ttWakeAlarmTime); + + // If the time being set has already passed today, the wake alarm should be set for tomorrow + if (wakeAlarm.hours < dateTimeController.Hours() || + (wakeAlarm.hours == dateTimeController.Hours() && wakeAlarm.minutes <= dateTimeController.Minutes())) { + tmWakeAlarmTime->tm_mday += 1; + // tm_wday doesn't update automatically + tmWakeAlarmTime->tm_wday = (tmWakeAlarmTime->tm_wday + 1) % 7; + } + + tmWakeAlarmTime->tm_hour = wakeAlarm.hours; + tmWakeAlarmTime->tm_min = wakeAlarm.minutes; + tmWakeAlarmTime->tm_sec = 0; + + // if alarm is in weekday-only mode, make sure it shifts to the next weekday + if (wakeAlarm.recurrence == RecurType::Weekdays) { + if (tmWakeAlarmTime->tm_wday == 0) {// Sunday, shift 1 day + tmWakeAlarmTime->tm_mday += 1; + } else if (tmWakeAlarmTime->tm_wday == 6) { // Saturday, shift 2 days + tmWakeAlarmTime->tm_mday += 2; + } + } + tmWakeAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST + + // now can convert back to a time_point + wakeAlarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmWakeAlarmTime)); + auto secondsToWakeAlarm = std::chrono::duration_cast(wakeAlarmTime - now).count(); + xTimerChangePeriod(wakeAlarmTimer, secondsToWakeAlarm * configTICK_RATE_HZ, 0); + xTimerStart(wakeAlarmTimer, 0); + + if (!wakeAlarm.isEnabled) { + wakeAlarm.isEnabled = true; + wakeAlarmChanged = true; + } +} + +uint32_t InfiniSleepController::SecondsToWakeAlarm() const { + return std::chrono::duration_cast(wakeAlarmTime - dateTimeController.CurrentDateTime()).count(); +} + +void InfiniSleepController::DisableWakeAlarm() { + xTimerStop(wakeAlarmTimer, 0); + isAlerting = false; + if (wakeAlarm.isEnabled) { + wakeAlarm.isEnabled = false; + wakeAlarmChanged = true; + } +} + +void InfiniSleepController::SetOffWakeAlarmNow() { + isAlerting = true; + systemTask->PushMessage(System::Messages::SetOffWakeAlarm); +} + +void InfiniSleepController::StopAlerting() { + isAlerting = false; + // Disable the alarm unless it is recurring + if (wakeAlarm.recurrence == RecurType::None) { + wakeAlarm.isEnabled = false; + wakeAlarmChanged = true; + } else { + // Schedule the alarm for the next day + ScheduleWakeAlarm(); + } +} + +void InfiniSleepController::SetRecurrence(RecurType recurrence) { + if (wakeAlarm.recurrence == recurrence) { + return; + } + wakeAlarm.recurrence = recurrence; + wakeAlarmChanged = true; +} + +void InfiniSleepController::LoadSettingsFromFile() { + lfs_file_t wakeAlarmFile; + WakeAlarmSettings wakeAlarmBuffer; + + if (fs.FileOpen(&wakeAlarmFile, "/.system/wakeAlarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) { + NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file"); + return; + } + + fs.FileRead(&wakeAlarmFile, reinterpret_cast(&wakeAlarmBuffer), sizeof(wakeAlarmBuffer)); + fs.FileClose(&wakeAlarmFile); + if (wakeAlarmBuffer.version != wakeAlarmFormatVersion) { + NRF_LOG_WARNING("[AlarmController] Loaded alarm settings has version %u instead of %u, discarding", + wakeAlarmBuffer.version, + wakeAlarmFormatVersion); + return; + } + + wakeAlarm = wakeAlarmBuffer; + NRF_LOG_INFO("[AlarmController] Loaded alarm settings from file"); +} + +void InfiniSleepController::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/wakeAlarm.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(&wakeAlarm), sizeof(wakeAlarm)); + fs.FileClose(&alarmFile); + NRF_LOG_INFO("[AlarmController] Saved alarm settings with format version %u to file", wakeAlarm.version); +} \ No newline at end of file diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h new file mode 100644 index 0000000000..2864a1659f --- /dev/null +++ b/src/components/infinisleep/InfiniSleepController.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include +#include "components/datetime/DateTimeController.h" + +namespace Pinetime { + namespace System { + class SystemTask; + } + + namespace Controllers { + class InfiniSleepController { + public: + InfiniSleepController(Controllers::DateTime& dateTimeCOntroller, Controllers::FS& fs); + + void Init(System::SystemTask* systemTask); + void SaveWakeAlarm(); + void SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin); + void ScheduleWakeAlarm(); + void DisableWakeAlarm(); + void SetOffWakeAlarmNow(); + uint32_t SecondsToWakeAlarm() const; + void StopAlerting(); + enum class RecurType { None, Daily, Weekdays }; + + uint8_t Hours() const { + return wakeAlarm.hours; + } + + uint8_t Minutes() const { + return wakeAlarm.minutes; + } + + bool IsAlerting() const { + return isAlerting; + } + + bool IsEnabled() const { + return wakeAlarm.isEnabled; + } + + RecurType Recurrence() const { + return wakeAlarm.recurrence; + } + + void SetRecurrence(RecurType recurrence); + + private: + // Versions 255 is reserved for now, so the version field can be made + // bigger, should it ever be needed. + static constexpr uint8_t wakeAlarmFormatVersion = 1; + + struct WakeAlarmSettings { + uint8_t version = wakeAlarmFormatVersion; + uint8_t hours = 7; + uint8_t minutes = 0; + RecurType recurrence = RecurType::None; + bool isEnabled = false; + }; + + bool isAlerting = false; + bool wakeAlarmChanged = false; + + Controllers::DateTime& dateTimeController; + Controllers::FS& fs; + System::SystemTask* systemTask = nullptr; + TimerHandle_t wakeAlarmTimer; + WakeAlarmSettings wakeAlarm; + std::chrono::time_point wakeAlarmTime; + + void LoadSettingsFromFile(); + void SaveSettingsToFile() const; + }; + } + +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 24f13caddd..14a3dba8bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,6 +105,8 @@ Pinetime::Drivers::Watchdog watchdog; Pinetime::Controllers::NotificationManager notificationManager; Pinetime::Controllers::MotionController motionController; Pinetime::Controllers::AlarmController alarmController {dateTimeController, fs}; +Pinetime::Controllers::InfiniSleepController infiniSleepController {dateTimeController, fs}; + Pinetime::Controllers::TouchHandler touchHandler; Pinetime::Controllers::ButtonHandler buttonHandler; Pinetime::Controllers::BrightnessController brightnessController {}; @@ -145,7 +147,8 @@ Pinetime::System::SystemTask systemTask(spi, heartRateApp, fs, touchHandler, - buttonHandler); + buttonHandler, + infiniSleepController); int mallocFailedCount = 0; int stackOverflowCount = 0; extern "C" { diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index fee94bb747..d00b27c150 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -25,6 +25,7 @@ namespace Pinetime { OnChargingEvent, OnPairing, SetOffAlarm, + SetOffWakeAlarm, MeasureBatteryTimerExpired, BatteryPercentageUpdated, StartFileTransfer, diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index eb013d6d1a..4ad20e5c30 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -51,7 +51,8 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, Pinetime::Applications::HeartRateTask& heartRateApp, Pinetime::Controllers::FS& fs, Pinetime::Controllers::TouchHandler& touchHandler, - Pinetime::Controllers::ButtonHandler& buttonHandler) + Pinetime::Controllers::ButtonHandler& buttonHandler, + Pinetime::Controllers::InfiniSleepController& infiniSleepController) : spi {spi}, spiNorFlash {spiNorFlash}, twiMaster {twiMaster}, @@ -80,7 +81,8 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, spiNorFlash, heartRateController, motionController, - fs) { + fs), + infiniSleepController {infiniSleepController} { } void SystemTask::Start() { @@ -128,6 +130,7 @@ void SystemTask::Work() { batteryController.Register(this); motionSensor.SoftReset(); alarmController.Init(this); + infiniSleepController.Init(this); // Reset the TWI device because the motion sensor chip most probably crashed it... twiMaster.Sleep(); @@ -218,6 +221,9 @@ void SystemTask::Work() { GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::AlarmTriggered); break; + case Messages::SetOffWakeAlarm: + // Code the screen trigger here + break; case Messages::BleConnected: displayApp.PushMessage(Pinetime::Applications::Display::Messages::NotifyDeviceActivity); isBleDiscoveryTimerRunning = true; diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index 0060e36096..f456a8fd3e 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -16,6 +16,7 @@ #include "components/ble/NimbleController.h" #include "components/ble/NotificationManager.h" #include "components/alarm/AlarmController.h" +#include "components/infinisleep/InfiniSleepController.h" #include "components/fs/FS.h" #include "touchhandler/TouchHandler.h" #include "buttonhandler/ButtonHandler.h" @@ -72,7 +73,8 @@ namespace Pinetime { Pinetime::Applications::HeartRateTask& heartRateApp, Pinetime::Controllers::FS& fs, Pinetime::Controllers::TouchHandler& touchHandler, - Pinetime::Controllers::ButtonHandler& buttonHandler); + Pinetime::Controllers::ButtonHandler& buttonHandler, + Pinetime::Controllers::InfiniSleepController& infiniSleepController); void Start(); void PushMessage(Messages msg); @@ -116,6 +118,7 @@ namespace Pinetime { Pinetime::Controllers::TouchHandler& touchHandler; Pinetime::Controllers::ButtonHandler& buttonHandler; Pinetime::Controllers::NimbleController nimbleController; + Pinetime::Controllers::InfiniSleepController& infiniSleepController; static void Process(void* instance); void Work(); From a84fa93580aed134b3b63c1864cfe5398d069565 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 29 Oct 2024 01:03:40 -0500 Subject: [PATCH 013/191] Ported Main Alarm into InfiniSleep, Need to add natural and gradual wake next --- .../infinisleep/InfiniSleepController.cpp | 8 +- src/displayapp/Controllers.h | 2 + src/displayapp/DisplayApp.cpp | 13 +- src/displayapp/DisplayApp.h | 4 +- src/displayapp/Messages.h | 1 + src/displayapp/screens/Sleep.cpp | 537 ++++++++---------- src/displayapp/screens/Sleep.h | 70 ++- src/main.cpp | 3 +- src/systemtask/SystemTask.cpp | 2 + 9 files changed, 324 insertions(+), 316 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index f9bedfbf36..17e2ba9a79 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -130,7 +130,7 @@ void InfiniSleepController::LoadSettingsFromFile() { lfs_file_t wakeAlarmFile; WakeAlarmSettings wakeAlarmBuffer; - if (fs.FileOpen(&wakeAlarmFile, "/.system/wakeAlarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) { + if (fs.FileOpen(&wakeAlarmFile, "/.system/sleep/wakeAlarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) { NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file"); return; } @@ -150,12 +150,12 @@ void InfiniSleepController::LoadSettingsFromFile() { void InfiniSleepController::SaveSettingsToFile() const { lfs_dir systemDir; - if (fs.DirOpen("/.system", &systemDir) != LFS_ERR_OK) { - fs.DirCreate("/.system"); + if (fs.DirOpen("/.system/sleep", &systemDir) != LFS_ERR_OK) { + fs.DirCreate("/.system/sleep"); } fs.DirClose(&systemDir); lfs_file_t alarmFile; - if (fs.FileOpen(&alarmFile, "/.system/wakeAlarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { + if (fs.FileOpen(&alarmFile, "/.system/sleep/wakeAlarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file for saving"); return; } diff --git a/src/displayapp/Controllers.h b/src/displayapp/Controllers.h index 9992426c5d..5116398e2e 100644 --- a/src/displayapp/Controllers.h +++ b/src/displayapp/Controllers.h @@ -19,6 +19,7 @@ namespace Pinetime { class MotorController; class MotionController; class AlarmController; + class InfiniSleepController; class BrightnessController; class SimpleWeatherService; class FS; @@ -42,6 +43,7 @@ namespace Pinetime { Pinetime::Controllers::MotorController& motorController; Pinetime::Controllers::MotionController& motionController; Pinetime::Controllers::AlarmController& alarmController; + Pinetime::Controllers::InfiniSleepController& infiniSleepController; Pinetime::Controllers::BrightnessController& brightnessController; Pinetime::Controllers::SimpleWeatherService* weatherController; Pinetime::Controllers::FS& filesystem; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 5f507ce76a..33cf838972 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -83,7 +83,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler, Pinetime::Controllers::FS& filesystem, - Pinetime::Drivers::SpiNorFlash& spiNorFlash) + Pinetime::Drivers::SpiNorFlash& spiNorFlash, + Pinetime::Controllers::InfiniSleepController& infiniSleepController) : lcd {lcd}, touchPanel {touchPanel}, batteryController {batteryController}, @@ -100,6 +101,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, touchHandler {touchHandler}, filesystem {filesystem}, spiNorFlash {spiNorFlash}, + infiniSleepController {infiniSleepController}, lvgl {lcd, filesystem}, timer(this, TimerCallback), controllers {batteryController, @@ -111,6 +113,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, motorController, motionController, alarmController, + infiniSleepController, brightnessController, nullptr, filesystem, @@ -383,6 +386,14 @@ void DisplayApp::Refresh() { LoadNewScreen(Apps::Alarm, DisplayApp::FullRefreshDirections::None); } break; + case Messages::WakeAlarmTriggered: + if (currentApp == Apps::Sleep) { + auto* sleep = static_cast(currentScreen.get()); + sleep->SetAlerting(); + } else { + LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); + } + break; case Messages::ShowPairingKey: LoadNewScreen(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); motorController.RunForDuration(35); diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 2f276eaf9e..9009d5daee 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -67,7 +67,8 @@ namespace Pinetime { Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler, Pinetime::Controllers::FS& filesystem, - Pinetime::Drivers::SpiNorFlash& spiNorFlash); + Pinetime::Drivers::SpiNorFlash& spiNorFlash, + Pinetime::Controllers::InfiniSleepController& infiniSleepController); void Start(System::BootErrors error); void PushMessage(Display::Messages msg); @@ -98,6 +99,7 @@ namespace Pinetime { Pinetime::Controllers::TouchHandler& touchHandler; Pinetime::Controllers::FS& filesystem; Pinetime::Drivers::SpiNorFlash& spiNorFlash; + Pinetime::Controllers::InfiniSleepController& infiniSleepController; Pinetime::Controllers::FirmwareValidator validator; Pinetime::Components::LittleVgl lvgl; diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index d2abc8e58d..fd112e7cb2 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -22,6 +22,7 @@ namespace Pinetime { NotifyDeviceActivity, ShowPairingKey, AlarmTriggered, + WakeAlarmTriggered, Chime, BleRadioEnableToggle, OnChargingEvent, diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 543f987235..0b3321abb6 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -1,324 +1,281 @@ #include "displayapp/screens/Sleep.h" - -#include -#include -#include -#include -#include - -#include -#include +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" +#include "components/settings/Settings.h" +#include "components/alarm/AlarmController.h" +#include "components/motor/MotorController.h" +#include "systemtask/SystemTask.h" using namespace Pinetime::Applications::Screens; +using Pinetime::Controllers::InfiniSleepController; namespace { - - void BpmDataCallback(lv_task_t* task) { - auto* screen = static_cast(task->user_data); - screen->GetBPM(); + void ValueChangedHandler(void* userData) { + auto* screen = static_cast(userData); + screen->OnValueChanged(); } +} - void ClearDataCallback(lv_obj_t* btn, lv_event_t event) { - if (event == LV_EVENT_CLICKED) { - auto* screen = static_cast(lv_obj_get_user_data(btn)); - screen->ClearDataCSV("Sleep_Data.csv"); - } - } +static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnButtonEvent(obj, event); +} - // void GetSleepInfoCallback(lv_obj_t* btn, lv_event_t event) { - // if (event == LV_EVENT_CLICKED) { - // auto* screen = static_cast(lv_obj_get_user_data(btn)); - // screen->GetSleepInfo(screen->ReadDataCSV("SleepTracker_Data.csv")); - // } - // } +static void StopAlarmTaskCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + screen->StopAlerting(); +} +Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, + Controllers::Settings::ClockType clockType, + System::SystemTask& systemTask, + Controllers::MotorController& motorController) + : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController} { + + hourCounter.Create(); + lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + if (clockType == Controllers::Settings::ClockType::H12) { + hourCounter.EnableTwelveHourMode(); + + lblampm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_text_static(lblampm, "AM"); + lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + } + hourCounter.SetValue(infiniSleepController.Hours()); + hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + minuteCounter.Create(); + lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + minuteCounter.SetValue(infiniSleepController.Minutes()); + minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_label_set_text_static(colonLabel, ":"); + lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); + + btnStop = lv_btn_create(lv_scr_act(), nullptr); + btnStop->user_data = this; + lv_obj_set_event_cb(btnStop, btnEventHandler); + lv_obj_set_size(btnStop, 115, 50); + lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + txtStop = lv_label_create(btnStop, nullptr); + lv_label_set_text_static(txtStop, Symbols::stop); + lv_obj_set_hidden(btnStop, true); + + static constexpr lv_color_t bgColor = Colors::bgAlt; + + btnRecur = lv_btn_create(lv_scr_act(), nullptr); + btnRecur->user_data = this; + lv_obj_set_event_cb(btnRecur, btnEventHandler); + lv_obj_set_size(btnRecur, 115, 50); + lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + txtRecur = lv_label_create(btnRecur, nullptr); + SetRecurButtonState(); + lv_obj_set_style_local_bg_color(btnRecur, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); + + btnInfo = lv_btn_create(lv_scr_act(), nullptr); + btnInfo->user_data = this; + lv_obj_set_event_cb(btnInfo, btnEventHandler); + lv_obj_set_size(btnInfo, 50, 50); + lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, -4); + lv_obj_set_style_local_bg_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); + lv_obj_set_style_local_border_width(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 4); + lv_obj_set_style_local_border_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + + lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); + lv_label_set_text_static(txtInfo, "i"); + + enableSwitch = lv_switch_create(lv_scr_act(), nullptr); + enableSwitch->user_data = this; + lv_obj_set_event_cb(enableSwitch, btnEventHandler); + lv_obj_set_size(enableSwitch, 100, 50); + // Align to the center of 115px from edge + lv_obj_align(enableSwitch, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 7, 0); + lv_obj_set_style_local_bg_color(enableSwitch, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, bgColor); + + UpdateWakeAlarmTime(); + + if (infiniSleepController.IsAlerting()) { + SetAlerting(); + } else { + SetSwitchState(LV_ANIM_OFF); + } } -Sleep::Sleep(Controllers::HeartRateController& heartRateController, Controllers::DateTime& dateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask) - : heartRateController {heartRateController}, dateTimeController {dateTimeController}, fsController {fsController}, wakeLock(systemTask) { +Sleep::~Sleep() { + if (infiniSleepController.IsAlerting()) { + StopAlerting(); + } + lv_obj_clean(lv_scr_act()); + infiniSleepController.SaveWakeAlarm(); +} - wakeLock.Lock(); +void Sleep::DisableWakeAlarm() { + if (infiniSleepController.IsEnabled()) { + infiniSleepController.DisableWakeAlarm(); + lv_switch_off(enableSwitch, LV_ANIM_ON); + } +} - constexpr uint8_t btnWidth = 115; - constexpr uint8_t btnHeight = 45; - - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Sleep Tracker"); - lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); - lv_obj_align(title, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); - - label_hr = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - - // Create the refresh task - mainRefreshTask = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); - hrRefreshTask = lv_task_create(BpmDataCallback, 3000, LV_TASK_PRIO_MID, this); - - // Create the clear data button - lv_obj_t* btnClear = lv_btn_create(lv_scr_act(), nullptr); - btnClear->user_data = this; - lv_obj_set_event_cb(btnClear, ClearDataCallback); - lv_obj_set_size(btnClear, btnWidth, btnHeight); - lv_obj_align(btnClear, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); - lv_obj_t* txtClear = lv_label_create(btnClear, nullptr); - lv_label_set_text(txtClear, "X"); - - // Create the get info button - // lv_obj_t* btnInfo = lv_btn_create(lv_scr_act(), nullptr); - // btnInfo->user_data = this; - // lv_obj_set_event_cb(btnInfo, GetSleepInfoCallback); - // lv_obj_set_size(btnInfo, btnWidth, btnHeight); - // lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - // lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); - // lv_label_set_text(txtInfo, "?"); - - // const auto data = ReadDataCSV("SleepTracker_Data.csv"); - // for (const auto& entry : data) { - // int hours, minutes, seconds, bpm, motion; - // std::tie(hours, minutes, seconds, bpm, motion) = entry; - // NRF_LOG_INFO("Read data: %02d:%02d:%02d, %d, %d", hours, minutes, seconds, bpm, motion); - // } - // NRF_LOG_INFO("-------------------------------"); +void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + if (obj == btnStop) { + StopAlerting(); + return; + } + if (obj == btnInfo) { + ShowAlarmInfo(); + return; + } + if (obj == btnMessage) { + HideAlarmInfo(); + return; + } + if (obj == enableSwitch) { + if (lv_switch_get_state(enableSwitch)) { + infiniSleepController.ScheduleWakeAlarm(); + } else { + infiniSleepController.DisableWakeAlarm(); + } + return; + } + if (obj == btnRecur) { + DisableWakeAlarm(); + ToggleRecurrence(); + } + } } -Sleep::~Sleep() { - wakeLock.Release(); +bool Sleep::OnButtonPushed() { + if (txtMessage != nullptr && btnMessage != nullptr) { + HideAlarmInfo(); + return true; + } + if (infiniSleepController.IsAlerting()) { + StopAlerting(); + return true; + } + return false; +} - lv_obj_clean(lv_scr_act()); - lv_task_del(mainRefreshTask); - lv_task_del(hrRefreshTask); +bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + // Don't allow closing the screen by swiping while the alarm is alerting + return infiniSleepController.IsAlerting() && event == TouchEvents::SwipeDown; } -// This function is called periodically from the refresh task -void Sleep::Refresh() { - // Get the current heart rate +void Sleep::OnValueChanged() { + DisableWakeAlarm(); + UpdateWakeAlarmTime(); } -// Convert time to minutes -float Sleep::ConvertToMinutes(int hours, int minutes, int seconds) const { - return hours * 60 + minutes + seconds / 60.0f; +void Sleep::UpdateWakeAlarmTime() { + if (lblampm != nullptr) { + if (hourCounter.GetValue() >= 12) { + lv_label_set_text_static(lblampm, "PM"); + } else { + lv_label_set_text_static(lblampm, "AM"); + } + } + infiniSleepController.SetWakeAlarmTime(hourCounter.GetValue(), minuteCounter.GetValue()); } -// Get the moving average of BPM Values -// std::vector Sleep::MovingAverage(const std::vector& bpmData, int windowSize) const { -// std::vector smoothedBpm; -// const int n = bpmData.size(); - -// for (int i = 0; i < n - windowSize + 1; ++i) { -// float sum = 0; -// for (int j = 0; j < windowSize; ++j) { -// sum += bpmData[i + j]; -// } -// smoothedBpm.push_back(sum / windowSize); -// } - -// return smoothedBpm; -// } - -// Detect the sleep regions -// std::vector> Sleep::DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const { -// std::vector> sleep_regions; -// float start_time = -1; -// bool in_sleep = false; - -// for (size_t i = 0; i < bpmData.size(); ++i) { -// if (bpmData[i] < threshold) { -// if (!in_sleep) { -// start_time = time[i]; // Mark the start of sleep -// in_sleep = true; -// } -// } else { -// if (in_sleep) { -// float end_time = time[i]; // Mark the end of sleep -// sleep_regions.emplace_back(start_time, end_time); -// in_sleep = false; -// } -// } -// } - -// // In case the last region extends to the end of the data -// if (in_sleep) { -// sleep_regions.emplace_back(start_time, time.back()); -// } - -// return sleep_regions; -// } - -// // Get Sleep Info -// void Sleep::GetSleepInfo(const std::vector>& data) const { -// std::vector time; -// std::vector bpm; - -// // Extract the time (in minutes) and bpm from the data -// for (const auto& entry : data) { -// int hours, minutes, seconds, bpm_value, motion; -// std::tie(hours, minutes, seconds, bpm_value, motion) = entry; -// time.push_back(ConvertToMinutes(hours, minutes, seconds)); -// bpm.push_back(bpm_value); -// } - -// // Compute the moving average with a window size of 5 (15 minutes smoothing, since each data point is 3 minutes) -// const auto smoothed_bpm = MovingAverage(bpm, 5); - -// // Calculate a threshold as 80% of the average BPM -// const float average_bpm = std::accumulate(bpm.begin(), bpm.end(), 0.0f) / bpm.size(); -// const float threshold = average_bpm * 0.8f; - -// // Detect multiple sleep regions -// const auto sleep_regions = DetectSleepRegions(smoothed_bpm, time, threshold); - -// // Output sleep regions -// if (!sleep_regions.empty()) { -// for (const auto& region : sleep_regions) { -// NRF_LOG_INFO("Sleep detected from %.2f minutes to %.2f minutes.", region.first, region.second); -// } -// } else { -// NRF_LOG_INFO("No significant sleep regions detected."); -// } - -// // Open the output file -// lfs_file_t file; -// int err = fsController.FileOpen(&file, "SleepTracker_SleepInfo.csv", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC); -// if (err < 0) { -// // Handle error -// NRF_LOG_INFO("Error opening file: %d", err); -// return; -// } - -// // Write sleep regions to the file -// if (!sleep_regions.empty()) { -// for (const auto& region : sleep_regions) { -// char buffer[64]; -// int len = snprintf(buffer, sizeof(buffer), "Sleep detected from %.2f minutes to %.2f minutes.\n", region.first, region.second); -// err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); -// if (err < 0) { -// // Handle error -// NRF_LOG_INFO("Error writing to file: %d", err); -// fsController.FileClose(&file); -// return; -// } -// } -// } else { -// const char* noSleepMsg = "No significant sleep regions detected.\n"; -// err = fsController.FileWrite(&file, reinterpret_cast(noSleepMsg), strlen(noSleepMsg)); -// if (err < 0) { -// // Handle error -// NRF_LOG_INFO("Error writing to file: %d", err); -// fsController.FileClose(&file); -// return; -// } -// } - -// // Close the file -// fsController.FileClose(&file); -// NRF_LOG_INFO("Sleep info written to SleepTracker_SleepInfo.csv"); -// } - -void Sleep::GetBPM() { - // Get the heart rate from the controller - prevBpm = bpm; - bpm = heartRateController.HeartRate(); - - if(prevBpm != 0) - rollingBpm = (rollingBpm + bpm) / 2; - else - rollingBpm = bpm; - - // Get the current time from DateTimeController - int hours = dateTimeController.Hours(); - int minutes = dateTimeController.Minutes(); - int seconds = dateTimeController.Seconds(); - - // Log the BPM and current time - NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); - - // Write data to CSV - const int motion = 0; // Placeholder for motion data - std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; - WriteDataCSV("SleepTracker_Data.csv", data, 1); +void Sleep::SetAlerting() { + lv_obj_set_hidden(enableSwitch, true); + lv_obj_set_hidden(btnStop, false); + taskStopWakeAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); + motorController.StartRinging(); + wakeLock.Lock(); } -// File IO Stuff - -/* -* Write data to a CSV file -* Format: Time,BPM,Motion -*/ -void Sleep::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { - lfs_file_t file; - int err = fsController.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error opening file: %d", err); - return; +void Sleep::StopAlerting() { + infiniSleepController.StopAlerting(); + motorController.StopRinging(); + SetSwitchState(LV_ANIM_OFF); + if (taskStopWakeAlarm != nullptr) { + lv_task_del(taskStopWakeAlarm); + taskStopWakeAlarm = nullptr; } + wakeLock.Release(); + lv_obj_set_hidden(enableSwitch, false); + lv_obj_set_hidden(btnStop, true); +} - for (int i = 0; i < dataSize; ++i) { - int hours, minutes, seconds, bpm, motion; - std::tie(hours, minutes, seconds, bpm, motion) = data[i]; - char buffer[64]; - int len = snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d,%d,%d\n", hours, minutes, seconds, bpm, motion); - err = fsController.FileWrite(&file, reinterpret_cast(buffer), len); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error writing to file: %d", err); - fsController.FileClose(&file); +void Sleep::SetSwitchState(lv_anim_enable_t anim) { + if (infiniSleepController.IsEnabled()) { + lv_switch_on(enableSwitch, anim); + } else { + lv_switch_off(enableSwitch, anim); + } +} - return; - } +void Sleep::ShowAlarmInfo() { + if (btnMessage != nullptr) { + return; + } + btnMessage = lv_btn_create(lv_scr_act(), nullptr); + btnMessage->user_data = this; + lv_obj_set_event_cb(btnMessage, btnEventHandler); + lv_obj_set_height(btnMessage, 200); + lv_obj_set_width(btnMessage, 150); + lv_obj_align(btnMessage, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + txtMessage = lv_label_create(btnMessage, nullptr); + lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY); + + if (infiniSleepController.IsEnabled()) { + auto timeToAlarm = infiniSleepController.SecondsToWakeAlarm(); + + auto daysToAlarm = timeToAlarm / 86400; + auto hrsToAlarm = (timeToAlarm % 86400) / 3600; + auto minToAlarm = (timeToAlarm % 3600) / 60; + auto secToAlarm = timeToAlarm % 60; + + lv_label_set_text_fmt(txtMessage, + "Time to\nalarm:\n%2lu Days\n%2lu Hours\n%2lu Minutes\n%2lu Seconds", + daysToAlarm, + hrsToAlarm, + minToAlarm, + secToAlarm); + } else { + lv_label_set_text_static(txtMessage, "Alarm\nis not\nset."); } +} - fsController.FileClose(&file); +void Sleep::HideAlarmInfo() { + lv_obj_del(btnMessage); + txtMessage = nullptr; + btnMessage = nullptr; } -// Read data from CSV -// std::vector> Sleep::ReadDataCSV(const char* filename) const { -// lfs_file_t file; -// int err = fsController.FileOpen(&file, filename, LFS_O_RDONLY); -// if (err < 0) { -// // Handle error -// NRF_LOG_INFO("Error opening file: %d", err); -// return {}; -// } - -// std::vector> data; -// char buffer[128]; -// int bytesRead; - -// // Read data -// while ((bytesRead = fsController.FileRead(&file, reinterpret_cast(buffer), sizeof(buffer))) > 0) { -// std::istringstream dataStream(buffer); -// std::string line; -// while (std::getline(dataStream, line)) { -// int hours, minutes, seconds, bpm, motion; -// char colon1, colon2, comma1, comma2; -// std::istringstream lineStream(line); -// if (lineStream >> hours >> colon1 >> minutes >> colon2 >> seconds >> comma1 >> bpm >> comma2 >> motion) { -// if (colon1 == ':' && colon2 == ':' && comma1 == ',' && comma2 == ',') { -// data.emplace_back(hours, minutes, seconds, bpm, motion); -// } else { -// NRF_LOG_INFO("Parsing error: incorrect format in line: %s", line.c_str()); -// } -// } else { -// NRF_LOG_INFO("Parsing error: failed to parse line: %s", line.c_str()); -// } -// } -// } - -// fsController.FileClose(&file); -// return data; -// } - -// Clear data in CSV -void Sleep::ClearDataCSV(const char* filename) const { - lfs_file_t file; - int err = fsController.FileOpen(&file, filename, LFS_O_WRONLY | LFS_O_TRUNC); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error opening file: %d", err); - return; +void Sleep::SetRecurButtonState() { + using Pinetime::Controllers::AlarmController; + switch (infiniSleepController.Recurrence()) { + case InfiniSleepController::RecurType::None: + lv_label_set_text_static(txtRecur, "ONCE"); + break; + case InfiniSleepController::RecurType::Daily: + lv_label_set_text_static(txtRecur, "DAILY"); + break; + case InfiniSleepController::RecurType::Weekdays: + lv_label_set_text_static(txtRecur, "MON-FRI"); } +} - fsController.FileClose(&file); - NRF_LOG_INFO("CSV data cleared"); +void Sleep::ToggleRecurrence() { + using Pinetime::Controllers::AlarmController; + switch (infiniSleepController.Recurrence()) { + case InfiniSleepController::RecurType::None: + infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Daily); + break; + case InfiniSleepController::RecurType::Daily: + infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Weekdays); + break; + case InfiniSleepController::RecurType::Weekdays: + infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); + } + SetRecurButtonState(); } \ No newline at end of file diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index c4d4dba5b2..b115efa8f7 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -1,7 +1,9 @@ #pragma once #include "displayapp/apps/Apps.h" +#include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" +#include "displayapp/widgets/Counter.h" #include "displayapp/Controllers.h" #include "systemtask/SystemTask.h" #include "systemtask/WakeLock.h" @@ -16,17 +18,24 @@ namespace Pinetime { namespace Screens { class Sleep : public Screen { public: - Sleep(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask); + //explicit Sleep(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask); + explicit Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, Controllers::MotorController& motorController); ~Sleep() override; + void SetAlerting(); + void OnButtonEvent(lv_obj_t* obj, lv_event_t event); + bool OnButtonPushed() override; + bool OnTouchEvent(TouchEvents event) override; + void OnValueChanged(); + void StopAlerting(); - void Refresh() override; + // void Refresh() override; - void GetBPM(); + // void GetBPM(); - void ClearDataCSV(const char* filename) const; + // void ClearDataCSV(const char* filename) const; - // Data Processing functions - float ConvertToMinutes(int hours, int minutes, int seconds) const; + // // Data Processing functions + // float ConvertToMinutes(int hours, int minutes, int seconds) const; // Get the moving average of BPM Values //std::vector MovingAverage(const std::vector& bpm, int windowSize) const; // Detect the sleep regions @@ -38,22 +47,44 @@ namespace Pinetime { //std::vector> ReadDataCSV(const char* fileName) const; private: - Controllers::HeartRateController& heartRateController; - Controllers::DateTime& dateTimeController; - Controllers::FS& fsController; - Pinetime::System::WakeLock wakeLock; + Controllers::InfiniSleepController& infiniSleepController; + System::WakeLock wakeLock; + Controllers::MotorController& motorController; - // For File IO - void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; + lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch; + lv_obj_t* lblampm = nullptr; + lv_obj_t* txtMessage = nullptr; + lv_obj_t* btnMessage = nullptr; + lv_task_t* taskStopWakeAlarm = nullptr; - int bpm = 0; - int prevBpm = 0; - int rollingBpm = 0; + enum class EnableButtonState { On, Off, Alerting }; + void DisableWakeAlarm(); + void SetRecurButtonState(); + void SetSwitchState(lv_anim_enable_t anim); + void SetWakeAlarm(); + void ShowAlarmInfo(); + void HideAlarmInfo(); + void ToggleRecurrence(); + void UpdateWakeAlarmTime(); + Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76); + Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); - lv_obj_t* label_hr; + // Controllers::HeartRateController& heartRateController; + // Controllers::DateTime& dateTimeController; + // Controllers::FS& fsController; + // Pinetime::System::WakeLock wakeLock; - lv_task_t* mainRefreshTask; - lv_task_t* hrRefreshTask; + // // For File IO + // void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; + + // int bpm = 0; + // int prevBpm = 0; + // int rollingBpm = 0; + + // lv_obj_t* label_hr; + + // lv_task_t* mainRefreshTask; + // lv_task_t* hrRefreshTask; }; } @@ -62,7 +93,8 @@ namespace Pinetime { static constexpr Apps app = Apps::Sleep; static constexpr const char* icon = Screens::Symbols::bed; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Sleep(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, *controllers.systemTask); + //return new Screens::Sleep(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, *controllers.systemTask); + return new Screens::Sleep(controllers.infiniSleepController, controllers.settingsController.GetClockType(), *controllers.systemTask, controllers.motorController); } }; } diff --git a/src/main.cpp b/src/main.cpp index 14a3dba8bb..c588211bd7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -126,7 +126,8 @@ Pinetime::Applications::DisplayApp displayApp(lcd, brightnessController, touchHandler, fs, - spiNorFlash); + spiNorFlash, + infiniSleepController); Pinetime::System::SystemTask systemTask(spi, spiNorFlash, diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 4ad20e5c30..6ceb17d6ec 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -223,6 +223,8 @@ void SystemTask::Work() { break; case Messages::SetOffWakeAlarm: // Code the screen trigger here + GoToRunning(); + displayApp.PushMessage(Pinetime::Applications::Display::Messages::WakeAlarmTriggered); break; case Messages::BleConnected: displayApp.PushMessage(Pinetime::Applications::Display::Messages::NotifyDeviceActivity); From a14ced04302678a0e5670bbde87b38e64f8ca740 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 29 Oct 2024 13:55:24 -0500 Subject: [PATCH 014/191] updated log messages --- src/components/infinisleep/InfiniSleepController.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 17e2ba9a79..e3f680ff12 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -131,21 +131,21 @@ void InfiniSleepController::LoadSettingsFromFile() { WakeAlarmSettings wakeAlarmBuffer; if (fs.FileOpen(&wakeAlarmFile, "/.system/sleep/wakeAlarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) { - NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file"); + NRF_LOG_WARNING("[InfiniSleepController] Failed to open alarm data file"); return; } fs.FileRead(&wakeAlarmFile, reinterpret_cast(&wakeAlarmBuffer), sizeof(wakeAlarmBuffer)); fs.FileClose(&wakeAlarmFile); if (wakeAlarmBuffer.version != wakeAlarmFormatVersion) { - NRF_LOG_WARNING("[AlarmController] Loaded alarm settings has version %u instead of %u, discarding", + NRF_LOG_WARNING("[InfiniSleepController] Loaded alarm settings has version %u instead of %u, discarding", wakeAlarmBuffer.version, wakeAlarmFormatVersion); return; } wakeAlarm = wakeAlarmBuffer; - NRF_LOG_INFO("[AlarmController] Loaded alarm settings from file"); + NRF_LOG_INFO("[InfiniSleepController] Loaded alarm settings from file"); } void InfiniSleepController::SaveSettingsToFile() const { @@ -156,11 +156,11 @@ void InfiniSleepController::SaveSettingsToFile() const { fs.DirClose(&systemDir); lfs_file_t alarmFile; if (fs.FileOpen(&alarmFile, "/.system/sleep/wakeAlarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { - NRF_LOG_WARNING("[AlarmController] Failed to open alarm data file for saving"); + NRF_LOG_WARNING("[InfiniSleepController] Failed to open alarm data file for saving"); return; } fs.FileWrite(&alarmFile, reinterpret_cast(&wakeAlarm), sizeof(wakeAlarm)); fs.FileClose(&alarmFile); - NRF_LOG_INFO("[AlarmController] Saved alarm settings with format version %u to file", wakeAlarm.version); + NRF_LOG_INFO("[InfiniSleepController] Saved alarm settings with format version %u to file", wakeAlarm.version); } \ No newline at end of file From b5dfc6c4cc4d5c28e66995356bc547d070fbe791 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 29 Oct 2024 14:29:24 -0500 Subject: [PATCH 015/191] Started working on screen states --- src/displayapp/screens/Sleep.cpp | 23 +++++++++++++++++++++-- src/displayapp/screens/Sleep.h | 3 +++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 0b3321abb6..aaf882d674 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -7,6 +7,8 @@ #include "components/motor/MotorController.h" #include "systemtask/SystemTask.h" +#include + using namespace Pinetime::Applications::Screens; using Pinetime::Controllers::InfiniSleepController; @@ -164,6 +166,23 @@ bool Sleep::OnButtonPushed() { } bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + + // The cases for swiping to change page on app + switch (event) { + case TouchEvents::SwipeLeft: + if (displayState != SleepDisplayState::Alarm) { + displayState = static_cast(static_cast(displayState) - 1); + } + NRF_LOG_INFO("SwipeLeft: %d", static_cast(displayState)); + return true; + case TouchEvents::SwipeRight: + if (displayState != SleepDisplayState::Settings) { + displayState = static_cast(static_cast(displayState) + 1); + } + NRF_LOG_INFO("SwipeRight: %d", static_cast(displayState)); + return true; + } + // Don't allow closing the screen by swiping while the alarm is alerting return infiniSleepController.IsAlerting() && event == TouchEvents::SwipeDown; } @@ -252,7 +271,7 @@ void Sleep::HideAlarmInfo() { } void Sleep::SetRecurButtonState() { - using Pinetime::Controllers::AlarmController; + using Pinetime::Controllers::InfiniSleepController; switch (infiniSleepController.Recurrence()) { case InfiniSleepController::RecurType::None: lv_label_set_text_static(txtRecur, "ONCE"); @@ -266,7 +285,7 @@ void Sleep::SetRecurButtonState() { } void Sleep::ToggleRecurrence() { - using Pinetime::Controllers::AlarmController; + using Pinetime::Controllers::InfiniSleepController; switch (infiniSleepController.Recurrence()) { case InfiniSleepController::RecurType::None: infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Daily); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index b115efa8f7..81f6dc45c3 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -27,6 +27,9 @@ namespace Pinetime { bool OnTouchEvent(TouchEvents event) override; void OnValueChanged(); void StopAlerting(); + + enum class SleepDisplayState { Alarm, Info, Settings }; + SleepDisplayState displayState = SleepDisplayState::Alarm; // void Refresh() override; From 69611aec1473a2ee5d1d1d3c2f2964dbc024bf6e Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 29 Oct 2024 14:47:01 -0500 Subject: [PATCH 016/191] Implemented Alarm page Function --- src/displayapp/screens/Sleep.cpp | 55 +++++++++++++++++++++++++------- src/displayapp/screens/Sleep.h | 7 +++- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index aaf882d674..644c1a11ed 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -33,8 +33,44 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, Controllers::MotorController& motorController) - : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController} { + : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController}, clockType {clockType} { + UpdateDisplay(); +} + +Sleep::~Sleep() { + if (infiniSleepController.IsAlerting()) { + StopAlerting(); + } + lv_obj_clean(lv_scr_act()); + infiniSleepController.SaveWakeAlarm(); +} + +void Sleep::DisableWakeAlarm() { + if (infiniSleepController.IsEnabled()) { + infiniSleepController.DisableWakeAlarm(); + lv_switch_off(enableSwitch, LV_ANIM_ON); + } +} + +void Sleep::UpdateDisplay() { + // Clear the screen + lv_obj_clean(lv_scr_act()); + // Draw the screen + switch (displayState) { + case SleepDisplayState::Alarm: + DrawAlarmScreen(); + break; + case SleepDisplayState::Info: + DrawInfoScreen(); + break; + case SleepDisplayState::Settings: + DrawSettingsScreen(); + break; + } +} + +void Sleep::DrawAlarmScreen() { hourCounter.Create(); lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); if (clockType == Controllers::Settings::ClockType::H12) { @@ -109,19 +145,12 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, } } -Sleep::~Sleep() { - if (infiniSleepController.IsAlerting()) { - StopAlerting(); - } - lv_obj_clean(lv_scr_act()); - infiniSleepController.SaveWakeAlarm(); +void Sleep::DrawInfoScreen() { + } -void Sleep::DisableWakeAlarm() { - if (infiniSleepController.IsEnabled()) { - infiniSleepController.DisableWakeAlarm(); - lv_switch_off(enableSwitch, LV_ANIM_ON); - } +void Sleep::DrawSettingsScreen() { + } void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { @@ -172,12 +201,14 @@ bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { case TouchEvents::SwipeLeft: if (displayState != SleepDisplayState::Alarm) { displayState = static_cast(static_cast(displayState) - 1); + UpdateDisplay(); } NRF_LOG_INFO("SwipeLeft: %d", static_cast(displayState)); return true; case TouchEvents::SwipeRight: if (displayState != SleepDisplayState::Settings) { displayState = static_cast(static_cast(displayState) + 1); + UpdateDisplay(); } NRF_LOG_INFO("SwipeRight: %d", static_cast(displayState)); return true; diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 81f6dc45c3..454ff79895 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -27,7 +27,7 @@ namespace Pinetime { bool OnTouchEvent(TouchEvents event) override; void OnValueChanged(); void StopAlerting(); - + void UpdateDisplay(); enum class SleepDisplayState { Alarm, Info, Settings }; SleepDisplayState displayState = SleepDisplayState::Alarm; @@ -53,6 +53,7 @@ namespace Pinetime { Controllers::InfiniSleepController& infiniSleepController; System::WakeLock wakeLock; Controllers::MotorController& motorController; + Controllers::Settings::ClockType clockType; lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch; lv_obj_t* lblampm = nullptr; @@ -72,6 +73,10 @@ namespace Pinetime { Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76); Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); + void DrawAlarmScreen(); + void DrawInfoScreen(); + void DrawSettingsScreen(); + // Controllers::HeartRateController& heartRateController; // Controllers::DateTime& dateTimeController; // Controllers::FS& fsController; From 65750b5c29c5cc377a0366e03818dbd41f4fb861 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 29 Oct 2024 15:18:49 -0500 Subject: [PATCH 017/191] Started Framework for settings page --- src/displayapp/screens/Sleep.cpp | 36 +++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 644c1a11ed..b2a7368307 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -146,11 +146,45 @@ void Sleep::DrawAlarmScreen() { } void Sleep::DrawInfoScreen() { - + lv_obj_t* lblInfo = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblInfo, "InfiniTime\nSleep\nApp"); + lv_obj_align(lblInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); } void Sleep::DrawSettingsScreen() { + lv_obj_t* lblSettings = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblSettings, "Settings"); + lv_obj_align(lblSettings, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 10); + + struct Setting { + const char* name; + bool enabled; + int offsetAfter = 30; + }; + + Setting settings[] = { + {"Body Tracking", false}, + {"Heart Rate\nTracking", false, 60}, + {"Gradual Wake", false}, + {"Smart Alarm\n(alpha)", false} + }; + + int y_offset = 50; + for (const auto& setting : settings) { + lv_obj_t* lblSetting = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblSetting, setting.name); + lv_obj_align(lblSetting, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + + lv_obj_t* toggle = lv_switch_create(lv_scr_act(), nullptr); + if (setting.enabled) { + lv_switch_on(toggle, LV_ANIM_OFF); + } else { + lv_switch_off(toggle, LV_ANIM_OFF); + } + lv_obj_align(toggle, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -10, y_offset); + y_offset += setting.offsetAfter; // Increase the offset to provide better spacing + } } void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { From 8325fdca59581f3dd0247152dae429be3bd07c22 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 30 Oct 2024 13:25:43 -0500 Subject: [PATCH 018/191] Made a sleep tracker settings struct in controller and made settings page save to variables --- .../infinisleep/InfiniSleepController.h | 42 +++++++++++++++++++ src/displayapp/screens/Sleep.cpp | 31 ++++++++++++-- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 2864a1659f..7dd1811d5d 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -47,6 +47,38 @@ namespace Pinetime { void SetRecurrence(RecurType recurrence); + bool BodyTrackingEnabled() const { + return infiniSleepSettings.bodyTracking; + } + + void SetBodyTrackingEnabled(bool enabled) { + infiniSleepSettings.bodyTracking = enabled; + } + + bool HeartRateTrackingEnabled() const { + return infiniSleepSettings.heartRateTracking; + } + + void SetHeartRateTrackingEnabled(bool enabled) { + infiniSleepSettings.heartRateTracking = enabled; + } + + bool GradualWakeEnabled() const { + return infiniSleepSettings.graddualWake; + } + + void SetGradualWakeEnabled(bool enabled) { + infiniSleepSettings.graddualWake = enabled; + } + + bool SmartAlarmEnabled() const { + return infiniSleepSettings.smartAlarm; + } + + void SetSmartAlarmEnabled(bool enabled) { + infiniSleepSettings.smartAlarm = enabled; + } + private: // Versions 255 is reserved for now, so the version field can be made // bigger, should it ever be needed. @@ -60,8 +92,18 @@ namespace Pinetime { bool isEnabled = false; }; + struct InfiniSleepSettings { + bool bodyTracking = false; + bool heartRateTracking = true; + bool graddualWake = false; + bool smartAlarm = false; + }; + bool isAlerting = false; bool wakeAlarmChanged = false; + bool isEnabled = false; + + InfiniSleepSettings infiniSleepSettings; Controllers::DateTime& dateTimeController; Controllers::FS& fs; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index b2a7368307..019b2d4820 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -8,6 +8,7 @@ #include "systemtask/SystemTask.h" #include +#include using namespace Pinetime::Applications::Screens; using Pinetime::Controllers::InfiniSleepController; @@ -19,6 +20,25 @@ namespace { } } +extern InfiniSleepController infiniSleepController; + +static void settingsToggleEventHandler(lv_obj_t* obj, lv_event_t e) { + lv_obj_t* toggle = obj; + const char* setting_name = static_cast(obj->user_data); + + bool enabled = lv_switch_get_state(toggle); + + if (strcmp(setting_name, "Body Tracking") == 0) { + infiniSleepController.SetBodyTrackingEnabled(enabled); + } else if (strcmp(setting_name, "Heart Rate\nTracking") == 0) { + infiniSleepController.SetHeartRateTrackingEnabled(enabled); + } else if (strcmp(setting_name, "Gradual Wake") == 0) { + infiniSleepController.SetGradualWakeEnabled(enabled); + } else if (strcmp(setting_name, "Smart Alarm\n(alpha)") == 0) { + infiniSleepController.SetSmartAlarmEnabled(enabled); + } + } + static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { auto* screen = static_cast(obj->user_data); screen->OnButtonEvent(obj, event); @@ -163,10 +183,10 @@ void Sleep::DrawSettingsScreen() { }; Setting settings[] = { - {"Body Tracking", false}, - {"Heart Rate\nTracking", false, 60}, - {"Gradual Wake", false}, - {"Smart Alarm\n(alpha)", false} + {"Body Tracking", infiniSleepController.BodyTrackingEnabled()}, + {"Heart Rate\nTracking", infiniSleepController.HeartRateTrackingEnabled(), 60}, + {"Gradual Wake", infiniSleepController.GradualWakeEnabled()}, + {"Smart Alarm\n(alpha)", infiniSleepController.SmartAlarmEnabled()} }; int y_offset = 50; @@ -176,6 +196,7 @@ void Sleep::DrawSettingsScreen() { lv_obj_align(lblSetting, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); lv_obj_t* toggle = lv_switch_create(lv_scr_act(), nullptr); + toggle->user_data = const_cast(setting.name); if (setting.enabled) { lv_switch_on(toggle, LV_ANIM_OFF); } else { @@ -183,6 +204,8 @@ void Sleep::DrawSettingsScreen() { } lv_obj_align(toggle, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -10, y_offset); + lv_obj_set_event_cb(toggle, settingsToggleEventHandler); + y_offset += setting.offsetAfter; // Increase the offset to provide better spacing } } From 703a6a5da480b48a48071d510d0c33be7b4f6b99 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 30 Oct 2024 13:40:39 -0500 Subject: [PATCH 019/191] Updated toggleEventHandler to check event type --- src/displayapp/screens/Sleep.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 019b2d4820..45981e4141 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -23,9 +23,12 @@ namespace { extern InfiniSleepController infiniSleepController; static void settingsToggleEventHandler(lv_obj_t* obj, lv_event_t e) { + if (e != LV_EVENT_VALUE_CHANGED) { + return; + } lv_obj_t* toggle = obj; const char* setting_name = static_cast(obj->user_data); - + bool enabled = lv_switch_get_state(toggle); if (strcmp(setting_name, "Body Tracking") == 0) { @@ -269,6 +272,8 @@ bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } NRF_LOG_INFO("SwipeRight: %d", static_cast(displayState)); return true; + default: + break; } // Don't allow closing the screen by swiping while the alarm is alerting From 6981d777168e2ea7c50d7245982b9e8ca4645642 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 30 Oct 2024 21:10:33 -0500 Subject: [PATCH 020/191] added saving and reading of InfiniSleepSettings --- .../infinisleep/InfiniSleepController.cpp | 32 +++++++++++++++++++ .../infinisleep/InfiniSleepController.h | 9 +++++- src/displayapp/screens/Sleep.cpp | 5 +++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index e3f680ff12..781c0a102c 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -36,6 +36,14 @@ void InfiniSleepController::SaveWakeAlarm() { wakeAlarmChanged = false; } +void InfiniSleepController::SaveInfiniSleepSettings() { + // verify is save needed + if (settingsChanged) { + SaveSettingsToFile(); + } + settingsChanged = false; +} + void InfiniSleepController::SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin) { if (wakeAlarm.hours == wakeAlarmHr && wakeAlarm.minutes == wakeAlarmMin) { return; @@ -146,6 +154,20 @@ void InfiniSleepController::LoadSettingsFromFile() { wakeAlarm = wakeAlarmBuffer; NRF_LOG_INFO("[InfiniSleepController] Loaded alarm settings from file"); + + lfs_file_t infiniSleepSettingsFile; + InfiniSleepSettings infiniSleepSettingsBuffer; + + if (fs.FileOpen(&infiniSleepSettingsFile, "/.system/sleep/infiniSleepSettings.dat", LFS_O_RDONLY) != LFS_ERR_OK) { + NRF_LOG_WARNING("[InfiniSleepController] Failed to open InfiniSleep settings file"); + return; + } + + fs.FileRead(&infiniSleepSettingsFile, reinterpret_cast(&infiniSleepSettingsBuffer), sizeof(infiniSleepSettingsBuffer)); + fs.FileClose(&infiniSleepSettingsFile); + + infiniSleepSettings = infiniSleepSettingsBuffer; + NRF_LOG_INFO("[InfiniSleepController] Loaded InfiniSleep settings from file"); } void InfiniSleepController::SaveSettingsToFile() const { @@ -163,4 +185,14 @@ void InfiniSleepController::SaveSettingsToFile() const { fs.FileWrite(&alarmFile, reinterpret_cast(&wakeAlarm), sizeof(wakeAlarm)); fs.FileClose(&alarmFile); NRF_LOG_INFO("[InfiniSleepController] Saved alarm settings with format version %u to file", wakeAlarm.version); + + lfs_file_t settingsFile; + if (fs.FileOpen(&settingsFile, "/.system/sleep/infiniSleepSettings.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { + NRF_LOG_WARNING("[InfiniSleepController] Failed to open InfiniSleep settings file for saving"); + return; + } + + fs.FileWrite(&settingsFile, reinterpret_cast(&infiniSleepSettings), sizeof(infiniSleepSettings)); + fs.FileClose(&settingsFile); + NRF_LOG_INFO("[InfiniSleepController] Saved InfiniSleep settings"); } \ No newline at end of file diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 7dd1811d5d..1e39cb1fae 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -17,6 +17,7 @@ namespace Pinetime { void Init(System::SystemTask* systemTask); void SaveWakeAlarm(); + void SaveInfiniSleepSettings(); void SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin); void ScheduleWakeAlarm(); void DisableWakeAlarm(); @@ -79,6 +80,10 @@ namespace Pinetime { infiniSleepSettings.smartAlarm = enabled; } + void SetSettingsChanged() { + settingsChanged = true; + } + private: // Versions 255 is reserved for now, so the version field can be made // bigger, should it ever be needed. @@ -90,7 +95,8 @@ namespace Pinetime { uint8_t minutes = 0; RecurType recurrence = RecurType::None; bool isEnabled = false; - }; + uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; + };; struct InfiniSleepSettings { bool bodyTracking = false; @@ -102,6 +108,7 @@ namespace Pinetime { bool isAlerting = false; bool wakeAlarmChanged = false; bool isEnabled = false; + bool settingsChanged = false; InfiniSleepSettings infiniSleepSettings; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 45981e4141..3483e80089 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -33,12 +33,16 @@ static void settingsToggleEventHandler(lv_obj_t* obj, lv_event_t e) { if (strcmp(setting_name, "Body Tracking") == 0) { infiniSleepController.SetBodyTrackingEnabled(enabled); + infiniSleepController.SetSettingsChanged(); } else if (strcmp(setting_name, "Heart Rate\nTracking") == 0) { infiniSleepController.SetHeartRateTrackingEnabled(enabled); + infiniSleepController.SetSettingsChanged(); } else if (strcmp(setting_name, "Gradual Wake") == 0) { infiniSleepController.SetGradualWakeEnabled(enabled); + infiniSleepController.SetSettingsChanged(); } else if (strcmp(setting_name, "Smart Alarm\n(alpha)") == 0) { infiniSleepController.SetSmartAlarmEnabled(enabled); + infiniSleepController.SetSettingsChanged(); } } @@ -67,6 +71,7 @@ Sleep::~Sleep() { } lv_obj_clean(lv_scr_act()); infiniSleepController.SaveWakeAlarm(); + infiniSleepController.SaveInfiniSleepSettings(); } void Sleep::DisableWakeAlarm() { From d4a1661177d7596827b77822e8f7ac848e3baa25 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 31 Oct 2024 00:40:29 -0500 Subject: [PATCH 021/191] Started working on gradual wake, but not being triggered right now. --- .../infinisleep/InfiniSleepController.cpp | 40 ++++++++++++++++++- .../infinisleep/InfiniSleepController.h | 23 +++++++++-- src/displayapp/DisplayApp.cpp | 10 +++++ src/displayapp/Messages.h | 1 + src/displayapp/screens/Sleep.cpp | 2 +- src/systemtask/Messages.h | 1 + src/systemtask/SystemTask.cpp | 4 ++ 7 files changed, 76 insertions(+), 5 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 781c0a102c..e3c43cf04b 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -16,11 +16,21 @@ namespace { auto* controller = static_cast(pvTimerGetTimerID(xTimer)); controller->SetOffWakeAlarmNow(); } + + void SetOffGradualWake(TimerHandle_t xTimer) { + auto* controller = static_cast(pvTimerGetTimerID(xTimer)); + if (controller->GetInfiniSleepSettings().graddualWake) { + return; + } + controller->SetOffGradualWakeNow(); + } } void InfiniSleepController::Init(System::SystemTask* systemTask) { this->systemTask = systemTask; wakeAlarmTimer = xTimerCreate("WakeAlarm", 1, pdFALSE, this, SetOffWakeAlarm); + gradualWakeTimer = xTimerCreate("GradualWake", 1, pdFALSE, this, SetOffGradualWake); + LoadSettingsFromFile(); if (wakeAlarm.isEnabled) { NRF_LOG_INFO("[InfiniSleepController] Loaded wake alarm was enabled, scheduling"); @@ -56,6 +66,9 @@ void InfiniSleepController::SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAl void InfiniSleepController::ScheduleWakeAlarm() { // Determine the next time the wake alarm needs to go off and set the timer xTimerStop(wakeAlarmTimer, 0); + xTimerStop(gradualWakeTimer, 0); + + gradualWakeStep = 2; auto now = dateTimeController.CurrentDateTime(); wakeAlarmTime = now; @@ -86,10 +99,22 @@ void InfiniSleepController::ScheduleWakeAlarm() { // now can convert back to a time_point wakeAlarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmWakeAlarmTime)); - auto secondsToWakeAlarm = std::chrono::duration_cast(wakeAlarmTime - now).count(); + secondsToWakeAlarm = std::chrono::duration_cast(wakeAlarmTime - now).count(); xTimerChangePeriod(wakeAlarmTimer, secondsToWakeAlarm * configTICK_RATE_HZ, 0); xTimerStart(wakeAlarmTimer, 0); + // make sure graudal wake steps are possible + while (gradualWakeStep > -1 && secondsToWakeAlarm <= wakeAlarm.gradualWakeSteps[gradualWakeStep]) { + gradualWakeStep--; + } + + // Calculate the period for the gradualWakeTimer + if (infiniSleepSettings.graddualWake && gradualWakeStep >= 0) { + int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) / (configTICK_RATE_HZ); + xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); + xTimerStart(gradualWakeTimer, 0); + } + if (!wakeAlarm.isEnabled) { wakeAlarm.isEnabled = true; wakeAlarmChanged = true; @@ -102,6 +127,8 @@ uint32_t InfiniSleepController::SecondsToWakeAlarm() const { void InfiniSleepController::DisableWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); + xTimerStop(gradualWakeTimer, 0); + gradualWakeStep = 9; isAlerting = false; if (wakeAlarm.isEnabled) { wakeAlarm.isEnabled = false; @@ -114,6 +141,17 @@ void InfiniSleepController::SetOffWakeAlarmNow() { systemTask->PushMessage(System::Messages::SetOffWakeAlarm); } +void InfiniSleepController::SetOffGradualWakeNow() { + //isGradualWakeAlerting = true; + systemTask->PushMessage(System::Messages::SetOffGradualWake); + // Calculate the period for the gradualWakeTimer + if (infiniSleepSettings.graddualWake && gradualWakeStep >= 0) { + int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) / (configTICK_RATE_HZ); + xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); + xTimerStart(gradualWakeTimer, 0); + } +} + void InfiniSleepController::StopAlerting() { isAlerting = false; // Disable the alarm unless it is recurring diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 1e39cb1fae..5613542227 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -5,6 +5,8 @@ #include #include "components/datetime/DateTimeController.h" +#include + namespace Pinetime { namespace System { class SystemTask; @@ -22,6 +24,7 @@ namespace Pinetime { void ScheduleWakeAlarm(); void DisableWakeAlarm(); void SetOffWakeAlarmNow(); + void SetOffGradualWakeNow(); uint32_t SecondsToWakeAlarm() const; void StopAlerting(); enum class RecurType { None, Daily, Weekdays }; @@ -84,7 +87,6 @@ namespace Pinetime { settingsChanged = true; } - private: // Versions 255 is reserved for now, so the version field can be made // bigger, should it ever be needed. static constexpr uint8_t wakeAlarmFormatVersion = 1; @@ -95,8 +97,12 @@ namespace Pinetime { uint8_t minutes = 0; RecurType recurrence = RecurType::None; bool isEnabled = false; - uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; - };; + uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds + }; + + WakeAlarmSettings GetWakeAlarm() const { + return wakeAlarm; + } struct InfiniSleepSettings { bool bodyTracking = false; @@ -105,7 +111,17 @@ namespace Pinetime { bool smartAlarm = false; }; + InfiniSleepSettings GetInfiniSleepSettings() const { + return infiniSleepSettings; + } + + int64_t secondsToWakeAlarm = 0; + + private: + bool isAlerting = false; + bool isGradualWakeAlerting = false; + uint8_t gradualWakeStep = 8; // used to keep track of which step to use bool wakeAlarmChanged = false; bool isEnabled = false; bool settingsChanged = false; @@ -116,6 +132,7 @@ namespace Pinetime { Controllers::FS& fs; System::SystemTask* systemTask = nullptr; TimerHandle_t wakeAlarmTimer; + TimerHandle_t gradualWakeTimer; WakeAlarmSettings wakeAlarm; std::chrono::time_point wakeAlarmTime; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 33cf838972..8b5ee02861 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -394,6 +394,16 @@ void DisplayApp::Refresh() { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } break; + case Messages::GradualWakeTriggered: + if (currentApp == Apps::Sleep) { + //auto* sleep = static_cast(currentScreen.get()); + //sleep->SetGradualWakeAlerting(); + } else { + LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); + } + motorController.RunForDuration(static_cast(3000)); + NRF_LOG_INFO("Gradual wake triggered"); + break; case Messages::ShowPairingKey: LoadNewScreen(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); motorController.RunForDuration(35); diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index fd112e7cb2..042fa15ec9 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -23,6 +23,7 @@ namespace Pinetime { ShowPairingKey, AlarmTriggered, WakeAlarmTriggered, + GradualWakeTriggered, Chime, BleRadioEnableToggle, OnChargingEvent, diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 3483e80089..e49ed4127e 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -323,7 +323,7 @@ void Sleep::StopAlerting() { } void Sleep::SetSwitchState(lv_anim_enable_t anim) { - if (infiniSleepController.IsEnabled()) { + if (infiniSleepController.GetWakeAlarm().isEnabled) { lv_switch_on(enableSwitch, anim); } else { lv_switch_off(enableSwitch, anim); diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index d00b27c150..7e844b37f7 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -26,6 +26,7 @@ namespace Pinetime { OnPairing, SetOffAlarm, SetOffWakeAlarm, + SetOffGradualWake, MeasureBatteryTimerExpired, BatteryPercentageUpdated, StartFileTransfer, diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 6ceb17d6ec..1e4921d891 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -226,6 +226,10 @@ void SystemTask::Work() { GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::WakeAlarmTriggered); break; + case Messages::SetOffGradualWake: + GoToRunning(); + displayApp.PushMessage(Pinetime::Applications::Display::Messages::GradualWakeTriggered); + break; case Messages::BleConnected: displayApp.PushMessage(Pinetime::Applications::Display::Messages::NotifyDeviceActivity); isBleDiscoveryTimerRunning = true; From 4dd520e045c951f5896008339d679b83f6e5c4d8 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 31 Oct 2024 10:27:30 -0500 Subject: [PATCH 022/191] Fixed gradual wake triggers --- src/components/infinisleep/InfiniSleepController.cpp | 10 +++++----- src/components/infinisleep/InfiniSleepController.h | 2 +- src/displayapp/screens/Sleep.cpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index e3c43cf04b..cc24c7c0b2 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -19,7 +19,7 @@ namespace { void SetOffGradualWake(TimerHandle_t xTimer) { auto* controller = static_cast(pvTimerGetTimerID(xTimer)); - if (controller->GetInfiniSleepSettings().graddualWake) { + if (controller->GetInfiniSleepSettings().graddualWake == false) { return; } controller->SetOffGradualWakeNow(); @@ -68,7 +68,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); - gradualWakeStep = 2; + gradualWakeStep = 8; auto now = dateTimeController.CurrentDateTime(); wakeAlarmTime = now; @@ -99,7 +99,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { // now can convert back to a time_point wakeAlarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmWakeAlarmTime)); - secondsToWakeAlarm = std::chrono::duration_cast(wakeAlarmTime - now).count(); + int64_t secondsToWakeAlarm = std::chrono::duration_cast(wakeAlarmTime - now).count(); xTimerChangePeriod(wakeAlarmTimer, secondsToWakeAlarm * configTICK_RATE_HZ, 0); xTimerStart(wakeAlarmTimer, 0); @@ -110,7 +110,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep >= 0) { - int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) / (configTICK_RATE_HZ); + int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } @@ -146,7 +146,7 @@ void InfiniSleepController::SetOffGradualWakeNow() { systemTask->PushMessage(System::Messages::SetOffGradualWake); // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep >= 0) { - int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) / (configTICK_RATE_HZ); + int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 5613542227..8c1c8d270c 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -115,7 +115,7 @@ namespace Pinetime { return infiniSleepSettings; } - int64_t secondsToWakeAlarm = 0; + //int64_t secondsToWakeAlarm = 0; private: diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index e49ed4127e..5dfa26c78a 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -75,7 +75,7 @@ Sleep::~Sleep() { } void Sleep::DisableWakeAlarm() { - if (infiniSleepController.IsEnabled()) { + if (infiniSleepController.GetWakeAlarm().isEnabled) { infiniSleepController.DisableWakeAlarm(); lv_switch_off(enableSwitch, LV_ANIM_ON); } @@ -343,7 +343,7 @@ void Sleep::ShowAlarmInfo() { txtMessage = lv_label_create(btnMessage, nullptr); lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY); - if (infiniSleepController.IsEnabled()) { + if (infiniSleepController.GetWakeAlarm().isEnabled) { auto timeToAlarm = infiniSleepController.SecondsToWakeAlarm(); auto daysToAlarm = timeToAlarm / 86400; From eb7775be488517e8d76bc7c031c3afb2281ad669 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 31 Oct 2024 11:44:46 -0500 Subject: [PATCH 023/191] fixed build error for always true conditions (dataType issues) --- src/components/infinisleep/InfiniSleepController.cpp | 12 ++++++------ src/components/infinisleep/InfiniSleepController.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index cc24c7c0b2..cab15f5022 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -68,7 +68,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); - gradualWakeStep = 8; + gradualWakeStep = 9; auto now = dateTimeController.CurrentDateTime(); wakeAlarmTime = now; @@ -104,13 +104,13 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStart(wakeAlarmTimer, 0); // make sure graudal wake steps are possible - while (gradualWakeStep > -1 && secondsToWakeAlarm <= wakeAlarm.gradualWakeSteps[gradualWakeStep]) { + while (gradualWakeStep != 0 && secondsToWakeAlarm <= wakeAlarm.gradualWakeSteps[gradualWakeStep-1]) { gradualWakeStep--; } // Calculate the period for the gradualWakeTimer - if (infiniSleepSettings.graddualWake && gradualWakeStep >= 0) { - int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) * (configTICK_RATE_HZ); + if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { + int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } @@ -145,8 +145,8 @@ void InfiniSleepController::SetOffGradualWakeNow() { //isGradualWakeAlerting = true; systemTask->PushMessage(System::Messages::SetOffGradualWake); // Calculate the period for the gradualWakeTimer - if (infiniSleepSettings.graddualWake && gradualWakeStep >= 0) { - int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - wakeAlarm.gradualWakeSteps[gradualWakeStep--])) * (configTICK_RATE_HZ); + if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { + int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - wakeAlarm.gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 8c1c8d270c..27944addc7 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -121,7 +121,7 @@ namespace Pinetime { bool isAlerting = false; bool isGradualWakeAlerting = false; - uint8_t gradualWakeStep = 8; // used to keep track of which step to use + uint8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex bool wakeAlarmChanged = false; bool isEnabled = false; bool settingsChanged = false; From 33706aacf2c90f26c170cd436a041cdee887e796 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 1 Nov 2024 23:57:15 -0500 Subject: [PATCH 024/191] Moved gradualSteps array out of settings Struct, updated motor controller to handle longer run times as input, fixed swipe motions in sleep app --- .../infinisleep/InfiniSleepController.cpp | 24 +++++++++---------- .../infinisleep/InfiniSleepController.h | 4 +++- src/components/motor/MotorController.cpp | 2 +- src/components/motor/MotorController.h | 2 +- src/displayapp/screens/Sleep.cpp | 6 ++--- src/displayapp/screens/Sleep.h | 2 ++ 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index cab15f5022..e4c0a26fc3 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -104,13 +104,13 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStart(wakeAlarmTimer, 0); // make sure graudal wake steps are possible - while (gradualWakeStep != 0 && secondsToWakeAlarm <= wakeAlarm.gradualWakeSteps[gradualWakeStep-1]) { + while (gradualWakeStep != 0 && secondsToWakeAlarm <= gradualWakeSteps[gradualWakeStep-1]) { gradualWakeStep--; } // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { - int64_t gradualWakePeriod = ((secondsToWakeAlarm - wakeAlarm.gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); + int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } @@ -146,7 +146,7 @@ void InfiniSleepController::SetOffGradualWakeNow() { systemTask->PushMessage(System::Messages::SetOffGradualWake); // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { - int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - wakeAlarm.gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); + int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } @@ -176,7 +176,7 @@ void InfiniSleepController::LoadSettingsFromFile() { lfs_file_t wakeAlarmFile; WakeAlarmSettings wakeAlarmBuffer; - if (fs.FileOpen(&wakeAlarmFile, "/.system/sleep/wakeAlarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) { + if (fs.FileOpen(&wakeAlarmFile, "wakeAlarm.dat", LFS_O_RDONLY) != LFS_ERR_OK) { NRF_LOG_WARNING("[InfiniSleepController] Failed to open alarm data file"); return; } @@ -196,7 +196,7 @@ void InfiniSleepController::LoadSettingsFromFile() { lfs_file_t infiniSleepSettingsFile; InfiniSleepSettings infiniSleepSettingsBuffer; - if (fs.FileOpen(&infiniSleepSettingsFile, "/.system/sleep/infiniSleepSettings.dat", LFS_O_RDONLY) != LFS_ERR_OK) { + if (fs.FileOpen(&infiniSleepSettingsFile, "infiniSleepSettings.dat", LFS_O_RDONLY) != LFS_ERR_OK) { NRF_LOG_WARNING("[InfiniSleepController] Failed to open InfiniSleep settings file"); return; } @@ -209,13 +209,13 @@ void InfiniSleepController::LoadSettingsFromFile() { } void InfiniSleepController::SaveSettingsToFile() const { - lfs_dir systemDir; - if (fs.DirOpen("/.system/sleep", &systemDir) != LFS_ERR_OK) { - fs.DirCreate("/.system/sleep"); - } - fs.DirClose(&systemDir); + // lfs_dir systemDir; + // if (fs.DirOpen("/system/sleep", &systemDir) != LFS_ERR_OK) { + // fs.DirCreate("/system/sleep"); + // } + // fs.DirClose(&systemDir); lfs_file_t alarmFile; - if (fs.FileOpen(&alarmFile, "/.system/sleep/wakeAlarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { + if (fs.FileOpen(&alarmFile, "wakeAlarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { NRF_LOG_WARNING("[InfiniSleepController] Failed to open alarm data file for saving"); return; } @@ -225,7 +225,7 @@ void InfiniSleepController::SaveSettingsToFile() const { NRF_LOG_INFO("[InfiniSleepController] Saved alarm settings with format version %u to file", wakeAlarm.version); lfs_file_t settingsFile; - if (fs.FileOpen(&settingsFile, "/.system/sleep/infiniSleepSettings.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { + if (fs.FileOpen(&settingsFile, "infiniSleepSettings.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { NRF_LOG_WARNING("[InfiniSleepController] Failed to open InfiniSleep settings file for saving"); return; } diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 27944addc7..8544833f78 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -97,9 +97,11 @@ namespace Pinetime { uint8_t minutes = 0; RecurType recurrence = RecurType::None; bool isEnabled = false; - uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds }; + uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds + + WakeAlarmSettings GetWakeAlarm() const { return wakeAlarm; } diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 4e392416ae..b280c2f988 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -18,7 +18,7 @@ void MotorController::Ring(TimerHandle_t xTimer) { motorController->RunForDuration(50); } -void MotorController::RunForDuration(uint8_t motorDuration) { +void MotorController::RunForDuration(uint16_t motorDuration) { if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) { nrf_gpio_pin_clear(PinMap::Motor); } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 6dea6d1f9e..1437349e5c 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -12,7 +12,7 @@ namespace Pinetime { MotorController() = default; void Init(); - void RunForDuration(uint8_t motorDuration); + void RunForDuration(uint16_t motorDuration); void StartRinging(); void StopRinging(); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 5dfa26c78a..4b74ee961f 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -263,14 +263,14 @@ bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { // The cases for swiping to change page on app switch (event) { - case TouchEvents::SwipeLeft: + case TouchEvents::SwipeRight: if (displayState != SleepDisplayState::Alarm) { displayState = static_cast(static_cast(displayState) - 1); UpdateDisplay(); } NRF_LOG_INFO("SwipeLeft: %d", static_cast(displayState)); return true; - case TouchEvents::SwipeRight: + case TouchEvents::SwipeLeft: if (displayState != SleepDisplayState::Settings) { displayState = static_cast(static_cast(displayState) + 1); UpdateDisplay(); @@ -304,7 +304,7 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); - taskStopWakeAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); + taskStopWakeAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(600 * 1000), LV_TASK_PRIO_MID, this); motorController.StartRinging(); wakeLock.Lock(); } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 454ff79895..749a58f1db 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -9,6 +9,8 @@ #include "systemtask/WakeLock.h" #include "Symbols.h" +#define GRADUAL_WAKE_MOTOR_DURATION_MS 1000 + //#include //#include // for accumulate //#include // for abs From fa52821b2b641909a990ca1e9d638fb987da609d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 1 Nov 2024 23:58:07 -0500 Subject: [PATCH 025/191] updated gradualWakeTriggered to use the defined constant --- src/displayapp/DisplayApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 8b5ee02861..e286dafb03 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -401,7 +401,7 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } - motorController.RunForDuration(static_cast(3000)); + motorController.RunForDuration(GRADUAL_WAKE_MOTOR_DURATION_MS); NRF_LOG_INFO("Gradual wake triggered"); break; case Messages::ShowPairingKey: From 97e788a6fc6575536390968416e8d74d112b87a1 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 2 Nov 2024 11:59:27 -0500 Subject: [PATCH 026/191] Switched settings to checkboxes --- src/displayapp/screens/Sleep.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 4b74ee961f..f030607719 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -26,10 +26,9 @@ static void settingsToggleEventHandler(lv_obj_t* obj, lv_event_t e) { if (e != LV_EVENT_VALUE_CHANGED) { return; } - lv_obj_t* toggle = obj; + const char* setting_name = static_cast(obj->user_data); - - bool enabled = lv_switch_get_state(toggle); + bool enabled = lv_checkbox_is_checked(obj); if (strcmp(setting_name, "Body Tracking") == 0) { infiniSleepController.SetBodyTrackingEnabled(enabled); @@ -199,20 +198,23 @@ void Sleep::DrawSettingsScreen() { int y_offset = 50; for (const auto& setting : settings) { - lv_obj_t* lblSetting = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(lblSetting, setting.name); - lv_obj_align(lblSetting, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + //lv_obj_t* lblSetting = lv_label_create(lv_scr_act(), nullptr); + // lv_label_set_text_static(lblSetting, setting.name); + // lv_obj_align(lblSetting, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + + lv_obj_t* checkbox = lv_checkbox_create(lv_scr_act(), nullptr); + checkbox->user_data = const_cast(setting.name); + lv_checkbox_set_text_static(checkbox, const_cast(setting.name)); - lv_obj_t* toggle = lv_switch_create(lv_scr_act(), nullptr); - toggle->user_data = const_cast(setting.name); if (setting.enabled) { - lv_switch_on(toggle, LV_ANIM_OFF); + lv_checkbox_set_checked(checkbox, true); } else { - lv_switch_off(toggle, LV_ANIM_OFF); + lv_checkbox_set_checked(checkbox, false); } - lv_obj_align(toggle, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -10, y_offset); + lv_obj_align(checkbox, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); - lv_obj_set_event_cb(toggle, settingsToggleEventHandler); + lv_obj_set_event_cb(checkbox, settingsToggleEventHandler); + //lv_obj_set_event_cb(lblSetting, settingsToggleEventHandler); y_offset += setting.offsetAfter; // Increase the offset to provide better spacing } From a90791d1ed2340e047a5043933e06096a88f380e Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 2 Nov 2024 12:01:21 -0500 Subject: [PATCH 027/191] Changed start page and made update display go to alarm if alerting --- src/displayapp/screens/Sleep.cpp | 3 +++ src/displayapp/screens/Sleep.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index f030607719..eba76b9183 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -83,6 +83,9 @@ void Sleep::DisableWakeAlarm() { void Sleep::UpdateDisplay() { // Clear the screen lv_obj_clean(lv_scr_act()); + if (infiniSleepController.IsAlerting()) { + displayState = SleepDisplayState::Alarm; + } // Draw the screen switch (displayState) { case SleepDisplayState::Alarm: diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 749a58f1db..bca10bafcf 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -31,7 +31,7 @@ namespace Pinetime { void StopAlerting(); void UpdateDisplay(); enum class SleepDisplayState { Alarm, Info, Settings }; - SleepDisplayState displayState = SleepDisplayState::Alarm; + SleepDisplayState displayState = SleepDisplayState::Info; // void Refresh() override; From c5c5727a3655614b103a458bd5fb3f3efccd017c Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 2 Nov 2024 18:24:42 -0500 Subject: [PATCH 028/191] Removed timer on alerting so alerts indeffinately, started working on start tracking button --- src/displayapp/screens/Sleep.cpp | 20 +++++++++++++------- src/displayapp/screens/Sleep.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index eba76b9183..5874dc8c4d 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -50,10 +50,10 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { screen->OnButtonEvent(obj, event); } -static void StopAlarmTaskCallback(lv_task_t* task) { - auto* screen = static_cast(task->user_data); - screen->StopAlerting(); -} +// static void StopAlarmTaskCallback(lv_task_t* task) { +// auto* screen = static_cast(task->user_data); +// screen->StopAlerting(); +// } Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, @@ -177,8 +177,14 @@ void Sleep::DrawAlarmScreen() { void Sleep::DrawInfoScreen() { lv_obj_t* lblInfo = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(lblInfo, "InfiniTime\nSleep\nApp"); - lv_obj_align(lblInfo, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_label_set_text_static(lblInfo, "InfiniSleep"); + lv_obj_align(lblInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); + + trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_align(trackerToggleBtn, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); + + trackerToggleLabel = lv_label_create(trackerToggleBtn, nullptr); + lv_label_set_text(trackerToggleLabel, "Start"); } void Sleep::DrawSettingsScreen() { @@ -309,7 +315,7 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); - taskStopWakeAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(600 * 1000), LV_TASK_PRIO_MID, this); + //taskStopWakeAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); motorController.StartRinging(); wakeLock.Lock(); } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index bca10bafcf..975667f855 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -58,6 +58,7 @@ namespace Pinetime { Controllers::Settings::ClockType clockType; lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch; + lv_obj_t *trackerToggleBtn, *trackerToggleLabel; lv_obj_t* lblampm = nullptr; lv_obj_t* txtMessage = nullptr; lv_obj_t* btnMessage = nullptr; From b705a093df90dacdc012a8b5f17637bd9b639847 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 2 Nov 2024 19:07:41 -0500 Subject: [PATCH 029/191] Made tracker toggle btn --- .../infinisleep/InfiniSleepController.h | 9 +++++++++ src/displayapp/screens/Sleep.cpp | 15 ++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 8544833f78..a2f84d1d9b 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -117,6 +117,15 @@ namespace Pinetime { return infiniSleepSettings; } + bool ToggleTracker() { + isEnabled = !isEnabled; + return isEnabled; + } + + bool IsTrackerEnabled() const { + return isEnabled; + } + //int64_t secondsToWakeAlarm = 0; private: diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 5874dc8c4d..c7105d8f4b 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -181,10 +181,18 @@ void Sleep::DrawInfoScreen() { lv_obj_align(lblInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); + trackerToggleBtn->user_data = this; lv_obj_align(trackerToggleBtn, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); trackerToggleLabel = lv_label_create(trackerToggleBtn, nullptr); - lv_label_set_text(trackerToggleLabel, "Start"); + if (infiniSleepController.IsTrackerEnabled()) { + lv_label_set_text_static(trackerToggleLabel, "Stop"); + lv_obj_set_style_local_bg_color(trackerToggleBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + } else { + lv_label_set_text_static(trackerToggleLabel, "Start"); + lv_obj_set_style_local_bg_color(trackerToggleBtn, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); + } + lv_obj_set_event_cb(trackerToggleBtn, btnEventHandler); } void Sleep::DrawSettingsScreen() { @@ -251,6 +259,11 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } return; } + if (obj == trackerToggleBtn) { + infiniSleepController.ToggleTracker(); + UpdateDisplay(); + return; + } if (obj == btnRecur) { DisableWakeAlarm(); ToggleRecurrence(); From 41032a0cd3a254ef1bc089b545bfd145a619b546 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 00:18:54 -0600 Subject: [PATCH 030/191] Updated rescheduling of wake alarm when system time changed --- src/systemtask/SystemTask.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 1e4921d891..15ca4b5ccb 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -208,6 +208,9 @@ void SystemTask::Work() { if (alarmController.IsEnabled()) { alarmController.ScheduleAlarm(); } + if (infiniSleepController.GetWakeAlarm().isEnabled) { + infiniSleepController.ScheduleWakeAlarm(); + } break; case Messages::OnNewNotification: if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) { From 835f5cf47fae536dbdf244faef85d0b3ba805796 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 00:37:07 -0600 Subject: [PATCH 031/191] accoutning for abnormal data --- src/displayapp/screens/Sleep.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index c7105d8f4b..3d4a8e1adf 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -403,6 +403,11 @@ void Sleep::SetRecurButtonState() { break; case InfiniSleepController::RecurType::Weekdays: lv_label_set_text_static(txtRecur, "MON-FRI"); + break; + default: + infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); + SetRecurButtonState(); + break; } } From c6bff435429d8e959cf7dd064fbd13467d83d638 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 00:43:10 -0600 Subject: [PATCH 032/191] removed recursive --- src/displayapp/screens/Sleep.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 3d4a8e1adf..a7d1a3fb41 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -406,7 +406,7 @@ void Sleep::SetRecurButtonState() { break; default: infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); - SetRecurButtonState(); + lv_label_set_text_static(txtRecur, "ONCE"); break; } } From 0902e3e3a1c043547bdcc7bb50d24c5da470c185 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 01:16:02 -0600 Subject: [PATCH 033/191] moved else logic --- src/displayapp/screens/Sleep.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index a7d1a3fb41..66a9f3760f 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -404,10 +404,6 @@ void Sleep::SetRecurButtonState() { case InfiniSleepController::RecurType::Weekdays: lv_label_set_text_static(txtRecur, "MON-FRI"); break; - default: - infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); - lv_label_set_text_static(txtRecur, "ONCE"); - break; } } @@ -422,6 +418,10 @@ void Sleep::ToggleRecurrence() { break; case InfiniSleepController::RecurType::Weekdays: infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); + break; + default: + infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); + break; } SetRecurButtonState(); } \ No newline at end of file From 41b3e92901cea4bdc5a3c164c84f7c1033d927c1 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 01:45:05 -0600 Subject: [PATCH 034/191] undid stuff, works now ?? idek --- src/displayapp/screens/Sleep.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 66a9f3760f..f9ff51c357 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -419,9 +419,6 @@ void Sleep::ToggleRecurrence() { case InfiniSleepController::RecurType::Weekdays: infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); break; - default: - infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); - break; } SetRecurButtonState(); } \ No newline at end of file From 62292e85b44d869e0ff88d4f2042b749f1b4d6f8 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 10:06:58 -0600 Subject: [PATCH 035/191] removed swiping while alerting --- src/displayapp/screens/Sleep.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index f9ff51c357..a4ce3cd5b5 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -285,6 +285,12 @@ bool Sleep::OnButtonPushed() { bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + // Swiping should be ignored when in alerting state + if (infiniSleepController.IsAlerting() && + (event != TouchEvents::SwipeDown && event != TouchEvents::SwipeUp && event != TouchEvents::SwipeLeft && event != TouchEvents::SwipeRight)) { + return true; + } + // The cases for swiping to change page on app switch (event) { case TouchEvents::SwipeRight: From 388aa9982f294f33fe715f40a54081676fc26d3d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 13:22:31 -0600 Subject: [PATCH 036/191] Added snoozing and made side button require 5 presses --- .../infinisleep/InfiniSleepController.cpp | 2 ++ .../infinisleep/InfiniSleepController.h | 28 +++++++++++++++++ src/displayapp/screens/Sleep.cpp | 30 +++++++++++++++++-- src/displayapp/screens/Sleep.h | 1 + 4 files changed, 58 insertions(+), 3 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index e4c0a26fc3..32600e7b68 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -68,6 +68,8 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); + pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; + gradualWakeStep = 9; auto now = dateTimeController.CurrentDateTime(); diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index a2f84d1d9b..85e75d1a72 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -7,6 +7,8 @@ #include +#define PSUHES_TO_STOP_ALARM 5 + namespace Pinetime { namespace System { class SystemTask; @@ -29,6 +31,23 @@ namespace Pinetime { void StopAlerting(); enum class RecurType { None, Daily, Weekdays }; + uint8_t pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; + + bool isSnoozing = false; + uint8_t preSnoozeMinutes = 10; + uint8_t preSnnoozeHours = 0; + + void SetPreSnoozeTime() { + preSnoozeMinutes = wakeAlarm.minutes; + preSnnoozeHours = wakeAlarm.hours; + } + + void RestorePreSnoozeTime() { + wakeAlarm.minutes = preSnoozeMinutes; + wakeAlarm.hours = preSnnoozeHours; + } + + uint8_t Hours() const { return wakeAlarm.hours; } @@ -126,6 +145,14 @@ namespace Pinetime { return isEnabled; } + uint8_t GetCurrentHour() { + return dateTimeController.Hours(); + } + + uint8_t GetCurrentMinute() { + return dateTimeController.Minutes(); + } + //int64_t secondsToWakeAlarm = 0; private: @@ -144,6 +171,7 @@ namespace Pinetime { System::SystemTask* systemTask = nullptr; TimerHandle_t wakeAlarmTimer; TimerHandle_t gradualWakeTimer; + TimerHandle_t trackerUpdateTimer; WakeAlarmSettings wakeAlarm; std::chrono::time_point wakeAlarmTime; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index a4ce3cd5b5..0a93148eba 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -130,7 +130,7 @@ void Sleep::DrawAlarmScreen() { lv_obj_set_event_cb(btnStop, btnEventHandler); lv_obj_set_size(btnStop, 115, 50); lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); - lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); txtStop = lv_label_create(btnStop, nullptr); lv_label_set_text_static(txtStop, Symbols::stop); lv_obj_set_hidden(btnStop, true); @@ -241,6 +241,7 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (event == LV_EVENT_CLICKED) { if (obj == btnStop) { StopAlerting(); + SnoozeWakeAlarm(); return; } if (obj == btnInfo) { @@ -277,8 +278,16 @@ bool Sleep::OnButtonPushed() { return true; } if (infiniSleepController.IsAlerting()) { - StopAlerting(); - return true; + if (infiniSleepController.pushesLeftToStopWakeAlarm > 1) { + infiniSleepController.pushesLeftToStopWakeAlarm--; + return true; + } else { + infiniSleepController.isSnoozing = false; + infiniSleepController.RestorePreSnoozeTime(); + StopAlerting(); + UpdateDisplay(); + return true; + } } return false; } @@ -320,6 +329,21 @@ void Sleep::OnValueChanged() { UpdateWakeAlarmTime(); } +// Currently snoozes 5 minutes +void Sleep::SnoozeWakeAlarm() { + if (minuteCounter.GetValue() >= 55) { + minuteCounter.SetValue(0); + hourCounter.SetValue((infiniSleepController.GetCurrentHour() + 1)); + } else { + minuteCounter.SetValue(infiniSleepController.GetCurrentMinute() + 5); + } + infiniSleepController.SetPreSnoozeTime(); + infiniSleepController.isSnoozing = true; + UpdateWakeAlarmTime(); + SetSwitchState(LV_ANIM_OFF); + infiniSleepController.ScheduleWakeAlarm(); +} + void Sleep::UpdateWakeAlarmTime() { if (lblampm != nullptr) { if (hourCounter.GetValue() >= 12) { diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 975667f855..49cbf3330c 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -69,6 +69,7 @@ namespace Pinetime { void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); + void SnoozeWakeAlarm(); void ShowAlarmInfo(); void HideAlarmInfo(); void ToggleRecurrence(); From f177a81226c6fb3c1ff079cb65f4fb5eaa07a53b Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 21:44:43 -0600 Subject: [PATCH 037/191] More setup for sleep tracking --- .../infinisleep/InfiniSleepController.cpp | 25 +++++++++++++++++++ .../infinisleep/InfiniSleepController.h | 13 ++++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 32600e7b68..01f1950b9d 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -24,6 +24,11 @@ namespace { } controller->SetOffGradualWakeNow(); } + + void SetOffTrackerUpdate(TimerHandle_t xTimer) { + auto* controller = static_cast(pvTimerGetTimerID(xTimer)); + controller->UpdateTracker(); + } } void InfiniSleepController::Init(System::SystemTask* systemTask) { @@ -38,6 +43,26 @@ void InfiniSleepController::Init(System::SystemTask* systemTask) { } } +void InfiniSleepController::EnableTracker() { + DisableTracker(); + NRF_LOG_INFO("[InfiniSleepController] Enabling tracker"); + isEnabled = true; + trackerUpdateTimer = xTimerCreate("TrackerUpdate", 5 * configTICK_RATE_HZ, pdFALSE, this, SetOffTrackerUpdate); + xTimerStart(trackerUpdateTimer, 0); +} + +void InfiniSleepController::DisableTracker() { + NRF_LOG_INFO("[InfiniSleepController] Disabling tracker"); + xTimerStop(trackerUpdateTimer, 0); + isEnabled = false; +} + +void InfiniSleepController::UpdateTracker() { + NRF_LOG_INFO("[InfiniSleepController] Updating tracker"); + xTimerStop(trackerUpdateTimer, 0); + xTimerStart(trackerUpdateTimer, 0); +} + void InfiniSleepController::SaveWakeAlarm() { // verify is save needed if (wakeAlarmChanged) { diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 85e75d1a72..ad3bc0e460 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -8,6 +8,7 @@ #include #define PSUHES_TO_STOP_ALARM 5 +#define TRACKER_UPDATE_INTERVAL_MINS 5 namespace Pinetime { namespace System { @@ -61,9 +62,13 @@ namespace Pinetime { } bool IsEnabled() const { - return wakeAlarm.isEnabled; + return isEnabled; } + void EnableTracker(); + void DisableTracker(); + void UpdateTracker(); + RecurType Recurrence() const { return wakeAlarm.recurrence; } @@ -137,7 +142,11 @@ namespace Pinetime { } bool ToggleTracker() { - isEnabled = !isEnabled; + if (isEnabled) { + DisableTracker(); + } else { + EnableTracker(); + } return isEnabled; } From 9eabb40d2077f139554872a48f2e9f02501de0fe Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 4 Nov 2024 22:01:43 -0600 Subject: [PATCH 038/191] Fixed bug that doesnt restore original alarm time after multiple snooze --- src/components/infinisleep/InfiniSleepController.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index ad3bc0e460..267358cc60 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -39,6 +39,9 @@ namespace Pinetime { uint8_t preSnnoozeHours = 0; void SetPreSnoozeTime() { + if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { + return; + } preSnoozeMinutes = wakeAlarm.minutes; preSnnoozeHours = wakeAlarm.hours; } @@ -46,6 +49,8 @@ namespace Pinetime { void RestorePreSnoozeTime() { wakeAlarm.minutes = preSnoozeMinutes; wakeAlarm.hours = preSnnoozeHours; + preSnoozeMinutes = 255; + preSnnoozeHours = 255; } From ff443859050cc2a2eb93e47de4e5ca4ad09e52c0 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 6 Nov 2024 23:48:16 -0600 Subject: [PATCH 039/191] Added basic HR periodic reading for sleep tracking and Fixed gradual wake alarm bug --- .../infinisleep/InfiniSleepController.cpp | 77 ++++++++++++++++++- .../infinisleep/InfiniSleepController.h | 22 +++++- src/displayapp/Messages.h | 1 + src/displayapp/screens/Sleep.cpp | 6 ++ src/displayapp/screens/Sleep.h | 2 +- src/systemtask/Messages.h | 3 +- src/systemtask/SystemTask.cpp | 3 + 7 files changed, 107 insertions(+), 7 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 01f1950b9d..0dc199d2a8 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -7,8 +7,8 @@ using namespace Pinetime::Controllers; using namespace std::chrono_literals; -InfiniSleepController::InfiniSleepController(Controllers::DateTime& dateTimeController, Controllers::FS& fs) - : dateTimeController {dateTimeController}, fs {fs} { +InfiniSleepController::InfiniSleepController(Controllers::DateTime& dateTimeController, Controllers::FS& fs, Controllers::HeartRateController& heartRateController) + : dateTimeController {dateTimeController}, fs {fs}, heartRateController {heartRateController} { } namespace { @@ -59,6 +59,10 @@ void InfiniSleepController::DisableTracker() { void InfiniSleepController::UpdateTracker() { NRF_LOG_INFO("[InfiniSleepController] Updating tracker"); + + UpdateBPM(); + systemTask->PushMessage(System::Messages::SleepTrackerUpdate); + xTimerStop(trackerUpdateTimer, 0); xTimerStart(trackerUpdateTimer, 0); } @@ -199,6 +203,75 @@ void InfiniSleepController::SetRecurrence(RecurType recurrence) { wakeAlarmChanged = true; } +/* Sleep Tracking Section */ + +void InfiniSleepController::UpdateBPM() { + // Get the heart rate from the controller + prevBpm = bpm; + bpm = heartRateController.HeartRate(); + + if(prevBpm != 0) + rollingBpm = (rollingBpm + bpm) / 2; + else + rollingBpm = bpm; + + // Get the current time from DateTimeController + int hours = dateTimeController.Hours(); + int minutes = dateTimeController.Minutes(); + int seconds = dateTimeController.Seconds(); + + // Log the BPM and current time + NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); + + // Write data to CSV + const int motion = 0; // Placeholder for motion data + std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; + WriteDataCSV("SleepTracker_Data.csv", data, 1); +} + +void InfiniSleepController::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { + lfs_file_t file; + int err = fs.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error opening file: %d", err); + return; + } + + for (int i = 0; i < dataSize; ++i) { + int hours, minutes, seconds, bpm, motion; + std::tie(hours, minutes, seconds, bpm, motion) = data[i]; + char buffer[64]; + int len = snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d,%d,%d\n", hours, minutes, seconds, bpm, motion); + err = fs.FileWrite(&file, reinterpret_cast(buffer), len); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error writing to file: %d", err); + fs.FileClose(&file); + + return; + } + } + + fs.FileClose(&file); +} + +// Clear data in CSV +void InfiniSleepController::ClearDataCSV(const char* filename) const { + lfs_file_t file; + int err = fs.FileOpen(&file, filename, LFS_O_WRONLY | LFS_O_TRUNC); + if (err < 0) { + // Handle error + NRF_LOG_INFO("Error opening file: %d", err); + return; + } + + fs.FileClose(&file); + NRF_LOG_INFO("CSV data cleared"); +} + +/* Sleep Tracking Section End */ + void InfiniSleepController::LoadSettingsFromFile() { lfs_file_t wakeAlarmFile; WakeAlarmSettings wakeAlarmBuffer; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 267358cc60..7b1c6e1172 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -4,6 +4,8 @@ #include #include #include "components/datetime/DateTimeController.h" +#include "components/fs/FS.h" +#include "components/heartrate/HeartRateController.h" #include @@ -18,7 +20,7 @@ namespace Pinetime { namespace Controllers { class InfiniSleepController { public: - InfiniSleepController(Controllers::DateTime& dateTimeCOntroller, Controllers::FS& fs); + InfiniSleepController(Controllers::DateTime& dateTimeCOntroller, Controllers::FS& , Controllers::HeartRateController& heartRateController); void Init(System::SystemTask* systemTask); void SaveWakeAlarm(); @@ -35,8 +37,8 @@ namespace Pinetime { uint8_t pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; bool isSnoozing = false; - uint8_t preSnoozeMinutes = 10; - uint8_t preSnnoozeHours = 0; + uint8_t preSnoozeMinutes = 255; + uint8_t preSnnoozeHours = 255; void SetPreSnoozeTime() { if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { @@ -47,6 +49,9 @@ namespace Pinetime { } void RestorePreSnoozeTime() { + if (preSnoozeMinutes == 255 || preSnnoozeHours == 255) { + return; + } wakeAlarm.minutes = preSnoozeMinutes; wakeAlarm.hours = preSnnoozeHours; preSnoozeMinutes = 255; @@ -169,6 +174,12 @@ namespace Pinetime { //int64_t secondsToWakeAlarm = 0; + int bpm = 0; + int prevBpm = 0; + int rollingBpm = 0; + + void UpdateBPM(); + private: bool isAlerting = false; @@ -182,6 +193,7 @@ namespace Pinetime { Controllers::DateTime& dateTimeController; Controllers::FS& fs; + Controllers::HeartRateController& heartRateController; System::SystemTask* systemTask = nullptr; TimerHandle_t wakeAlarmTimer; TimerHandle_t gradualWakeTimer; @@ -191,6 +203,10 @@ namespace Pinetime { void LoadSettingsFromFile(); void SaveSettingsToFile() const; + + // For File IO + void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; + void ClearDataCSV(const char* fileName) const; }; } diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index 042fa15ec9..ce25df5a7b 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -27,6 +27,7 @@ namespace Pinetime { Chime, BleRadioEnableToggle, OnChargingEvent, + SleepTrackerUpdate, }; } } diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 0a93148eba..4c34df42a2 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -179,6 +179,12 @@ void Sleep::DrawInfoScreen() { lv_obj_t* lblInfo = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(lblInfo, "InfiniSleep"); lv_obj_align(lblInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); + lv_obj_set_style_local_text_color(lblInfo, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + + label_hr = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(label_hr, "HR: %d", infiniSleepController.rollingBpm); + lv_obj_align(label_hr, lblInfo, LV_ALIGN_CENTER, 0, 50); + lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); trackerToggleBtn->user_data = this; diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 49cbf3330c..7927e37564 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -93,7 +93,7 @@ namespace Pinetime { // int prevBpm = 0; // int rollingBpm = 0; - // lv_obj_t* label_hr; + lv_obj_t* label_hr; // lv_task_t* mainRefreshTask; // lv_task_t* hrRefreshTask; diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index 7e844b37f7..1f61239608 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -31,7 +31,8 @@ namespace Pinetime { BatteryPercentageUpdated, StartFileTransfer, StopFileTransfer, - BleRadioEnableToggle + BleRadioEnableToggle, + SleepTrackerUpdate, }; } } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 15ca4b5ccb..bc92f1d83e 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -373,6 +373,9 @@ void SystemTask::Work() { nimbleController.DisableRadio(); } break; + case Messages::SleepTrackerUpdate: + displayApp.PushMessage(Pinetime::Applications::Display::Messages::SleepTrackerUpdate); + break; default: break; } From 629d95846e7d1ab8532118be3b65e077b4c7265c Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 7 Nov 2024 00:09:03 -0600 Subject: [PATCH 040/191] Made a define statement for file name --- src/components/infinisleep/InfiniSleepController.cpp | 2 +- src/components/infinisleep/InfiniSleepController.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 0dc199d2a8..2121c3fc58 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -226,7 +226,7 @@ void InfiniSleepController::UpdateBPM() { // Write data to CSV const int motion = 0; // Placeholder for motion data std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; - WriteDataCSV("SleepTracker_Data.csv", data, 1); + WriteDataCSV(TrackerDataFile, data, 1); } void InfiniSleepController::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 7b1c6e1172..a95335a9db 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -11,6 +11,7 @@ #define PSUHES_TO_STOP_ALARM 5 #define TRACKER_UPDATE_INTERVAL_MINS 5 +#define TrackerDataFile "SleepTracker_Data.csv" namespace Pinetime { namespace System { @@ -155,6 +156,7 @@ namespace Pinetime { if (isEnabled) { DisableTracker(); } else { + ClearDataCSV(TrackerDataFile); EnableTracker(); } return isEnabled; From 6ca4cdcb20fa36756e62a68a391560c45a036585 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 8 Nov 2024 15:06:44 -0600 Subject: [PATCH 041/191] Made a new alarm for sleep in motor controller --- src/components/motor/MotorController.cpp | 16 ++++++++++++++++ src/components/motor/MotorController.h | 4 ++++ src/displayapp/screens/Sleep.cpp | 4 ++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index b280c2f988..044bc24bd2 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -11,6 +11,7 @@ void MotorController::Init() { shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor); longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring); + alarmVib = xTimerCreate("alarmVib", pdMS_TO_TICKS(500), pdTRUE, this, AlarmRing); } void MotorController::Ring(TimerHandle_t xTimer) { @@ -18,6 +19,11 @@ void MotorController::Ring(TimerHandle_t xTimer) { motorController->RunForDuration(50); } +void MotorController::AlarmRing(TimerHandle_t xTimer) { + auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); + motorController->RunForDuration(300); +} + void MotorController::RunForDuration(uint16_t motorDuration) { if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) { nrf_gpio_pin_clear(PinMap::Motor); @@ -34,6 +40,16 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(PinMap::Motor); } +void MotorController::StartAlarm() { + RunForDuration(300); + xTimerStart(alarmVib, 0); +} + +void MotorController::StopAlarm() { + xTimerStop(alarmVib, 0); + nrf_gpio_pin_set(PinMap::Motor); +} + void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_gpio_pin_set(PinMap::Motor); } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 1437349e5c..4acbeda710 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -15,12 +15,16 @@ namespace Pinetime { void RunForDuration(uint16_t motorDuration); void StartRinging(); void StopRinging(); + void StartAlarm(); + void StopAlarm(); private: static void Ring(TimerHandle_t xTimer); + static void AlarmRing(TimerHandle_t xTimer); static void StopMotor(TimerHandle_t xTimer); TimerHandle_t shortVib; TimerHandle_t longVib; + TimerHandle_t alarmVib; }; } } diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 4c34df42a2..fff9070dc8 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -365,13 +365,13 @@ void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); //taskStopWakeAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); - motorController.StartRinging(); + motorController.StartAlarm(); wakeLock.Lock(); } void Sleep::StopAlerting() { infiniSleepController.StopAlerting(); - motorController.StopRinging(); + motorController.StopAlarm(); SetSwitchState(LV_ANIM_OFF); if (taskStopWakeAlarm != nullptr) { lv_task_del(taskStopWakeAlarm); From 1cbb9cbedb8197fc13fc7fc35ceb0e0db36bd2a5 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 8 Nov 2024 16:43:50 -0600 Subject: [PATCH 042/191] Added refresh task for sleep app and added to info screen --- .../infinisleep/InfiniSleepController.h | 4 +++ src/displayapp/screens/Sleep.cpp | 25 ++++++++++++++----- src/displayapp/screens/Sleep.h | 4 +++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index a95335a9db..13dce8751b 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -40,6 +40,8 @@ namespace Pinetime { bool isSnoozing = false; uint8_t preSnoozeMinutes = 255; uint8_t preSnnoozeHours = 255; + uint8_t startTimeHours = 0; + uint8_t startTimeMinutes = 0; void SetPreSnoozeTime() { if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { @@ -157,6 +159,8 @@ namespace Pinetime { DisableTracker(); } else { ClearDataCSV(TrackerDataFile); + startTimeHours = GetCurrentHour(); + startTimeMinutes = GetCurrentMinute(); EnableTracker(); } return isEnabled; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index fff9070dc8..cbe2f78b63 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -62,12 +62,14 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController}, clockType {clockType} { UpdateDisplay(); + taskRefresh = lv_task_create(RefreshTaskCallback, 2000, LV_TASK_PRIO_MID, this); } Sleep::~Sleep() { if (infiniSleepController.IsAlerting()) { StopAlerting(); } + lv_task_del(taskRefresh); lv_obj_clean(lv_scr_act()); infiniSleepController.SaveWakeAlarm(); infiniSleepController.SaveInfiniSleepSettings(); @@ -80,6 +82,10 @@ void Sleep::DisableWakeAlarm() { } } +void Sleep::Refresh() { + UpdateDisplay(); +} + void Sleep::UpdateDisplay() { // Clear the screen lv_obj_clean(lv_scr_act()); @@ -176,16 +182,23 @@ void Sleep::DrawAlarmScreen() { } void Sleep::DrawInfoScreen() { - lv_obj_t* lblInfo = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(lblInfo, "InfiniSleep"); - lv_obj_align(lblInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); - lv_obj_set_style_local_text_color(lblInfo, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + lv_obj_t* lblTime = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); + lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); + lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); label_hr = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_fmt(label_hr, "HR: %d", infiniSleepController.rollingBpm); - lv_obj_align(label_hr, lblInfo, LV_ALIGN_CENTER, 0, 50); + lv_obj_align(label_hr, lblTime, LV_ALIGN_CENTER, 0, 50); lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - + + if (infiniSleepController.IsEnabled()) { + label_start_time = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(label_start_time, "Began at: %02d:%02d", infiniSleepController.startTimeHours, infiniSleepController.startTimeMinutes); + lv_obj_align(label_start_time, label_hr, LV_ALIGN_CENTER, 0, 20); + lv_obj_set_style_local_text_color(label_start_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + } + trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); trackerToggleBtn->user_data = this; lv_obj_align(trackerToggleBtn, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 7927e37564..e7863d55c3 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -23,6 +23,7 @@ namespace Pinetime { //explicit Sleep(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask); explicit Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, Controllers::MotorController& motorController); ~Sleep() override; + void Refresh() override; void SetAlerting(); void OnButtonEvent(lv_obj_t* obj, lv_event_t event); bool OnButtonPushed() override; @@ -64,6 +65,8 @@ namespace Pinetime { lv_obj_t* btnMessage = nullptr; lv_task_t* taskStopWakeAlarm = nullptr; + lv_task_t* taskRefresh = nullptr; + enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); void SetRecurButtonState(); @@ -94,6 +97,7 @@ namespace Pinetime { // int rollingBpm = 0; lv_obj_t* label_hr; + lv_obj_t* label_start_time; // lv_task_t* mainRefreshTask; // lv_task_t* hrRefreshTask; From ced2ee2d3f35d84d7b2f1d6e0986bb31a9435b74 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 8 Nov 2024 16:50:50 -0600 Subject: [PATCH 043/191] Updated main.cpp and added display update when sleep tracker is updated --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index c588211bd7..3efc6bb59d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,7 +105,7 @@ Pinetime::Drivers::Watchdog watchdog; Pinetime::Controllers::NotificationManager notificationManager; Pinetime::Controllers::MotionController motionController; Pinetime::Controllers::AlarmController alarmController {dateTimeController, fs}; -Pinetime::Controllers::InfiniSleepController infiniSleepController {dateTimeController, fs}; +Pinetime::Controllers::InfiniSleepController infiniSleepController {dateTimeController, fs, heartRateController}; Pinetime::Controllers::TouchHandler touchHandler; Pinetime::Controllers::ButtonHandler buttonHandler; From 7d8c8d9f7e17b7b5656a53f60aacab6b69825084 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 8 Nov 2024 16:52:03 -0600 Subject: [PATCH 044/191] Last commit didn't have the SleepTrackerUpdate message --- src/displayapp/DisplayApp.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index e286dafb03..4729bdc163 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -404,6 +404,12 @@ void DisplayApp::Refresh() { motorController.RunForDuration(GRADUAL_WAKE_MOTOR_DURATION_MS); NRF_LOG_INFO("Gradual wake triggered"); break; + case Messages::SleepTrackerUpdate: + if (currentApp == Apps::Sleep) { + auto* sleep = static_cast(currentScreen.get()); + sleep->UpdateDisplay(); + } + break; case Messages::ShowPairingKey: LoadNewScreen(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); motorController.RunForDuration(35); From 593bdd54c2c1300f9ba3b066900690003a3ff8e1 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 10 Nov 2024 02:57:35 -0600 Subject: [PATCH 045/191] Fixed bug where snoozing and closing saved the snooze time as alarm instead of pre snooze time --- src/components/infinisleep/InfiniSleepController.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 2121c3fc58..4636e47c66 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -315,14 +315,19 @@ void InfiniSleepController::SaveSettingsToFile() const { // } // fs.DirClose(&systemDir); lfs_file_t alarmFile; + WakeAlarmSettings tempWakeAlarm = wakeAlarm; + if (isSnoozing) { + tempWakeAlarm.hours = preSnnoozeHours; + tempWakeAlarm.minutes = preSnoozeMinutes; + } if (fs.FileOpen(&alarmFile, "wakeAlarm.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { NRF_LOG_WARNING("[InfiniSleepController] Failed to open alarm data file for saving"); return; } - fs.FileWrite(&alarmFile, reinterpret_cast(&wakeAlarm), sizeof(wakeAlarm)); + fs.FileWrite(&alarmFile, reinterpret_cast(&tempWakeAlarm), sizeof(tempWakeAlarm)); fs.FileClose(&alarmFile); - NRF_LOG_INFO("[InfiniSleepController] Saved alarm settings with format version %u to file", wakeAlarm.version); + NRF_LOG_INFO("[InfiniSleepController] Saved alarm settings with format version %u to file", tempWakeAlarm.version); lfs_file_t settingsFile; if (fs.FileOpen(&settingsFile, "infiniSleepSettings.dat", LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { From 8147ffa197e98ed8c116d875b21ab2294c3773f9 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 18 Nov 2024 13:04:50 -0600 Subject: [PATCH 046/191] Added ability to customize gradual wake intensity at each step --- src/components/infinisleep/InfiniSleepController.cpp | 1 + src/components/infinisleep/InfiniSleepController.h | 9 +++++++++ src/displayapp/DisplayApp.cpp | 2 +- src/displayapp/screens/Sleep.h | 2 +- 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 4636e47c66..3807efe79a 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -100,6 +100,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; gradualWakeStep = 9; + gradualWakeVibration = 9; auto now = dateTimeController.CurrentDateTime(); wakeAlarmTime = now; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 13dce8751b..f75812036c 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -136,7 +136,12 @@ namespace Pinetime { bool isEnabled = false; }; + // Dertermine the steps for the gradual wake alarm, the corresponding vibration durations determine the power of the vibration uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds + uint16_t gradualWakeVibrationDurations[9] = {1200, 1200, 1000, 1000, 1000, 700, 700, 700, 500}; // In ms + + uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex + WakeAlarmSettings GetWakeAlarm() const { @@ -186,6 +191,10 @@ namespace Pinetime { void UpdateBPM(); + uint8_t GetGradualWakeStep() const { + return (9 - gradualWakeStep) + 1; + } + private: bool isAlerting = false; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 4729bdc163..fdeba6dd09 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -401,7 +401,7 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } - motorController.RunForDuration(GRADUAL_WAKE_MOTOR_DURATION_MS); + motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1+infiniSleepController.gradualWakeVibration--]); NRF_LOG_INFO("Gradual wake triggered"); break; case Messages::SleepTrackerUpdate: diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index e7863d55c3..993789e1bc 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -9,7 +9,7 @@ #include "systemtask/WakeLock.h" #include "Symbols.h" -#define GRADUAL_WAKE_MOTOR_DURATION_MS 1000 +//#define GRADUAL_WAKE_MOTOR_DURATION_MS 1000 //#include //#include // for accumulate From d76144ebab42b3ea06d1bae2c8d7e6cd2621187e Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 18 Nov 2024 20:52:48 -0600 Subject: [PATCH 047/191] Added to info page and fixded total sleep display. Also put back code to auto-snooze the wake alarm after 3 minutes. --- .../infinisleep/InfiniSleepController.h | 8 +++ src/displayapp/screens/Sleep.cpp | 64 +++++++++++++++---- src/displayapp/screens/Sleep.h | 8 ++- 3 files changed, 67 insertions(+), 13 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index f75812036c..0035bbd117 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -9,6 +9,7 @@ #include +#define SNOOZE_MINUTES 3 #define PSUHES_TO_STOP_ALARM 5 #define TRACKER_UPDATE_INTERVAL_MINS 5 #define TrackerDataFile "SleepTracker_Data.csv" @@ -142,7 +143,14 @@ namespace Pinetime { uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex + uint16_t sleepCycleDuration = 90; // sleep cycle duration in minutes + uint16_t GetSleepCycles() { + uint8_t hours = GetCurrentHour() - startTimeHours; + uint8_t minutes = GetCurrentMinute() - startTimeMinutes; + uint16_t totalMinutes = hours * 60 + minutes; + return totalMinutes * 100 / sleepCycleDuration; + } WakeAlarmSettings GetWakeAlarm() const { return wakeAlarm; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index cbe2f78b63..65ab14bd42 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -50,10 +50,11 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { screen->OnButtonEvent(obj, event); } -// static void StopAlarmTaskCallback(lv_task_t* task) { -// auto* screen = static_cast(task->user_data); -// screen->StopAlerting(); -// } +static void SnoozeAlarmTaskCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + screen->StopAlerting(); + screen->SnoozeWakeAlarm(); +} Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, @@ -199,9 +200,50 @@ void Sleep::DrawInfoScreen() { lv_obj_set_style_local_text_color(label_start_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); } + // The alarm info + label_alarm_time = lv_label_create(lv_scr_act(), nullptr); + if (infiniSleepController.GetWakeAlarm().isEnabled) { + lv_label_set_text_fmt(label_alarm_time, "Alarm at: %02d:%02d", infiniSleepController.GetWakeAlarm().hours, infiniSleepController.GetWakeAlarm().minutes); + } else { + lv_label_set_text_static(label_alarm_time, "Alarm is not set."); + } + lv_obj_align(label_alarm_time, label_hr, LV_ALIGN_CENTER, 0, 40); + lv_obj_set_style_local_text_color(label_alarm_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + + // Gradual Wake info + label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); + if (infiniSleepController.GetInfiniSleepSettings().graddualWake) { + lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: %d/9", infiniSleepController.gradualWakeVibration); + } else { + lv_label_set_text_static(label_gradual_wake, "Gradual Wake: OFF"); + } + lv_obj_align(label_gradual_wake, label_hr, LV_ALIGN_CENTER, 0, 60); + lv_obj_set_style_local_text_color(label_gradual_wake, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + + // Sleep Cycles Info + if (infiniSleepController.IsEnabled()) { + label_sleep_cycles = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(label_sleep_cycles, "Sleep Cycles: %1i.%02i", infiniSleepController.GetSleepCycles() / 100, infiniSleepController.GetSleepCycles() % 100); + lv_obj_align(label_sleep_cycles, label_hr, LV_ALIGN_CENTER, 0, 80); + lv_obj_set_style_local_text_color(label_sleep_cycles, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + } + + // Total sleep time + if (infiniSleepController.IsEnabled()) { + label_total_sleep = lv_label_create(lv_scr_act(), nullptr); + + uint8_t hours = infiniSleepController.GetCurrentHour() - infiniSleepController.startTimeHours; + uint8_t minutes = infiniSleepController.GetCurrentMinute() - infiniSleepController.startTimeMinutes; + uint16_t totalMinutes = hours * 60 + minutes; + + lv_label_set_text_fmt(label_total_sleep, "Total Sleep: %dh%dm", totalMinutes / 60, totalMinutes % 60); + lv_obj_align(label_total_sleep, label_hr, LV_ALIGN_CENTER, 0, 100); + lv_obj_set_style_local_text_color(label_total_sleep, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + } + trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); trackerToggleBtn->user_data = this; - lv_obj_align(trackerToggleBtn, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); + lv_obj_align(trackerToggleBtn, lv_scr_act(), LV_ALIGN_CENTER, 0, 100); trackerToggleLabel = lv_label_create(trackerToggleBtn, nullptr); if (infiniSleepController.IsTrackerEnabled()) { @@ -348,13 +390,13 @@ void Sleep::OnValueChanged() { UpdateWakeAlarmTime(); } -// Currently snoozes 5 minutes +// Currently snoozes baeed on define statement in InfiniSleepController.h void Sleep::SnoozeWakeAlarm() { if (minuteCounter.GetValue() >= 55) { minuteCounter.SetValue(0); hourCounter.SetValue((infiniSleepController.GetCurrentHour() + 1)); } else { - minuteCounter.SetValue(infiniSleepController.GetCurrentMinute() + 5); + minuteCounter.SetValue(infiniSleepController.GetCurrentMinute() + SNOOZE_MINUTES); } infiniSleepController.SetPreSnoozeTime(); infiniSleepController.isSnoozing = true; @@ -377,7 +419,7 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); - //taskStopWakeAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); + taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(180 * 1000), LV_TASK_PRIO_MID, this); motorController.StartAlarm(); wakeLock.Lock(); } @@ -386,9 +428,9 @@ void Sleep::StopAlerting() { infiniSleepController.StopAlerting(); motorController.StopAlarm(); SetSwitchState(LV_ANIM_OFF); - if (taskStopWakeAlarm != nullptr) { - lv_task_del(taskStopWakeAlarm); - taskStopWakeAlarm = nullptr; + if (taskSnoozeWakeAlarm != nullptr) { + lv_task_del(taskSnoozeWakeAlarm); + taskSnoozeWakeAlarm = nullptr; } wakeLock.Release(); lv_obj_set_hidden(enableSwitch, false); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 993789e1bc..70f76ec20c 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -30,6 +30,7 @@ namespace Pinetime { bool OnTouchEvent(TouchEvents event) override; void OnValueChanged(); void StopAlerting(); + void SnoozeWakeAlarm(); void UpdateDisplay(); enum class SleepDisplayState { Alarm, Info, Settings }; SleepDisplayState displayState = SleepDisplayState::Info; @@ -63,7 +64,7 @@ namespace Pinetime { lv_obj_t* lblampm = nullptr; lv_obj_t* txtMessage = nullptr; lv_obj_t* btnMessage = nullptr; - lv_task_t* taskStopWakeAlarm = nullptr; + lv_task_t* taskSnoozeWakeAlarm = nullptr; lv_task_t* taskRefresh = nullptr; @@ -72,7 +73,6 @@ namespace Pinetime { void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); - void SnoozeWakeAlarm(); void ShowAlarmInfo(); void HideAlarmInfo(); void ToggleRecurrence(); @@ -98,6 +98,10 @@ namespace Pinetime { lv_obj_t* label_hr; lv_obj_t* label_start_time; + lv_obj_t* label_alarm_time; + lv_obj_t* label_gradual_wake; + lv_obj_t* label_total_sleep; + lv_obj_t* label_sleep_cycles; // lv_task_t* mainRefreshTask; // lv_task_t* hrRefreshTask; From 1c183903c96a79d436a37549f19dbd58fb2a1587 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 19 Nov 2024 09:53:26 -0600 Subject: [PATCH 048/191] Made info screen show info from last session after tracker stopped --- .../infinisleep/InfiniSleepController.cpp | 4 ++- .../infinisleep/InfiniSleepController.h | 22 +++++++++++----- src/displayapp/screens/Sleep.cpp | 25 ++++++++----------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 3807efe79a..904bb439d6 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -60,7 +60,9 @@ void InfiniSleepController::DisableTracker() { void InfiniSleepController::UpdateTracker() { NRF_LOG_INFO("[InfiniSleepController] Updating tracker"); - UpdateBPM(); + if (infiniSleepSettings.heartRateTracking) { + UpdateBPM(); + } systemTask->PushMessage(System::Messages::SleepTrackerUpdate); xTimerStop(trackerUpdateTimer, 0); diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 0035bbd117..b0dc78f127 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -13,6 +13,7 @@ #define PSUHES_TO_STOP_ALARM 5 #define TRACKER_UPDATE_INTERVAL_MINS 5 #define TrackerDataFile "SleepTracker_Data.csv" +#define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes namespace Pinetime { namespace System { @@ -43,6 +44,8 @@ namespace Pinetime { uint8_t preSnnoozeHours = 255; uint8_t startTimeHours = 0; uint8_t startTimeMinutes = 0; + uint8_t endTimeHours = 0; + uint8_t endTimeMinutes = 0; void SetPreSnoozeTime() { if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { @@ -143,13 +146,18 @@ namespace Pinetime { uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex - uint16_t sleepCycleDuration = 90; // sleep cycle duration in minutes - uint16_t GetSleepCycles() { - uint8_t hours = GetCurrentHour() - startTimeHours; - uint8_t minutes = GetCurrentMinute() - startTimeMinutes; - uint16_t totalMinutes = hours * 60 + minutes; - return totalMinutes * 100 / sleepCycleDuration; + uint16_t totalMinutes = GetTotalSleep(); + return (totalMinutes * 100 / SLEEP_CYCLE_DURATION); + } + + uint16_t GetTotalSleep() { + uint8_t hours = (IsEnabled() ? GetCurrentHour() : endTimeHours) - startTimeHours; + uint8_t minutes = (IsEnabled() ? GetCurrentMinute() : endTimeMinutes) - startTimeMinutes; + if (hours <= 0 && minutes <= 0) { + return 0; + } + return hours * 60 + minutes; } WakeAlarmSettings GetWakeAlarm() const { @@ -169,6 +177,8 @@ namespace Pinetime { bool ToggleTracker() { if (isEnabled) { + endTimeHours = GetCurrentHour(); + endTimeMinutes = GetCurrentMinute(); DisableTracker(); } else { ClearDataCSV(TrackerDataFile); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 65ab14bd42..6dd5439d31 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -221,30 +221,25 @@ void Sleep::DrawInfoScreen() { lv_obj_set_style_local_text_color(label_gradual_wake, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); // Sleep Cycles Info - if (infiniSleepController.IsEnabled()) { - label_sleep_cycles = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_sleep_cycles, "Sleep Cycles: %1i.%02i", infiniSleepController.GetSleepCycles() / 100, infiniSleepController.GetSleepCycles() % 100); - lv_obj_align(label_sleep_cycles, label_hr, LV_ALIGN_CENTER, 0, 80); - lv_obj_set_style_local_text_color(label_sleep_cycles, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - } + label_sleep_cycles = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(label_sleep_cycles, "Sleep Cycles: %d.%d", infiniSleepController.GetSleepCycles() / 100, infiniSleepController.GetSleepCycles() % 100); + lv_obj_align(label_sleep_cycles, label_hr, LV_ALIGN_CENTER, 0, 80); + lv_obj_set_style_local_text_color(label_sleep_cycles, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); // Total sleep time - if (infiniSleepController.IsEnabled()) { - label_total_sleep = lv_label_create(lv_scr_act(), nullptr); + label_total_sleep = lv_label_create(lv_scr_act(), nullptr); - uint8_t hours = infiniSleepController.GetCurrentHour() - infiniSleepController.startTimeHours; - uint8_t minutes = infiniSleepController.GetCurrentMinute() - infiniSleepController.startTimeMinutes; - uint16_t totalMinutes = hours * 60 + minutes; + uint16_t totalMinutes = infiniSleepController.GetTotalSleep(); - lv_label_set_text_fmt(label_total_sleep, "Total Sleep: %dh%dm", totalMinutes / 60, totalMinutes % 60); - lv_obj_align(label_total_sleep, label_hr, LV_ALIGN_CENTER, 0, 100); - lv_obj_set_style_local_text_color(label_total_sleep, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - } + lv_label_set_text_fmt(label_total_sleep, "Total Sleep: %dh%dm", totalMinutes / 60, totalMinutes % 60); + lv_obj_align(label_total_sleep, label_hr, LV_ALIGN_CENTER, 0, 100); + lv_obj_set_style_local_text_color(label_total_sleep, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); trackerToggleBtn->user_data = this; lv_obj_align(trackerToggleBtn, lv_scr_act(), LV_ALIGN_CENTER, 0, 100); + // Tracker toggle button trackerToggleLabel = lv_label_create(trackerToggleBtn, nullptr); if (infiniSleepController.IsTrackerEnabled()) { lv_label_set_text_static(trackerToggleLabel, "Stop"); From 2ad5dd9d2a1ca92b99ab5322a9932f0403da4a4c Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 19 Nov 2024 10:26:36 -0600 Subject: [PATCH 049/191] Fixed bug with gradualWakeVibration not in sync with step when scheduling --- src/components/infinisleep/InfiniSleepController.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 904bb439d6..032c69c9d1 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -140,6 +140,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { // make sure graudal wake steps are possible while (gradualWakeStep != 0 && secondsToWakeAlarm <= gradualWakeSteps[gradualWakeStep-1]) { gradualWakeStep--; + gradualWakeVibration = gradualWakeStep; } // Calculate the period for the gradualWakeTimer From 18a4d4ef2e853426474e432f65b63b0cd1c5a1db Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 19 Nov 2024 14:17:48 -0600 Subject: [PATCH 050/191] Added suggestion alarm time based on desired sleep cycles constant Removed recurrence toggle since alarm would be adjusted each night. Updated tracker file name define name --- .../infinisleep/InfiniSleepController.cpp | 5 ++- .../infinisleep/InfiniSleepController.h | 11 +++-- src/displayapp/screens/Sleep.cpp | 43 +++++++++++++++---- src/displayapp/screens/Sleep.h | 1 + 4 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 032c69c9d1..02aae14042 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -95,6 +95,9 @@ void InfiniSleepController::SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAl } void InfiniSleepController::ScheduleWakeAlarm() { + // This line essentially removes the ability to change recurrance type and sets it to daily + SetRecurrence(RecurType::Daily); + // Determine the next time the wake alarm needs to go off and set the timer xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); @@ -230,7 +233,7 @@ void InfiniSleepController::UpdateBPM() { // Write data to CSV const int motion = 0; // Placeholder for motion data std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; - WriteDataCSV(TrackerDataFile, data, 1); + WriteDataCSV(TRACKER_DATA_FILE_NAME, data, 1); } void InfiniSleepController::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index b0dc78f127..c260884c00 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -12,8 +12,9 @@ #define SNOOZE_MINUTES 3 #define PSUHES_TO_STOP_ALARM 5 #define TRACKER_UPDATE_INTERVAL_MINS 5 -#define TrackerDataFile "SleepTracker_Data.csv" +#define TRACKER_DATA_FILE_NAME "SleepTracker_Data.csv" #define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes +#define DESIRED_CYCLES 5 // desired number of sleep cycles namespace Pinetime { namespace System { @@ -136,7 +137,7 @@ namespace Pinetime { uint8_t version = wakeAlarmFormatVersion; uint8_t hours = 7; uint8_t minutes = 0; - RecurType recurrence = RecurType::None; + RecurType recurrence = RecurType::Daily; bool isEnabled = false; }; @@ -160,6 +161,10 @@ namespace Pinetime { return hours * 60 + minutes; } + uint16_t GetSuggestedSleepTime() { + return SLEEP_CYCLE_DURATION * DESIRED_CYCLES; + } + WakeAlarmSettings GetWakeAlarm() const { return wakeAlarm; } @@ -181,7 +186,7 @@ namespace Pinetime { endTimeMinutes = GetCurrentMinute(); DisableTracker(); } else { - ClearDataCSV(TrackerDataFile); + ClearDataCSV(TRACKER_DATA_FILE_NAME); startTimeHours = GetCurrentHour(); startTimeMinutes = GetCurrentMinute(); EnableTracker(); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 6dd5439d31..6aaad63dd0 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -144,14 +144,22 @@ void Sleep::DrawAlarmScreen() { static constexpr lv_color_t bgColor = Colors::bgAlt; - btnRecur = lv_btn_create(lv_scr_act(), nullptr); - btnRecur->user_data = this; - lv_obj_set_event_cb(btnRecur, btnEventHandler); - lv_obj_set_size(btnRecur, 115, 50); - lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - txtRecur = lv_label_create(btnRecur, nullptr); - SetRecurButtonState(); - lv_obj_set_style_local_bg_color(btnRecur, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); + btnSuggestedAlarm = lv_btn_create(lv_scr_act(), nullptr); + btnSuggestedAlarm->user_data = this; + lv_obj_set_event_cb(btnSuggestedAlarm, btnEventHandler); + lv_obj_set_size(btnSuggestedAlarm, 115, 50); + lv_obj_align(btnSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + txtSuggestedAlarm = lv_label_create(btnSuggestedAlarm, nullptr); + lv_label_set_text_static(txtSuggestedAlarm, "Suggested"); + + // btnRecur = lv_btn_create(lv_scr_act(), nullptr); + // btnRecur->user_data = this; + // lv_obj_set_event_cb(btnRecur, btnEventHandler); + // lv_obj_set_size(btnRecur, 115, 50); + // lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + // txtRecur = lv_label_create(btnRecur, nullptr); + // SetRecurButtonState(); + // lv_obj_set_style_local_bg_color(btnRecur, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); btnInfo = lv_btn_create(lv_scr_act(), nullptr); btnInfo->user_data = this; @@ -321,6 +329,25 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { UpdateDisplay(); return; } + if (obj == btnSuggestedAlarm) { + // Set the suggested time + uint16_t totalSuggestedMinutes = infiniSleepController.GetSuggestedSleepTime(); + uint8_t suggestedHours = totalSuggestedMinutes / 60; + uint8_t suggestedMinutes = totalSuggestedMinutes % 60; + + // Time for alarm, current time + suggested sleep time + uint8_t alarmHour = (infiniSleepController.GetCurrentHour() + suggestedHours) % 24; + uint8_t alarmMinute = (infiniSleepController.GetCurrentMinute() + suggestedMinutes) % 60; + + hourCounter.SetValue(alarmHour); + minuteCounter.SetValue(alarmMinute); + + infiniSleepController.DisableWakeAlarm(); + UpdateWakeAlarmTime(); + lv_switch_on(enableSwitch, LV_ANIM_OFF); + infiniSleepController.ScheduleWakeAlarm(); + return; + } if (obj == btnRecur) { DisableWakeAlarm(); ToggleRecurrence(); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 70f76ec20c..23b208b9c4 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -102,6 +102,7 @@ namespace Pinetime { lv_obj_t* label_gradual_wake; lv_obj_t* label_total_sleep; lv_obj_t* label_sleep_cycles; + lv_obj_t *btnSuggestedAlarm, *txtSuggestedAlarm; // lv_task_t* mainRefreshTask; // lv_task_t* hrRefreshTask; From 1354a197973ff11a76953ca262b1933473a0cf12 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 19 Nov 2024 20:06:27 -0600 Subject: [PATCH 051/191] Fixed total sleep calculation and cycles display bugs --- .../infinisleep/InfiniSleepController.cpp | 2 +- .../infinisleep/InfiniSleepController.h | 19 ++++++++++++++----- src/displayapp/screens/Sleep.cpp | 2 +- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 02aae14042..bcb42e997f 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -47,7 +47,7 @@ void InfiniSleepController::EnableTracker() { DisableTracker(); NRF_LOG_INFO("[InfiniSleepController] Enabling tracker"); isEnabled = true; - trackerUpdateTimer = xTimerCreate("TrackerUpdate", 5 * configTICK_RATE_HZ, pdFALSE, this, SetOffTrackerUpdate); + trackerUpdateTimer = xTimerCreate("TrackerUpdate", pdMS_TO_TICKS(TRACKER_UPDATE_INTERVAL_MINS * 60 * 1000), pdFALSE, this, SetOffTrackerUpdate); xTimerStart(trackerUpdateTimer, 0); } diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index c260884c00..53af458988 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -153,12 +153,21 @@ namespace Pinetime { } uint16_t GetTotalSleep() { - uint8_t hours = (IsEnabled() ? GetCurrentHour() : endTimeHours) - startTimeHours; - uint8_t minutes = (IsEnabled() ? GetCurrentMinute() : endTimeMinutes) - startTimeMinutes; - if (hours <= 0 && minutes <= 0) { - return 0; + uint8_t endHours = IsEnabled() ? GetCurrentHour() : endTimeHours; + uint8_t endMinutes = IsEnabled() ? GetCurrentMinute() : endTimeMinutes; + + // Calculate total minutes for start and end times + uint16_t startTotalMinutes = startTimeHours * 60 + startTimeMinutes; + uint16_t endTotalMinutes = endHours * 60 + endMinutes; + + // If end time is before start time, add 24 hours to end time (handle crossing midnight) + if (endTotalMinutes < startTotalMinutes) { + endTotalMinutes += 24 * 60; } - return hours * 60 + minutes; + + uint16_t sleepMinutes = endTotalMinutes - startTotalMinutes; + + return sleepMinutes; } uint16_t GetSuggestedSleepTime() { diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 6aaad63dd0..dd768c0986 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -230,7 +230,7 @@ void Sleep::DrawInfoScreen() { // Sleep Cycles Info label_sleep_cycles = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_sleep_cycles, "Sleep Cycles: %d.%d", infiniSleepController.GetSleepCycles() / 100, infiniSleepController.GetSleepCycles() % 100); + lv_label_set_text_fmt(label_sleep_cycles, "Sleep Cycles: %d.%02d", infiniSleepController.GetSleepCycles() / 100, infiniSleepController.GetSleepCycles() % 100); lv_obj_align(label_sleep_cycles, label_hr, LV_ALIGN_CENTER, 0, 80); lv_obj_set_style_local_text_color(label_sleep_cycles, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); From e896e6a17ca55e4a3576e99cbeeeb3f4cd21db39 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 20 Nov 2024 12:39:40 -0600 Subject: [PATCH 052/191] Added a timeout to pushes required to stop alarm so the presses dont carry over if some time has passed This can be adjusted with the PUSHES_TO_STOP_ALARM_TIMEOUT constant in InfiniSleepController.h --- .../infinisleep/InfiniSleepController.h | 1 + src/displayapp/screens/Sleep.cpp | 17 +++++++++++++++-- src/displayapp/screens/Sleep.h | 5 ++++- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 53af458988..62152d4882 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -15,6 +15,7 @@ #define TRACKER_DATA_FILE_NAME "SleepTracker_Data.csv" #define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes #define DESIRED_CYCLES 5 // desired number of sleep cycles +#define PUSHES_TO_STOP_ALARM_TIMEOUT 2 // in seconds namespace Pinetime { namespace System { diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index dd768c0986..cbc195dfaf 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -56,6 +56,12 @@ static void SnoozeAlarmTaskCallback(lv_task_t* task) { screen->SnoozeWakeAlarm(); } +static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + screen->infiniSleepController.pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; + screen->UpdateDisplay(); +} + Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, @@ -71,6 +77,9 @@ Sleep::~Sleep() { StopAlerting(); } lv_task_del(taskRefresh); + if (taskPressesToStopAlarmTimeout != nullptr) { + lv_task_del(taskPressesToStopAlarmTimeout); + } lv_obj_clean(lv_scr_act()); infiniSleepController.SaveWakeAlarm(); infiniSleepController.SaveInfiniSleepSettings(); @@ -342,8 +351,7 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { hourCounter.SetValue(alarmHour); minuteCounter.SetValue(alarmMinute); - infiniSleepController.DisableWakeAlarm(); - UpdateWakeAlarmTime(); + OnValueChanged(); lv_switch_on(enableSwitch, LV_ANIM_OFF); infiniSleepController.ScheduleWakeAlarm(); return; @@ -362,6 +370,11 @@ bool Sleep::OnButtonPushed() { } if (infiniSleepController.IsAlerting()) { if (infiniSleepController.pushesLeftToStopWakeAlarm > 1) { + if (taskPressesToStopAlarmTimeout == nullptr) { + taskPressesToStopAlarmTimeout = lv_task_create(PressesToStopAlarmTimeoutCallback, PUSHES_TO_STOP_ALARM_TIMEOUT * 1000, LV_TASK_PRIO_MID, this); + } else { + lv_task_reset(taskPressesToStopAlarmTimeout); + } infiniSleepController.pushesLeftToStopWakeAlarm--; return true; } else { diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 23b208b9c4..a92810efb9 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -53,8 +53,9 @@ namespace Pinetime { // Read IO //std::vector> ReadDataCSV(const char* fileName) const; - private: Controllers::InfiniSleepController& infiniSleepController; + + private: System::WakeLock wakeLock; Controllers::MotorController& motorController; Controllers::Settings::ClockType clockType; @@ -68,6 +69,8 @@ namespace Pinetime { lv_task_t* taskRefresh = nullptr; + lv_task_t* taskPressesToStopAlarmTimeout = nullptr; + enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); void SetRecurButtonState(); From c2b77d3dfa55976c9972d3b1851af0819215f3d8 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 20 Nov 2024 13:23:48 -0600 Subject: [PATCH 053/191] Made the watch open to the sleep app when in an active session --- src/displayapp/DisplayApp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index fdeba6dd09..5ecac9a14e 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -354,6 +354,11 @@ void DisplayApp::Refresh() { lcd.LowPowerOff(); } else { lcd.Wakeup(); + if (infiniSleepController.IsEnabled()) { + if (currentApp != Apps::Sleep) { + LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::Up); + } + } } lv_disp_trig_activity(nullptr); ApplyBrightness(); From 8e56830a89123142863028c57d5ac332dfa515dd Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 21 Nov 2024 09:41:50 -0600 Subject: [PATCH 054/191] Restructured pushes to stop timeout --- .../infinisleep/InfiniSleepController.cpp | 2 +- src/components/infinisleep/InfiniSleepController.h | 4 ++-- src/displayapp/screens/Sleep.cpp | 13 ++++--------- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index bcb42e997f..cdee6e7128 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -102,7 +102,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); - pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; + pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; gradualWakeStep = 9; gradualWakeVibration = 9; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 62152d4882..5e95f9cc5b 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -10,7 +10,7 @@ #include #define SNOOZE_MINUTES 3 -#define PSUHES_TO_STOP_ALARM 5 +#define PUSHES_TO_STOP_ALARM 5 #define TRACKER_UPDATE_INTERVAL_MINS 5 #define TRACKER_DATA_FILE_NAME "SleepTracker_Data.csv" #define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes @@ -39,7 +39,7 @@ namespace Pinetime { void StopAlerting(); enum class RecurType { None, Daily, Weekdays }; - uint8_t pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; + uint8_t pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; bool isSnoozing = false; uint8_t preSnoozeMinutes = 255; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index cbc195dfaf..679b40e8ce 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -58,7 +58,7 @@ static void SnoozeAlarmTaskCallback(lv_task_t* task) { static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { auto* screen = static_cast(task->user_data); - screen->infiniSleepController.pushesLeftToStopWakeAlarm = PSUHES_TO_STOP_ALARM; + screen->infiniSleepController.pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; screen->UpdateDisplay(); } @@ -70,6 +70,7 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, UpdateDisplay(); taskRefresh = lv_task_create(RefreshTaskCallback, 2000, LV_TASK_PRIO_MID, this); + taskPressesToStopAlarmTimeout = lv_task_create(PressesToStopAlarmTimeoutCallback, PUSHES_TO_STOP_ALARM_TIMEOUT * 1000, LV_TASK_PRIO_MID, this); } Sleep::~Sleep() { @@ -77,9 +78,7 @@ Sleep::~Sleep() { StopAlerting(); } lv_task_del(taskRefresh); - if (taskPressesToStopAlarmTimeout != nullptr) { - lv_task_del(taskPressesToStopAlarmTimeout); - } + lv_task_del(taskPressesToStopAlarmTimeout); lv_obj_clean(lv_scr_act()); infiniSleepController.SaveWakeAlarm(); infiniSleepController.SaveInfiniSleepSettings(); @@ -370,11 +369,7 @@ bool Sleep::OnButtonPushed() { } if (infiniSleepController.IsAlerting()) { if (infiniSleepController.pushesLeftToStopWakeAlarm > 1) { - if (taskPressesToStopAlarmTimeout == nullptr) { - taskPressesToStopAlarmTimeout = lv_task_create(PressesToStopAlarmTimeoutCallback, PUSHES_TO_STOP_ALARM_TIMEOUT * 1000, LV_TASK_PRIO_MID, this); - } else { - lv_task_reset(taskPressesToStopAlarmTimeout); - } + lv_task_reset(taskPressesToStopAlarmTimeout); infiniSleepController.pushesLeftToStopWakeAlarm--; return true; } else { From 797dc584a122cf6e54147dfa53e49bdae0dc8443 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 21 Nov 2024 10:31:30 -0600 Subject: [PATCH 055/191] Added saving of prev sleep session info in case watch crashes so it can be loaded --- .../infinisleep/InfiniSleepController.cpp | 25 ++++++++++++ .../infinisleep/InfiniSleepController.h | 38 ++++++++++++------- src/displayapp/screens/Sleep.cpp | 8 +++- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index cdee6e7128..ebc36ff294 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -37,6 +37,7 @@ void InfiniSleepController::Init(System::SystemTask* systemTask) { gradualWakeTimer = xTimerCreate("GradualWake", 1, pdFALSE, this, SetOffGradualWake); LoadSettingsFromFile(); + LoadPrevSessionData(); if (wakeAlarm.isEnabled) { NRF_LOG_INFO("[InfiniSleepController] Loaded wake alarm was enabled, scheduling"); ScheduleWakeAlarm(); @@ -345,4 +346,28 @@ void InfiniSleepController::SaveSettingsToFile() const { fs.FileWrite(&settingsFile, reinterpret_cast(&infiniSleepSettings), sizeof(infiniSleepSettings)); fs.FileClose(&settingsFile); NRF_LOG_INFO("[InfiniSleepController] Saved InfiniSleep settings"); +} + +void InfiniSleepController::SavePrevSessionData() const { + lfs_file_t prevSessionFile; + if (fs.FileOpen(&prevSessionFile, PREV_SESSION_DATA_FILE_NAME, LFS_O_WRONLY | LFS_O_CREAT) != LFS_ERR_OK) { + NRF_LOG_WARNING("[InfiniSleepController] Failed to open previous session data file for saving"); + return; + } + + fs.FileWrite(&prevSessionFile, reinterpret_cast(&prevSessionData), sizeof(prevSessionData)); + fs.FileClose(&prevSessionFile); + NRF_LOG_INFO("[InfiniSleepController] Saved previous session data"); +} + +void InfiniSleepController::LoadPrevSessionData() { + lfs_file_t prevSessionFile; + if (fs.FileOpen(&prevSessionFile, PREV_SESSION_DATA_FILE_NAME, LFS_O_RDONLY) != LFS_ERR_OK) { + NRF_LOG_WARNING("[InfiniSleepController] Failed to open previous session data file"); + return; + } + + fs.FileRead(&prevSessionFile, reinterpret_cast(&prevSessionData), sizeof(prevSessionData)); + fs.FileClose(&prevSessionFile); + NRF_LOG_INFO("[InfiniSleepController] Loaded previous session data"); } \ No newline at end of file diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 5e95f9cc5b..22286d1abb 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -13,6 +13,7 @@ #define PUSHES_TO_STOP_ALARM 5 #define TRACKER_UPDATE_INTERVAL_MINS 5 #define TRACKER_DATA_FILE_NAME "SleepTracker_Data.csv" +#define PREV_SESSION_DATA_FILE_NAME "SleepTracker_PrevSession.csv" #define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes #define DESIRED_CYCLES 5 // desired number of sleep cycles #define PUSHES_TO_STOP_ALARM_TIMEOUT 2 // in seconds @@ -44,10 +45,16 @@ namespace Pinetime { bool isSnoozing = false; uint8_t preSnoozeMinutes = 255; uint8_t preSnnoozeHours = 255; - uint8_t startTimeHours = 0; - uint8_t startTimeMinutes = 0; - uint8_t endTimeHours = 0; - uint8_t endTimeMinutes = 0; + + // Struct for sessions + struct SessionData { + uint8_t startTimeHours = 0; + uint8_t startTimeMinutes = 0; + uint8_t endTimeHours = 0; + uint8_t endTimeMinutes = 0; + }; + + SessionData prevSessionData; void SetPreSnoozeTime() { if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { @@ -153,12 +160,12 @@ namespace Pinetime { return (totalMinutes * 100 / SLEEP_CYCLE_DURATION); } - uint16_t GetTotalSleep() { - uint8_t endHours = IsEnabled() ? GetCurrentHour() : endTimeHours; - uint8_t endMinutes = IsEnabled() ? GetCurrentMinute() : endTimeMinutes; + uint16_t GetTotalSleep() const { + uint8_t endHours = IsEnabled() ? GetCurrentHour() : prevSessionData.endTimeHours; + uint8_t endMinutes = IsEnabled() ? GetCurrentMinute() : prevSessionData.endTimeMinutes; // Calculate total minutes for start and end times - uint16_t startTotalMinutes = startTimeHours * 60 + startTimeMinutes; + uint16_t startTotalMinutes = prevSessionData.startTimeHours * 60 + prevSessionData.startTimeMinutes; uint16_t endTotalMinutes = endHours * 60 + endMinutes; // If end time is before start time, add 24 hours to end time (handle crossing midnight) @@ -192,13 +199,14 @@ namespace Pinetime { bool ToggleTracker() { if (isEnabled) { - endTimeHours = GetCurrentHour(); - endTimeMinutes = GetCurrentMinute(); + prevSessionData.endTimeHours = GetCurrentHour(); + prevSessionData.endTimeMinutes = GetCurrentMinute(); + SavePrevSessionData(); DisableTracker(); } else { ClearDataCSV(TRACKER_DATA_FILE_NAME); - startTimeHours = GetCurrentHour(); - startTimeMinutes = GetCurrentMinute(); + prevSessionData.startTimeHours = GetCurrentHour(); + prevSessionData.startTimeMinutes = GetCurrentMinute(); EnableTracker(); } return isEnabled; @@ -208,11 +216,11 @@ namespace Pinetime { return isEnabled; } - uint8_t GetCurrentHour() { + uint8_t GetCurrentHour() const { return dateTimeController.Hours(); } - uint8_t GetCurrentMinute() { + uint8_t GetCurrentMinute() const { return dateTimeController.Minutes(); } @@ -251,6 +259,8 @@ namespace Pinetime { void LoadSettingsFromFile(); void SaveSettingsToFile() const; + void LoadPrevSessionData(); + void SavePrevSessionData() const; // For File IO void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 679b40e8ce..56d0c088ec 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -205,13 +205,17 @@ void Sleep::DrawInfoScreen() { lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); label_hr = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_hr, "HR: %d", infiniSleepController.rollingBpm); + if (infiniSleepController.rollingBpm == 0) { + lv_label_set_text_static(label_hr, "HR: --"); + } else { + lv_label_set_text_fmt(label_hr, "HR: %d", infiniSleepController.rollingBpm); + } lv_obj_align(label_hr, lblTime, LV_ALIGN_CENTER, 0, 50); lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); if (infiniSleepController.IsEnabled()) { label_start_time = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_start_time, "Began at: %02d:%02d", infiniSleepController.startTimeHours, infiniSleepController.startTimeMinutes); + lv_label_set_text_fmt(label_start_time, "Began at: %02d:%02d", infiniSleepController.prevSessionData.startTimeHours, infiniSleepController.prevSessionData.startTimeMinutes); lv_obj_align(label_start_time, label_hr, LV_ALIGN_CENTER, 0, 20); lv_obj_set_style_local_text_color(label_start_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); } From 19b51e8d24cd7bb08c70499688a57f95f538beb5 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 21 Nov 2024 10:35:47 -0600 Subject: [PATCH 056/191] Reset pushes needed to stop alarm when watch sleeps --- src/displayapp/DisplayApp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 5ecac9a14e..8a4c15076a 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -295,6 +295,7 @@ void DisplayApp::Refresh() { if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) { switch (msg) { case Messages::GoToSleep: + infiniSleepController.pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; case Messages::GoToAOD: // Checking if SystemTask is sleeping is purely an optimisation. // If it's no longer sleeping since it sent GoToSleep, it has From 344f5b0a6e9438dc2bac41d51bf9955947de92e4 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 21 Nov 2024 22:03:41 -0600 Subject: [PATCH 057/191] Moved pushes count reset to system task --- src/displayapp/DisplayApp.cpp | 1 - src/systemtask/SystemTask.cpp | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 8a4c15076a..5ecac9a14e 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -295,7 +295,6 @@ void DisplayApp::Refresh() { if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) { switch (msg) { case Messages::GoToSleep: - infiniSleepController.pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; case Messages::GoToAOD: // Checking if SystemTask is sleeping is purely an optimisation. // If it's no longer sleeping since it sent GoToSleep, it has diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index bc92f1d83e..1425b308cf 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -202,6 +202,7 @@ void SystemTask::Work() { GoToRunning(); break; case Messages::GoToSleep: + infiniSleepController.pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; GoToSleep(); break; case Messages::OnNewTime: From 95e868bef171920571236878b52f1b396125a87e Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 22 Nov 2024 11:41:30 -0600 Subject: [PATCH 058/191] Fixed some bugs with snooze time being set weird --- .../infinisleep/InfiniSleepController.cpp | 9 ++++ .../infinisleep/InfiniSleepController.h | 4 +- src/displayapp/DisplayApp.cpp | 4 +- src/displayapp/screens/Sleep.cpp | 49 +++++++++++++------ src/displayapp/screens/Sleep.h | 1 + 5 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index ebc36ff294..1d44ad438c 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -150,6 +150,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); + gradualWakeVibration = gradualWakeStep; xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } @@ -168,6 +169,7 @@ void InfiniSleepController::DisableWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); gradualWakeStep = 9; + gradualWakeVibration = 9; isAlerting = false; if (wakeAlarm.isEnabled) { wakeAlarm.isEnabled = false; @@ -175,6 +177,12 @@ void InfiniSleepController::DisableWakeAlarm() { } } +void InfiniSleepController::EnableWakeAlarm() { + wakeAlarm.isEnabled = true; + wakeAlarmChanged = true; + ScheduleWakeAlarm(); +} + void InfiniSleepController::SetOffWakeAlarmNow() { isAlerting = true; systemTask->PushMessage(System::Messages::SetOffWakeAlarm); @@ -186,6 +194,7 @@ void InfiniSleepController::SetOffGradualWakeNow() { // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); + gradualWakeVibration = gradualWakeStep; xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 22286d1abb..c6fd926198 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -34,6 +34,7 @@ namespace Pinetime { void SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin); void ScheduleWakeAlarm(); void DisableWakeAlarm(); + void EnableWakeAlarm(); void SetOffWakeAlarmNow(); void SetOffGradualWakeNow(); uint32_t SecondsToWakeAlarm() const; @@ -155,6 +156,8 @@ namespace Pinetime { uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex + uint8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex + uint16_t GetSleepCycles() { uint16_t totalMinutes = GetTotalSleep(); return (totalMinutes * 100 / SLEEP_CYCLE_DURATION); @@ -240,7 +243,6 @@ namespace Pinetime { bool isAlerting = false; bool isGradualWakeAlerting = false; - uint8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex bool wakeAlarmChanged = false; bool isEnabled = false; bool settingsChanged = false; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 5ecac9a14e..c39e5fd045 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -406,8 +406,10 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } - motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1+infiniSleepController.gradualWakeVibration--]); + motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1+infiniSleepController.gradualWakeVibration]); + NRF_LOG_INFO("Gradual wake triggered"); + break; case Messages::SleepTrackerUpdate: if (currentApp == Apps::Sleep) { diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 56d0c088ec..dbca31c763 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -50,11 +50,11 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { screen->OnButtonEvent(obj, event); } -static void SnoozeAlarmTaskCallback(lv_task_t* task) { - auto* screen = static_cast(task->user_data); - screen->StopAlerting(); - screen->SnoozeWakeAlarm(); -} +// static void SnoozeAlarmTaskCallback(lv_task_t* task) { +// auto* screen = static_cast(task->user_data); +// screen->StopAlerting(); +// screen->SnoozeWakeAlarm(); +// } static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { auto* screen = static_cast(task->user_data); @@ -79,6 +79,9 @@ Sleep::~Sleep() { } lv_task_del(taskRefresh); lv_task_del(taskPressesToStopAlarmTimeout); + if (taskSnoozeWakeAlarm != nullptr) { + lv_task_del(taskSnoozeWakeAlarm); + } lv_obj_clean(lv_scr_act()); infiniSleepController.SaveWakeAlarm(); infiniSleepController.SaveInfiniSleepSettings(); @@ -91,6 +94,13 @@ void Sleep::DisableWakeAlarm() { } } +void Sleep::EnableWakeAlarm() { + if (!infiniSleepController.GetWakeAlarm().isEnabled) { + infiniSleepController.EnableWakeAlarm(); + lv_switch_on(enableSwitch, LV_ANIM_ON); + } +} + void Sleep::Refresh() { UpdateDisplay(); } @@ -127,12 +137,12 @@ void Sleep::DrawAlarmScreen() { lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); } - hourCounter.SetValue(infiniSleepController.Hours()); + hourCounter.SetValue(infiniSleepController.GetWakeAlarm().hours); hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler); minuteCounter.Create(); lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - minuteCounter.SetValue(infiniSleepController.Minutes()); + minuteCounter.SetValue(infiniSleepController.GetWakeAlarm().minutes); minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler); lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); @@ -351,6 +361,8 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { uint8_t alarmHour = (infiniSleepController.GetCurrentHour() + suggestedHours) % 24; uint8_t alarmMinute = (infiniSleepController.GetCurrentMinute() + suggestedMinutes) % 60; + infiniSleepController.SetWakeAlarmTime(alarmHour, alarmMinute); + hourCounter.SetValue(alarmHour); minuteCounter.SetValue(alarmMinute); @@ -426,16 +438,23 @@ void Sleep::OnValueChanged() { // Currently snoozes baeed on define statement in InfiniSleepController.h void Sleep::SnoozeWakeAlarm() { - if (minuteCounter.GetValue() >= 55) { - minuteCounter.SetValue(0); - hourCounter.SetValue((infiniSleepController.GetCurrentHour() + 1)); - } else { - minuteCounter.SetValue(infiniSleepController.GetCurrentMinute() + SNOOZE_MINUTES); + if (taskSnoozeWakeAlarm != nullptr) { + lv_task_del(taskSnoozeWakeAlarm); + taskSnoozeWakeAlarm = nullptr; } + + uint16_t totalAlarmMinutes = infiniSleepController.GetCurrentHour() * 60 + infiniSleepController.GetCurrentMinute(); + uint16_t newSnoozeMinutes = totalAlarmMinutes + SNOOZE_MINUTES; + infiniSleepController.SetPreSnoozeTime(); infiniSleepController.isSnoozing = true; - UpdateWakeAlarmTime(); - SetSwitchState(LV_ANIM_OFF); + + infiniSleepController.SetWakeAlarmTime(newSnoozeMinutes / 60, newSnoozeMinutes % 60); + + hourCounter.SetValue(newSnoozeMinutes / 60); + minuteCounter.SetValue(newSnoozeMinutes % 60); + + lv_switch_on(enableSwitch, LV_ANIM_OFF); infiniSleepController.ScheduleWakeAlarm(); } @@ -453,7 +472,7 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); - taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(180 * 1000), LV_TASK_PRIO_MID, this); + //taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(5 * 1000), LV_TASK_PRIO_MID, this); motorController.StartAlarm(); wakeLock.Lock(); } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index a92810efb9..5e24b79812 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -73,6 +73,7 @@ namespace Pinetime { enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); + void EnableWakeAlarm(); void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); From 99c43fbb27fef3395cfd97f590b1138cb9c2db4e Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 22 Nov 2024 13:24:39 -0600 Subject: [PATCH 059/191] Code optimizations & brought back more memory --- src/FreeRTOSConfig.h | 2 +- .../infinisleep/InfiniSleepController.cpp | 40 +++++------ .../infinisleep/InfiniSleepController.h | 19 +++--- src/displayapp/screens/Sleep.cpp | 66 +++++++++---------- src/displayapp/screens/Sleep.h | 6 +- 5 files changed, 67 insertions(+), 66 deletions(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 67c33a34cc..4696e386f0 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,7 +62,7 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) -#define configTOTAL_HEAP_SIZE (1024 * 40) +#define configTOTAL_HEAP_SIZE (1024 * 39) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 1d44ad438c..03552291b7 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -97,7 +97,7 @@ void InfiniSleepController::SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAl void InfiniSleepController::ScheduleWakeAlarm() { // This line essentially removes the ability to change recurrance type and sets it to daily - SetRecurrence(RecurType::Daily); + //SetRecurrence(RecurType::Daily); // Determine the next time the wake alarm needs to go off and set the timer xTimerStop(wakeAlarmTimer, 0); @@ -126,13 +126,13 @@ void InfiniSleepController::ScheduleWakeAlarm() { tmWakeAlarmTime->tm_sec = 0; // if alarm is in weekday-only mode, make sure it shifts to the next weekday - if (wakeAlarm.recurrence == RecurType::Weekdays) { - if (tmWakeAlarmTime->tm_wday == 0) {// Sunday, shift 1 day - tmWakeAlarmTime->tm_mday += 1; - } else if (tmWakeAlarmTime->tm_wday == 6) { // Saturday, shift 2 days - tmWakeAlarmTime->tm_mday += 2; - } - } + // if (wakeAlarm.recurrence == RecurType::Weekdays) { + // if (tmWakeAlarmTime->tm_wday == 0) {// Sunday, shift 1 day + // tmWakeAlarmTime->tm_mday += 1; + // } else if (tmWakeAlarmTime->tm_wday == 6) { // Saturday, shift 2 days + // tmWakeAlarmTime->tm_mday += 2; + // } + // } tmWakeAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST // now can convert back to a time_point @@ -203,22 +203,22 @@ void InfiniSleepController::SetOffGradualWakeNow() { void InfiniSleepController::StopAlerting() { isAlerting = false; // Disable the alarm unless it is recurring - if (wakeAlarm.recurrence == RecurType::None) { + //if (wakeAlarm.recurrence == RecurType::None) { wakeAlarm.isEnabled = false; wakeAlarmChanged = true; - } else { - // Schedule the alarm for the next day - ScheduleWakeAlarm(); - } + // } else { + // // Schedule the alarm for the next day + // ScheduleWakeAlarm(); + // } } -void InfiniSleepController::SetRecurrence(RecurType recurrence) { - if (wakeAlarm.recurrence == recurrence) { - return; - } - wakeAlarm.recurrence = recurrence; - wakeAlarmChanged = true; -} +// void InfiniSleepController::SetRecurrence(RecurType recurrence) { +// if (wakeAlarm.recurrence == recurrence) { +// return; +// } +// wakeAlarm.recurrence = recurrence; +// wakeAlarmChanged = true; +// } /* Sleep Tracking Section */ diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index c6fd926198..004a5c1ae2 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -6,6 +6,7 @@ #include "components/datetime/DateTimeController.h" #include "components/fs/FS.h" #include "components/heartrate/HeartRateController.h" +#include "components/alarm/AlarmController.h" #include @@ -39,7 +40,7 @@ namespace Pinetime { void SetOffGradualWakeNow(); uint32_t SecondsToWakeAlarm() const; void StopAlerting(); - enum class RecurType { None, Daily, Weekdays }; + //enum class RecurType { None, Daily, Weekdays }; uint8_t pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; @@ -96,11 +97,11 @@ namespace Pinetime { void DisableTracker(); void UpdateTracker(); - RecurType Recurrence() const { - return wakeAlarm.recurrence; - } + // RecurType Recurrence() const { + // return wakeAlarm.recurrence; + // } - void SetRecurrence(RecurType recurrence); + // void SetRecurrence(RecurType recurrence); bool BodyTrackingEnabled() const { return infiniSleepSettings.bodyTracking; @@ -143,16 +144,16 @@ namespace Pinetime { static constexpr uint8_t wakeAlarmFormatVersion = 1; struct WakeAlarmSettings { - uint8_t version = wakeAlarmFormatVersion; + static constexpr uint8_t version = wakeAlarmFormatVersion; uint8_t hours = 7; uint8_t minutes = 0; - RecurType recurrence = RecurType::Daily; + AlarmController::RecurType recurrence = AlarmController::RecurType::Daily; bool isEnabled = false; }; // Dertermine the steps for the gradual wake alarm, the corresponding vibration durations determine the power of the vibration - uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds - uint16_t gradualWakeVibrationDurations[9] = {1200, 1200, 1000, 1000, 1000, 700, 700, 700, 500}; // In ms + static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds + static constexpr uint16_t gradualWakeVibrationDurations[9] = {1200, 1200, 1000, 1000, 1000, 700, 700, 700, 500}; // In ms uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index dbca31c763..aba30425ee 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -371,10 +371,10 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { infiniSleepController.ScheduleWakeAlarm(); return; } - if (obj == btnRecur) { - DisableWakeAlarm(); - ToggleRecurrence(); - } + // if (obj == btnRecur) { + // DisableWakeAlarm(); + // ToggleRecurrence(); + // } } } @@ -536,33 +536,33 @@ void Sleep::HideAlarmInfo() { btnMessage = nullptr; } -void Sleep::SetRecurButtonState() { - using Pinetime::Controllers::InfiniSleepController; - switch (infiniSleepController.Recurrence()) { - case InfiniSleepController::RecurType::None: - lv_label_set_text_static(txtRecur, "ONCE"); - break; - case InfiniSleepController::RecurType::Daily: - lv_label_set_text_static(txtRecur, "DAILY"); - break; - case InfiniSleepController::RecurType::Weekdays: - lv_label_set_text_static(txtRecur, "MON-FRI"); - break; - } -} +// void Sleep::SetRecurButtonState() { +// using Pinetime::Controllers::InfiniSleepController; +// switch (infiniSleepController.Recurrence()) { +// case InfiniSleepController::RecurType::None: +// lv_label_set_text_static(txtRecur, "ONCE"); +// break; +// case InfiniSleepController::RecurType::Daily: +// lv_label_set_text_static(txtRecur, "DAILY"); +// break; +// case InfiniSleepController::RecurType::Weekdays: +// lv_label_set_text_static(txtRecur, "MON-FRI"); +// break; +// } +// } -void Sleep::ToggleRecurrence() { - using Pinetime::Controllers::InfiniSleepController; - switch (infiniSleepController.Recurrence()) { - case InfiniSleepController::RecurType::None: - infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Daily); - break; - case InfiniSleepController::RecurType::Daily: - infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Weekdays); - break; - case InfiniSleepController::RecurType::Weekdays: - infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); - break; - } - SetRecurButtonState(); -} \ No newline at end of file +// void Sleep::ToggleRecurrence() { +// using Pinetime::Controllers::InfiniSleepController; +// switch (infiniSleepController.Recurrence()) { +// case InfiniSleepController::RecurType::None: +// infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Daily); +// break; +// case InfiniSleepController::RecurType::Daily: +// infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Weekdays); +// break; +// case InfiniSleepController::RecurType::Weekdays: +// infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); +// break; +// } +// SetRecurButtonState(); +// } \ No newline at end of file diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 5e24b79812..fb25743089 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -60,7 +60,7 @@ namespace Pinetime { Controllers::MotorController& motorController; Controllers::Settings::ClockType clockType; - lv_obj_t *btnStop, *txtStop, *btnRecur, *txtRecur, *btnInfo, *enableSwitch; + lv_obj_t *btnStop, *txtStop, /**btnRecur, *txtRecur,*/ *btnInfo, *enableSwitch; lv_obj_t *trackerToggleBtn, *trackerToggleLabel; lv_obj_t* lblampm = nullptr; lv_obj_t* txtMessage = nullptr; @@ -74,12 +74,12 @@ namespace Pinetime { enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); void EnableWakeAlarm(); - void SetRecurButtonState(); + //void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); void ShowAlarmInfo(); void HideAlarmInfo(); - void ToggleRecurrence(); + //void ToggleRecurrence(); void UpdateWakeAlarmTime(); Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76); Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); From 38666de7070e19098afc9d5dca6a9873c3d06e56 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 22 Nov 2024 20:10:40 -0600 Subject: [PATCH 060/191] Added buttons to set desired cycles count and duration per cycle. Removed settings that don't do anything yet. --- .../infinisleep/InfiniSleepController.h | 11 +-- src/displayapp/screens/Sleep.cpp | 72 ++++++++++++++++--- src/displayapp/screens/Sleep.h | 2 +- 3 files changed, 69 insertions(+), 16 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 004a5c1ae2..d624136c52 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -151,6 +151,8 @@ namespace Pinetime { bool isEnabled = false; }; + WakeAlarmSettings wakeAlarm; + // Dertermine the steps for the gradual wake alarm, the corresponding vibration durations determine the power of the vibration static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds static constexpr uint16_t gradualWakeVibrationDurations[9] = {1200, 1200, 1000, 1000, 1000, 700, 700, 700, 500}; // In ms @@ -183,7 +185,7 @@ namespace Pinetime { } uint16_t GetSuggestedSleepTime() { - return SLEEP_CYCLE_DURATION * DESIRED_CYCLES; + return infiniSleepSettings.desiredCycles * infiniSleepSettings.sleepCycleDuration; } WakeAlarmSettings GetWakeAlarm() const { @@ -195,8 +197,12 @@ namespace Pinetime { bool heartRateTracking = true; bool graddualWake = false; bool smartAlarm = false; + uint8_t sleepCycleDuration = SLEEP_CYCLE_DURATION; + uint8_t desiredCycles = DESIRED_CYCLES; }; + InfiniSleepSettings infiniSleepSettings; + InfiniSleepSettings GetInfiniSleepSettings() const { return infiniSleepSettings; } @@ -248,8 +254,6 @@ namespace Pinetime { bool isEnabled = false; bool settingsChanged = false; - InfiniSleepSettings infiniSleepSettings; - Controllers::DateTime& dateTimeController; Controllers::FS& fs; Controllers::HeartRateController& heartRateController; @@ -257,7 +261,6 @@ namespace Pinetime { TimerHandle_t wakeAlarmTimer; TimerHandle_t gradualWakeTimer; TimerHandle_t trackerUpdateTimer; - WakeAlarmSettings wakeAlarm; std::chrono::time_point wakeAlarmTime; void LoadSettingsFromFile(); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index aba30425ee..4b07e1137b 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -94,12 +94,12 @@ void Sleep::DisableWakeAlarm() { } } -void Sleep::EnableWakeAlarm() { - if (!infiniSleepController.GetWakeAlarm().isEnabled) { - infiniSleepController.EnableWakeAlarm(); - lv_switch_on(enableSwitch, LV_ANIM_ON); - } -} +// void Sleep::EnableWakeAlarm() { +// if (!infiniSleepController.GetWakeAlarm().isEnabled) { +// infiniSleepController.EnableWakeAlarm(); +// lv_switch_on(enableSwitch, LV_ANIM_ON); +// } +// } void Sleep::Refresh() { UpdateDisplay(); @@ -292,11 +292,11 @@ void Sleep::DrawSettingsScreen() { int offsetAfter = 30; }; - Setting settings[] = { - {"Body Tracking", infiniSleepController.BodyTrackingEnabled()}, + const Setting settings[] = { + //{"Body Tracking", infiniSleepController.BodyTrackingEnabled()}, {"Heart Rate\nTracking", infiniSleepController.HeartRateTrackingEnabled(), 60}, {"Gradual Wake", infiniSleepController.GradualWakeEnabled()}, - {"Smart Alarm\n(alpha)", infiniSleepController.SmartAlarmEnabled()} + //{"Smart Alarm\n(alpha)", infiniSleepController.SmartAlarmEnabled()} }; int y_offset = 50; @@ -321,6 +321,57 @@ void Sleep::DrawSettingsScreen() { y_offset += setting.offsetAfter; // Increase the offset to provide better spacing } + + lv_obj_t* lblCycles = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblCycles, "Cycles <----> Mins"); + lv_obj_align(lblCycles, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + + lv_obj_t* btnCycles = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnCycles, 100, 50); + lv_obj_align(btnCycles, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset + 30); + btnCycles->user_data = this; + lv_obj_set_event_cb(btnCycles, [](lv_obj_t* obj, lv_event_t e) { + if (e == LV_EVENT_CLICKED) { + auto* screen = static_cast(obj->user_data); + int value = screen->infiniSleepController.infiniSleepSettings.desiredCycles; + value = (value % 10) + 1; // Cycle through values 1 to 10 + screen->infiniSleepController.infiniSleepSettings.desiredCycles = value; + screen->infiniSleepController.SetSettingsChanged(); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); + } + }); + + lv_obj_t* lblCycleValue = lv_label_create(btnCycles, nullptr); + lv_label_set_text_fmt(lblCycleValue, "%d", infiniSleepController.infiniSleepSettings.desiredCycles); + lv_obj_align(lblCycleValue, nullptr, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t* btnCycleDuration = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnCycleDuration, 100, 50); + lv_obj_align(btnCycleDuration, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 120, y_offset + 30); + btnCycleDuration->user_data = this; + lv_obj_set_event_cb(btnCycleDuration, [](lv_obj_t* obj, lv_event_t e) { + if (e == LV_EVENT_CLICKED) { + auto* screen = static_cast(obj->user_data); + int value = screen->infiniSleepController.infiniSleepSettings.sleepCycleDuration; + switch (value) { + case 80: value = 85; break; + case 85: value = 90; break; + case 90: value = 95; break; + case 95: value = 100; break; + case 100: value = 80; break; + default: value = 80; break; + } + screen->infiniSleepController.infiniSleepSettings.sleepCycleDuration = value; + screen->infiniSleepController.SetSettingsChanged(); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); + } + }); + + lv_obj_t* lblCycleDurationValue = lv_label_create(btnCycleDuration, nullptr); + lv_label_set_text_fmt(lblCycleDurationValue, "%d", infiniSleepController.infiniSleepSettings.sleepCycleDuration); + lv_obj_align(lblCycleDurationValue, nullptr, LV_ALIGN_CENTER, 0, 0); + + y_offset += 70; // Adjust the offset for the next UI element } void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { @@ -367,7 +418,6 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { minuteCounter.SetValue(alarmMinute); OnValueChanged(); - lv_switch_on(enableSwitch, LV_ANIM_OFF); infiniSleepController.ScheduleWakeAlarm(); return; } @@ -454,7 +504,6 @@ void Sleep::SnoozeWakeAlarm() { hourCounter.SetValue(newSnoozeMinutes / 60); minuteCounter.SetValue(newSnoozeMinutes % 60); - lv_switch_on(enableSwitch, LV_ANIM_OFF); infiniSleepController.ScheduleWakeAlarm(); } @@ -467,6 +516,7 @@ void Sleep::UpdateWakeAlarmTime() { } } infiniSleepController.SetWakeAlarmTime(hourCounter.GetValue(), minuteCounter.GetValue()); + SetSwitchState(LV_ANIM_OFF); } void Sleep::SetAlerting() { diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index fb25743089..b3f11cddff 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -73,7 +73,7 @@ namespace Pinetime { enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); - void EnableWakeAlarm(); + //void EnableWakeAlarm(); //void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); From 44a0ee29e3ee8668fbd4b92c436fe7be9424d248 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 23 Nov 2024 14:51:59 -0600 Subject: [PATCH 061/191] Bug fixes Fixed crash on destructor cal Removed info button on alarm screen --- src/displayapp/screens/Sleep.cpp | 61 ++++++++++++++++---------------- src/displayapp/screens/Sleep.h | 2 +- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 4b07e1137b..316db79281 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -50,11 +50,12 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { screen->OnButtonEvent(obj, event); } -// static void SnoozeAlarmTaskCallback(lv_task_t* task) { -// auto* screen = static_cast(task->user_data); -// screen->StopAlerting(); -// screen->SnoozeWakeAlarm(); -// } +static void SnoozeAlarmTaskCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + lv_task_del(task); + screen->StopAlerting(false); + screen->SnoozeWakeAlarm(); +} static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { auto* screen = static_cast(task->user_data); @@ -179,17 +180,17 @@ void Sleep::DrawAlarmScreen() { // SetRecurButtonState(); // lv_obj_set_style_local_bg_color(btnRecur, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); - btnInfo = lv_btn_create(lv_scr_act(), nullptr); - btnInfo->user_data = this; - lv_obj_set_event_cb(btnInfo, btnEventHandler); - lv_obj_set_size(btnInfo, 50, 50); - lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, -4); - lv_obj_set_style_local_bg_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); - lv_obj_set_style_local_border_width(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 4); - lv_obj_set_style_local_border_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + // btnInfo = lv_btn_create(lv_scr_act(), nullptr); + // btnInfo->user_data = this; + // lv_obj_set_event_cb(btnInfo, btnEventHandler); + // lv_obj_set_size(btnInfo, 50, 50); + // lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, -4); + // lv_obj_set_style_local_bg_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); + // lv_obj_set_style_local_border_width(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 4); + // lv_obj_set_style_local_border_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); - lv_label_set_text_static(txtInfo, "i"); + // lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); + // lv_label_set_text_static(txtInfo, "i"); enableSwitch = lv_switch_create(lv_scr_act(), nullptr); enableSwitch->user_data = this; @@ -242,8 +243,8 @@ void Sleep::DrawInfoScreen() { // Gradual Wake info label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.GetInfiniSleepSettings().graddualWake) { - lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: %d/9", infiniSleepController.gradualWakeVibration); + if (infiniSleepController.GetWakeAlarm().isEnabled && infiniSleepController.GetInfiniSleepSettings().graddualWake && infiniSleepController.gradualWakeStep > 0) { + lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: %d/9", infiniSleepController.gradualWakeStep); } else { lv_label_set_text_static(label_gradual_wake, "Gradual Wake: OFF"); } @@ -381,10 +382,10 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { SnoozeWakeAlarm(); return; } - if (obj == btnInfo) { - ShowAlarmInfo(); - return; - } + // if (obj == btnInfo) { + // ShowAlarmInfo(); + // return; + // } if (obj == btnMessage) { HideAlarmInfo(); return; @@ -488,10 +489,8 @@ void Sleep::OnValueChanged() { // Currently snoozes baeed on define statement in InfiniSleepController.h void Sleep::SnoozeWakeAlarm() { - if (taskSnoozeWakeAlarm != nullptr) { - lv_task_del(taskSnoozeWakeAlarm); - taskSnoozeWakeAlarm = nullptr; - } + lv_task_del(taskSnoozeWakeAlarm); + taskSnoozeWakeAlarm = nullptr; uint16_t totalAlarmMinutes = infiniSleepController.GetCurrentHour() * 60 + infiniSleepController.GetCurrentMinute(); uint16_t newSnoozeMinutes = totalAlarmMinutes + SNOOZE_MINUTES; @@ -522,19 +521,19 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); - //taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(5 * 1000), LV_TASK_PRIO_MID, this); + taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(5 * 1000), LV_TASK_PRIO_MID, this); motorController.StartAlarm(); wakeLock.Lock(); } -void Sleep::StopAlerting() { +void Sleep::StopAlerting(bool setSwitch) { infiniSleepController.StopAlerting(); motorController.StopAlarm(); - SetSwitchState(LV_ANIM_OFF); - if (taskSnoozeWakeAlarm != nullptr) { - lv_task_del(taskSnoozeWakeAlarm); - taskSnoozeWakeAlarm = nullptr; + if (setSwitch) { + SetSwitchState(LV_ANIM_OFF); } + lv_task_del(taskSnoozeWakeAlarm); + taskSnoozeWakeAlarm = nullptr; wakeLock.Release(); lv_obj_set_hidden(enableSwitch, false); lv_obj_set_hidden(btnStop, true); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index b3f11cddff..7a9ccb4096 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -29,7 +29,7 @@ namespace Pinetime { bool OnButtonPushed() override; bool OnTouchEvent(TouchEvents event) override; void OnValueChanged(); - void StopAlerting(); + void StopAlerting(bool setSwitch = true); void SnoozeWakeAlarm(); void UpdateDisplay(); enum class SleepDisplayState { Alarm, Info, Settings }; From 3f06850639a852e1ddcfc7ab099558f3a673daab Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 23 Nov 2024 14:53:32 -0600 Subject: [PATCH 062/191] Switched vibration index variable to use the gradualStep and fixed issues with index updates --- .../infinisleep/InfiniSleepController.cpp | 30 ++++++++++++------- .../infinisleep/InfiniSleepController.h | 6 ++-- src/displayapp/DisplayApp.cpp | 2 +- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 03552291b7..bdf9628672 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -106,7 +106,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; gradualWakeStep = 9; - gradualWakeVibration = 9; + //gradualWakeVibration = 9; auto now = dateTimeController.CurrentDateTime(); wakeAlarmTime = now; @@ -142,15 +142,15 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStart(wakeAlarmTimer, 0); // make sure graudal wake steps are possible - while (gradualWakeStep != 0 && secondsToWakeAlarm <= gradualWakeSteps[gradualWakeStep-1]) { + while (gradualWakeStep > 0 && secondsToWakeAlarm <= gradualWakeSteps[gradualWakeStep-1]) { gradualWakeStep--; - gradualWakeVibration = gradualWakeStep; + //gradualWakeVibration = gradualWakeStep; } // Calculate the period for the gradualWakeTimer - if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { - int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); - gradualWakeVibration = gradualWakeStep; + if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { + int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1+gradualWakeStep])) * (configTICK_RATE_HZ); + //gradualWakeVibration = gradualWakeStep; xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } @@ -169,7 +169,7 @@ void InfiniSleepController::DisableWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); gradualWakeStep = 9; - gradualWakeVibration = 9; + //gradualWakeVibration = 9; isAlerting = false; if (wakeAlarm.isEnabled) { wakeAlarm.isEnabled = false; @@ -190,13 +190,23 @@ void InfiniSleepController::SetOffWakeAlarmNow() { void InfiniSleepController::SetOffGradualWakeNow() { //isGradualWakeAlerting = true; + systemTask->PushMessage(System::Messages::SetOffGradualWake); + + // make sure graudal wake steps are possible + while (gradualWakeStep > 0 && SecondsToWakeAlarm() <= gradualWakeSteps[gradualWakeStep-1]) { + gradualWakeStep--; + //gradualWakeVibration = gradualWakeStep; + } + // Calculate the period for the gradualWakeTimer - if (infiniSleepSettings.graddualWake && gradualWakeStep != 0) { - int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1+gradualWakeStep--])) * (configTICK_RATE_HZ); - gradualWakeVibration = gradualWakeStep; + if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { + int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1+gradualWakeStep])) * (configTICK_RATE_HZ); + //gradualWakeVibration = gradualWakeStep; xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); + } else { + xTimerStop(gradualWakeTimer, 0); } } diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index d624136c52..686ea7d322 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -155,11 +155,11 @@ namespace Pinetime { // Dertermine the steps for the gradual wake alarm, the corresponding vibration durations determine the power of the vibration static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds - static constexpr uint16_t gradualWakeVibrationDurations[9] = {1200, 1200, 1000, 1000, 1000, 700, 700, 700, 500}; // In ms + static constexpr uint16_t gradualWakeVibrationDurations[9] = {1000, 1000, 900, 800, 800, 700, 700, 700, 500}; // In ms - uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex + //uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex - uint8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex + int8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex uint16_t GetSleepCycles() { uint16_t totalMinutes = GetTotalSleep(); diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index c39e5fd045..2719616676 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -406,7 +406,7 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } - motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1+infiniSleepController.gradualWakeVibration]); + motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1+infiniSleepController.gradualWakeStep]); NRF_LOG_INFO("Gradual wake triggered"); From 3a35bd9f3ff29a8c09f08cb676a392121c4960b0 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 24 Nov 2024 11:15:42 -0600 Subject: [PATCH 063/191] Formatted with clang-format --- .../infinisleep/InfiniSleepController.cpp | 194 +++---- .../infinisleep/InfiniSleepController.h | 520 +++++++++--------- src/displayapp/DisplayApp.cpp | 6 +- src/displayapp/screens/Sleep.cpp | 124 +++-- src/displayapp/screens/Sleep.h | 34 +- 5 files changed, 465 insertions(+), 413 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index bdf9628672..46361f65c9 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -1,4 +1,4 @@ -# include "components/infinisleep/InfiniSleepController.h" +#include "components/infinisleep/InfiniSleepController.h" #include "systemtask/SystemTask.h" #include "task.h" #include @@ -7,7 +7,9 @@ using namespace Pinetime::Controllers; using namespace std::chrono_literals; -InfiniSleepController::InfiniSleepController(Controllers::DateTime& dateTimeController, Controllers::FS& fs, Controllers::HeartRateController& heartRateController) +InfiniSleepController::InfiniSleepController(Controllers::DateTime& dateTimeController, + Controllers::FS& fs, + Controllers::HeartRateController& heartRateController) : dateTimeController {dateTimeController}, fs {fs}, heartRateController {heartRateController} { } @@ -32,23 +34,24 @@ namespace { } void InfiniSleepController::Init(System::SystemTask* systemTask) { - this->systemTask = systemTask; - wakeAlarmTimer = xTimerCreate("WakeAlarm", 1, pdFALSE, this, SetOffWakeAlarm); - gradualWakeTimer = xTimerCreate("GradualWake", 1, pdFALSE, this, SetOffGradualWake); - - LoadSettingsFromFile(); - LoadPrevSessionData(); - if (wakeAlarm.isEnabled) { - NRF_LOG_INFO("[InfiniSleepController] Loaded wake alarm was enabled, scheduling"); - ScheduleWakeAlarm(); - } + this->systemTask = systemTask; + wakeAlarmTimer = xTimerCreate("WakeAlarm", 1, pdFALSE, this, SetOffWakeAlarm); + gradualWakeTimer = xTimerCreate("GradualWake", 1, pdFALSE, this, SetOffGradualWake); + + LoadSettingsFromFile(); + LoadPrevSessionData(); + if (wakeAlarm.isEnabled) { + NRF_LOG_INFO("[InfiniSleepController] Loaded wake alarm was enabled, scheduling"); + ScheduleWakeAlarm(); + } } void InfiniSleepController::EnableTracker() { DisableTracker(); NRF_LOG_INFO("[InfiniSleepController] Enabling tracker"); isEnabled = true; - trackerUpdateTimer = xTimerCreate("TrackerUpdate", pdMS_TO_TICKS(TRACKER_UPDATE_INTERVAL_MINS * 60 * 1000), pdFALSE, this, SetOffTrackerUpdate); + trackerUpdateTimer = + xTimerCreate("TrackerUpdate", pdMS_TO_TICKS(TRACKER_UPDATE_INTERVAL_MINS * 60 * 1000), pdFALSE, this, SetOffTrackerUpdate); xTimerStart(trackerUpdateTimer, 0); } @@ -71,105 +74,106 @@ void InfiniSleepController::UpdateTracker() { } void InfiniSleepController::SaveWakeAlarm() { - // verify is save needed - if (wakeAlarmChanged) { - SaveSettingsToFile(); - } - wakeAlarmChanged = false; + // verify is save needed + if (wakeAlarmChanged) { + SaveSettingsToFile(); + } + wakeAlarmChanged = false; } void InfiniSleepController::SaveInfiniSleepSettings() { - // verify is save needed - if (settingsChanged) { - SaveSettingsToFile(); - } - settingsChanged = false; + // verify is save needed + if (settingsChanged) { + SaveSettingsToFile(); + } + settingsChanged = false; } void InfiniSleepController::SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin) { - if (wakeAlarm.hours == wakeAlarmHr && wakeAlarm.minutes == wakeAlarmMin) { - return; - } - wakeAlarm.hours = wakeAlarmHr; - wakeAlarm.minutes = wakeAlarmMin; - wakeAlarmChanged = true; + if (wakeAlarm.hours == wakeAlarmHr && wakeAlarm.minutes == wakeAlarmMin) { + return; + } + wakeAlarm.hours = wakeAlarmHr; + wakeAlarm.minutes = wakeAlarmMin; + wakeAlarmChanged = true; } void InfiniSleepController::ScheduleWakeAlarm() { - // This line essentially removes the ability to change recurrance type and sets it to daily - //SetRecurrence(RecurType::Daily); + // This line essentially removes the ability to change recurrance type and sets it to daily + // SetRecurrence(RecurType::Daily); - // Determine the next time the wake alarm needs to go off and set the timer - xTimerStop(wakeAlarmTimer, 0); - xTimerStop(gradualWakeTimer, 0); + // Determine the next time the wake alarm needs to go off and set the timer + xTimerStop(wakeAlarmTimer, 0); + xTimerStop(gradualWakeTimer, 0); - pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; + pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; - gradualWakeStep = 9; - //gradualWakeVibration = 9; + gradualWakeStep = 9; + // gradualWakeVibration = 9; + + auto now = dateTimeController.CurrentDateTime(); + wakeAlarmTime = now; + time_t ttWakeAlarmTime = + std::chrono::system_clock::to_time_t(std::chrono::time_point_cast(wakeAlarmTime)); + tm* tmWakeAlarmTime = std::localtime(&ttWakeAlarmTime); + + // If the time being set has already passed today, the wake alarm should be set for tomorrow + if (wakeAlarm.hours < dateTimeController.Hours() || + (wakeAlarm.hours == dateTimeController.Hours() && wakeAlarm.minutes <= dateTimeController.Minutes())) { + tmWakeAlarmTime->tm_mday += 1; + // tm_wday doesn't update automatically + tmWakeAlarmTime->tm_wday = (tmWakeAlarmTime->tm_wday + 1) % 7; + } - auto now = dateTimeController.CurrentDateTime(); - wakeAlarmTime = now; - time_t ttWakeAlarmTime = std::chrono::system_clock::to_time_t(std::chrono::time_point_cast(wakeAlarmTime)); - tm* tmWakeAlarmTime = std::localtime(&ttWakeAlarmTime); + tmWakeAlarmTime->tm_hour = wakeAlarm.hours; + tmWakeAlarmTime->tm_min = wakeAlarm.minutes; + tmWakeAlarmTime->tm_sec = 0; + + // if alarm is in weekday-only mode, make sure it shifts to the next weekday + // if (wakeAlarm.recurrence == RecurType::Weekdays) { + // if (tmWakeAlarmTime->tm_wday == 0) {// Sunday, shift 1 day + // tmWakeAlarmTime->tm_mday += 1; + // } else if (tmWakeAlarmTime->tm_wday == 6) { // Saturday, shift 2 days + // tmWakeAlarmTime->tm_mday += 2; + // } + // } + tmWakeAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST - // If the time being set has already passed today, the wake alarm should be set for tomorrow - if (wakeAlarm.hours < dateTimeController.Hours() || - (wakeAlarm.hours == dateTimeController.Hours() && wakeAlarm.minutes <= dateTimeController.Minutes())) { - tmWakeAlarmTime->tm_mday += 1; - // tm_wday doesn't update automatically - tmWakeAlarmTime->tm_wday = (tmWakeAlarmTime->tm_wday + 1) % 7; - } + // now can convert back to a time_point + wakeAlarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmWakeAlarmTime)); + int64_t secondsToWakeAlarm = std::chrono::duration_cast(wakeAlarmTime - now).count(); + xTimerChangePeriod(wakeAlarmTimer, secondsToWakeAlarm * configTICK_RATE_HZ, 0); + xTimerStart(wakeAlarmTimer, 0); - tmWakeAlarmTime->tm_hour = wakeAlarm.hours; - tmWakeAlarmTime->tm_min = wakeAlarm.minutes; - tmWakeAlarmTime->tm_sec = 0; - - // if alarm is in weekday-only mode, make sure it shifts to the next weekday - // if (wakeAlarm.recurrence == RecurType::Weekdays) { - // if (tmWakeAlarmTime->tm_wday == 0) {// Sunday, shift 1 day - // tmWakeAlarmTime->tm_mday += 1; - // } else if (tmWakeAlarmTime->tm_wday == 6) { // Saturday, shift 2 days - // tmWakeAlarmTime->tm_mday += 2; - // } - // } - tmWakeAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST - - // now can convert back to a time_point - wakeAlarmTime = std::chrono::system_clock::from_time_t(std::mktime(tmWakeAlarmTime)); - int64_t secondsToWakeAlarm = std::chrono::duration_cast(wakeAlarmTime - now).count(); - xTimerChangePeriod(wakeAlarmTimer, secondsToWakeAlarm * configTICK_RATE_HZ, 0); - xTimerStart(wakeAlarmTimer, 0); - - // make sure graudal wake steps are possible - while (gradualWakeStep > 0 && secondsToWakeAlarm <= gradualWakeSteps[gradualWakeStep-1]) { - gradualWakeStep--; - //gradualWakeVibration = gradualWakeStep; - } + // make sure graudal wake steps are possible + while (gradualWakeStep > 0 && secondsToWakeAlarm <= gradualWakeSteps[gradualWakeStep - 1]) { + gradualWakeStep--; + // gradualWakeVibration = gradualWakeStep; + } - // Calculate the period for the gradualWakeTimer - if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { - int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1+gradualWakeStep])) * (configTICK_RATE_HZ); - //gradualWakeVibration = gradualWakeStep; - xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); - xTimerStart(gradualWakeTimer, 0); - } + // Calculate the period for the gradualWakeTimer + if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { + int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); + // gradualWakeVibration = gradualWakeStep; + xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); + xTimerStart(gradualWakeTimer, 0); + } - if (!wakeAlarm.isEnabled) { - wakeAlarm.isEnabled = true; - wakeAlarmChanged = true; - } + if (!wakeAlarm.isEnabled) { + wakeAlarm.isEnabled = true; + wakeAlarmChanged = true; + } } uint32_t InfiniSleepController::SecondsToWakeAlarm() const { - return std::chrono::duration_cast(wakeAlarmTime - dateTimeController.CurrentDateTime()).count(); + return std::chrono::duration_cast(wakeAlarmTime - dateTimeController.CurrentDateTime()).count(); } void InfiniSleepController::DisableWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); gradualWakeStep = 9; - //gradualWakeVibration = 9; + // gradualWakeVibration = 9; isAlerting = false; if (wakeAlarm.isEnabled) { wakeAlarm.isEnabled = false; @@ -189,20 +193,20 @@ void InfiniSleepController::SetOffWakeAlarmNow() { } void InfiniSleepController::SetOffGradualWakeNow() { - //isGradualWakeAlerting = true; + // isGradualWakeAlerting = true; systemTask->PushMessage(System::Messages::SetOffGradualWake); // make sure graudal wake steps are possible - while (gradualWakeStep > 0 && SecondsToWakeAlarm() <= gradualWakeSteps[gradualWakeStep-1]) { + while (gradualWakeStep > 0 && SecondsToWakeAlarm() <= gradualWakeSteps[gradualWakeStep - 1]) { gradualWakeStep--; - //gradualWakeVibration = gradualWakeStep; + // gradualWakeVibration = gradualWakeStep; } // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { - int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1+gradualWakeStep])) * (configTICK_RATE_HZ); - //gradualWakeVibration = gradualWakeStep; + int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); + // gradualWakeVibration = gradualWakeStep; xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } else { @@ -213,9 +217,9 @@ void InfiniSleepController::SetOffGradualWakeNow() { void InfiniSleepController::StopAlerting() { isAlerting = false; // Disable the alarm unless it is recurring - //if (wakeAlarm.recurrence == RecurType::None) { - wakeAlarm.isEnabled = false; - wakeAlarmChanged = true; + // if (wakeAlarm.recurrence == RecurType::None) { + wakeAlarm.isEnabled = false; + wakeAlarmChanged = true; // } else { // // Schedule the alarm for the next day // ScheduleWakeAlarm(); @@ -237,7 +241,7 @@ void InfiniSleepController::UpdateBPM() { prevBpm = bpm; bpm = heartRateController.HeartRate(); - if(prevBpm != 0) + if (prevBpm != 0) rollingBpm = (rollingBpm + bpm) / 2; else rollingBpm = bpm; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 686ea7d322..21f318679e 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -10,268 +10,268 @@ #include -#define SNOOZE_MINUTES 3 -#define PUSHES_TO_STOP_ALARM 5 +#define SNOOZE_MINUTES 3 +#define PUSHES_TO_STOP_ALARM 5 #define TRACKER_UPDATE_INTERVAL_MINS 5 -#define TRACKER_DATA_FILE_NAME "SleepTracker_Data.csv" -#define PREV_SESSION_DATA_FILE_NAME "SleepTracker_PrevSession.csv" -#define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes -#define DESIRED_CYCLES 5 // desired number of sleep cycles -#define PUSHES_TO_STOP_ALARM_TIMEOUT 2 // in seconds +#define TRACKER_DATA_FILE_NAME "SleepTracker_Data.csv" +#define PREV_SESSION_DATA_FILE_NAME "SleepTracker_PrevSession.csv" +#define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes +#define DESIRED_CYCLES 5 // desired number of sleep cycles +#define PUSHES_TO_STOP_ALARM_TIMEOUT 2 // in seconds namespace Pinetime { - namespace System { - class SystemTask; - } - - namespace Controllers { - class InfiniSleepController { - public: - InfiniSleepController(Controllers::DateTime& dateTimeCOntroller, Controllers::FS& , Controllers::HeartRateController& heartRateController); - - void Init(System::SystemTask* systemTask); - void SaveWakeAlarm(); - void SaveInfiniSleepSettings(); - void SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin); - void ScheduleWakeAlarm(); - void DisableWakeAlarm(); - void EnableWakeAlarm(); - void SetOffWakeAlarmNow(); - void SetOffGradualWakeNow(); - uint32_t SecondsToWakeAlarm() const; - void StopAlerting(); - //enum class RecurType { None, Daily, Weekdays }; - - uint8_t pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; - - bool isSnoozing = false; - uint8_t preSnoozeMinutes = 255; - uint8_t preSnnoozeHours = 255; - - // Struct for sessions - struct SessionData { - uint8_t startTimeHours = 0; - uint8_t startTimeMinutes = 0; - uint8_t endTimeHours = 0; - uint8_t endTimeMinutes = 0; - }; - - SessionData prevSessionData; - - void SetPreSnoozeTime() { - if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { - return; - } - preSnoozeMinutes = wakeAlarm.minutes; - preSnnoozeHours = wakeAlarm.hours; - } - - void RestorePreSnoozeTime() { - if (preSnoozeMinutes == 255 || preSnnoozeHours == 255) { - return; - } - wakeAlarm.minutes = preSnoozeMinutes; - wakeAlarm.hours = preSnnoozeHours; - preSnoozeMinutes = 255; - preSnnoozeHours = 255; - } - - - uint8_t Hours() const { - return wakeAlarm.hours; - } - - uint8_t Minutes() const { - return wakeAlarm.minutes; - } - - bool IsAlerting() const { - return isAlerting; - } - - bool IsEnabled() const { - return isEnabled; - } - - void EnableTracker(); - void DisableTracker(); - void UpdateTracker(); - - // RecurType Recurrence() const { - // return wakeAlarm.recurrence; - // } - - // void SetRecurrence(RecurType recurrence); - - bool BodyTrackingEnabled() const { - return infiniSleepSettings.bodyTracking; - } - - void SetBodyTrackingEnabled(bool enabled) { - infiniSleepSettings.bodyTracking = enabled; - } - - bool HeartRateTrackingEnabled() const { - return infiniSleepSettings.heartRateTracking; - } - - void SetHeartRateTrackingEnabled(bool enabled) { - infiniSleepSettings.heartRateTracking = enabled; - } - - bool GradualWakeEnabled() const { - return infiniSleepSettings.graddualWake; - } - - void SetGradualWakeEnabled(bool enabled) { - infiniSleepSettings.graddualWake = enabled; - } - - bool SmartAlarmEnabled() const { - return infiniSleepSettings.smartAlarm; - } - - void SetSmartAlarmEnabled(bool enabled) { - infiniSleepSettings.smartAlarm = enabled; - } - - void SetSettingsChanged() { - settingsChanged = true; - } - - // Versions 255 is reserved for now, so the version field can be made - // bigger, should it ever be needed. - static constexpr uint8_t wakeAlarmFormatVersion = 1; - - struct WakeAlarmSettings { - static constexpr uint8_t version = wakeAlarmFormatVersion; - uint8_t hours = 7; - uint8_t minutes = 0; - AlarmController::RecurType recurrence = AlarmController::RecurType::Daily; - bool isEnabled = false; - }; - - WakeAlarmSettings wakeAlarm; - - // Dertermine the steps for the gradual wake alarm, the corresponding vibration durations determine the power of the vibration - static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds - static constexpr uint16_t gradualWakeVibrationDurations[9] = {1000, 1000, 900, 800, 800, 700, 700, 700, 500}; // In ms - - //uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex - - int8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex - - uint16_t GetSleepCycles() { - uint16_t totalMinutes = GetTotalSleep(); - return (totalMinutes * 100 / SLEEP_CYCLE_DURATION); - } - - uint16_t GetTotalSleep() const { - uint8_t endHours = IsEnabled() ? GetCurrentHour() : prevSessionData.endTimeHours; - uint8_t endMinutes = IsEnabled() ? GetCurrentMinute() : prevSessionData.endTimeMinutes; - - // Calculate total minutes for start and end times - uint16_t startTotalMinutes = prevSessionData.startTimeHours * 60 + prevSessionData.startTimeMinutes; - uint16_t endTotalMinutes = endHours * 60 + endMinutes; - - // If end time is before start time, add 24 hours to end time (handle crossing midnight) - if (endTotalMinutes < startTotalMinutes) { - endTotalMinutes += 24 * 60; - } - - uint16_t sleepMinutes = endTotalMinutes - startTotalMinutes; - - return sleepMinutes; - } - - uint16_t GetSuggestedSleepTime() { - return infiniSleepSettings.desiredCycles * infiniSleepSettings.sleepCycleDuration; - } - - WakeAlarmSettings GetWakeAlarm() const { - return wakeAlarm; - } - - struct InfiniSleepSettings { - bool bodyTracking = false; - bool heartRateTracking = true; - bool graddualWake = false; - bool smartAlarm = false; - uint8_t sleepCycleDuration = SLEEP_CYCLE_DURATION; - uint8_t desiredCycles = DESIRED_CYCLES; - }; - - InfiniSleepSettings infiniSleepSettings; - - InfiniSleepSettings GetInfiniSleepSettings() const { - return infiniSleepSettings; - } - - bool ToggleTracker() { - if (isEnabled) { - prevSessionData.endTimeHours = GetCurrentHour(); - prevSessionData.endTimeMinutes = GetCurrentMinute(); - SavePrevSessionData(); - DisableTracker(); - } else { - ClearDataCSV(TRACKER_DATA_FILE_NAME); - prevSessionData.startTimeHours = GetCurrentHour(); - prevSessionData.startTimeMinutes = GetCurrentMinute(); - EnableTracker(); - } - return isEnabled; - } - - bool IsTrackerEnabled() const { - return isEnabled; - } - - uint8_t GetCurrentHour() const { - return dateTimeController.Hours(); - } - - uint8_t GetCurrentMinute() const { - return dateTimeController.Minutes(); - } - - //int64_t secondsToWakeAlarm = 0; - - int bpm = 0; - int prevBpm = 0; - int rollingBpm = 0; - - void UpdateBPM(); - - uint8_t GetGradualWakeStep() const { - return (9 - gradualWakeStep) + 1; - } - - private: - - bool isAlerting = false; - bool isGradualWakeAlerting = false; - bool wakeAlarmChanged = false; - bool isEnabled = false; - bool settingsChanged = false; - - Controllers::DateTime& dateTimeController; - Controllers::FS& fs; - Controllers::HeartRateController& heartRateController; - System::SystemTask* systemTask = nullptr; - TimerHandle_t wakeAlarmTimer; - TimerHandle_t gradualWakeTimer; - TimerHandle_t trackerUpdateTimer; - std::chrono::time_point wakeAlarmTime; - - void LoadSettingsFromFile(); - void SaveSettingsToFile() const; - void LoadPrevSessionData(); - void SavePrevSessionData() const; - - // For File IO - void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; - void ClearDataCSV(const char* fileName) const; - }; - } + namespace System { + class SystemTask; + } + + namespace Controllers { + class InfiniSleepController { + public: + InfiniSleepController(Controllers::DateTime& dateTimeCOntroller, + Controllers::FS&, + Controllers::HeartRateController& heartRateController); + + void Init(System::SystemTask* systemTask); + void SaveWakeAlarm(); + void SaveInfiniSleepSettings(); + void SetWakeAlarmTime(uint8_t wakeAlarmHr, uint8_t wakeAlarmMin); + void ScheduleWakeAlarm(); + void DisableWakeAlarm(); + void EnableWakeAlarm(); + void SetOffWakeAlarmNow(); + void SetOffGradualWakeNow(); + uint32_t SecondsToWakeAlarm() const; + void StopAlerting(); + // enum class RecurType { None, Daily, Weekdays }; + + uint8_t pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; + + bool isSnoozing = false; + uint8_t preSnoozeMinutes = 255; + uint8_t preSnnoozeHours = 255; + + // Struct for sessions + struct SessionData { + uint8_t startTimeHours = 0; + uint8_t startTimeMinutes = 0; + uint8_t endTimeHours = 0; + uint8_t endTimeMinutes = 0; + }; + + SessionData prevSessionData; + + void SetPreSnoozeTime() { + if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { + return; + } + preSnoozeMinutes = wakeAlarm.minutes; + preSnnoozeHours = wakeAlarm.hours; + } + + void RestorePreSnoozeTime() { + if (preSnoozeMinutes == 255 || preSnnoozeHours == 255) { + return; + } + wakeAlarm.minutes = preSnoozeMinutes; + wakeAlarm.hours = preSnnoozeHours; + preSnoozeMinutes = 255; + preSnnoozeHours = 255; + } + + uint8_t Hours() const { + return wakeAlarm.hours; + } + + uint8_t Minutes() const { + return wakeAlarm.minutes; + } + + bool IsAlerting() const { + return isAlerting; + } + + bool IsEnabled() const { + return isEnabled; + } + + void EnableTracker(); + void DisableTracker(); + void UpdateTracker(); + + // RecurType Recurrence() const { + // return wakeAlarm.recurrence; + // } + + // void SetRecurrence(RecurType recurrence); + + bool BodyTrackingEnabled() const { + return infiniSleepSettings.bodyTracking; + } + + void SetBodyTrackingEnabled(bool enabled) { + infiniSleepSettings.bodyTracking = enabled; + } + + bool HeartRateTrackingEnabled() const { + return infiniSleepSettings.heartRateTracking; + } + + void SetHeartRateTrackingEnabled(bool enabled) { + infiniSleepSettings.heartRateTracking = enabled; + } + + bool GradualWakeEnabled() const { + return infiniSleepSettings.graddualWake; + } + + void SetGradualWakeEnabled(bool enabled) { + infiniSleepSettings.graddualWake = enabled; + } + + bool SmartAlarmEnabled() const { + return infiniSleepSettings.smartAlarm; + } + + void SetSmartAlarmEnabled(bool enabled) { + infiniSleepSettings.smartAlarm = enabled; + } + + void SetSettingsChanged() { + settingsChanged = true; + } + + // Versions 255 is reserved for now, so the version field can be made + // bigger, should it ever be needed. + static constexpr uint8_t wakeAlarmFormatVersion = 1; + + struct WakeAlarmSettings { + static constexpr uint8_t version = wakeAlarmFormatVersion; + uint8_t hours = 7; + uint8_t minutes = 0; + AlarmController::RecurType recurrence = AlarmController::RecurType::Daily; + bool isEnabled = false; + }; + + WakeAlarmSettings wakeAlarm; + + // Dertermine the steps for the gradual wake alarm, the corresponding vibration durations determine the power of the vibration + static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds + static constexpr uint16_t gradualWakeVibrationDurations[9] = {1000, 1000, 900, 800, 800, 700, 700, 700, 500}; // In ms + + // uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex + + int8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex + + uint16_t GetSleepCycles() { + uint16_t totalMinutes = GetTotalSleep(); + return (totalMinutes * 100 / SLEEP_CYCLE_DURATION); + } + + uint16_t GetTotalSleep() const { + uint8_t endHours = IsEnabled() ? GetCurrentHour() : prevSessionData.endTimeHours; + uint8_t endMinutes = IsEnabled() ? GetCurrentMinute() : prevSessionData.endTimeMinutes; + + // Calculate total minutes for start and end times + uint16_t startTotalMinutes = prevSessionData.startTimeHours * 60 + prevSessionData.startTimeMinutes; + uint16_t endTotalMinutes = endHours * 60 + endMinutes; + + // If end time is before start time, add 24 hours to end time (handle crossing midnight) + if (endTotalMinutes < startTotalMinutes) { + endTotalMinutes += 24 * 60; + } + + uint16_t sleepMinutes = endTotalMinutes - startTotalMinutes; + + return sleepMinutes; + } + + uint16_t GetSuggestedSleepTime() { + return infiniSleepSettings.desiredCycles * infiniSleepSettings.sleepCycleDuration; + } + + WakeAlarmSettings GetWakeAlarm() const { + return wakeAlarm; + } + + struct InfiniSleepSettings { + bool bodyTracking = false; + bool heartRateTracking = true; + bool graddualWake = false; + bool smartAlarm = false; + uint8_t sleepCycleDuration = SLEEP_CYCLE_DURATION; + uint8_t desiredCycles = DESIRED_CYCLES; + }; + + InfiniSleepSettings infiniSleepSettings; + + InfiniSleepSettings GetInfiniSleepSettings() const { + return infiniSleepSettings; + } + + bool ToggleTracker() { + if (isEnabled) { + prevSessionData.endTimeHours = GetCurrentHour(); + prevSessionData.endTimeMinutes = GetCurrentMinute(); + SavePrevSessionData(); + DisableTracker(); + } else { + ClearDataCSV(TRACKER_DATA_FILE_NAME); + prevSessionData.startTimeHours = GetCurrentHour(); + prevSessionData.startTimeMinutes = GetCurrentMinute(); + EnableTracker(); + } + return isEnabled; + } + + bool IsTrackerEnabled() const { + return isEnabled; + } + + uint8_t GetCurrentHour() const { + return dateTimeController.Hours(); + } + + uint8_t GetCurrentMinute() const { + return dateTimeController.Minutes(); + } + + // int64_t secondsToWakeAlarm = 0; + + int bpm = 0; + int prevBpm = 0; + int rollingBpm = 0; + + void UpdateBPM(); + + uint8_t GetGradualWakeStep() const { + return (9 - gradualWakeStep) + 1; + } + + private: + bool isAlerting = false; + bool isGradualWakeAlerting = false; + bool wakeAlarmChanged = false; + bool isEnabled = false; + bool settingsChanged = false; + + Controllers::DateTime& dateTimeController; + Controllers::FS& fs; + Controllers::HeartRateController& heartRateController; + System::SystemTask* systemTask = nullptr; + TimerHandle_t wakeAlarmTimer; + TimerHandle_t gradualWakeTimer; + TimerHandle_t trackerUpdateTimer; + std::chrono::time_point wakeAlarmTime; + + void LoadSettingsFromFile(); + void SaveSettingsToFile() const; + void LoadPrevSessionData(); + void SavePrevSessionData() const; + + // For File IO + void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; + void ClearDataCSV(const char* fileName) const; + }; + } } \ No newline at end of file diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 2719616676..af2675ccf2 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -401,12 +401,12 @@ void DisplayApp::Refresh() { break; case Messages::GradualWakeTriggered: if (currentApp == Apps::Sleep) { - //auto* sleep = static_cast(currentScreen.get()); - //sleep->SetGradualWakeAlerting(); + // auto* sleep = static_cast(currentScreen.get()); + // sleep->SetGradualWakeAlerting(); } else { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } - motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1+infiniSleepController.gradualWakeStep]); + motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); NRF_LOG_INFO("Gradual wake triggered"); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 316db79281..638ffb210b 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -23,27 +23,27 @@ namespace { extern InfiniSleepController infiniSleepController; static void settingsToggleEventHandler(lv_obj_t* obj, lv_event_t e) { - if (e != LV_EVENT_VALUE_CHANGED) { - return; - } + if (e != LV_EVENT_VALUE_CHANGED) { + return; + } - const char* setting_name = static_cast(obj->user_data); - bool enabled = lv_checkbox_is_checked(obj); - - if (strcmp(setting_name, "Body Tracking") == 0) { - infiniSleepController.SetBodyTrackingEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } else if (strcmp(setting_name, "Heart Rate\nTracking") == 0) { - infiniSleepController.SetHeartRateTrackingEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } else if (strcmp(setting_name, "Gradual Wake") == 0) { - infiniSleepController.SetGradualWakeEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } else if (strcmp(setting_name, "Smart Alarm\n(alpha)") == 0) { - infiniSleepController.SetSmartAlarmEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } + const char* setting_name = static_cast(obj->user_data); + bool enabled = lv_checkbox_is_checked(obj); + + if (strcmp(setting_name, "Body Tracking") == 0) { + infiniSleepController.SetBodyTrackingEnabled(enabled); + infiniSleepController.SetSettingsChanged(); + } else if (strcmp(setting_name, "Heart Rate\nTracking") == 0) { + infiniSleepController.SetHeartRateTrackingEnabled(enabled); + infiniSleepController.SetSettingsChanged(); + } else if (strcmp(setting_name, "Gradual Wake") == 0) { + infiniSleepController.SetGradualWakeEnabled(enabled); + infiniSleepController.SetSettingsChanged(); + } else if (strcmp(setting_name, "Smart Alarm\n(alpha)") == 0) { + infiniSleepController.SetSmartAlarmEnabled(enabled); + infiniSleepController.SetSettingsChanged(); } +} static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { auto* screen = static_cast(obj->user_data); @@ -71,7 +71,8 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, UpdateDisplay(); taskRefresh = lv_task_create(RefreshTaskCallback, 2000, LV_TASK_PRIO_MID, this); - taskPressesToStopAlarmTimeout = lv_task_create(PressesToStopAlarmTimeoutCallback, PUSHES_TO_STOP_ALARM_TIMEOUT * 1000, LV_TASK_PRIO_MID, this); + taskPressesToStopAlarmTimeout = + lv_task_create(PressesToStopAlarmTimeoutCallback, PUSHES_TO_STOP_ALARM_TIMEOUT * 1000, LV_TASK_PRIO_MID, this); } Sleep::~Sleep() { @@ -222,11 +223,17 @@ void Sleep::DrawInfoScreen() { lv_label_set_text_fmt(label_hr, "HR: %d", infiniSleepController.rollingBpm); } lv_obj_align(label_hr, lblTime, LV_ALIGN_CENTER, 0, 50); - lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - + lv_obj_set_style_local_text_color(label_hr, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + if (infiniSleepController.IsEnabled()) { label_start_time = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_start_time, "Began at: %02d:%02d", infiniSleepController.prevSessionData.startTimeHours, infiniSleepController.prevSessionData.startTimeMinutes); + lv_label_set_text_fmt(label_start_time, + "Began at: %02d:%02d", + infiniSleepController.prevSessionData.startTimeHours, + infiniSleepController.prevSessionData.startTimeMinutes); lv_obj_align(label_start_time, label_hr, LV_ALIGN_CENTER, 0, 20); lv_obj_set_style_local_text_color(label_start_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); } @@ -234,28 +241,44 @@ void Sleep::DrawInfoScreen() { // The alarm info label_alarm_time = lv_label_create(lv_scr_act(), nullptr); if (infiniSleepController.GetWakeAlarm().isEnabled) { - lv_label_set_text_fmt(label_alarm_time, "Alarm at: %02d:%02d", infiniSleepController.GetWakeAlarm().hours, infiniSleepController.GetWakeAlarm().minutes); + lv_label_set_text_fmt(label_alarm_time, + "Alarm at: %02d:%02d", + infiniSleepController.GetWakeAlarm().hours, + infiniSleepController.GetWakeAlarm().minutes); } else { lv_label_set_text_static(label_alarm_time, "Alarm is not set."); } lv_obj_align(label_alarm_time, label_hr, LV_ALIGN_CENTER, 0, 40); - lv_obj_set_style_local_text_color(label_alarm_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(label_alarm_time, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); // Gradual Wake info label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.GetWakeAlarm().isEnabled && infiniSleepController.GetInfiniSleepSettings().graddualWake && infiniSleepController.gradualWakeStep > 0) { + if (infiniSleepController.GetWakeAlarm().isEnabled && infiniSleepController.GetInfiniSleepSettings().graddualWake && + infiniSleepController.gradualWakeStep > 0) { lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: %d/9", infiniSleepController.gradualWakeStep); } else { lv_label_set_text_static(label_gradual_wake, "Gradual Wake: OFF"); } lv_obj_align(label_gradual_wake, label_hr, LV_ALIGN_CENTER, 0, 60); - lv_obj_set_style_local_text_color(label_gradual_wake, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(label_gradual_wake, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); // Sleep Cycles Info label_sleep_cycles = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_sleep_cycles, "Sleep Cycles: %d.%02d", infiniSleepController.GetSleepCycles() / 100, infiniSleepController.GetSleepCycles() % 100); + lv_label_set_text_fmt(label_sleep_cycles, + "Sleep Cycles: %d.%02d", + infiniSleepController.GetSleepCycles() / 100, + infiniSleepController.GetSleepCycles() % 100); lv_obj_align(label_sleep_cycles, label_hr, LV_ALIGN_CENTER, 0, 80); - lv_obj_set_style_local_text_color(label_sleep_cycles, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(label_sleep_cycles, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); // Total sleep time label_total_sleep = lv_label_create(lv_scr_act(), nullptr); @@ -264,7 +287,10 @@ void Sleep::DrawInfoScreen() { lv_label_set_text_fmt(label_total_sleep, "Total Sleep: %dh%dm", totalMinutes / 60, totalMinutes % 60); lv_obj_align(label_total_sleep, label_hr, LV_ALIGN_CENTER, 0, 100); - lv_obj_set_style_local_text_color(label_total_sleep, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(label_total_sleep, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); trackerToggleBtn->user_data = this; @@ -302,9 +328,9 @@ void Sleep::DrawSettingsScreen() { int y_offset = 50; for (const auto& setting : settings) { - //lv_obj_t* lblSetting = lv_label_create(lv_scr_act(), nullptr); - // lv_label_set_text_static(lblSetting, setting.name); - // lv_obj_align(lblSetting, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + // lv_obj_t* lblSetting = lv_label_create(lv_scr_act(), nullptr); + // lv_label_set_text_static(lblSetting, setting.name); + // lv_obj_align(lblSetting, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); lv_obj_t* checkbox = lv_checkbox_create(lv_scr_act(), nullptr); checkbox->user_data = const_cast(setting.name); @@ -318,7 +344,7 @@ void Sleep::DrawSettingsScreen() { lv_obj_align(checkbox, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); lv_obj_set_event_cb(checkbox, settingsToggleEventHandler); - //lv_obj_set_event_cb(lblSetting, settingsToggleEventHandler); + // lv_obj_set_event_cb(lblSetting, settingsToggleEventHandler); y_offset += setting.offsetAfter; // Increase the offset to provide better spacing } @@ -355,12 +381,24 @@ void Sleep::DrawSettingsScreen() { auto* screen = static_cast(obj->user_data); int value = screen->infiniSleepController.infiniSleepSettings.sleepCycleDuration; switch (value) { - case 80: value = 85; break; - case 85: value = 90; break; - case 90: value = 95; break; - case 95: value = 100; break; - case 100: value = 80; break; - default: value = 80; break; + case 80: + value = 85; + break; + case 85: + value = 90; + break; + case 90: + value = 95; + break; + case 95: + value = 100; + break; + case 100: + value = 80; + break; + default: + value = 80; + break; } screen->infiniSleepController.infiniSleepSettings.sleepCycleDuration = value; screen->infiniSleepController.SetSettingsChanged(); @@ -453,8 +491,8 @@ bool Sleep::OnButtonPushed() { bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { // Swiping should be ignored when in alerting state - if (infiniSleepController.IsAlerting() && - (event != TouchEvents::SwipeDown && event != TouchEvents::SwipeUp && event != TouchEvents::SwipeLeft && event != TouchEvents::SwipeRight)) { + if (infiniSleepController.IsAlerting() && (event != TouchEvents::SwipeDown && event != TouchEvents::SwipeUp && + event != TouchEvents::SwipeLeft && event != TouchEvents::SwipeRight)) { return true; } @@ -502,7 +540,7 @@ void Sleep::SnoozeWakeAlarm() { hourCounter.SetValue(newSnoozeMinutes / 60); minuteCounter.SetValue(newSnoozeMinutes % 60); - + infiniSleepController.ScheduleWakeAlarm(); } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 7a9ccb4096..7ab7703f81 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -20,8 +20,12 @@ namespace Pinetime { namespace Screens { class Sleep : public Screen { public: - //explicit Sleep(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, Controllers::FS& fsController, System::SystemTask& systemTask); - explicit Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, Controllers::MotorController& motorController); + // explicit Sleep(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, Controllers::FS& + // fsController, System::SystemTask& systemTask); + explicit Sleep(Controllers::InfiniSleepController& infiniSleepController, + Controllers::Settings::ClockType clockType, + System::SystemTask& systemTask, + Controllers::MotorController& motorController); ~Sleep() override; void Refresh() override; void SetAlerting(); @@ -44,14 +48,15 @@ namespace Pinetime { // // Data Processing functions // float ConvertToMinutes(int hours, int minutes, int seconds) const; // Get the moving average of BPM Values - //std::vector MovingAverage(const std::vector& bpm, int windowSize) const; + // std::vector MovingAverage(const std::vector& bpm, int windowSize) const; // Detect the sleep regions - //std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float threshold) const; + // std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float + // threshold) const; // Get the sleep info - //void GetSleepInfo(const std::vector>& data) const; + // void GetSleepInfo(const std::vector>& data) const; // Read IO - //std::vector> ReadDataCSV(const char* fileName) const; + // std::vector> ReadDataCSV(const char* fileName) const; Controllers::InfiniSleepController& infiniSleepController; @@ -73,13 +78,13 @@ namespace Pinetime { enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); - //void EnableWakeAlarm(); - //void SetRecurButtonState(); + // void EnableWakeAlarm(); + // void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); void ShowAlarmInfo(); void HideAlarmInfo(); - //void ToggleRecurrence(); + // void ToggleRecurrence(); void UpdateWakeAlarmTime(); Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76); Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); @@ -112,14 +117,19 @@ namespace Pinetime { // lv_task_t* hrRefreshTask; }; } - + template <> struct AppTraits { static constexpr Apps app = Apps::Sleep; static constexpr const char* icon = Screens::Symbols::bed; + static Screens::Screen* Create(AppControllers& controllers) { - //return new Screens::Sleep(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, *controllers.systemTask); - return new Screens::Sleep(controllers.infiniSleepController, controllers.settingsController.GetClockType(), *controllers.systemTask, controllers.motorController); + // return new Screens::Sleep(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, + // *controllers.systemTask); + return new Screens::Sleep(controllers.infiniSleepController, + controllers.settingsController.GetClockType(), + *controllers.systemTask, + controllers.motorController); } }; } From 4426c22a3cfef9f4f79b53e42cc3d58194546e5d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 24 Nov 2024 11:34:38 -0600 Subject: [PATCH 064/191] Updated DisplayAppRecovery --- src/displayapp/DisplayAppRecovery.cpp | 4 +++- src/displayapp/DisplayAppRecovery.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index bcb8db0e9d..72ce4955ba 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -7,6 +7,7 @@ #include "touchhandler/TouchHandler.h" #include "displayapp/icons/infinitime/infinitime-nb.c" #include "components/ble/BleController.h" +#include "displayapp/screens/Sleep.h" using namespace Pinetime::Applications; @@ -25,7 +26,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::BrightnessController& /*brightnessController*/, Pinetime::Controllers::TouchHandler& /*touchHandler*/, Pinetime::Controllers::FS& /*filesystem*/, - Pinetime::Drivers::SpiNorFlash& /*spiNorFlash*/) + Pinetime::Drivers::SpiNorFlash& /*spiNorFlash*/, + Pinetime::Controllers::InfiniSleepController& infiniSleepController) : lcd {lcd}, bleController {bleController} { } diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 162ff2575e..6cb3e7394d 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -61,7 +61,8 @@ namespace Pinetime { Pinetime::Controllers::BrightnessController& brightnessController, Pinetime::Controllers::TouchHandler& touchHandler, Pinetime::Controllers::FS& filesystem, - Pinetime::Drivers::SpiNorFlash& spiNorFlash); + Pinetime::Drivers::SpiNorFlash& spiNorFlash, + Pinetime::Controllers::InfiniSleepController& infiniSleepController); void Start(); void Start(Pinetime::System::BootErrors) { From 245ebed8abaa4485e5970e8b1eb4f3775e4c96cc Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 24 Nov 2024 16:05:30 -0600 Subject: [PATCH 065/191] Trying to fix error from Github Build Action --- src/displayapp/DisplayApp.h | 1 + src/displayapp/DisplayAppRecovery.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 9009d5daee..0be91e848a 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -14,6 +14,7 @@ #include "displayapp/screens/Screen.h" #include "components/timer/Timer.h" #include "components/alarm/AlarmController.h" +#include "components/infinisleep/InfiniSleepController.h" #include "touchhandler/TouchHandler.h" #include "displayapp/Messages.h" diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 6cb3e7394d..dc5108b66f 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -37,6 +37,7 @@ namespace Pinetime { class SimpleWeatherService; class MusicService; class NavigationService; + class InfiniSleepController; } namespace System { From 2773f2898856e858ee9d74c543bb7f44a4659eb9 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 24 Nov 2024 16:32:13 -0600 Subject: [PATCH 066/191] Undid some edits that were for testing --- src/components/infinisleep/InfiniSleepController.cpp | 2 ++ src/components/infinisleep/InfiniSleepController.h | 3 ++- src/displayapp/DisplayApp.cpp | 2 ++ src/displayapp/screens/Sleep.cpp | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 46361f65c9..d1b93e3664 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -196,7 +196,9 @@ void InfiniSleepController::SetOffGradualWakeNow() { // isGradualWakeAlerting = true; systemTask->PushMessage(System::Messages::SetOffGradualWake); +} +void InfiniSleepController::UpdateGradualWake() { // make sure graudal wake steps are possible while (gradualWakeStep > 0 && SecondsToWakeAlarm() <= gradualWakeSteps[gradualWakeStep - 1]) { gradualWakeStep--; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 21f318679e..69aa809004 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -40,6 +40,7 @@ namespace Pinetime { void EnableWakeAlarm(); void SetOffWakeAlarmNow(); void SetOffGradualWakeNow(); + void UpdateGradualWake(); uint32_t SecondsToWakeAlarm() const; void StopAlerting(); // enum class RecurType { None, Daily, Weekdays }; @@ -164,7 +165,7 @@ namespace Pinetime { uint16_t GetSleepCycles() { uint16_t totalMinutes = GetTotalSleep(); - return (totalMinutes * 100 / SLEEP_CYCLE_DURATION); + return (totalMinutes * 100 / infiniSleepSettings.sleepCycleDuration); } uint16_t GetTotalSleep() const { diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index af2675ccf2..08a524bf00 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -408,6 +408,8 @@ void DisplayApp::Refresh() { } motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); + infiniSleepController.UpdateGradualWake(); + NRF_LOG_INFO("Gradual wake triggered"); break; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 638ffb210b..d2995cecfb 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -559,7 +559,7 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); - taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(5 * 1000), LV_TASK_PRIO_MID, this); + taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(120 * 1000), LV_TASK_PRIO_MID, this); motorController.StartAlarm(); wakeLock.Lock(); } From 25830599340777e4d35ac15236780eb7fa46d71d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 24 Nov 2024 17:28:36 -0600 Subject: [PATCH 067/191] removed commented code --- .../infinisleep/InfiniSleepController.cpp | 32 -------- .../infinisleep/InfiniSleepController.h | 11 --- src/displayapp/screens/Sleep.cpp | 74 +------------------ src/displayapp/screens/Sleep.h | 47 ------------ 4 files changed, 1 insertion(+), 163 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index d1b93e3664..362bbb06d0 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -109,7 +109,6 @@ void InfiniSleepController::ScheduleWakeAlarm() { pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; gradualWakeStep = 9; - // gradualWakeVibration = 9; auto now = dateTimeController.CurrentDateTime(); wakeAlarmTime = now; @@ -129,14 +128,6 @@ void InfiniSleepController::ScheduleWakeAlarm() { tmWakeAlarmTime->tm_min = wakeAlarm.minutes; tmWakeAlarmTime->tm_sec = 0; - // if alarm is in weekday-only mode, make sure it shifts to the next weekday - // if (wakeAlarm.recurrence == RecurType::Weekdays) { - // if (tmWakeAlarmTime->tm_wday == 0) {// Sunday, shift 1 day - // tmWakeAlarmTime->tm_mday += 1; - // } else if (tmWakeAlarmTime->tm_wday == 6) { // Saturday, shift 2 days - // tmWakeAlarmTime->tm_mday += 2; - // } - // } tmWakeAlarmTime->tm_isdst = -1; // use system timezone setting to determine DST // now can convert back to a time_point @@ -154,7 +145,6 @@ void InfiniSleepController::ScheduleWakeAlarm() { // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); - // gradualWakeVibration = gradualWakeStep; xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } @@ -173,7 +163,6 @@ void InfiniSleepController::DisableWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); gradualWakeStep = 9; - // gradualWakeVibration = 9; isAlerting = false; if (wakeAlarm.isEnabled) { wakeAlarm.isEnabled = false; @@ -202,13 +191,11 @@ void InfiniSleepController::UpdateGradualWake() { // make sure graudal wake steps are possible while (gradualWakeStep > 0 && SecondsToWakeAlarm() <= gradualWakeSteps[gradualWakeStep - 1]) { gradualWakeStep--; - // gradualWakeVibration = gradualWakeStep; } // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); - // gradualWakeVibration = gradualWakeStep; xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } else { @@ -218,24 +205,10 @@ void InfiniSleepController::UpdateGradualWake() { void InfiniSleepController::StopAlerting() { isAlerting = false; - // Disable the alarm unless it is recurring - // if (wakeAlarm.recurrence == RecurType::None) { wakeAlarm.isEnabled = false; wakeAlarmChanged = true; - // } else { - // // Schedule the alarm for the next day - // ScheduleWakeAlarm(); - // } } -// void InfiniSleepController::SetRecurrence(RecurType recurrence) { -// if (wakeAlarm.recurrence == recurrence) { -// return; -// } -// wakeAlarm.recurrence = recurrence; -// wakeAlarmChanged = true; -// } - /* Sleep Tracking Section */ void InfiniSleepController::UpdateBPM() { @@ -342,11 +315,6 @@ void InfiniSleepController::LoadSettingsFromFile() { } void InfiniSleepController::SaveSettingsToFile() const { - // lfs_dir systemDir; - // if (fs.DirOpen("/system/sleep", &systemDir) != LFS_ERR_OK) { - // fs.DirCreate("/system/sleep"); - // } - // fs.DirClose(&systemDir); lfs_file_t alarmFile; WakeAlarmSettings tempWakeAlarm = wakeAlarm; if (isSnoozing) { diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 69aa809004..e777f6e2a2 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -43,7 +43,6 @@ namespace Pinetime { void UpdateGradualWake(); uint32_t SecondsToWakeAlarm() const; void StopAlerting(); - // enum class RecurType { None, Daily, Weekdays }; uint8_t pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; @@ -99,12 +98,6 @@ namespace Pinetime { void DisableTracker(); void UpdateTracker(); - // RecurType Recurrence() const { - // return wakeAlarm.recurrence; - // } - - // void SetRecurrence(RecurType recurrence); - bool BodyTrackingEnabled() const { return infiniSleepSettings.bodyTracking; } @@ -159,8 +152,6 @@ namespace Pinetime { static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds static constexpr uint16_t gradualWakeVibrationDurations[9] = {1000, 1000, 900, 800, 800, 700, 700, 700, 500}; // In ms - // uint8_t gradualWakeVibration = 9; // used to keep track of which vibration duration to use, in position form not idex - int8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex uint16_t GetSleepCycles() { @@ -236,8 +227,6 @@ namespace Pinetime { return dateTimeController.Minutes(); } - // int64_t secondsToWakeAlarm = 0; - int bpm = 0; int prevBpm = 0; int rollingBpm = 0; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index d2995cecfb..10b2f63470 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -96,13 +96,6 @@ void Sleep::DisableWakeAlarm() { } } -// void Sleep::EnableWakeAlarm() { -// if (!infiniSleepController.GetWakeAlarm().isEnabled) { -// infiniSleepController.EnableWakeAlarm(); -// lv_switch_on(enableSwitch, LV_ANIM_ON); -// } -// } - void Sleep::Refresh() { UpdateDisplay(); } @@ -172,27 +165,6 @@ void Sleep::DrawAlarmScreen() { txtSuggestedAlarm = lv_label_create(btnSuggestedAlarm, nullptr); lv_label_set_text_static(txtSuggestedAlarm, "Suggested"); - // btnRecur = lv_btn_create(lv_scr_act(), nullptr); - // btnRecur->user_data = this; - // lv_obj_set_event_cb(btnRecur, btnEventHandler); - // lv_obj_set_size(btnRecur, 115, 50); - // lv_obj_align(btnRecur, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - // txtRecur = lv_label_create(btnRecur, nullptr); - // SetRecurButtonState(); - // lv_obj_set_style_local_bg_color(btnRecur, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); - - // btnInfo = lv_btn_create(lv_scr_act(), nullptr); - // btnInfo->user_data = this; - // lv_obj_set_event_cb(btnInfo, btnEventHandler); - // lv_obj_set_size(btnInfo, 50, 50); - // lv_obj_align(btnInfo, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, -4); - // lv_obj_set_style_local_bg_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, bgColor); - // lv_obj_set_style_local_border_width(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 4); - // lv_obj_set_style_local_border_color(btnInfo, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - - // lv_obj_t* txtInfo = lv_label_create(btnInfo, nullptr); - // lv_label_set_text_static(txtInfo, "i"); - enableSwitch = lv_switch_create(lv_scr_act(), nullptr); enableSwitch->user_data = this; lv_obj_set_event_cb(enableSwitch, btnEventHandler); @@ -328,9 +300,6 @@ void Sleep::DrawSettingsScreen() { int y_offset = 50; for (const auto& setting : settings) { - // lv_obj_t* lblSetting = lv_label_create(lv_scr_act(), nullptr); - // lv_label_set_text_static(lblSetting, setting.name); - // lv_obj_align(lblSetting, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); lv_obj_t* checkbox = lv_checkbox_create(lv_scr_act(), nullptr); checkbox->user_data = const_cast(setting.name); @@ -344,8 +313,6 @@ void Sleep::DrawSettingsScreen() { lv_obj_align(checkbox, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); lv_obj_set_event_cb(checkbox, settingsToggleEventHandler); - // lv_obj_set_event_cb(lblSetting, settingsToggleEventHandler); - y_offset += setting.offsetAfter; // Increase the offset to provide better spacing } @@ -420,10 +387,6 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { SnoozeWakeAlarm(); return; } - // if (obj == btnInfo) { - // ShowAlarmInfo(); - // return; - // } if (obj == btnMessage) { HideAlarmInfo(); return; @@ -460,10 +423,6 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { infiniSleepController.ScheduleWakeAlarm(); return; } - // if (obj == btnRecur) { - // DisableWakeAlarm(); - // ToggleRecurrence(); - // } } } @@ -621,35 +580,4 @@ void Sleep::HideAlarmInfo() { lv_obj_del(btnMessage); txtMessage = nullptr; btnMessage = nullptr; -} - -// void Sleep::SetRecurButtonState() { -// using Pinetime::Controllers::InfiniSleepController; -// switch (infiniSleepController.Recurrence()) { -// case InfiniSleepController::RecurType::None: -// lv_label_set_text_static(txtRecur, "ONCE"); -// break; -// case InfiniSleepController::RecurType::Daily: -// lv_label_set_text_static(txtRecur, "DAILY"); -// break; -// case InfiniSleepController::RecurType::Weekdays: -// lv_label_set_text_static(txtRecur, "MON-FRI"); -// break; -// } -// } - -// void Sleep::ToggleRecurrence() { -// using Pinetime::Controllers::InfiniSleepController; -// switch (infiniSleepController.Recurrence()) { -// case InfiniSleepController::RecurType::None: -// infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Daily); -// break; -// case InfiniSleepController::RecurType::Daily: -// infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::Weekdays); -// break; -// case InfiniSleepController::RecurType::Weekdays: -// infiniSleepController.SetRecurrence(InfiniSleepController::RecurType::None); -// break; -// } -// SetRecurButtonState(); -// } \ No newline at end of file +} \ No newline at end of file diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 7ab7703f81..1a41cb43cf 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -9,19 +9,11 @@ #include "systemtask/WakeLock.h" #include "Symbols.h" -//#define GRADUAL_WAKE_MOTOR_DURATION_MS 1000 - -//#include -//#include // for accumulate -//#include // for abs - namespace Pinetime { namespace Applications { namespace Screens { class Sleep : public Screen { public: - // explicit Sleep(Controllers::HeartRateController& HeartRateController, Controllers::DateTime& DateTimeController, Controllers::FS& - // fsController, System::SystemTask& systemTask); explicit Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, @@ -39,25 +31,6 @@ namespace Pinetime { enum class SleepDisplayState { Alarm, Info, Settings }; SleepDisplayState displayState = SleepDisplayState::Info; - // void Refresh() override; - - // void GetBPM(); - - // void ClearDataCSV(const char* filename) const; - - // // Data Processing functions - // float ConvertToMinutes(int hours, int minutes, int seconds) const; - // Get the moving average of BPM Values - // std::vector MovingAverage(const std::vector& bpm, int windowSize) const; - // Detect the sleep regions - // std::vector> DetectSleepRegions(const std::vector& bpmData, const std::vector& time, float - // threshold) const; - // Get the sleep info - // void GetSleepInfo(const std::vector>& data) const; - - // Read IO - // std::vector> ReadDataCSV(const char* fileName) const; - Controllers::InfiniSleepController& infiniSleepController; private: @@ -78,13 +51,10 @@ namespace Pinetime { enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); - // void EnableWakeAlarm(); - // void SetRecurButtonState(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); void ShowAlarmInfo(); void HideAlarmInfo(); - // void ToggleRecurrence(); void UpdateWakeAlarmTime(); Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76); Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); @@ -93,18 +63,6 @@ namespace Pinetime { void DrawInfoScreen(); void DrawSettingsScreen(); - // Controllers::HeartRateController& heartRateController; - // Controllers::DateTime& dateTimeController; - // Controllers::FS& fsController; - // Pinetime::System::WakeLock wakeLock; - - // // For File IO - // void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; - - // int bpm = 0; - // int prevBpm = 0; - // int rollingBpm = 0; - lv_obj_t* label_hr; lv_obj_t* label_start_time; lv_obj_t* label_alarm_time; @@ -112,9 +70,6 @@ namespace Pinetime { lv_obj_t* label_total_sleep; lv_obj_t* label_sleep_cycles; lv_obj_t *btnSuggestedAlarm, *txtSuggestedAlarm; - - // lv_task_t* mainRefreshTask; - // lv_task_t* hrRefreshTask; }; } @@ -124,8 +79,6 @@ namespace Pinetime { static constexpr const char* icon = Screens::Symbols::bed; static Screens::Screen* Create(AppControllers& controllers) { - // return new Screens::Sleep(controllers.heartRateController, controllers.dateTimeController, controllers.filesystem, - // *controllers.systemTask); return new Screens::Sleep(controllers.infiniSleepController, controllers.settingsController.GetClockType(), *controllers.systemTask, From 47732745a8d58a92916674741b47a95e85ae1188 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 24 Nov 2024 18:18:25 -0600 Subject: [PATCH 068/191] Finally fixed errors during "make -j4 all" --- src/displayapp/DisplayAppRecovery.cpp | 2 +- src/displayapp/DisplayAppRecovery.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index 72ce4955ba..82d8c99c5e 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -28,7 +28,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::FS& /*filesystem*/, Pinetime::Drivers::SpiNorFlash& /*spiNorFlash*/, Pinetime::Controllers::InfiniSleepController& infiniSleepController) - : lcd {lcd}, bleController {bleController} { + : lcd {lcd}, bleController {bleController}, infiniSleepController {infiniSleepController} { } void DisplayApp::Start() { diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index dc5108b66f..937265d41b 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -85,6 +85,7 @@ namespace Pinetime { void Refresh(); Pinetime::Drivers::St7789& lcd; const Controllers::Ble& bleController; + const Controllers::InfiniSleepController& infiniSleepController; static constexpr uint8_t queueSize = 10; static constexpr uint8_t itemSize = 1; From 466bdbed54d8f00ad732819021961180f6f11a88 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 24 Nov 2024 20:23:17 -0600 Subject: [PATCH 069/191] Removed sleep controller from recovery firmware --- src/displayapp/DisplayAppRecovery.cpp | 4 ++-- src/displayapp/DisplayAppRecovery.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index 82d8c99c5e..2500dcad32 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -27,8 +27,8 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::TouchHandler& /*touchHandler*/, Pinetime::Controllers::FS& /*filesystem*/, Pinetime::Drivers::SpiNorFlash& /*spiNorFlash*/, - Pinetime::Controllers::InfiniSleepController& infiniSleepController) - : lcd {lcd}, bleController {bleController}, infiniSleepController {infiniSleepController} { + Pinetime::Controllers::InfiniSleepController& /*infiniSleepController*/) + : lcd {lcd}, bleController {bleController} { } void DisplayApp::Start() { diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 937265d41b..dc5108b66f 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -85,7 +85,6 @@ namespace Pinetime { void Refresh(); Pinetime::Drivers::St7789& lcd; const Controllers::Ble& bleController; - const Controllers::InfiniSleepController& infiniSleepController; static constexpr uint8_t queueSize = 10; static constexpr uint8_t itemSize = 1; From fca1c482116f437027e0c7c04d8f2d638d6ed033 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 25 Nov 2024 18:44:22 -0600 Subject: [PATCH 070/191] Fixed Alert retriggering due to Display Update. This seems to be the root of most of the previous bugs of the snooze alarm time constantly changing and the motor buzzing weird due to retriggering --- src/displayapp/screens/Sleep.cpp | 36 +++++++++++++++++++++++++------- src/displayapp/screens/Sleep.h | 6 +++++- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 10b2f63470..1876b32091 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -52,7 +52,7 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { static void SnoozeAlarmTaskCallback(lv_task_t* task) { auto* screen = static_cast(task->user_data); - lv_task_del(task); + lv_task_set_prio(task, LV_TASK_PRIO_OFF); screen->StopAlerting(false); screen->SnoozeWakeAlarm(); } @@ -175,6 +175,12 @@ void Sleep::DrawAlarmScreen() { UpdateWakeAlarmTime(); + if (alreadyAlerting) { + RedrawSetAlerting(); + return; + } + + if (infiniSleepController.IsAlerting()) { SetAlerting(); } else { @@ -437,8 +443,10 @@ bool Sleep::OnButtonPushed() { infiniSleepController.pushesLeftToStopWakeAlarm--; return true; } else { + if (infiniSleepController.isSnoozing) { + infiniSleepController.RestorePreSnoozeTime(); + } infiniSleepController.isSnoozing = false; - infiniSleepController.RestorePreSnoozeTime(); StopAlerting(); UpdateDisplay(); return true; @@ -455,6 +463,9 @@ bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return true; } + lastDisplayState = displayState; + NRF_LOG_INFO("Last Display State: %d", static_cast(lastDisplayState)); + // The cases for swiping to change page on app switch (event) { case TouchEvents::SwipeRight: @@ -486,8 +497,12 @@ void Sleep::OnValueChanged() { // Currently snoozes baeed on define statement in InfiniSleepController.h void Sleep::SnoozeWakeAlarm() { - lv_task_del(taskSnoozeWakeAlarm); - taskSnoozeWakeAlarm = nullptr; + if (taskSnoozeWakeAlarm != nullptr) { + lv_task_del(taskSnoozeWakeAlarm); + taskSnoozeWakeAlarm = nullptr; + } + + NRF_LOG_INFO("Snoozing alarm for %d minutes", SNOOZE_MINUTES); uint16_t totalAlarmMinutes = infiniSleepController.GetCurrentHour() * 60 + infiniSleepController.GetCurrentMinute(); uint16_t newSnoozeMinutes = totalAlarmMinutes + SNOOZE_MINUTES; @@ -518,9 +533,17 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); lv_obj_set_hidden(btnStop, false); - taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, pdMS_TO_TICKS(120 * 1000), LV_TASK_PRIO_MID, this); + NRF_LOG_INFO("Alarm is alerting"); + taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); motorController.StartAlarm(); wakeLock.Lock(); + alreadyAlerting = true; +} + +void Sleep::RedrawSetAlerting() { + lv_obj_set_hidden(enableSwitch, true); + lv_obj_set_hidden(btnStop, false); + wakeLock.Lock(); } void Sleep::StopAlerting(bool setSwitch) { @@ -529,11 +552,10 @@ void Sleep::StopAlerting(bool setSwitch) { if (setSwitch) { SetSwitchState(LV_ANIM_OFF); } - lv_task_del(taskSnoozeWakeAlarm); - taskSnoozeWakeAlarm = nullptr; wakeLock.Release(); lv_obj_set_hidden(enableSwitch, false); lv_obj_set_hidden(btnStop, true); + alreadyAlerting = false; } void Sleep::SetSwitchState(lv_anim_enable_t anim) { diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 1a41cb43cf..514867917a 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -21,6 +21,7 @@ namespace Pinetime { ~Sleep() override; void Refresh() override; void SetAlerting(); + void RedrawSetAlerting(); void OnButtonEvent(lv_obj_t* obj, lv_event_t event); bool OnButtonPushed() override; bool OnTouchEvent(TouchEvents event) override; @@ -30,6 +31,7 @@ namespace Pinetime { void UpdateDisplay(); enum class SleepDisplayState { Alarm, Info, Settings }; SleepDisplayState displayState = SleepDisplayState::Info; + SleepDisplayState lastDisplayState = SleepDisplayState::Info; Controllers::InfiniSleepController& infiniSleepController; @@ -49,7 +51,7 @@ namespace Pinetime { lv_task_t* taskPressesToStopAlarmTimeout = nullptr; - enum class EnableButtonState { On, Off, Alerting }; + //enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); @@ -63,6 +65,8 @@ namespace Pinetime { void DrawInfoScreen(); void DrawSettingsScreen(); + bool alreadyAlerting = false; + lv_obj_t* label_hr; lv_obj_t* label_start_time; lv_obj_t* label_alarm_time; From 50a9bf4970579642cdced365ad5127d06c675c73 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 25 Nov 2024 18:45:26 -0600 Subject: [PATCH 071/191] Formatted Code --- src/displayapp/screens/Sleep.cpp | 1 - src/displayapp/screens/Sleep.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 1876b32091..36fb60bf17 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -180,7 +180,6 @@ void Sleep::DrawAlarmScreen() { return; } - if (infiniSleepController.IsAlerting()) { SetAlerting(); } else { diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 514867917a..4e33cf5e89 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -51,7 +51,7 @@ namespace Pinetime { lv_task_t* taskPressesToStopAlarmTimeout = nullptr; - //enum class EnableButtonState { On, Off, Alerting }; + // enum class EnableButtonState { On, Off, Alerting }; void DisableWakeAlarm(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); From 8ffc94ff764cddb108a22205c45e64aa65eb3359 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Wed, 27 Nov 2024 12:51:45 -0600 Subject: [PATCH 072/191] Made suggested alarm time label more descriptive --- src/displayapp/screens/Sleep.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 36fb60bf17..1270d9c0f0 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -163,7 +163,7 @@ void Sleep::DrawAlarmScreen() { lv_obj_set_size(btnSuggestedAlarm, 115, 50); lv_obj_align(btnSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); txtSuggestedAlarm = lv_label_create(btnSuggestedAlarm, nullptr); - lv_label_set_text_static(txtSuggestedAlarm, "Suggested"); + lv_label_set_text_static(txtSuggestedAlarm, "Use Sugg.\nAlarmTime"); enableSwitch = lv_switch_create(lv_scr_act(), nullptr); enableSwitch->user_data = this; From 7f0a7c22b5b176d3c59ef1a9f3107a69e3e173a5 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 00:17:55 -0600 Subject: [PATCH 073/191] Made sure double clicking side button doesn't show notifications when alerting --- src/displayapp/DisplayApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 08a524bf00..fdd3ee567f 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -497,7 +497,7 @@ void DisplayApp::Refresh() { LoadNewScreen(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up); break; case Messages::ButtonDoubleClicked: - if (currentApp != Apps::Notifications && currentApp != Apps::NotificationsPreview) { + if (!infiniSleepController.IsAlerting() && currentApp != Apps::Notifications && currentApp != Apps::NotificationsPreview) { LoadNewScreen(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); } break; From 673873e6bb8aa9d78044975514b9de0e7495c069 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 00:18:57 -0600 Subject: [PATCH 074/191] Added PWM to motor controller Main reason is to control the intensity of the wakeup vibrations --- src/CMakeLists.txt | 1 + src/components/motor/MotorController.cpp | 74 ++++++++++++++++++++++++ src/components/motor/MotorController.h | 9 +++ src/displayapp/DisplayApp.cpp | 5 +- src/sdk_config.h | 4 +- 5 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e6f3ee54b..a9c3b6d8e6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(SDK_SOURCE_FILES "${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_gpiote.c" "${NRF5_SDK_PATH}/modules/nrfx/soc/nrfx_atomic.c" "${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_saadc.c" + "${NRF5_SDK_PATH}/modules/nrfx/drivers/src/nrfx_pwm.c" # FreeRTOS ${NRF5_SDK_PATH}/external/freertos/source/croutine.c diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 044bc24bd2..cdc41ae6e4 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -2,9 +2,21 @@ #include #include "systemtask/SystemTask.h" #include "drivers/PinMap.h" +#include "nrf_drv_pwm.h" using namespace Pinetime::Controllers; +static nrf_drv_pwm_t m_pwm2 = NRF_DRV_PWM_INSTANCE(2); +static nrf_pwm_values_individual_t seq_values; +static nrf_pwm_sequence_t const seq = { + { + .p_individual = &seq_values + }, + NRF_PWM_VALUES_LENGTH(seq_values), + 0, + 0 +}; + void MotorController::Init() { nrf_gpio_cfg_output(PinMap::Motor); nrf_gpio_pin_set(PinMap::Motor); @@ -12,6 +24,38 @@ void MotorController::Init() { shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor); longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring); alarmVib = xTimerCreate("alarmVib", pdMS_TO_TICKS(500), pdTRUE, this, AlarmRing); + //gradualWakeBuzzDelay = xTimerCreate("gradualWakeBuzzDelay", pdMS_TO_TICKS(15), pdTRUE, this, GradualWakeBuzzRing); + //gradualWakeBuzzEnd = xTimerCreate("gradualWakeBuzzEnd", pdMS_TO_TICKS(550), pdTRUE, this, StopGradualWakeBuzzCallback); + + InitPWM(); +} + +void MotorController::InitPWM() { + nrf_drv_pwm_config_t const config2 = { + .output_pins = { + PinMap::Motor, // channel 0 + NRF_DRV_PWM_PIN_NOT_USED, // channel 1 + NRF_DRV_PWM_PIN_NOT_USED, // channel 2 + NRF_DRV_PWM_PIN_NOT_USED // channel 3 + }, + .irq_priority = APP_IRQ_PRIORITY_LOWEST, + .base_clock = NRF_PWM_CLK_1MHz, + .count_mode = NRF_PWM_MODE_UP, + .top_value = 100, + .load_mode = NRF_PWM_LOAD_INDIVIDUAL, + .step_mode = NRF_PWM_STEP_AUTO + }; + + nrf_drv_pwm_init(&m_pwm2, &config2, NULL); + seq_values.channel_0 = 0; + nrf_drv_pwm_simple_playback(&m_pwm2, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); + + SetMotorStrength(100); +} + +void MotorController::SetMotorStrength(uint8_t strength) { + if (strength > 100) strength = 100; + seq_values.channel_0 = strength; } void MotorController::Ring(TimerHandle_t xTimer) { @@ -27,10 +71,12 @@ void MotorController::AlarmRing(TimerHandle_t xTimer) { void MotorController::RunForDuration(uint16_t motorDuration) { if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) { nrf_gpio_pin_clear(PinMap::Motor); + nrf_drv_pwm_simple_playback(&m_pwm2, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); } } void MotorController::StartRinging() { + SetMotorStrength(100); RunForDuration(50); xTimerStart(longVib, 0); } @@ -38,9 +84,11 @@ void MotorController::StartRinging() { void MotorController::StopRinging() { xTimerStop(longVib, 0); nrf_gpio_pin_set(PinMap::Motor); + nrf_drv_pwm_stop(&m_pwm2, true); } void MotorController::StartAlarm() { + SetMotorStrength(100); RunForDuration(300); xTimerStart(alarmVib, 0); } @@ -48,8 +96,34 @@ void MotorController::StartAlarm() { void MotorController::StopAlarm() { xTimerStop(alarmVib, 0); nrf_gpio_pin_set(PinMap::Motor); + nrf_drv_pwm_stop(&m_pwm2, true); } void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_gpio_pin_set(PinMap::Motor); + nrf_drv_pwm_stop(&m_pwm2, true); +} + +void MotorController::GradualWakeBuzz() { + SetMotorStrength(40); + RunForDuration(540); + //xTimerStart(gradualWakeBuzzDelay, 0); + //xTimerStart(gradualWakeBuzzEnd, 0); +} + +void MotorController::GradualWakeBuzzRing(TimerHandle_t xTimer) { + auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); + motorController->RunForDuration(12); +} + +void MotorController::StopGradualWakeBuzzCallback(TimerHandle_t xTimer) { + auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); + motorController->StopGradualWakeBuzz(); +} + +void MotorController::StopGradualWakeBuzz() { + //xTimerStop(gradualWakeBuzzDelay, 0); + xTimerStop(gradualWakeBuzzEnd, 0); + SetMotorStrength(100); + StopMotor(nullptr); } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 4acbeda710..455d04c1f0 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -17,14 +17,23 @@ namespace Pinetime { void StopRinging(); void StartAlarm(); void StopAlarm(); + void GradualWakeBuzz(); + void StopGradualWakeBuzz(); private: static void Ring(TimerHandle_t xTimer); static void AlarmRing(TimerHandle_t xTimer); static void StopMotor(TimerHandle_t xTimer); + static void GradualWakeBuzzRing(TimerHandle_t xTimer); + static void StopGradualWakeBuzzCallback(TimerHandle_t xTimer); + void InitPWM(); + void SetMotorStrength(uint8_t strength); + TimerHandle_t shortVib; TimerHandle_t longVib; TimerHandle_t alarmVib; + TimerHandle_t gradualWakeBuzzDelay; + TimerHandle_t gradualWakeBuzzEnd; }; } } diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index fdd3ee567f..388be56657 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -406,8 +406,9 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } - motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); - + //motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); + motorController.GradualWakeBuzz(); + infiniSleepController.UpdateGradualWake(); NRF_LOG_INFO("Gradual wake triggered"); diff --git a/src/sdk_config.h b/src/sdk_config.h index b42b39244f..da44682d4b 100644 --- a/src/sdk_config.h +++ b/src/sdk_config.h @@ -5633,7 +5633,7 @@ // PWM_ENABLED - nrf_drv_pwm - PWM peripheral driver - legacy layer //========================================================== #ifndef PWM_ENABLED - #define PWM_ENABLED 0 + #define PWM_ENABLED 1 #endif // PWM_DEFAULT_CONFIG_OUT0_PIN - Out0 pin <0-31> @@ -5739,7 +5739,7 @@ // PWM2_ENABLED - Enable PWM2 instance #ifndef PWM2_ENABLED - #define PWM2_ENABLED 0 + #define PWM2_ENABLED 1 #endif // PWM_NRF52_ANOMALY_109_WORKAROUND_ENABLED - Enables nRF52 Anomaly 109 workaround for PWM. From 8b96598813ace80ff002bf74e387dbde1d498f50 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 00:32:56 -0600 Subject: [PATCH 075/191] Updated Gradual Wake Buzz values to try to match SleepTk --- src/components/motor/MotorController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index cdc41ae6e4..cf9b3ae84f 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -105,8 +105,8 @@ void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { } void MotorController::GradualWakeBuzz() { - SetMotorStrength(40); - RunForDuration(540); + SetMotorStrength(80); + RunForDuration(100); //xTimerStart(gradualWakeBuzzDelay, 0); //xTimerStart(gradualWakeBuzzEnd, 0); } From be88829ea2a038715bd9c17f82c54ae45b3ed57f Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 20:13:57 -0600 Subject: [PATCH 076/191] Removed periodic file logging --- src/components/infinisleep/InfiniSleepController.cpp | 6 +++--- src/displayapp/screens/Sleep.cpp | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 362bbb06d0..dffbb0bc6e 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -230,9 +230,9 @@ void InfiniSleepController::UpdateBPM() { NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); // Write data to CSV - const int motion = 0; // Placeholder for motion data - std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; - WriteDataCSV(TRACKER_DATA_FILE_NAME, data, 1); + //const int motion = 0; // Placeholder for motion data + //std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; + //WriteDataCSV(TRACKER_DATA_FILE_NAME, data, 1); } void InfiniSleepController::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 1270d9c0f0..82b692ea6b 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -69,6 +69,8 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::MotorController& motorController) : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController}, clockType {clockType} { + infiniSleepController.SetHeartRateTrackingEnabled(false); + infiniSleepController.SetSettingsChanged(); UpdateDisplay(); taskRefresh = lv_task_create(RefreshTaskCallback, 2000, LV_TASK_PRIO_MID, this); taskPressesToStopAlarmTimeout = @@ -298,7 +300,7 @@ void Sleep::DrawSettingsScreen() { const Setting settings[] = { //{"Body Tracking", infiniSleepController.BodyTrackingEnabled()}, - {"Heart Rate\nTracking", infiniSleepController.HeartRateTrackingEnabled(), 60}, + // {"Heart Rate\nTracking", infiniSleepController.HeartRateTrackingEnabled(), 60}, {"Gradual Wake", infiniSleepController.GradualWakeEnabled()}, //{"Smart Alarm\n(alpha)", infiniSleepController.SmartAlarmEnabled()} }; From 522315a491f7b318b5dac372213f09660f10e4dd Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 20:15:27 -0600 Subject: [PATCH 077/191] UI Tweaks --- src/displayapp/screens/Sleep.cpp | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 82b692ea6b..d13242b2a7 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -154,7 +154,7 @@ void Sleep::DrawAlarmScreen() { lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); txtStop = lv_label_create(btnStop, nullptr); - lv_label_set_text_static(txtStop, Symbols::stop); + lv_label_set_text_static(txtStop, "ZzZz"); lv_obj_set_hidden(btnStop, true); static constexpr lv_color_t bgColor = Colors::bgAlt; @@ -164,8 +164,19 @@ void Sleep::DrawAlarmScreen() { lv_obj_set_event_cb(btnSuggestedAlarm, btnEventHandler); lv_obj_set_size(btnSuggestedAlarm, 115, 50); lv_obj_align(btnSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - txtSuggestedAlarm = lv_label_create(btnSuggestedAlarm, nullptr); - lv_label_set_text_static(txtSuggestedAlarm, "Use Sugg.\nAlarmTime"); + //txtSuggestedAlarm = lv_label_create(btnSuggestedAlarm, nullptr); + //lv_label_set_text_static(txtSuggestedAlarm, "Use Sugg.\nAlarmTime"); + + txtSuggestedAlarm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(txtSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10); + lv_label_set_text_static(txtSuggestedAlarm, "Auto"); + + + 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_WHITE); + lv_obj_align(icon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -50, -10); + lv_label_set_text_static(icon, Symbols::sun); + enableSwitch = lv_switch_create(lv_scr_act(), nullptr); enableSwitch->user_data = this; @@ -235,8 +246,8 @@ void Sleep::DrawInfoScreen() { // Gradual Wake info label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.GetWakeAlarm().isEnabled && infiniSleepController.GetInfiniSleepSettings().graddualWake && - infiniSleepController.gradualWakeStep > 0) { + if (infiniSleepController.GetInfiniSleepSettings().graddualWake && + infiniSleepController.gradualWakeStep >= 0) { lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: %d/9", infiniSleepController.gradualWakeStep); } else { lv_label_set_text_static(label_gradual_wake, "Gradual Wake: OFF"); From c2f356f425d3968ff6cb4b7f87441abb48b04596 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 22:43:47 -0600 Subject: [PATCH 078/191] Removed extra data write --- src/components/infinisleep/InfiniSleepController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index e777f6e2a2..be80a270d5 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -207,7 +207,7 @@ namespace Pinetime { SavePrevSessionData(); DisableTracker(); } else { - ClearDataCSV(TRACKER_DATA_FILE_NAME); + //ClearDataCSV(TRACKER_DATA_FILE_NAME); prevSessionData.startTimeHours = GetCurrentHour(); prevSessionData.startTimeMinutes = GetCurrentMinute(); EnableTracker(); From 2b3bf3865ccffa683c8529376ef740b474b85d6c Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 22:47:23 -0600 Subject: [PATCH 079/191] Make app go to info page when alarm is turned off and also turn of tracker. Also removed screen turning on when gradual wake --- src/displayapp/DisplayApp.cpp | 2 +- src/displayapp/screens/Sleep.cpp | 7 +++++++ src/systemtask/SystemTask.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 388be56657..784b6473cc 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -404,7 +404,7 @@ void DisplayApp::Refresh() { // auto* sleep = static_cast(currentScreen.get()); // sleep->SetGradualWakeAlerting(); } else { - LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); + //LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } //motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); motorController.GradualWakeBuzz(); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index d13242b2a7..76f2a3aa5c 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -460,6 +460,13 @@ bool Sleep::OnButtonPushed() { } infiniSleepController.isSnoozing = false; StopAlerting(); + if (infiniSleepController.IsTrackerEnabled()) { + displayState = SleepDisplayState::Info; + UpdateDisplay(); + OnButtonEvent(trackerToggleBtn, LV_EVENT_CLICKED); + return true; + } + displayState = SleepDisplayState::Info; UpdateDisplay(); return true; } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 1425b308cf..c574e8fd30 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -231,7 +231,7 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::WakeAlarmTriggered); break; case Messages::SetOffGradualWake: - GoToRunning(); + //GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::GradualWakeTriggered); break; case Messages::BleConnected: From 015808bff2720b696c64370e85105385545ecd5d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 28 Nov 2024 22:48:30 -0600 Subject: [PATCH 080/191] Added PWM to Motor Controller --- src/components/motor/MotorController.cpp | 101 +++++++++++------------ src/components/motor/MotorController.h | 3 +- 2 files changed, 49 insertions(+), 55 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index cf9b3ae84f..9d02d0a8cb 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -2,60 +2,52 @@ #include #include "systemtask/SystemTask.h" #include "drivers/PinMap.h" -#include "nrf_drv_pwm.h" +#include "nrf_pwm.h" using namespace Pinetime::Controllers; -static nrf_drv_pwm_t m_pwm2 = NRF_DRV_PWM_INSTANCE(2); -static nrf_pwm_values_individual_t seq_values; -static nrf_pwm_sequence_t const seq = { - { - .p_individual = &seq_values - }, - NRF_PWM_VALUES_LENGTH(seq_values), - 0, - 0 -}; +static uint16_t pwmValue = 0; // Declare the variable for PWM value void MotorController::Init() { + // Configure the motor pin as an output nrf_gpio_cfg_output(PinMap::Motor); nrf_gpio_pin_set(PinMap::Motor); + // Configure the PWM sequence + static nrf_pwm_sequence_t seq; + seq.values.p_common = &pwmValue; // Use the PWM value array + seq.length = NRF_PWM_VALUES_LENGTH(pwmValue); + seq.repeats = 0; + seq.end_delay = 0; + + // Configure the PWM pins + uint32_t out_pins[] = {PinMap::Motor, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}; + nrf_pwm_pins_set(NRF_PWM2, out_pins); + + // Enable and configure the PWM peripheral + nrf_pwm_enable(NRF_PWM2); + nrf_pwm_configure(NRF_PWM2, NRF_PWM_CLK_1MHz, NRF_PWM_MODE_UP, 255); // Top value determines the resolution + nrf_pwm_loop_set(NRF_PWM2, 0); // Infinite loop + nrf_pwm_decoder_set(NRF_PWM2, NRF_PWM_LOAD_COMMON, NRF_PWM_STEP_AUTO); + nrf_pwm_sequence_set(NRF_PWM2, 0, &seq); + + // Start the PWM with an initial value of 0 + pwmValue = 0; + nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_SEQSTART0); + + // Initialize timers for motor actions shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor); longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring); alarmVib = xTimerCreate("alarmVib", pdMS_TO_TICKS(500), pdTRUE, this, AlarmRing); - //gradualWakeBuzzDelay = xTimerCreate("gradualWakeBuzzDelay", pdMS_TO_TICKS(15), pdTRUE, this, GradualWakeBuzzRing); - //gradualWakeBuzzEnd = xTimerCreate("gradualWakeBuzzEnd", pdMS_TO_TICKS(550), pdTRUE, this, StopGradualWakeBuzzCallback); - - InitPWM(); -} - -void MotorController::InitPWM() { - nrf_drv_pwm_config_t const config2 = { - .output_pins = { - PinMap::Motor, // channel 0 - NRF_DRV_PWM_PIN_NOT_USED, // channel 1 - NRF_DRV_PWM_PIN_NOT_USED, // channel 2 - NRF_DRV_PWM_PIN_NOT_USED // channel 3 - }, - .irq_priority = APP_IRQ_PRIORITY_LOWEST, - .base_clock = NRF_PWM_CLK_1MHz, - .count_mode = NRF_PWM_MODE_UP, - .top_value = 100, - .load_mode = NRF_PWM_LOAD_INDIVIDUAL, - .step_mode = NRF_PWM_STEP_AUTO - }; - - nrf_drv_pwm_init(&m_pwm2, &config2, NULL); - seq_values.channel_0 = 0; - nrf_drv_pwm_simple_playback(&m_pwm2, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); - - SetMotorStrength(100); } void MotorController::SetMotorStrength(uint8_t strength) { - if (strength > 100) strength = 100; - seq_values.channel_0 = strength; + // Ensure strength is within bounds (0-100) + if (strength > 100) + strength = 100; + + // Map the strength to the PWM value (0-100 -> 0-top_value) + pwmValue = (strength * 255) / 100; } void MotorController::Ring(TimerHandle_t xTimer) { @@ -65,13 +57,14 @@ void MotorController::Ring(TimerHandle_t xTimer) { void MotorController::AlarmRing(TimerHandle_t xTimer) { auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); + motorController->SetMotorStrength(80); motorController->RunForDuration(300); } void MotorController::RunForDuration(uint16_t motorDuration) { if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) { - nrf_gpio_pin_clear(PinMap::Motor); - nrf_drv_pwm_simple_playback(&m_pwm2, &seq, 1, NRF_DRV_PWM_FLAG_LOOP); + // nrf_gpio_pin_clear(PinMap::Motor); + nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_SEQSTART0); // Restart the PWM sequence with the updated value } } @@ -83,32 +76,35 @@ void MotorController::StartRinging() { void MotorController::StopRinging() { xTimerStop(longVib, 0); + nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence + pwmValue = 0; // Reset the PWM value nrf_gpio_pin_set(PinMap::Motor); - nrf_drv_pwm_stop(&m_pwm2, true); } void MotorController::StartAlarm() { - SetMotorStrength(100); + SetMotorStrength(80); RunForDuration(300); xTimerStart(alarmVib, 0); } void MotorController::StopAlarm() { xTimerStop(alarmVib, 0); + nrf_pwm_task_trigger(NRF_PWM0, NRF_PWM_TASK_STOP); // Stop the PWM sequence + pwmValue = 0; // Reset the PWM value nrf_gpio_pin_set(PinMap::Motor); - nrf_drv_pwm_stop(&m_pwm2, true); } void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { - nrf_gpio_pin_set(PinMap::Motor); - nrf_drv_pwm_stop(&m_pwm2, true); + nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence + pwmValue = 0; // Reset the PWM value + nrf_gpio_pin_set(PinMap::Motor); // Set the motor pin to the off state } void MotorController::GradualWakeBuzz() { - SetMotorStrength(80); + SetMotorStrength(60); RunForDuration(100); - //xTimerStart(gradualWakeBuzzDelay, 0); - //xTimerStart(gradualWakeBuzzEnd, 0); + // xTimerStart(gradualWakeBuzzDelay, 0); + // xTimerStart(gradualWakeBuzzEnd, 0); } void MotorController::GradualWakeBuzzRing(TimerHandle_t xTimer) { @@ -122,8 +118,7 @@ void MotorController::StopGradualWakeBuzzCallback(TimerHandle_t xTimer) { } void MotorController::StopGradualWakeBuzz() { - //xTimerStop(gradualWakeBuzzDelay, 0); + // xTimerStop(gradualWakeBuzzDelay, 0); xTimerStop(gradualWakeBuzzEnd, 0); - SetMotorStrength(100); - StopMotor(nullptr); + // StopMotor(nullptr); } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 455d04c1f0..087074b850 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -19,6 +19,7 @@ namespace Pinetime { void StopAlarm(); void GradualWakeBuzz(); void StopGradualWakeBuzz(); + void SetMotorStrength(uint8_t strength); private: static void Ring(TimerHandle_t xTimer); @@ -26,8 +27,6 @@ namespace Pinetime { static void StopMotor(TimerHandle_t xTimer); static void GradualWakeBuzzRing(TimerHandle_t xTimer); static void StopGradualWakeBuzzCallback(TimerHandle_t xTimer); - void InitPWM(); - void SetMotorStrength(uint8_t strength); TimerHandle_t shortVib; TimerHandle_t longVib; From 44fad6a50fc2bc04ddf22edca142f2f8bcd284ba Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 29 Nov 2024 21:04:49 -0600 Subject: [PATCH 081/191] Reworked UI Layout Changed to vertical swiping and made the order: Info, Alarm, Settings Reworked Info page text and made tracker toggle button larger. Removed cycle duration setting. --- src/displayapp/screens/Sleep.cpp | 128 +++++++++++-------------------- src/displayapp/screens/Sleep.h | 2 +- 2 files changed, 45 insertions(+), 85 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 76f2a3aa5c..a5330f3e20 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -75,6 +75,8 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, taskRefresh = lv_task_create(RefreshTaskCallback, 2000, LV_TASK_PRIO_MID, this); taskPressesToStopAlarmTimeout = lv_task_create(PressesToStopAlarmTimeoutCallback, PUSHES_TO_STOP_ALARM_TIMEOUT * 1000, LV_TASK_PRIO_MID, this); + infiniSleepController.infiniSleepSettings.sleepCycleDuration = 90; + infiniSleepController.SetSettingsChanged(); } Sleep::~Sleep() { @@ -206,25 +208,38 @@ void Sleep::DrawInfoScreen() { lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - label_hr = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.rollingBpm == 0) { - lv_label_set_text_static(label_hr, "HR: --"); - } else { - lv_label_set_text_fmt(label_hr, "HR: %d", infiniSleepController.rollingBpm); - } - lv_obj_align(label_hr, lblTime, LV_ALIGN_CENTER, 0, 50); - lv_obj_set_style_local_text_color(label_hr, + // Total sleep time + label_total_sleep = lv_label_create(lv_scr_act(), nullptr); + + uint16_t totalMinutes = infiniSleepController.GetTotalSleep(); + + lv_label_set_text_fmt(label_total_sleep, "Time Asleep: %dh%dm", totalMinutes / 60, totalMinutes % 60); + lv_obj_align(label_total_sleep, lv_scr_act(), LV_ALIGN_CENTER, 0, -60); + lv_obj_set_style_local_text_color(label_total_sleep, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + + // Sleep Cycles Info + label_sleep_cycles = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(label_sleep_cycles, + "Sleep Cycles: %d.%02d", + infiniSleepController.GetSleepCycles() / 100, + infiniSleepController.GetSleepCycles() % 100); + lv_obj_align(label_sleep_cycles, lv_scr_act(), LV_ALIGN_CENTER, 0, -40); + lv_obj_set_style_local_text_color(label_sleep_cycles, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); + // Start time if (infiniSleepController.IsEnabled()) { label_start_time = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_fmt(label_start_time, "Began at: %02d:%02d", infiniSleepController.prevSessionData.startTimeHours, infiniSleepController.prevSessionData.startTimeMinutes); - lv_obj_align(label_start_time, label_hr, LV_ALIGN_CENTER, 0, 20); + lv_obj_align(label_start_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_local_text_color(label_start_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); } @@ -238,7 +253,7 @@ void Sleep::DrawInfoScreen() { } else { lv_label_set_text_static(label_alarm_time, "Alarm is not set."); } - lv_obj_align(label_alarm_time, label_hr, LV_ALIGN_CENTER, 0, 40); + lv_obj_align(label_alarm_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 20); lv_obj_set_style_local_text_color(label_alarm_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, @@ -248,43 +263,21 @@ void Sleep::DrawInfoScreen() { label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); if (infiniSleepController.GetInfiniSleepSettings().graddualWake && infiniSleepController.gradualWakeStep >= 0) { - lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: %d/9", infiniSleepController.gradualWakeStep); + lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: ON"); } else { lv_label_set_text_static(label_gradual_wake, "Gradual Wake: OFF"); } - lv_obj_align(label_gradual_wake, label_hr, LV_ALIGN_CENTER, 0, 60); + lv_obj_align(label_gradual_wake, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); lv_obj_set_style_local_text_color(label_gradual_wake, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - // Sleep Cycles Info - label_sleep_cycles = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_sleep_cycles, - "Sleep Cycles: %d.%02d", - infiniSleepController.GetSleepCycles() / 100, - infiniSleepController.GetSleepCycles() % 100); - lv_obj_align(label_sleep_cycles, label_hr, LV_ALIGN_CENTER, 0, 80); - lv_obj_set_style_local_text_color(label_sleep_cycles, - LV_LABEL_PART_MAIN, - LV_STATE_DEFAULT, - infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - - // Total sleep time - label_total_sleep = lv_label_create(lv_scr_act(), nullptr); - - uint16_t totalMinutes = infiniSleepController.GetTotalSleep(); - - lv_label_set_text_fmt(label_total_sleep, "Total Sleep: %dh%dm", totalMinutes / 60, totalMinutes % 60); - lv_obj_align(label_total_sleep, label_hr, LV_ALIGN_CENTER, 0, 100); - lv_obj_set_style_local_text_color(label_total_sleep, - LV_LABEL_PART_MAIN, - LV_STATE_DEFAULT, - infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - + // Start/Stop button trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); trackerToggleBtn->user_data = this; - lv_obj_align(trackerToggleBtn, lv_scr_act(), LV_ALIGN_CENTER, 0, 100); + lv_obj_set_height(trackerToggleBtn, 50); + lv_obj_align(trackerToggleBtn, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); // Tracker toggle button trackerToggleLabel = lv_label_create(trackerToggleBtn, nullptr); @@ -335,12 +328,12 @@ void Sleep::DrawSettingsScreen() { } lv_obj_t* lblCycles = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(lblCycles, "Cycles <----> Mins"); + lv_label_set_text_static(lblCycles, "Desired\nCycles"); lv_obj_align(lblCycles, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); lv_obj_t* btnCycles = lv_btn_create(lv_scr_act(), nullptr); lv_obj_set_size(btnCycles, 100, 50); - lv_obj_align(btnCycles, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset + 30); + lv_obj_align(btnCycles, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); btnCycles->user_data = this; lv_obj_set_event_cb(btnCycles, [](lv_obj_t* obj, lv_event_t e) { if (e == LV_EVENT_CLICKED) { @@ -357,43 +350,8 @@ void Sleep::DrawSettingsScreen() { lv_label_set_text_fmt(lblCycleValue, "%d", infiniSleepController.infiniSleepSettings.desiredCycles); lv_obj_align(lblCycleValue, nullptr, LV_ALIGN_CENTER, 0, 0); - lv_obj_t* btnCycleDuration = lv_btn_create(lv_scr_act(), nullptr); - lv_obj_set_size(btnCycleDuration, 100, 50); - lv_obj_align(btnCycleDuration, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 120, y_offset + 30); - btnCycleDuration->user_data = this; - lv_obj_set_event_cb(btnCycleDuration, [](lv_obj_t* obj, lv_event_t e) { - if (e == LV_EVENT_CLICKED) { - auto* screen = static_cast(obj->user_data); - int value = screen->infiniSleepController.infiniSleepSettings.sleepCycleDuration; - switch (value) { - case 80: - value = 85; - break; - case 85: - value = 90; - break; - case 90: - value = 95; - break; - case 95: - value = 100; - break; - case 100: - value = 80; - break; - default: - value = 80; - break; - } - screen->infiniSleepController.infiniSleepSettings.sleepCycleDuration = value; - screen->infiniSleepController.SetSettingsChanged(); - lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); - } - }); - - lv_obj_t* lblCycleDurationValue = lv_label_create(btnCycleDuration, nullptr); - lv_label_set_text_fmt(lblCycleDurationValue, "%d", infiniSleepController.infiniSleepSettings.sleepCycleDuration); - lv_obj_align(lblCycleDurationValue, nullptr, LV_ALIGN_CENTER, 0, 0); + infiniSleepController.infiniSleepSettings.sleepCycleDuration = 90; + infiniSleepController.SetSettingsChanged(); y_offset += 70; // Adjust the offset for the next UI element } @@ -483,23 +441,25 @@ bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } lastDisplayState = displayState; - NRF_LOG_INFO("Last Display State: %d", static_cast(lastDisplayState)); + NRF_LOG_INFO("Last Display State: %d", static_cast(lastDisplayState)); // The cases for swiping to change page on app switch (event) { - case TouchEvents::SwipeRight: - if (displayState != SleepDisplayState::Alarm) { + case TouchEvents::SwipeDown: + if (static_cast(displayState) != 0) { displayState = static_cast(static_cast(displayState) - 1); UpdateDisplay(); + } else { + return false; } - NRF_LOG_INFO("SwipeLeft: %d", static_cast(displayState)); + NRF_LOG_INFO("SwipeDown: %d", static_cast(displayState)); return true; - case TouchEvents::SwipeLeft: - if (displayState != SleepDisplayState::Settings) { - displayState = static_cast(static_cast(displayState) + 1); + case TouchEvents::SwipeUp: + if (static_cast(displayState) != 2) { + displayState = static_cast(static_cast(displayState) + 1); UpdateDisplay(); } - NRF_LOG_INFO("SwipeRight: %d", static_cast(displayState)); + NRF_LOG_INFO("SwipeUp: %d", static_cast(displayState)); return true; default: break; diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 4e33cf5e89..f482e64018 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -29,7 +29,7 @@ namespace Pinetime { void StopAlerting(bool setSwitch = true); void SnoozeWakeAlarm(); void UpdateDisplay(); - enum class SleepDisplayState { Alarm, Info, Settings }; + enum class SleepDisplayState { Info, Alarm, Settings }; SleepDisplayState displayState = SleepDisplayState::Info; SleepDisplayState lastDisplayState = SleepDisplayState::Info; From db2febce61fcb410ea8db2a8006df4f81fcb3d8b Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 29 Nov 2024 21:40:39 -0600 Subject: [PATCH 082/191] Added stop button to alerting UI, goal is to more it easier to understand what to do to stop the alarm. --- src/displayapp/screens/Sleep.cpp | 68 +++++++++++++++++++++++--------- src/displayapp/screens/Sleep.h | 3 +- 2 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index a5330f3e20..237afc2967 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -149,14 +149,24 @@ void Sleep::DrawAlarmScreen() { lv_label_set_text_static(colonLabel, ":"); lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); + btnSnooze = lv_btn_create(lv_scr_act(), nullptr); + btnSnooze->user_data = this; + lv_obj_set_event_cb(btnSnooze, btnEventHandler); + lv_obj_set_size(btnSnooze, 115, 50); + lv_obj_align(btnSnooze, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_style_local_bg_color(btnSnooze, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + txtSnooze = lv_label_create(btnSnooze, nullptr); + lv_label_set_text_static(txtSnooze, "ZzZz"); + lv_obj_set_hidden(btnSnooze, true); + btnStop = lv_btn_create(lv_scr_act(), nullptr); btnStop->user_data = this; lv_obj_set_event_cb(btnStop, btnEventHandler); lv_obj_set_size(btnStop, 115, 50); lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); - lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); txtStop = lv_label_create(btnStop, nullptr); - lv_label_set_text_static(txtStop, "ZzZz"); + lv_label_set_text_fmt(txtStop, "Stop: %d", infiniSleepController.pushesLeftToStopWakeAlarm); lv_obj_set_hidden(btnStop, true); static constexpr lv_color_t bgColor = Colors::bgAlt; @@ -358,11 +368,15 @@ void Sleep::DrawSettingsScreen() { void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (event == LV_EVENT_CLICKED) { - if (obj == btnStop) { + if (obj == btnSnooze) { StopAlerting(); SnoozeWakeAlarm(); return; } + if (obj == btnStop) { + StopAlarmPush(); + return; + } if (obj == btnMessage) { HideAlarmInfo(); return; @@ -408,28 +422,35 @@ bool Sleep::OnButtonPushed() { return true; } if (infiniSleepController.IsAlerting()) { - if (infiniSleepController.pushesLeftToStopWakeAlarm > 1) { - lv_task_reset(taskPressesToStopAlarmTimeout); - infiniSleepController.pushesLeftToStopWakeAlarm--; + if (StopAlarmPush()) { return true; - } else { - if (infiniSleepController.isSnoozing) { - infiniSleepController.RestorePreSnoozeTime(); - } - infiniSleepController.isSnoozing = false; - StopAlerting(); - if (infiniSleepController.IsTrackerEnabled()) { - displayState = SleepDisplayState::Info; - UpdateDisplay(); - OnButtonEvent(trackerToggleBtn, LV_EVENT_CLICKED); - return true; - } + } + } + return false; +} + +bool Sleep::StopAlarmPush() { + if (infiniSleepController.pushesLeftToStopWakeAlarm > 1) { + lv_task_reset(taskPressesToStopAlarmTimeout); + infiniSleepController.pushesLeftToStopWakeAlarm--; + UpdateDisplay(); + return true; + } else { + if (infiniSleepController.isSnoozing) { + infiniSleepController.RestorePreSnoozeTime(); + } + infiniSleepController.isSnoozing = false; + StopAlerting(); + if (infiniSleepController.IsTrackerEnabled()) { displayState = SleepDisplayState::Info; UpdateDisplay(); + OnButtonEvent(trackerToggleBtn, LV_EVENT_CLICKED); return true; } + displayState = SleepDisplayState::Info; + UpdateDisplay(); + return true; } - return false; } bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { @@ -511,7 +532,10 @@ void Sleep::UpdateWakeAlarmTime() { void Sleep::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); + lv_obj_set_hidden(btnSnooze, false); lv_obj_set_hidden(btnStop, false); + lv_obj_set_hidden(btnSuggestedAlarm, true); + lv_obj_set_hidden(txtSuggestedAlarm, true); NRF_LOG_INFO("Alarm is alerting"); taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); motorController.StartAlarm(); @@ -521,7 +545,10 @@ void Sleep::SetAlerting() { void Sleep::RedrawSetAlerting() { lv_obj_set_hidden(enableSwitch, true); + lv_obj_set_hidden(btnSnooze, false); lv_obj_set_hidden(btnStop, false); + lv_obj_set_hidden(btnSuggestedAlarm, true); + lv_obj_set_hidden(txtSuggestedAlarm, true); wakeLock.Lock(); } @@ -533,7 +560,10 @@ void Sleep::StopAlerting(bool setSwitch) { } wakeLock.Release(); lv_obj_set_hidden(enableSwitch, false); + lv_obj_set_hidden(btnSnooze, true); lv_obj_set_hidden(btnStop, true); + lv_obj_set_hidden(btnSuggestedAlarm, false); + lv_obj_set_hidden(txtSuggestedAlarm, false); alreadyAlerting = false; } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index f482e64018..003bdceb71 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -40,7 +40,7 @@ namespace Pinetime { Controllers::MotorController& motorController; Controllers::Settings::ClockType clockType; - lv_obj_t *btnStop, *txtStop, /**btnRecur, *txtRecur,*/ *btnInfo, *enableSwitch; + lv_obj_t *btnStop, *btnSnooze, *txtStop, *txtSnooze, /**btnRecur, *txtRecur,*/ *btnInfo, *enableSwitch; lv_obj_t *trackerToggleBtn, *trackerToggleLabel; lv_obj_t* lblampm = nullptr; lv_obj_t* txtMessage = nullptr; @@ -64,6 +64,7 @@ namespace Pinetime { void DrawAlarmScreen(); void DrawInfoScreen(); void DrawSettingsScreen(); + bool StopAlarmPush(); bool alreadyAlerting = false; From d736f0311fda4c6a78c77f37e2042030fb77a415 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 29 Nov 2024 23:27:35 -0600 Subject: [PATCH 083/191] Forgot to hide the auto icon --- src/displayapp/screens/Sleep.cpp | 11 +++++++---- src/displayapp/screens/Sleep.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 237afc2967..946a85f318 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -184,10 +184,10 @@ void Sleep::DrawAlarmScreen() { lv_label_set_text_static(txtSuggestedAlarm, "Auto"); - 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_WHITE); - lv_obj_align(icon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -50, -10); - lv_label_set_text_static(icon, Symbols::sun); + iconSuggestedAlarm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(iconSuggestedAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_align(iconSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -50, -10); + lv_label_set_text_static(iconSuggestedAlarm, Symbols::sun); enableSwitch = lv_switch_create(lv_scr_act(), nullptr); @@ -536,6 +536,7 @@ void Sleep::SetAlerting() { lv_obj_set_hidden(btnStop, false); lv_obj_set_hidden(btnSuggestedAlarm, true); lv_obj_set_hidden(txtSuggestedAlarm, true); + lv_obj_set_hidden(iconSuggestedAlarm, true); NRF_LOG_INFO("Alarm is alerting"); taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); motorController.StartAlarm(); @@ -549,6 +550,7 @@ void Sleep::RedrawSetAlerting() { lv_obj_set_hidden(btnStop, false); lv_obj_set_hidden(btnSuggestedAlarm, true); lv_obj_set_hidden(txtSuggestedAlarm, true); + lv_obj_set_hidden(iconSuggestedAlarm, true); wakeLock.Lock(); } @@ -564,6 +566,7 @@ void Sleep::StopAlerting(bool setSwitch) { lv_obj_set_hidden(btnStop, true); lv_obj_set_hidden(btnSuggestedAlarm, false); lv_obj_set_hidden(txtSuggestedAlarm, false); + lv_obj_set_hidden(iconSuggestedAlarm, false); alreadyAlerting = false; } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 003bdceb71..06dd2f5462 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -74,7 +74,7 @@ namespace Pinetime { lv_obj_t* label_gradual_wake; lv_obj_t* label_total_sleep; lv_obj_t* label_sleep_cycles; - lv_obj_t *btnSuggestedAlarm, *txtSuggestedAlarm; + lv_obj_t *btnSuggestedAlarm, *txtSuggestedAlarm, *iconSuggestedAlarm; }; } From a2de43463cd2d664fec9778b5359b55e74876ec1 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 29 Nov 2024 23:29:42 -0600 Subject: [PATCH 084/191] Added "Ramping Up" of Wake Alarm Buzz Made new function in motor controller for this --- src/components/motor/MotorController.cpp | 32 ++++++++++++++++++++++++ src/components/motor/MotorController.h | 8 ++++++ src/displayapp/screens/Sleep.cpp | 4 +-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 9d02d0a8cb..8122cab0fe 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -39,6 +39,7 @@ void MotorController::Init() { shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor); longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring); alarmVib = xTimerCreate("alarmVib", pdMS_TO_TICKS(500), pdTRUE, this, AlarmRing); + wakeAlarmVib = xTimerCreate("wakeAlarmVib", pdMS_TO_TICKS(1000), pdTRUE, this, WakeAlarmRing); } void MotorController::SetMotorStrength(uint8_t strength) { @@ -48,6 +49,7 @@ void MotorController::SetMotorStrength(uint8_t strength) { // Map the strength to the PWM value (0-100 -> 0-top_value) pwmValue = (strength * 255) / 100; + // pwmValue = strength; } void MotorController::Ring(TimerHandle_t xTimer) { @@ -63,6 +65,9 @@ void MotorController::AlarmRing(TimerHandle_t xTimer) { void MotorController::RunForDuration(uint16_t motorDuration) { if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) { + if (pwmValue == 0) { + SetMotorStrength(100); + } // nrf_gpio_pin_clear(PinMap::Motor); nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_SEQSTART0); // Restart the PWM sequence with the updated value } @@ -94,6 +99,33 @@ void MotorController::StopAlarm() { nrf_gpio_pin_set(PinMap::Motor); } +void MotorController::StartWakeAlarm() { + wakeAlarmStrength = 80; + wakeAlarmDuration = 100; + SetMotorStrength(wakeAlarmStrength); + RunForDuration(wakeAlarmDuration); + xTimerStart(wakeAlarmVib, 0); +} + +void MotorController::WakeAlarmRing(TimerHandle_t xTimer) { + auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); + if (motorController->wakeAlarmStrength > 20) { + motorController->wakeAlarmStrength -= 1; + } + if (motorController->wakeAlarmDuration < 500) { + motorController->wakeAlarmDuration += 6; + } + motorController->SetMotorStrength(motorController->wakeAlarmStrength); + motorController->RunForDuration(motorController->wakeAlarmDuration); +} + +void MotorController::StopWakeAlarm() { + xTimerStop(wakeAlarmVib, 0); + nrf_pwm_task_trigger(NRF_PWM0, NRF_PWM_TASK_STOP); // Stop the PWM sequence + pwmValue = 0; // Reset the PWM value + nrf_gpio_pin_set(PinMap::Motor); +} + void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence pwmValue = 0; // Reset the PWM value diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 087074b850..8fca89cfe5 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -17,13 +17,19 @@ namespace Pinetime { void StopRinging(); void StartAlarm(); void StopAlarm(); + void StartWakeAlarm(); + void StopWakeAlarm(); void GradualWakeBuzz(); void StopGradualWakeBuzz(); void SetMotorStrength(uint8_t strength); + uint8_t wakeAlarmStrength = 80; + uint16_t wakeAlarmDuration = 100; + private: static void Ring(TimerHandle_t xTimer); static void AlarmRing(TimerHandle_t xTimer); + static void WakeAlarmRing(TimerHandle_t xTimer); static void StopMotor(TimerHandle_t xTimer); static void GradualWakeBuzzRing(TimerHandle_t xTimer); static void StopGradualWakeBuzzCallback(TimerHandle_t xTimer); @@ -33,6 +39,8 @@ namespace Pinetime { TimerHandle_t alarmVib; TimerHandle_t gradualWakeBuzzDelay; TimerHandle_t gradualWakeBuzzEnd; + + TimerHandle_t wakeAlarmVib; }; } } diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 946a85f318..5d25c8aa55 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -539,7 +539,7 @@ void Sleep::SetAlerting() { lv_obj_set_hidden(iconSuggestedAlarm, true); NRF_LOG_INFO("Alarm is alerting"); taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); - motorController.StartAlarm(); + motorController.StartWakeAlarm(); wakeLock.Lock(); alreadyAlerting = true; } @@ -556,7 +556,7 @@ void Sleep::RedrawSetAlerting() { void Sleep::StopAlerting(bool setSwitch) { infiniSleepController.StopAlerting(); - motorController.StopAlarm(); + motorController.StopWakeAlarm(); if (setSwitch) { SetSwitchState(LV_ANIM_OFF); } From 701d08bf5fe54c4bbe3037782dc9767c10c32c29 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 16:17:40 -0600 Subject: [PATCH 085/191] Changed UI of Alerting Alarm screen and added page inditors with scroll animations. the time on the alerting page is not interactable and I also made the snooze button bigger. Also added check to display time in proper formats --- src/displayapp/screens/Sleep.cpp | 104 +++++++++++++++++++++---------- src/displayapp/screens/Sleep.h | 13 +++- 2 files changed, 81 insertions(+), 36 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 5d25c8aa55..5954019caf 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -66,8 +66,9 @@ static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, - Controllers::MotorController& motorController) - : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController}, clockType {clockType} { + Controllers::MotorController& motorController, + DisplayApp& displayApp) + : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController}, clockType {clockType}, displayApp {displayApp} { infiniSleepController.SetHeartRateTrackingEnabled(false); infiniSleepController.SetSettingsChanged(); @@ -114,45 +115,60 @@ void Sleep::UpdateDisplay() { switch (displayState) { case SleepDisplayState::Alarm: DrawAlarmScreen(); + pageIndicator2.Create(); break; case SleepDisplayState::Info: DrawInfoScreen(); + pageIndicator1.Create(); break; case SleepDisplayState::Settings: DrawSettingsScreen(); + pageIndicator3.Create(); break; } } void Sleep::DrawAlarmScreen() { - hourCounter.Create(); - lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); - if (clockType == Controllers::Settings::ClockType::H12) { - hourCounter.EnableTwelveHourMode(); - - lblampm = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - lv_label_set_text_static(lblampm, "AM"); - lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); - lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + if (!infiniSleepController.IsAlerting()) { + hourCounter.Create(); + lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + if (clockType == Controllers::Settings::ClockType::H12) { + hourCounter.EnableTwelveHourMode(); + + lblampm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_text_static(lblampm, "AM"); + lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + } + hourCounter.SetValue(infiniSleepController.GetWakeAlarm().hours); + hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + minuteCounter.Create(); + lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + minuteCounter.SetValue(infiniSleepController.GetWakeAlarm().minutes); + minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_label_set_text_static(colonLabel, ":"); + lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); + } else { + lv_obj_t* lblTime = lv_label_create(lv_scr_act(), nullptr); + if (clockType == Controllers::Settings::ClockType::H24) { + lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); + } else { + lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour() % 12, infiniSleepController.GetCurrentMinute()); + } + lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_CENTER, -90, -50); + lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_font(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); } - hourCounter.SetValue(infiniSleepController.GetWakeAlarm().hours); - hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler); - - minuteCounter.Create(); - lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - minuteCounter.SetValue(infiniSleepController.GetWakeAlarm().minutes); - minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler); - - lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - lv_label_set_text_static(colonLabel, ":"); - lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); btnSnooze = lv_btn_create(lv_scr_act(), nullptr); btnSnooze->user_data = this; lv_obj_set_event_cb(btnSnooze, btnEventHandler); - lv_obj_set_size(btnSnooze, 115, 50); + lv_obj_set_size(btnSnooze, 115, 100); lv_obj_align(btnSnooze, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); lv_obj_set_style_local_bg_color(btnSnooze, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); txtSnooze = lv_label_create(btnSnooze, nullptr); @@ -214,7 +230,11 @@ void Sleep::DrawAlarmScreen() { void Sleep::DrawInfoScreen() { lv_obj_t* lblTime = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); + if (clockType == Controllers::Settings::ClockType::H24) { + lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); + } else { + lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour() % 12, infiniSleepController.GetCurrentMinute()); + } lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); @@ -245,10 +265,17 @@ void Sleep::DrawInfoScreen() { // Start time if (infiniSleepController.IsEnabled()) { label_start_time = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_fmt(label_start_time, - "Began at: %02d:%02d", - infiniSleepController.prevSessionData.startTimeHours, - infiniSleepController.prevSessionData.startTimeMinutes); + if (clockType == Controllers::Settings::ClockType::H24) { + lv_label_set_text_fmt(label_start_time, + "Began at: %02d:%02d", + infiniSleepController.prevSessionData.startTimeHours, + infiniSleepController.prevSessionData.startTimeMinutes); + } else { + lv_label_set_text_fmt(label_start_time, + "Began at: %02d:%02d", + infiniSleepController.prevSessionData.startTimeHours % 12, + infiniSleepController.prevSessionData.startTimeMinutes); + } lv_obj_align(label_start_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_local_text_color(label_start_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); } @@ -256,10 +283,17 @@ void Sleep::DrawInfoScreen() { // The alarm info label_alarm_time = lv_label_create(lv_scr_act(), nullptr); if (infiniSleepController.GetWakeAlarm().isEnabled) { - lv_label_set_text_fmt(label_alarm_time, - "Alarm at: %02d:%02d", - infiniSleepController.GetWakeAlarm().hours, - infiniSleepController.GetWakeAlarm().minutes); + if (clockType == Controllers::Settings::ClockType::H24) { + lv_label_set_text_fmt(label_alarm_time, + "Alarm at: %02d:%02d", + infiniSleepController.GetWakeAlarm().hours, + infiniSleepController.GetWakeAlarm().minutes); + } else { + lv_label_set_text_fmt(label_alarm_time, + "Alarm at: %02d:%02d", + (infiniSleepController.GetWakeAlarm().hours % 12 == 0) ? 12 : infiniSleepController.GetWakeAlarm().hours % 12, + infiniSleepController.GetWakeAlarm().minutes); + } } else { lv_label_set_text_static(label_alarm_time, "Alarm is not set."); } @@ -468,6 +502,7 @@ bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { switch (event) { case TouchEvents::SwipeDown: if (static_cast(displayState) != 0) { + displayApp.SetFullRefresh(Pinetime::Applications::DisplayApp::FullRefreshDirections::Down); displayState = static_cast(static_cast(displayState) - 1); UpdateDisplay(); } else { @@ -477,6 +512,7 @@ bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return true; case TouchEvents::SwipeUp: if (static_cast(displayState) != 2) { + displayApp.SetFullRefresh(Pinetime::Applications::DisplayApp::FullRefreshDirections::Up); displayState = static_cast(static_cast(displayState) + 1); UpdateDisplay(); } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 06dd2f5462..1b6bb4b56b 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -4,9 +4,11 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" #include "displayapp/widgets/Counter.h" +#include "displayapp/widgets/PageIndicator.h" #include "displayapp/Controllers.h" #include "systemtask/SystemTask.h" #include "systemtask/WakeLock.h" +#include "displayapp/DisplayApp.h" #include "Symbols.h" namespace Pinetime { @@ -17,7 +19,8 @@ namespace Pinetime { explicit Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, - Controllers::MotorController& motorController); + Controllers::MotorController& motorController, + DisplayApp& displayApp); ~Sleep() override; void Refresh() override; void SetAlerting(); @@ -39,6 +42,7 @@ namespace Pinetime { System::WakeLock wakeLock; Controllers::MotorController& motorController; Controllers::Settings::ClockType clockType; + DisplayApp& displayApp; lv_obj_t *btnStop, *btnSnooze, *txtStop, *txtSnooze, /**btnRecur, *txtRecur,*/ *btnInfo, *enableSwitch; lv_obj_t *trackerToggleBtn, *trackerToggleLabel; @@ -75,6 +79,10 @@ namespace Pinetime { lv_obj_t* label_total_sleep; lv_obj_t* label_sleep_cycles; lv_obj_t *btnSuggestedAlarm, *txtSuggestedAlarm, *iconSuggestedAlarm; + + Widgets::PageIndicator pageIndicator1 = Widgets::PageIndicator(0,3); + Widgets::PageIndicator pageIndicator2 = Widgets::PageIndicator(1,3); + Widgets::PageIndicator pageIndicator3 = Widgets::PageIndicator(2,3); }; } @@ -87,7 +95,8 @@ namespace Pinetime { return new Screens::Sleep(controllers.infiniSleepController, controllers.settingsController.GetClockType(), *controllers.systemTask, - controllers.motorController); + controllers.motorController, + *controllers.displayApp); } }; } From 560b1185f05be29f90396e9f4677e30d154a82f0 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 16:22:16 -0600 Subject: [PATCH 086/191] Changed motor strength to use 0-255 --- src/components/motor/MotorController.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 8122cab0fe..8ec5cf86d1 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -44,12 +44,12 @@ void MotorController::Init() { void MotorController::SetMotorStrength(uint8_t strength) { // Ensure strength is within bounds (0-100) - if (strength > 100) - strength = 100; + // if (strength > 100) + // strength = 100; // Map the strength to the PWM value (0-100 -> 0-top_value) - pwmValue = (strength * 255) / 100; - // pwmValue = strength; + // pwmValue = (strength * 255) / 100; + pwmValue = strength; } void MotorController::Ring(TimerHandle_t xTimer) { @@ -66,7 +66,7 @@ void MotorController::AlarmRing(TimerHandle_t xTimer) { void MotorController::RunForDuration(uint16_t motorDuration) { if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) { if (pwmValue == 0) { - SetMotorStrength(100); + SetMotorStrength(255); } // nrf_gpio_pin_clear(PinMap::Motor); nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_SEQSTART0); // Restart the PWM sequence with the updated value @@ -109,7 +109,7 @@ void MotorController::StartWakeAlarm() { void MotorController::WakeAlarmRing(TimerHandle_t xTimer) { auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); - if (motorController->wakeAlarmStrength > 20) { + if (motorController->wakeAlarmStrength > 40) { motorController->wakeAlarmStrength -= 1; } if (motorController->wakeAlarmDuration < 500) { From d51c3190f5524de43cd939091f213e67db840b29 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 16:24:12 -0600 Subject: [PATCH 087/191] Ran formatter --- .../infinisleep/InfiniSleepController.cpp | 6 +++--- .../infinisleep/InfiniSleepController.h | 2 +- src/displayapp/screens/Sleep.cpp | 21 ++++++++++--------- src/displayapp/screens/Sleep.h | 6 +++--- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index dffbb0bc6e..dea1ae75b2 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -230,9 +230,9 @@ void InfiniSleepController::UpdateBPM() { NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); // Write data to CSV - //const int motion = 0; // Placeholder for motion data - //std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; - //WriteDataCSV(TRACKER_DATA_FILE_NAME, data, 1); + // const int motion = 0; // Placeholder for motion data + // std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; + // WriteDataCSV(TRACKER_DATA_FILE_NAME, data, 1); } void InfiniSleepController::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index be80a270d5..02ab98ebdb 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -207,7 +207,7 @@ namespace Pinetime { SavePrevSessionData(); DisableTracker(); } else { - //ClearDataCSV(TRACKER_DATA_FILE_NAME); + // ClearDataCSV(TRACKER_DATA_FILE_NAME); prevSessionData.startTimeHours = GetCurrentHour(); prevSessionData.startTimeMinutes = GetCurrentMinute(); EnableTracker(); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 5954019caf..cd29e90b6b 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -68,7 +68,11 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, System::SystemTask& systemTask, Controllers::MotorController& motorController, DisplayApp& displayApp) - : infiniSleepController {infiniSleepController}, wakeLock(systemTask), motorController {motorController}, clockType {clockType}, displayApp {displayApp} { + : infiniSleepController {infiniSleepController}, + wakeLock(systemTask), + motorController {motorController}, + clockType {clockType}, + displayApp {displayApp} { infiniSleepController.SetHeartRateTrackingEnabled(false); infiniSleepController.SetSettingsChanged(); @@ -192,20 +196,18 @@ void Sleep::DrawAlarmScreen() { lv_obj_set_event_cb(btnSuggestedAlarm, btnEventHandler); lv_obj_set_size(btnSuggestedAlarm, 115, 50); lv_obj_align(btnSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); - //txtSuggestedAlarm = lv_label_create(btnSuggestedAlarm, nullptr); - //lv_label_set_text_static(txtSuggestedAlarm, "Use Sugg.\nAlarmTime"); + // txtSuggestedAlarm = lv_label_create(btnSuggestedAlarm, nullptr); + // lv_label_set_text_static(txtSuggestedAlarm, "Use Sugg.\nAlarmTime"); txtSuggestedAlarm = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(txtSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10); lv_label_set_text_static(txtSuggestedAlarm, "Auto"); - iconSuggestedAlarm = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(iconSuggestedAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_obj_align(iconSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -50, -10); lv_label_set_text_static(iconSuggestedAlarm, Symbols::sun); - enableSwitch = lv_switch_create(lv_scr_act(), nullptr); enableSwitch->user_data = this; lv_obj_set_event_cb(enableSwitch, btnEventHandler); @@ -290,9 +292,9 @@ void Sleep::DrawInfoScreen() { infiniSleepController.GetWakeAlarm().minutes); } else { lv_label_set_text_fmt(label_alarm_time, - "Alarm at: %02d:%02d", - (infiniSleepController.GetWakeAlarm().hours % 12 == 0) ? 12 : infiniSleepController.GetWakeAlarm().hours % 12, - infiniSleepController.GetWakeAlarm().minutes); + "Alarm at: %02d:%02d", + (infiniSleepController.GetWakeAlarm().hours % 12 == 0) ? 12 : infiniSleepController.GetWakeAlarm().hours % 12, + infiniSleepController.GetWakeAlarm().minutes); } } else { lv_label_set_text_static(label_alarm_time, "Alarm is not set."); @@ -305,8 +307,7 @@ void Sleep::DrawInfoScreen() { // Gradual Wake info label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.GetInfiniSleepSettings().graddualWake && - infiniSleepController.gradualWakeStep >= 0) { + if (infiniSleepController.GetInfiniSleepSettings().graddualWake && infiniSleepController.gradualWakeStep >= 0) { lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: ON"); } else { lv_label_set_text_static(label_gradual_wake, "Gradual Wake: OFF"); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 1b6bb4b56b..006c8f3573 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -80,9 +80,9 @@ namespace Pinetime { lv_obj_t* label_sleep_cycles; lv_obj_t *btnSuggestedAlarm, *txtSuggestedAlarm, *iconSuggestedAlarm; - Widgets::PageIndicator pageIndicator1 = Widgets::PageIndicator(0,3); - Widgets::PageIndicator pageIndicator2 = Widgets::PageIndicator(1,3); - Widgets::PageIndicator pageIndicator3 = Widgets::PageIndicator(2,3); + Widgets::PageIndicator pageIndicator1 = Widgets::PageIndicator(0, 3); + Widgets::PageIndicator pageIndicator2 = Widgets::PageIndicator(1, 3); + Widgets::PageIndicator pageIndicator3 = Widgets::PageIndicator(2, 3); }; } From dc9bc3245af69fb8fa41b6408472697f746ce8ae Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 16:35:44 -0600 Subject: [PATCH 088/191] more formatting --- src/displayapp/DisplayApp.cpp | 6 +++--- src/systemtask/SystemTask.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 784b6473cc..ef0218d392 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -404,11 +404,11 @@ void DisplayApp::Refresh() { // auto* sleep = static_cast(currentScreen.get()); // sleep->SetGradualWakeAlerting(); } else { - //LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); + // LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } - //motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); + // motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); motorController.GradualWakeBuzz(); - + infiniSleepController.UpdateGradualWake(); NRF_LOG_INFO("Gradual wake triggered"); diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index c574e8fd30..8136e5630a 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -231,7 +231,7 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::WakeAlarmTriggered); break; case Messages::SetOffGradualWake: - //GoToRunning(); + // GoToRunning(); displayApp.PushMessage(Pinetime::Applications::Display::Messages::GradualWakeTriggered); break; case Messages::BleConnected: From 59db2493a834cd756bc44ad3988fdcac2bb959dc Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 16:47:12 -0600 Subject: [PATCH 089/191] Fixed bug where snoozing causes crash due to widget not being on screen --- src/displayapp/screens/Sleep.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index cd29e90b6b..4ea1d21f98 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -405,6 +405,7 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (event == LV_EVENT_CLICKED) { if (obj == btnSnooze) { StopAlerting(); + UpdateDisplay(); SnoozeWakeAlarm(); return; } From 0e719b5c190776ec794438fa24bbefdc04f2ef49 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 22:36:31 -0600 Subject: [PATCH 090/191] Fixed PWM controller number typo --- src/components/motor/MotorController.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 8ec5cf86d1..ad98dca581 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -94,7 +94,7 @@ void MotorController::StartAlarm() { void MotorController::StopAlarm() { xTimerStop(alarmVib, 0); - nrf_pwm_task_trigger(NRF_PWM0, NRF_PWM_TASK_STOP); // Stop the PWM sequence + nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence pwmValue = 0; // Reset the PWM value nrf_gpio_pin_set(PinMap::Motor); } @@ -121,7 +121,7 @@ void MotorController::WakeAlarmRing(TimerHandle_t xTimer) { void MotorController::StopWakeAlarm() { xTimerStop(wakeAlarmVib, 0); - nrf_pwm_task_trigger(NRF_PWM0, NRF_PWM_TASK_STOP); // Stop the PWM sequence + nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence pwmValue = 0; // Reset the PWM value nrf_gpio_pin_set(PinMap::Motor); } From 49b5955d13b7d9aec6e94563c3bd2e194a85250a Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 22:42:59 -0600 Subject: [PATCH 091/191] Fixed make all error displayapp include wasnt needed --- src/displayapp/screens/Sleep.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 006c8f3573..514fdd57c4 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -8,7 +8,6 @@ #include "displayapp/Controllers.h" #include "systemtask/SystemTask.h" #include "systemtask/WakeLock.h" -#include "displayapp/DisplayApp.h" #include "Symbols.h" namespace Pinetime { From b0f8998fbd40e219c22f306051840fce3a7b51c0 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 30 Nov 2024 22:52:54 -0600 Subject: [PATCH 092/191] Fixed autosnooze crash --- src/displayapp/screens/Sleep.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 4ea1d21f98..5a39dd1809 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -54,6 +54,7 @@ static void SnoozeAlarmTaskCallback(lv_task_t* task) { auto* screen = static_cast(task->user_data); lv_task_set_prio(task, LV_TASK_PRIO_OFF); screen->StopAlerting(false); + screen->UpdateDisplay(); screen->SnoozeWakeAlarm(); } From 27b5634cf01d742ebb8e40bf7cb4ee1d6a08a348 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 1 Dec 2024 15:31:38 -0600 Subject: [PATCH 093/191] Changed the Alerting UI and removed gradual wake while snooze --- .../infinisleep/InfiniSleepController.cpp | 2 +- src/displayapp/screens/Sleep.cpp | 92 +++++++++++-------- 2 files changed, 56 insertions(+), 38 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index dea1ae75b2..432b09d0f6 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -143,7 +143,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { } // Calculate the period for the gradualWakeTimer - if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { + if (isSnoozing != true && infiniSleepSettings.graddualWake && gradualWakeStep > 0) { int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 5a39dd1809..770706204e 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -134,60 +134,72 @@ void Sleep::UpdateDisplay() { } void Sleep::DrawAlarmScreen() { - if (!infiniSleepController.IsAlerting()) { - hourCounter.Create(); - lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); - if (clockType == Controllers::Settings::ClockType::H12) { - hourCounter.EnableTwelveHourMode(); - - lblampm = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - lv_label_set_text_static(lblampm, "AM"); - lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); - lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); - } - hourCounter.SetValue(infiniSleepController.GetWakeAlarm().hours); - hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler); - - minuteCounter.Create(); - lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - minuteCounter.SetValue(infiniSleepController.GetWakeAlarm().minutes); - minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler); - - lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); - lv_label_set_text_static(colonLabel, ":"); - lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); - } else { + hourCounter.Create(); + lv_obj_align(hourCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + if (clockType == Controllers::Settings::ClockType::H12) { + hourCounter.EnableTwelveHourMode(); + + lblampm = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(lblampm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_text_static(lblampm, "AM"); + lv_label_set_align(lblampm, LV_LABEL_ALIGN_CENTER); + lv_obj_align(lblampm, lv_scr_act(), LV_ALIGN_CENTER, 0, 30); + } + hourCounter.SetValue(infiniSleepController.GetWakeAlarm().hours); + hourCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + minuteCounter.Create(); + lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); + minuteCounter.SetValue(infiniSleepController.GetWakeAlarm().minutes); + minuteCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + lv_label_set_text_static(colonLabel, ":"); + lv_obj_align(colonLabel, lv_scr_act(), LV_ALIGN_CENTER, 0, -29); + + if (infiniSleepController.IsAlerting()) { + lv_obj_set_hidden(hourCounter.GetObject(), true); + lv_obj_set_hidden(minuteCounter.GetObject(), true); + lv_obj_set_hidden(colonLabel, true); + lv_obj_t* lblTime = lv_label_create(lv_scr_act(), nullptr); if (clockType == Controllers::Settings::ClockType::H24) { lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); } else { - lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour() % 12, infiniSleepController.GetCurrentMinute()); + lv_label_set_text_fmt(lblTime, "%02d:%02d", (infiniSleepController.GetCurrentHour() % 12 == 0) ? 12 : infiniSleepController.GetCurrentHour() % 12, infiniSleepController.GetCurrentMinute()); } - lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_CENTER, -90, -50); + lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_CENTER, -87, -100); lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_obj_set_style_local_text_font(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); + lv_label_set_align(lblTime, LV_LABEL_ALIGN_CENTER); + lv_obj_set_style_local_text_font(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); + + lv_obj_t* lblWaketxt = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblWaketxt, "Wake Up!"); + lv_obj_align(lblWaketxt, lv_scr_act(), LV_ALIGN_CENTER, 0, -22); + lv_label_set_align(lblWaketxt, LV_LABEL_ALIGN_CENTER); + lv_obj_set_style_local_text_font(lblWaketxt, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_obj_set_style_local_text_color(lblWaketxt, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); } btnSnooze = lv_btn_create(lv_scr_act(), nullptr); btnSnooze->user_data = this; lv_obj_set_event_cb(btnSnooze, btnEventHandler); - lv_obj_set_size(btnSnooze, 115, 100); - lv_obj_align(btnSnooze, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_set_size(btnSnooze, 200, 63); + lv_obj_align(btnSnooze, lv_scr_act(), LV_ALIGN_CENTER, 0, 28); lv_obj_set_style_local_bg_color(btnSnooze, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); txtSnooze = lv_label_create(btnSnooze, nullptr); - lv_label_set_text_static(txtSnooze, "ZzZz"); + lv_label_set_text_static(txtSnooze, "Snooze"); lv_obj_set_hidden(btnSnooze, true); btnStop = lv_btn_create(lv_scr_act(), nullptr); btnStop->user_data = this; lv_obj_set_event_cb(btnStop, btnEventHandler); - lv_obj_set_size(btnStop, 115, 50); - lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_set_size(btnStop, 130, 50); + lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); txtStop = lv_label_create(btnStop, nullptr); - lv_label_set_text_fmt(txtStop, "Stop: %d", infiniSleepController.pushesLeftToStopWakeAlarm); + lv_label_set_text_fmt(txtStop, "Stop: %d/%d", PUSHES_TO_STOP_ALARM - infiniSleepController.pushesLeftToStopWakeAlarm, PUSHES_TO_STOP_ALARM); lv_obj_set_hidden(btnStop, true); static constexpr lv_color_t bgColor = Colors::bgAlt; @@ -234,9 +246,15 @@ void Sleep::DrawAlarmScreen() { void Sleep::DrawInfoScreen() { lv_obj_t* lblTime = lv_label_create(lv_scr_act(), nullptr); if (clockType == Controllers::Settings::ClockType::H24) { - lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); + lv_label_set_text_fmt(lblTime, + "%02d:%02d", + infiniSleepController.GetCurrentHour(), + infiniSleepController.GetCurrentMinute()); } else { - lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour() % 12, infiniSleepController.GetCurrentMinute()); + lv_label_set_text_fmt(lblTime, + "%02d:%02d", + (infiniSleepController.GetCurrentHour() % 12 == 0) ? 12 : infiniSleepController.GetCurrentHour() % 12, + infiniSleepController.GetCurrentMinute()); } lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 5); lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); @@ -276,7 +294,7 @@ void Sleep::DrawInfoScreen() { } else { lv_label_set_text_fmt(label_start_time, "Began at: %02d:%02d", - infiniSleepController.prevSessionData.startTimeHours % 12, + (infiniSleepController.prevSessionData.startTimeHours % 12 == 0) ? 12 : infiniSleepController.prevSessionData.startTimeHours % 12, infiniSleepController.prevSessionData.startTimeMinutes); } lv_obj_align(label_start_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); From 0608e0f53311fcf421bdb2fa51b6a1076f5dd10e Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 1 Dec 2024 15:32:02 -0600 Subject: [PATCH 094/191] Formatting --- src/displayapp/screens/Sleep.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 770706204e..274b8d1a44 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -167,7 +167,10 @@ void Sleep::DrawAlarmScreen() { if (clockType == Controllers::Settings::ClockType::H24) { lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); } else { - lv_label_set_text_fmt(lblTime, "%02d:%02d", (infiniSleepController.GetCurrentHour() % 12 == 0) ? 12 : infiniSleepController.GetCurrentHour() % 12, infiniSleepController.GetCurrentMinute()); + lv_label_set_text_fmt(lblTime, + "%02d:%02d", + (infiniSleepController.GetCurrentHour() % 12 == 0) ? 12 : infiniSleepController.GetCurrentHour() % 12, + infiniSleepController.GetCurrentMinute()); } lv_obj_align(lblTime, lv_scr_act(), LV_ALIGN_CENTER, -87, -100); lv_obj_set_style_local_text_color(lblTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); @@ -199,7 +202,10 @@ void Sleep::DrawAlarmScreen() { lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); txtStop = lv_label_create(btnStop, nullptr); - lv_label_set_text_fmt(txtStop, "Stop: %d/%d", PUSHES_TO_STOP_ALARM - infiniSleepController.pushesLeftToStopWakeAlarm, PUSHES_TO_STOP_ALARM); + lv_label_set_text_fmt(txtStop, + "Stop: %d/%d", + PUSHES_TO_STOP_ALARM - infiniSleepController.pushesLeftToStopWakeAlarm, + PUSHES_TO_STOP_ALARM); lv_obj_set_hidden(btnStop, true); static constexpr lv_color_t bgColor = Colors::bgAlt; @@ -246,10 +252,7 @@ void Sleep::DrawAlarmScreen() { void Sleep::DrawInfoScreen() { lv_obj_t* lblTime = lv_label_create(lv_scr_act(), nullptr); if (clockType == Controllers::Settings::ClockType::H24) { - lv_label_set_text_fmt(lblTime, - "%02d:%02d", - infiniSleepController.GetCurrentHour(), - infiniSleepController.GetCurrentMinute()); + lv_label_set_text_fmt(lblTime, "%02d:%02d", infiniSleepController.GetCurrentHour(), infiniSleepController.GetCurrentMinute()); } else { lv_label_set_text_fmt(lblTime, "%02d:%02d", @@ -292,10 +295,11 @@ void Sleep::DrawInfoScreen() { infiniSleepController.prevSessionData.startTimeHours, infiniSleepController.prevSessionData.startTimeMinutes); } else { - lv_label_set_text_fmt(label_start_time, - "Began at: %02d:%02d", - (infiniSleepController.prevSessionData.startTimeHours % 12 == 0) ? 12 : infiniSleepController.prevSessionData.startTimeHours % 12, - infiniSleepController.prevSessionData.startTimeMinutes); + lv_label_set_text_fmt( + label_start_time, + "Began at: %02d:%02d", + (infiniSleepController.prevSessionData.startTimeHours % 12 == 0) ? 12 : infiniSleepController.prevSessionData.startTimeHours % 12, + infiniSleepController.prevSessionData.startTimeMinutes); } lv_obj_align(label_start_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); lv_obj_set_style_local_text_color(label_start_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); From 2fc156b63c5aa46c6a91bfa39a39237d8bf7d3e0 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 2 Dec 2024 21:49:03 -0600 Subject: [PATCH 095/191] Added Setting to decide motor strength removed some unsed code in motorcontroller made snoozing take user to info page fixed logic for skipping gradual wake while in snooze --- .../infinisleep/InfiniSleepController.cpp | 2 +- .../infinisleep/InfiniSleepController.h | 1 + src/components/motor/MotorController.cpp | 46 ++------------ src/components/motor/MotorController.h | 9 +-- src/displayapp/DisplayApp.cpp | 8 ++- src/displayapp/screens/Sleep.cpp | 60 ++++++++++++++++++- 6 files changed, 71 insertions(+), 55 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 432b09d0f6..dea1ae75b2 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -143,7 +143,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { } // Calculate the period for the gradualWakeTimer - if (isSnoozing != true && infiniSleepSettings.graddualWake && gradualWakeStep > 0) { + if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { int64_t gradualWakePeriod = ((secondsToWakeAlarm - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 02ab98ebdb..e1f739c5c2 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -192,6 +192,7 @@ namespace Pinetime { bool smartAlarm = false; uint8_t sleepCycleDuration = SLEEP_CYCLE_DURATION; uint8_t desiredCycles = DESIRED_CYCLES; + uint8_t motorStrength = 100; }; InfiniSleepSettings infiniSleepSettings; diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index ad98dca581..310f361950 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -38,7 +38,6 @@ void MotorController::Init() { // Initialize timers for motor actions shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor); longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring); - alarmVib = xTimerCreate("alarmVib", pdMS_TO_TICKS(500), pdTRUE, this, AlarmRing); wakeAlarmVib = xTimerCreate("wakeAlarmVib", pdMS_TO_TICKS(1000), pdTRUE, this, WakeAlarmRing); } @@ -57,12 +56,6 @@ void MotorController::Ring(TimerHandle_t xTimer) { motorController->RunForDuration(50); } -void MotorController::AlarmRing(TimerHandle_t xTimer) { - auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); - motorController->SetMotorStrength(80); - motorController->RunForDuration(300); -} - void MotorController::RunForDuration(uint16_t motorDuration) { if (motorDuration > 0 && xTimerChangePeriod(shortVib, pdMS_TO_TICKS(motorDuration), 0) == pdPASS && xTimerStart(shortVib, 0) == pdPASS) { if (pwmValue == 0) { @@ -86,21 +79,8 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(PinMap::Motor); } -void MotorController::StartAlarm() { - SetMotorStrength(80); - RunForDuration(300); - xTimerStart(alarmVib, 0); -} - -void MotorController::StopAlarm() { - xTimerStop(alarmVib, 0); - nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence - pwmValue = 0; // Reset the PWM value - nrf_gpio_pin_set(PinMap::Motor); -} - void MotorController::StartWakeAlarm() { - wakeAlarmStrength = 80; + wakeAlarmStrength = (80 * infiniSleepMotorStrength) / 100; wakeAlarmDuration = 100; SetMotorStrength(wakeAlarmStrength); RunForDuration(wakeAlarmDuration); @@ -109,8 +89,8 @@ void MotorController::StartWakeAlarm() { void MotorController::WakeAlarmRing(TimerHandle_t xTimer) { auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); - if (motorController->wakeAlarmStrength > 40) { - motorController->wakeAlarmStrength -= 1; + if (motorController->wakeAlarmStrength > (40 * motorController->infiniSleepMotorStrength) / 100) { + motorController->wakeAlarmStrength -= (1 * motorController->infiniSleepMotorStrength) / 100; } if (motorController->wakeAlarmDuration < 500) { motorController->wakeAlarmDuration += 6; @@ -133,24 +113,6 @@ void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { } void MotorController::GradualWakeBuzz() { - SetMotorStrength(60); + SetMotorStrength((60 * infiniSleepMotorStrength) / 100); RunForDuration(100); - // xTimerStart(gradualWakeBuzzDelay, 0); - // xTimerStart(gradualWakeBuzzEnd, 0); -} - -void MotorController::GradualWakeBuzzRing(TimerHandle_t xTimer) { - auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); - motorController->RunForDuration(12); -} - -void MotorController::StopGradualWakeBuzzCallback(TimerHandle_t xTimer) { - auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); - motorController->StopGradualWakeBuzz(); -} - -void MotorController::StopGradualWakeBuzz() { - // xTimerStop(gradualWakeBuzzDelay, 0); - xTimerStop(gradualWakeBuzzEnd, 0); - // StopMotor(nullptr); } diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 8fca89cfe5..33d9f08b1f 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -15,8 +15,6 @@ namespace Pinetime { void RunForDuration(uint16_t motorDuration); void StartRinging(); void StopRinging(); - void StartAlarm(); - void StopAlarm(); void StartWakeAlarm(); void StopWakeAlarm(); void GradualWakeBuzz(); @@ -25,20 +23,15 @@ namespace Pinetime { uint8_t wakeAlarmStrength = 80; uint16_t wakeAlarmDuration = 100; + uint8_t infiniSleepMotorStrength = 100; private: static void Ring(TimerHandle_t xTimer); - static void AlarmRing(TimerHandle_t xTimer); static void WakeAlarmRing(TimerHandle_t xTimer); static void StopMotor(TimerHandle_t xTimer); - static void GradualWakeBuzzRing(TimerHandle_t xTimer); - static void StopGradualWakeBuzzCallback(TimerHandle_t xTimer); TimerHandle_t shortVib; TimerHandle_t longVib; - TimerHandle_t alarmVib; - TimerHandle_t gradualWakeBuzzDelay; - TimerHandle_t gradualWakeBuzzEnd; TimerHandle_t wakeAlarmVib; }; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index ef0218d392..e9f19ed508 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -407,12 +407,14 @@ void DisplayApp::Refresh() { // LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } // motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); - motorController.GradualWakeBuzz(); + + if (infiniSleepController.isSnoozing == false) { + motorController.GradualWakeBuzz(); + NRF_LOG_INFO("Gradual wake triggered"); + } infiniSleepController.UpdateGradualWake(); - NRF_LOG_INFO("Gradual wake triggered"); - break; case Messages::SleepTrackerUpdate: if (currentApp == Apps::Sleep) { diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 274b8d1a44..5834c7f9e8 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -56,6 +56,8 @@ static void SnoozeAlarmTaskCallback(lv_task_t* task) { screen->StopAlerting(false); screen->UpdateDisplay(); screen->SnoozeWakeAlarm(); + screen->displayState = Sleep::SleepDisplayState::Info; + screen->UpdateDisplay(); } static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { @@ -377,7 +379,7 @@ void Sleep::DrawSettingsScreen() { //{"Smart Alarm\n(alpha)", infiniSleepController.SmartAlarmEnabled()} }; - int y_offset = 50; + int y_offset = 30; for (const auto& setting : settings) { lv_obj_t* checkbox = lv_checkbox_create(lv_scr_act(), nullptr); @@ -421,6 +423,51 @@ void Sleep::DrawSettingsScreen() { infiniSleepController.infiniSleepSettings.sleepCycleDuration = 90; infiniSleepController.SetSettingsChanged(); + y_offset += 60; // Adjust the offset for the next UI element + + lv_obj_t* lblMotorStrength = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblMotorStrength, "Vibration\nStrength"); + lv_obj_align(lblMotorStrength, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + + lv_obj_t* btnMotorStrength = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnMotorStrength, 100, 50); + lv_obj_align(btnMotorStrength, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); + btnMotorStrength->user_data = this; + lv_obj_set_event_cb(btnMotorStrength, [](lv_obj_t* obj, lv_event_t e) { + if (e == LV_EVENT_CLICKED) { + auto* screen = static_cast(obj->user_data); + uint8_t value = screen->infiniSleepController.infiniSleepSettings.motorStrength; + value += 25; + if (value > 200) value = 100; + screen->infiniSleepController.infiniSleepSettings.motorStrength = value; + screen->infiniSleepController.SetSettingsChanged(); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d%", value); + screen->motorController.infiniSleepMotorStrength = value; + } + }); + + lv_obj_t* lblMotorStrengthValue = lv_label_create(btnMotorStrength, nullptr); + lv_label_set_text_fmt(lblMotorStrengthValue, "%d%", infiniSleepController.infiniSleepSettings.motorStrength); + motorController.infiniSleepMotorStrength = infiniSleepController.infiniSleepSettings.motorStrength; + lv_obj_align(lblMotorStrengthValue, nullptr, LV_ALIGN_CENTER, 0, 0); + + y_offset += 60; // Adjust the offset for the next UI element + + lv_obj_t* btnTestMotorGradual = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnTestMotorGradual, 220, 50); + lv_obj_align(btnTestMotorGradual, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + btnTestMotorGradual->user_data = this; + lv_obj_set_event_cb(btnTestMotorGradual, [](lv_obj_t* obj, lv_event_t e) { + if (e == LV_EVENT_CLICKED) { + auto* screen = static_cast(obj->user_data); + screen->motorController.GradualWakeBuzz(); + } + }); + + lv_obj_t* txtTestMotorGradual = lv_label_create(btnTestMotorGradual, nullptr); + lv_label_set_text_static(txtTestMotorGradual, "Test Motor"); + lv_obj_align(txtTestMotorGradual, nullptr, LV_ALIGN_CENTER, 0, 0); + y_offset += 70; // Adjust the offset for the next UI element } @@ -430,6 +477,8 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { StopAlerting(); UpdateDisplay(); SnoozeWakeAlarm(); + displayState = SleepDisplayState::Info; + UpdateDisplay(); return; } if (obj == btnStop) { @@ -446,6 +495,10 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } else { infiniSleepController.DisableWakeAlarm(); } + if (infiniSleepController.isSnoozing) { + infiniSleepController.RestorePreSnoozeTime(); + } + infiniSleepController.isSnoozing = false; return; } if (obj == trackerToggleBtn) { @@ -485,6 +538,11 @@ bool Sleep::OnButtonPushed() { return true; } } + if (displayState != SleepDisplayState::Info) { + displayState = SleepDisplayState::Info; + UpdateDisplay(); + return true; + } return false; } From b8d27b918c77e10609e6edea5658c94b6a5c1d52 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 5 Dec 2024 19:31:22 -0600 Subject: [PATCH 096/191] Added Setting to select pushes required to stop alarm Also added setting for natural awake, will implement next --- .../infinisleep/InfiniSleepController.cpp | 7 +- .../infinisleep/InfiniSleepController.h | 2 + src/displayapp/screens/Sleep.cpp | 136 +++++++++++------- src/systemtask/SystemTask.cpp | 2 +- 4 files changed, 91 insertions(+), 56 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index dea1ae75b2..645f8a9083 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -40,6 +40,11 @@ void InfiniSleepController::Init(System::SystemTask* systemTask) { LoadSettingsFromFile(); LoadPrevSessionData(); + if (infiniSleepSettings.pushesToStopAlarm == 0) { + infiniSleepSettings.pushesToStopAlarm = PUSHES_TO_STOP_ALARM; + settingsChanged = true; + } + pushesLeftToStopWakeAlarm = infiniSleepSettings.pushesToStopAlarm; if (wakeAlarm.isEnabled) { NRF_LOG_INFO("[InfiniSleepController] Loaded wake alarm was enabled, scheduling"); ScheduleWakeAlarm(); @@ -106,7 +111,7 @@ void InfiniSleepController::ScheduleWakeAlarm() { xTimerStop(wakeAlarmTimer, 0); xTimerStop(gradualWakeTimer, 0); - pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; + pushesLeftToStopWakeAlarm = infiniSleepSettings.pushesToStopAlarm; gradualWakeStep = 9; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index e1f739c5c2..14355679ce 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -193,6 +193,8 @@ namespace Pinetime { uint8_t sleepCycleDuration = SLEEP_CYCLE_DURATION; uint8_t desiredCycles = DESIRED_CYCLES; uint8_t motorStrength = 100; + bool naturalWake = false; + uint8_t pushesToStopAlarm = PUSHES_TO_STOP_ALARM; }; InfiniSleepSettings infiniSleepSettings; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 5834c7f9e8..28ec9d50d5 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -62,7 +62,7 @@ static void SnoozeAlarmTaskCallback(lv_task_t* task) { static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { auto* screen = static_cast(task->user_data); - screen->infiniSleepController.pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; + screen->infiniSleepController.pushesLeftToStopWakeAlarm = screen->infiniSleepController.infiniSleepSettings.pushesToStopAlarm; screen->UpdateDisplay(); } @@ -206,8 +206,8 @@ void Sleep::DrawAlarmScreen() { txtStop = lv_label_create(btnStop, nullptr); lv_label_set_text_fmt(txtStop, "Stop: %d/%d", - PUSHES_TO_STOP_ALARM - infiniSleepController.pushesLeftToStopWakeAlarm, - PUSHES_TO_STOP_ALARM); + infiniSleepController.infiniSleepSettings.pushesToStopAlarm - infiniSleepController.pushesLeftToStopWakeAlarm, + infiniSleepController.infiniSleepSettings.pushesToStopAlarm); lv_obj_set_hidden(btnStop, true); static constexpr lv_color_t bgColor = Colors::bgAlt; @@ -362,40 +362,46 @@ void Sleep::DrawInfoScreen() { } void Sleep::DrawSettingsScreen() { - lv_obj_t* lblSettings = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(lblSettings, "Settings"); - lv_obj_align(lblSettings, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 10); - - struct Setting { - const char* name; - bool enabled; - int offsetAfter = 30; - }; - - const Setting settings[] = { - //{"Body Tracking", infiniSleepController.BodyTrackingEnabled()}, - // {"Heart Rate\nTracking", infiniSleepController.HeartRateTrackingEnabled(), 60}, - {"Gradual Wake", infiniSleepController.GradualWakeEnabled()}, - //{"Smart Alarm\n(alpha)", infiniSleepController.SmartAlarmEnabled()} - }; - - int y_offset = 30; - for (const auto& setting : settings) { - - lv_obj_t* checkbox = lv_checkbox_create(lv_scr_act(), nullptr); - checkbox->user_data = const_cast(setting.name); - lv_checkbox_set_text_static(checkbox, const_cast(setting.name)); - - if (setting.enabled) { - lv_checkbox_set_checked(checkbox, true); - } else { - lv_checkbox_set_checked(checkbox, false); + // lv_obj_t* lblSettings = lv_label_create(lv_scr_act(), nullptr); + // lv_label_set_text_static(lblSettings, "Settings"); + // lv_obj_align(lblSettings, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 10); + + int y_offset = 10; + + lv_obj_t* lblWakeMode = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblWakeMode, "Wake\nMode"); + lv_obj_align(lblWakeMode, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + + lv_obj_t* btnWakeMode = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnWakeMode, 100, 50); + lv_obj_align(btnWakeMode, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); + btnWakeMode->user_data = this; + lv_obj_set_event_cb(btnWakeMode, [](lv_obj_t* obj, lv_event_t e) { + if (e == LV_EVENT_CLICKED) { + auto* screen = static_cast(obj->user_data); + auto& settings = screen->infiniSleepController.infiniSleepSettings; + if (settings.graddualWake) { + settings.graddualWake = false; + settings.naturalWake = true; + } else if (settings.naturalWake) { + settings.naturalWake = false; + settings.graddualWake = false; + } else if (!settings.graddualWake && !settings.naturalWake) { + settings.graddualWake = true; + } + screen->infiniSleepController.SetSettingsChanged(); + const char* mode = settings.graddualWake ? "Grad." : settings.naturalWake ? "Nat." : "Off"; + lv_label_set_text_static(lv_obj_get_child(obj, nullptr), mode); } - lv_obj_align(checkbox, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + }); + const char* mode = infiniSleepController.infiniSleepSettings.graddualWake ? "Grad." + : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." + : "Off"; + lv_obj_t* lblWakeModeValue = lv_label_create(btnWakeMode, nullptr); + lv_label_set_text_static(lblWakeModeValue, mode); + lv_obj_align(lblWakeModeValue, nullptr, LV_ALIGN_CENTER, 0, 0); - lv_obj_set_event_cb(checkbox, settingsToggleEventHandler); - y_offset += setting.offsetAfter; // Increase the offset to provide better spacing - } + y_offset += 60; // Adjust the offset for the next UI element lv_obj_t* lblCycles = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(lblCycles, "Desired\nCycles"); @@ -425,9 +431,20 @@ void Sleep::DrawSettingsScreen() { y_offset += 60; // Adjust the offset for the next UI element - lv_obj_t* lblMotorStrength = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(lblMotorStrength, "Vibration\nStrength"); - lv_obj_align(lblMotorStrength, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + lv_obj_t* btnTestMotorGradual = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnTestMotorGradual, 110, 50); + lv_obj_align(btnTestMotorGradual, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + btnTestMotorGradual->user_data = this; + lv_obj_set_event_cb(btnTestMotorGradual, [](lv_obj_t* obj, lv_event_t e) { + if (e == LV_EVENT_CLICKED) { + auto* screen = static_cast(obj->user_data); + screen->motorController.GradualWakeBuzz(); + } + }); + + lv_obj_t* lblMotorStrength = lv_label_create(btnTestMotorGradual, nullptr); + lv_label_set_text_static(lblMotorStrength, "Motor\nPower"); + lv_obj_align(lblMotorStrength, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0); lv_obj_t* btnMotorStrength = lv_btn_create(lv_scr_act(), nullptr); lv_obj_set_size(btnMotorStrength, 100, 50); @@ -438,37 +455,44 @@ void Sleep::DrawSettingsScreen() { auto* screen = static_cast(obj->user_data); uint8_t value = screen->infiniSleepController.infiniSleepSettings.motorStrength; value += 25; - if (value > 200) value = 100; + if (value > 200) + value = 100; screen->infiniSleepController.infiniSleepSettings.motorStrength = value; screen->infiniSleepController.SetSettingsChanged(); - lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d%", value); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); screen->motorController.infiniSleepMotorStrength = value; } }); lv_obj_t* lblMotorStrengthValue = lv_label_create(btnMotorStrength, nullptr); - lv_label_set_text_fmt(lblMotorStrengthValue, "%d%", infiniSleepController.infiniSleepSettings.motorStrength); + lv_label_set_text_fmt(lblMotorStrengthValue, "%d", infiniSleepController.infiniSleepSettings.motorStrength); motorController.infiniSleepMotorStrength = infiniSleepController.infiniSleepSettings.motorStrength; lv_obj_align(lblMotorStrengthValue, nullptr, LV_ALIGN_CENTER, 0, 0); y_offset += 60; // Adjust the offset for the next UI element - lv_obj_t* btnTestMotorGradual = lv_btn_create(lv_scr_act(), nullptr); - lv_obj_set_size(btnTestMotorGradual, 220, 50); - lv_obj_align(btnTestMotorGradual, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); - btnTestMotorGradual->user_data = this; - lv_obj_set_event_cb(btnTestMotorGradual, [](lv_obj_t* obj, lv_event_t e) { + lv_obj_t* lblPushesToStop = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblPushesToStop, "Pushes\nto Stop"); + lv_obj_align(lblPushesToStop, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); + + lv_obj_t* btnPushesToStop = lv_btn_create(lv_scr_act(), nullptr); + lv_obj_set_size(btnPushesToStop, 100, 50); + lv_obj_align(btnPushesToStop, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); + btnPushesToStop->user_data = this; + lv_obj_set_event_cb(btnPushesToStop, [](lv_obj_t* obj, lv_event_t e) { if (e == LV_EVENT_CLICKED) { auto* screen = static_cast(obj->user_data); - screen->motorController.GradualWakeBuzz(); + int value = screen->infiniSleepController.infiniSleepSettings.pushesToStopAlarm; + value = (value % 10) + 1; // Cycle through values 1 to 10 + screen->infiniSleepController.infiniSleepSettings.pushesToStopAlarm = value; + screen->infiniSleepController.SetSettingsChanged(); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); } }); - lv_obj_t* txtTestMotorGradual = lv_label_create(btnTestMotorGradual, nullptr); - lv_label_set_text_static(txtTestMotorGradual, "Test Motor"); - lv_obj_align(txtTestMotorGradual, nullptr, LV_ALIGN_CENTER, 0, 0); - - y_offset += 70; // Adjust the offset for the next UI element + lv_obj_t* lblPushesToStopValue = lv_label_create(btnPushesToStop, nullptr); + lv_label_set_text_fmt(lblPushesToStopValue, "%d", infiniSleepController.infiniSleepSettings.pushesToStopAlarm); + lv_obj_align(lblPushesToStopValue, nullptr, LV_ALIGN_CENTER, 0, 0); } void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { @@ -658,7 +682,9 @@ void Sleep::SetAlerting() { lv_obj_set_hidden(iconSuggestedAlarm, true); NRF_LOG_INFO("Alarm is alerting"); taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); - motorController.StartWakeAlarm(); + if (infiniSleepController.infiniSleepSettings.graddualWake) { + motorController.StartWakeAlarm(); + } wakeLock.Lock(); alreadyAlerting = true; } @@ -675,7 +701,9 @@ void Sleep::RedrawSetAlerting() { void Sleep::StopAlerting(bool setSwitch) { infiniSleepController.StopAlerting(); - motorController.StopWakeAlarm(); + if (infiniSleepController.infiniSleepSettings.graddualWake) { + motorController.StopWakeAlarm(); + } if (setSwitch) { SetSwitchState(LV_ANIM_OFF); } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 8136e5630a..df69091bef 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -202,7 +202,7 @@ void SystemTask::Work() { GoToRunning(); break; case Messages::GoToSleep: - infiniSleepController.pushesLeftToStopWakeAlarm = PUSHES_TO_STOP_ALARM; + infiniSleepController.pushesLeftToStopWakeAlarm = infiniSleepController.infiniSleepSettings.pushesToStopAlarm; GoToSleep(); break; case Messages::OnNewTime: From 8d2e5f55b394fce04b2d87dc232b67c1bbed72e3 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 5 Dec 2024 19:41:28 -0600 Subject: [PATCH 097/191] Disabled settings while alarm is active. Dif this to avoid weird behavior that can happen if changed during alarm active state. This also remove the need to handle those in code. --- src/displayapp/screens/Sleep.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 28ec9d50d5..357382ba03 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -366,6 +366,14 @@ void Sleep::DrawSettingsScreen() { // lv_label_set_text_static(lblSettings, "Settings"); // lv_obj_align(lblSettings, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 0, 10); + if (infiniSleepController.wakeAlarm.isEnabled) { + lv_obj_t* lblWarning = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(lblWarning, "Disable alarm to\nchange settings."); + lv_obj_align(lblWarning, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + lv_obj_set_style_local_text_color(lblWarning, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + return; + } + int y_offset = 10; lv_obj_t* lblWakeMode = lv_label_create(lv_scr_act(), nullptr); From 073599eb033cf97f31eeb582ff30dbc7e7a0a4ed Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 5 Dec 2024 20:04:51 -0600 Subject: [PATCH 098/191] Added natural wake alarm to motor controller. removed wakelock when using natural alrm mode as user may not wake up soon and unintended taps may happen. --- src/components/motor/MotorController.cpp | 20 ++++++ src/components/motor/MotorController.h | 4 ++ src/displayapp/screens/Sleep.cpp | 83 +++--------------------- src/displayapp/screens/Sleep.h | 2 - 4 files changed, 34 insertions(+), 75 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 310f361950..dd4ed64b29 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -39,6 +39,7 @@ void MotorController::Init() { shortVib = xTimerCreate("shortVib", 1, pdFALSE, nullptr, StopMotor); longVib = xTimerCreate("longVib", pdMS_TO_TICKS(1000), pdTRUE, this, Ring); wakeAlarmVib = xTimerCreate("wakeAlarmVib", pdMS_TO_TICKS(1000), pdTRUE, this, WakeAlarmRing); + naturalWakeAlarmVib = xTimerCreate("natWakeVib", pdMS_TO_TICKS(30 * 1000), pdTRUE, this, NaturalWakeAlarmRing); } void MotorController::SetMotorStrength(uint8_t strength) { @@ -106,6 +107,25 @@ void MotorController::StopWakeAlarm() { nrf_gpio_pin_set(PinMap::Motor); } +void MotorController::StartNaturalWakeAlarm() { + SetMotorStrength((60 * infiniSleepMotorStrength) / 100); + RunForDuration(280); + xTimerStart(naturalWakeAlarmVib, 0); +} + +void MotorController::NaturalWakeAlarmRing(TimerHandle_t xTimer) { + auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); + motorController->SetMotorStrength((60 * motorController->infiniSleepMotorStrength) / 100); + motorController->RunForDuration(280); +} + +void MotorController::StopNaturalWakeAlarm() { + xTimerStop(naturalWakeAlarmVib, 0); + nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence + pwmValue = 0; // Reset the PWM value + nrf_gpio_pin_set(PinMap::Motor); +} + void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_pwm_task_trigger(NRF_PWM2, NRF_PWM_TASK_STOP); // Stop the PWM sequence pwmValue = 0; // Reset the PWM value diff --git a/src/components/motor/MotorController.h b/src/components/motor/MotorController.h index 33d9f08b1f..cfeeb22a25 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -17,6 +17,8 @@ namespace Pinetime { void StopRinging(); void StartWakeAlarm(); void StopWakeAlarm(); + void StartNaturalWakeAlarm(); + void StopNaturalWakeAlarm(); void GradualWakeBuzz(); void StopGradualWakeBuzz(); void SetMotorStrength(uint8_t strength); @@ -28,12 +30,14 @@ namespace Pinetime { private: static void Ring(TimerHandle_t xTimer); static void WakeAlarmRing(TimerHandle_t xTimer); + static void NaturalWakeAlarmRing(TimerHandle_t xTimer); static void StopMotor(TimerHandle_t xTimer); TimerHandle_t shortVib; TimerHandle_t longVib; TimerHandle_t wakeAlarmVib; + TimerHandle_t naturalWakeAlarmVib; }; } } diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 357382ba03..49fd987428 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -20,31 +20,6 @@ namespace { } } -extern InfiniSleepController infiniSleepController; - -static void settingsToggleEventHandler(lv_obj_t* obj, lv_event_t e) { - if (e != LV_EVENT_VALUE_CHANGED) { - return; - } - - const char* setting_name = static_cast(obj->user_data); - bool enabled = lv_checkbox_is_checked(obj); - - if (strcmp(setting_name, "Body Tracking") == 0) { - infiniSleepController.SetBodyTrackingEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } else if (strcmp(setting_name, "Heart Rate\nTracking") == 0) { - infiniSleepController.SetHeartRateTrackingEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } else if (strcmp(setting_name, "Gradual Wake") == 0) { - infiniSleepController.SetGradualWakeEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } else if (strcmp(setting_name, "Smart Alarm\n(alpha)") == 0) { - infiniSleepController.SetSmartAlarmEnabled(enabled); - infiniSleepController.SetSettingsChanged(); - } -} - static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { auto* screen = static_cast(obj->user_data); screen->OnButtonEvent(obj, event); @@ -517,10 +492,6 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { StopAlarmPush(); return; } - if (obj == btnMessage) { - HideAlarmInfo(); - return; - } if (obj == enableSwitch) { if (lv_switch_get_state(enableSwitch)) { infiniSleepController.ScheduleWakeAlarm(); @@ -561,10 +532,6 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } bool Sleep::OnButtonPushed() { - if (txtMessage != nullptr && btnMessage != nullptr) { - HideAlarmInfo(); - return true; - } if (infiniSleepController.IsAlerting()) { if (StopAlarmPush()) { return true; @@ -692,8 +659,12 @@ void Sleep::SetAlerting() { taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); if (infiniSleepController.infiniSleepSettings.graddualWake) { motorController.StartWakeAlarm(); + } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + motorController.StartNaturalWakeAlarm(); + } + if (infiniSleepController.infiniSleepSettings.naturalWake != true) { + wakeLock.Lock(); } - wakeLock.Lock(); alreadyAlerting = true; } @@ -704,13 +675,17 @@ void Sleep::RedrawSetAlerting() { lv_obj_set_hidden(btnSuggestedAlarm, true); lv_obj_set_hidden(txtSuggestedAlarm, true); lv_obj_set_hidden(iconSuggestedAlarm, true); - wakeLock.Lock(); + if (infiniSleepController.infiniSleepSettings.naturalWake != true) { + wakeLock.Lock(); + } } void Sleep::StopAlerting(bool setSwitch) { infiniSleepController.StopAlerting(); if (infiniSleepController.infiniSleepSettings.graddualWake) { motorController.StopWakeAlarm(); + } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + motorController.StopNaturalWakeAlarm(); } if (setSwitch) { SetSwitchState(LV_ANIM_OFF); @@ -731,42 +706,4 @@ void Sleep::SetSwitchState(lv_anim_enable_t anim) { } else { lv_switch_off(enableSwitch, anim); } -} - -void Sleep::ShowAlarmInfo() { - if (btnMessage != nullptr) { - return; - } - btnMessage = lv_btn_create(lv_scr_act(), nullptr); - btnMessage->user_data = this; - lv_obj_set_event_cb(btnMessage, btnEventHandler); - lv_obj_set_height(btnMessage, 200); - lv_obj_set_width(btnMessage, 150); - lv_obj_align(btnMessage, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); - txtMessage = lv_label_create(btnMessage, nullptr); - lv_obj_set_style_local_bg_color(btnMessage, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_NAVY); - - if (infiniSleepController.GetWakeAlarm().isEnabled) { - auto timeToAlarm = infiniSleepController.SecondsToWakeAlarm(); - - auto daysToAlarm = timeToAlarm / 86400; - auto hrsToAlarm = (timeToAlarm % 86400) / 3600; - auto minToAlarm = (timeToAlarm % 3600) / 60; - auto secToAlarm = timeToAlarm % 60; - - lv_label_set_text_fmt(txtMessage, - "Time to\nalarm:\n%2lu Days\n%2lu Hours\n%2lu Minutes\n%2lu Seconds", - daysToAlarm, - hrsToAlarm, - minToAlarm, - secToAlarm); - } else { - lv_label_set_text_static(txtMessage, "Alarm\nis not\nset."); - } -} - -void Sleep::HideAlarmInfo() { - lv_obj_del(btnMessage); - txtMessage = nullptr; - btnMessage = nullptr; } \ No newline at end of file diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 514fdd57c4..7e5ce3738b 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -58,8 +58,6 @@ namespace Pinetime { void DisableWakeAlarm(); void SetSwitchState(lv_anim_enable_t anim); void SetWakeAlarm(); - void ShowAlarmInfo(); - void HideAlarmInfo(); void UpdateWakeAlarmTime(); Widgets::Counter hourCounter = Widgets::Counter(0, 23, jetbrains_mono_76); Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76); From fe9f176329f8aab108dcca17e98af0f9a16a62f5 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 7 Dec 2024 12:16:40 -0600 Subject: [PATCH 099/191] Made sure to wait for sleep app to load before doing things on wake I think this fixed some things --- src/displayapp/DisplayApp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index e9f19ed508..4f6381789b 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -357,6 +357,9 @@ void DisplayApp::Refresh() { if (infiniSleepController.IsEnabled()) { if (currentApp != Apps::Sleep) { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::Up); + // Wait for the sleep app to load before moving on. + while (!lv_task_handler()) { + }; } } } From 01b32557061bb1293eda66ae4422b90709044bca Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 7 Dec 2024 12:18:45 -0600 Subject: [PATCH 100/191] Updated info page to show current wake mode instead of just gradual wake --- src/displayapp/screens/Sleep.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 49fd987428..e91ac4abc5 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -307,10 +307,12 @@ void Sleep::DrawInfoScreen() { // Gradual Wake info label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.GetInfiniSleepSettings().graddualWake && infiniSleepController.gradualWakeStep >= 0) { - lv_label_set_text_fmt(label_gradual_wake, "Gradual Wake: ON"); + if (infiniSleepController.infiniSleepSettings.graddualWake) { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Gradual"); + } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Natural"); } else { - lv_label_set_text_static(label_gradual_wake, "Gradual Wake: OFF"); + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Off"); } lv_obj_align(label_gradual_wake, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); lv_obj_set_style_local_text_color(label_gradual_wake, From aff5c7e01c7421d7f1f252f826b4b558dfa900d5 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 7 Dec 2024 12:20:32 -0600 Subject: [PATCH 101/191] Removed suto display refresh on alarm screen, allows for holding down on widget without 2 second stutter. Formatted DisplayApp.cpp --- src/displayapp/DisplayApp.cpp | 2 +- src/displayapp/screens/Sleep.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 4f6381789b..f69cd63268 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -410,7 +410,7 @@ void DisplayApp::Refresh() { // LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::None); } // motorController.RunForDuration(infiniSleepController.gradualWakeVibrationDurations[-1 + infiniSleepController.gradualWakeStep]); - + if (infiniSleepController.isSnoozing == false) { motorController.GradualWakeBuzz(); NRF_LOG_INFO("Gradual wake triggered"); diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index e91ac4abc5..b3a99b4ea2 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -88,6 +88,10 @@ void Sleep::Refresh() { } void Sleep::UpdateDisplay() { + if (lastDisplayState == displayState && displayState == SleepDisplayState::Alarm) { + return; + } + // Clear the screen lv_obj_clean(lv_scr_act()); if (infiniSleepController.IsAlerting()) { @@ -528,6 +532,7 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { OnValueChanged(); infiniSleepController.ScheduleWakeAlarm(); + SetSwitchState(LV_ANIM_OFF); return; } } From 101c0c962c5492e62ef05d5c56f3d3dcb2bb40c6 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 9 Dec 2024 00:11:41 -0600 Subject: [PATCH 102/191] Fixed display not upadting on alerting screen. removed auto snooze for natural wake removed side button to stop alarm --- src/displayapp/screens/Sleep.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index b3a99b4ea2..1011b097f1 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -88,7 +88,7 @@ void Sleep::Refresh() { } void Sleep::UpdateDisplay() { - if (lastDisplayState == displayState && displayState == SleepDisplayState::Alarm) { + if (infiniSleepController.IsAlerting() != true && lastDisplayState == displayState && displayState == SleepDisplayState::Alarm) { return; } @@ -540,11 +540,8 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { bool Sleep::OnButtonPushed() { if (infiniSleepController.IsAlerting()) { - if (StopAlarmPush()) { - return true; - } - } - if (displayState != SleepDisplayState::Info) { + return true; + } else if (displayState != SleepDisplayState::Info) { displayState = SleepDisplayState::Info; UpdateDisplay(); return true; @@ -579,8 +576,8 @@ bool Sleep::StopAlarmPush() { bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { // Swiping should be ignored when in alerting state - if (infiniSleepController.IsAlerting() && (event != TouchEvents::SwipeDown && event != TouchEvents::SwipeUp && - event != TouchEvents::SwipeLeft && event != TouchEvents::SwipeRight)) { + if (infiniSleepController.IsAlerting() && (event == TouchEvents::SwipeDown || event == TouchEvents::SwipeUp || + event == TouchEvents::SwipeLeft || event == TouchEvents::SwipeRight)) { return true; } @@ -663,7 +660,9 @@ void Sleep::SetAlerting() { lv_obj_set_hidden(txtSuggestedAlarm, true); lv_obj_set_hidden(iconSuggestedAlarm, true); NRF_LOG_INFO("Alarm is alerting"); - taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); + if (infiniSleepController.infiniSleepSettings.naturalWake != true) { + taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); + } if (infiniSleepController.infiniSleepSettings.graddualWake) { motorController.StartWakeAlarm(); } else if (infiniSleepController.infiniSleepSettings.naturalWake) { From 8cfabeae537ebad8fab32343637df332e79bb78d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 9 Dec 2024 01:11:03 -0600 Subject: [PATCH 103/191] Moved Code event code for settings page into btnHandler, better convention. --- src/displayapp/screens/Sleep.cpp | 209 +++++++++++++++---------------- src/displayapp/screens/Sleep.h | 3 + 2 files changed, 106 insertions(+), 106 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 1011b097f1..c47b7b9840 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -11,36 +11,36 @@ #include using namespace Pinetime::Applications::Screens; -using Pinetime::Controllers::InfiniSleepController; namespace { void ValueChangedHandler(void* userData) { auto* screen = static_cast(userData); screen->OnValueChanged(); } -} -static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast(obj->user_data); - screen->OnButtonEvent(obj, event); -} + void btnEventHandler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + screen->OnButtonEvent(obj, event); + } -static void SnoozeAlarmTaskCallback(lv_task_t* task) { - auto* screen = static_cast(task->user_data); - lv_task_set_prio(task, LV_TASK_PRIO_OFF); - screen->StopAlerting(false); - screen->UpdateDisplay(); - screen->SnoozeWakeAlarm(); - screen->displayState = Sleep::SleepDisplayState::Info; - screen->UpdateDisplay(); -} + void SnoozeAlarmTaskCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + lv_task_set_prio(task, LV_TASK_PRIO_OFF); + screen->StopAlerting(false); + screen->UpdateDisplay(); + screen->SnoozeWakeAlarm(); + screen->displayState = Sleep::SleepDisplayState::Info; + screen->UpdateDisplay(); + } -static void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { - auto* screen = static_cast(task->user_data); - screen->infiniSleepController.pushesLeftToStopWakeAlarm = screen->infiniSleepController.infiniSleepSettings.pushesToStopAlarm; - screen->UpdateDisplay(); + void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { + auto* screen = static_cast(task->user_data); + screen->infiniSleepController.pushesLeftToStopWakeAlarm = screen->infiniSleepController.infiniSleepSettings.pushesToStopAlarm; + screen->UpdateDisplay(); + } } + Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, @@ -355,63 +355,37 @@ void Sleep::DrawSettingsScreen() { return; } - int y_offset = 10; + uint8_t y_offset = 10; - lv_obj_t* lblWakeMode = lv_label_create(lv_scr_act(), nullptr); + lblWakeMode = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(lblWakeMode, "Wake\nMode"); lv_obj_align(lblWakeMode, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); - lv_obj_t* btnWakeMode = lv_btn_create(lv_scr_act(), nullptr); + btnWakeMode = lv_btn_create(lv_scr_act(), nullptr); lv_obj_set_size(btnWakeMode, 100, 50); lv_obj_align(btnWakeMode, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); btnWakeMode->user_data = this; - lv_obj_set_event_cb(btnWakeMode, [](lv_obj_t* obj, lv_event_t e) { - if (e == LV_EVENT_CLICKED) { - auto* screen = static_cast(obj->user_data); - auto& settings = screen->infiniSleepController.infiniSleepSettings; - if (settings.graddualWake) { - settings.graddualWake = false; - settings.naturalWake = true; - } else if (settings.naturalWake) { - settings.naturalWake = false; - settings.graddualWake = false; - } else if (!settings.graddualWake && !settings.naturalWake) { - settings.graddualWake = true; - } - screen->infiniSleepController.SetSettingsChanged(); - const char* mode = settings.graddualWake ? "Grad." : settings.naturalWake ? "Nat." : "Off"; - lv_label_set_text_static(lv_obj_get_child(obj, nullptr), mode); - } - }); + lv_obj_set_event_cb(btnWakeMode, btnEventHandler); const char* mode = infiniSleepController.infiniSleepSettings.graddualWake ? "Grad." : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." : "Off"; - lv_obj_t* lblWakeModeValue = lv_label_create(btnWakeMode, nullptr); + lblWakeModeValue = lv_label_create(btnWakeMode, nullptr); lv_label_set_text_static(lblWakeModeValue, mode); lv_obj_align(lblWakeModeValue, nullptr, LV_ALIGN_CENTER, 0, 0); y_offset += 60; // Adjust the offset for the next UI element - lv_obj_t* lblCycles = lv_label_create(lv_scr_act(), nullptr); + lblCycles = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(lblCycles, "Desired\nCycles"); lv_obj_align(lblCycles, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); - lv_obj_t* btnCycles = lv_btn_create(lv_scr_act(), nullptr); + btnCycles = lv_btn_create(lv_scr_act(), nullptr); lv_obj_set_size(btnCycles, 100, 50); lv_obj_align(btnCycles, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); btnCycles->user_data = this; - lv_obj_set_event_cb(btnCycles, [](lv_obj_t* obj, lv_event_t e) { - if (e == LV_EVENT_CLICKED) { - auto* screen = static_cast(obj->user_data); - int value = screen->infiniSleepController.infiniSleepSettings.desiredCycles; - value = (value % 10) + 1; // Cycle through values 1 to 10 - screen->infiniSleepController.infiniSleepSettings.desiredCycles = value; - screen->infiniSleepController.SetSettingsChanged(); - lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); - } - }); + lv_obj_set_event_cb(btnCycles, btnEventHandler); - lv_obj_t* lblCycleValue = lv_label_create(btnCycles, nullptr); + lblCycleValue = lv_label_create(btnCycles, nullptr); lv_label_set_text_fmt(lblCycleValue, "%d", infiniSleepController.infiniSleepSettings.desiredCycles); lv_obj_align(lblCycleValue, nullptr, LV_ALIGN_CENTER, 0, 0); @@ -420,66 +394,40 @@ void Sleep::DrawSettingsScreen() { y_offset += 60; // Adjust the offset for the next UI element - lv_obj_t* btnTestMotorGradual = lv_btn_create(lv_scr_act(), nullptr); + btnTestMotorGradual = lv_btn_create(lv_scr_act(), nullptr); lv_obj_set_size(btnTestMotorGradual, 110, 50); lv_obj_align(btnTestMotorGradual, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); btnTestMotorGradual->user_data = this; - lv_obj_set_event_cb(btnTestMotorGradual, [](lv_obj_t* obj, lv_event_t e) { - if (e == LV_EVENT_CLICKED) { - auto* screen = static_cast(obj->user_data); - screen->motorController.GradualWakeBuzz(); - } - }); + lv_obj_set_event_cb(btnTestMotorGradual, btnEventHandler); - lv_obj_t* lblMotorStrength = lv_label_create(btnTestMotorGradual, nullptr); + lblMotorStrength = lv_label_create(btnTestMotorGradual, nullptr); lv_label_set_text_static(lblMotorStrength, "Motor\nPower"); lv_obj_align(lblMotorStrength, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0); - lv_obj_t* btnMotorStrength = lv_btn_create(lv_scr_act(), nullptr); + btnMotorStrength = lv_btn_create(lv_scr_act(), nullptr); lv_obj_set_size(btnMotorStrength, 100, 50); lv_obj_align(btnMotorStrength, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); btnMotorStrength->user_data = this; - lv_obj_set_event_cb(btnMotorStrength, [](lv_obj_t* obj, lv_event_t e) { - if (e == LV_EVENT_CLICKED) { - auto* screen = static_cast(obj->user_data); - uint8_t value = screen->infiniSleepController.infiniSleepSettings.motorStrength; - value += 25; - if (value > 200) - value = 100; - screen->infiniSleepController.infiniSleepSettings.motorStrength = value; - screen->infiniSleepController.SetSettingsChanged(); - lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); - screen->motorController.infiniSleepMotorStrength = value; - } - }); + lv_obj_set_event_cb(btnMotorStrength, btnEventHandler); - lv_obj_t* lblMotorStrengthValue = lv_label_create(btnMotorStrength, nullptr); + lblMotorStrengthValue = lv_label_create(btnMotorStrength, nullptr); lv_label_set_text_fmt(lblMotorStrengthValue, "%d", infiniSleepController.infiniSleepSettings.motorStrength); motorController.infiniSleepMotorStrength = infiniSleepController.infiniSleepSettings.motorStrength; lv_obj_align(lblMotorStrengthValue, nullptr, LV_ALIGN_CENTER, 0, 0); y_offset += 60; // Adjust the offset for the next UI element - lv_obj_t* lblPushesToStop = lv_label_create(lv_scr_act(), nullptr); + lblPushesToStop = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(lblPushesToStop, "Pushes\nto Stop"); lv_obj_align(lblPushesToStop, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 10, y_offset); - lv_obj_t* btnPushesToStop = lv_btn_create(lv_scr_act(), nullptr); + btnPushesToStop = lv_btn_create(lv_scr_act(), nullptr); lv_obj_set_size(btnPushesToStop, 100, 50); lv_obj_align(btnPushesToStop, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); btnPushesToStop->user_data = this; - lv_obj_set_event_cb(btnPushesToStop, [](lv_obj_t* obj, lv_event_t e) { - if (e == LV_EVENT_CLICKED) { - auto* screen = static_cast(obj->user_data); - int value = screen->infiniSleepController.infiniSleepSettings.pushesToStopAlarm; - value = (value % 10) + 1; // Cycle through values 1 to 10 - screen->infiniSleepController.infiniSleepSettings.pushesToStopAlarm = value; - screen->infiniSleepController.SetSettingsChanged(); - lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); - } - }); + lv_obj_set_event_cb(btnPushesToStop, btnEventHandler); - lv_obj_t* lblPushesToStopValue = lv_label_create(btnPushesToStop, nullptr); + lblPushesToStopValue = lv_label_create(btnPushesToStop, nullptr); lv_label_set_text_fmt(lblPushesToStopValue, "%d", infiniSleepController.infiniSleepSettings.pushesToStopAlarm); lv_obj_align(lblPushesToStopValue, nullptr, LV_ALIGN_CENTER, 0, 0); } @@ -535,13 +483,61 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { SetSwitchState(LV_ANIM_OFF); return; } + if (obj == btnWakeMode) { + if (infiniSleepController.infiniSleepSettings.graddualWake) { + infiniSleepController.infiniSleepSettings.graddualWake = false; + infiniSleepController.infiniSleepSettings.naturalWake = true; + } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + infiniSleepController.infiniSleepSettings.naturalWake = false; + infiniSleepController.infiniSleepSettings.graddualWake = false; + } else if (!infiniSleepController.infiniSleepSettings.graddualWake && !infiniSleepController.infiniSleepSettings.naturalWake) { + infiniSleepController.infiniSleepSettings.graddualWake = true; + } + infiniSleepController.SetSettingsChanged(); + const char* mode = infiniSleepController.infiniSleepSettings.graddualWake ? "Grad." : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." : "Off"; + lv_label_set_text_static(lv_obj_get_child(obj, nullptr), mode); + return; + } + if (obj == btnCycles) { + uint8_t value = infiniSleepController.infiniSleepSettings.desiredCycles; + value = (value % 10) + 1; // Cycle through values 1 to 10 + infiniSleepController.infiniSleepSettings.desiredCycles = value; + infiniSleepController.SetSettingsChanged(); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); + return; + } + if (obj == btnTestMotorGradual) { + motorController.GradualWakeBuzz(); + return; + } + if (obj == btnMotorStrength) { + uint8_t value = infiniSleepController.infiniSleepSettings.motorStrength; + value += 25; + if (value > 200) { + value = 100; + } + infiniSleepController.infiniSleepSettings.motorStrength = value; + infiniSleepController.SetSettingsChanged(); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); + motorController.infiniSleepMotorStrength = value; + return; + } + if (obj == btnPushesToStop) { + uint8_t value = infiniSleepController.infiniSleepSettings.pushesToStopAlarm; + value = (value % 10) + 1; // Cycle through values 1 to 10 + infiniSleepController.infiniSleepSettings.pushesToStopAlarm = value; + infiniSleepController.SetSettingsChanged(); + lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); + return; + } } } bool Sleep::OnButtonPushed() { if (infiniSleepController.IsAlerting()) { return true; - } else if (displayState != SleepDisplayState::Info) { + } + if (displayState != SleepDisplayState::Info) { displayState = SleepDisplayState::Info; UpdateDisplay(); return true; @@ -555,22 +551,23 @@ bool Sleep::StopAlarmPush() { infiniSleepController.pushesLeftToStopWakeAlarm--; UpdateDisplay(); return true; - } else { - if (infiniSleepController.isSnoozing) { - infiniSleepController.RestorePreSnoozeTime(); - } - infiniSleepController.isSnoozing = false; - StopAlerting(); - if (infiniSleepController.IsTrackerEnabled()) { - displayState = SleepDisplayState::Info; - UpdateDisplay(); - OnButtonEvent(trackerToggleBtn, LV_EVENT_CLICKED); - return true; - } + } + + if (infiniSleepController.isSnoozing) { + infiniSleepController.RestorePreSnoozeTime(); + } + infiniSleepController.isSnoozing = false; + StopAlerting(); + if (infiniSleepController.IsTrackerEnabled()) { displayState = SleepDisplayState::Info; UpdateDisplay(); + infiniSleepController.ToggleTracker(); + UpdateDisplay(); return true; } + displayState = SleepDisplayState::Info; + UpdateDisplay(); + return true; } bool Sleep::OnTouchEvent(Pinetime::Applications::TouchEvents event) { @@ -660,7 +657,7 @@ void Sleep::SetAlerting() { lv_obj_set_hidden(txtSuggestedAlarm, true); lv_obj_set_hidden(iconSuggestedAlarm, true); NRF_LOG_INFO("Alarm is alerting"); - if (infiniSleepController.infiniSleepSettings.naturalWake != true) { + if (!infiniSleepController.infiniSleepSettings.naturalWake) { taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); } if (infiniSleepController.infiniSleepSettings.graddualWake) { @@ -668,7 +665,7 @@ void Sleep::SetAlerting() { } else if (infiniSleepController.infiniSleepSettings.naturalWake) { motorController.StartNaturalWakeAlarm(); } - if (infiniSleepController.infiniSleepSettings.naturalWake != true) { + if (!infiniSleepController.infiniSleepSettings.naturalWake) { wakeLock.Lock(); } alreadyAlerting = true; @@ -681,7 +678,7 @@ void Sleep::RedrawSetAlerting() { lv_obj_set_hidden(btnSuggestedAlarm, true); lv_obj_set_hidden(txtSuggestedAlarm, true); lv_obj_set_hidden(iconSuggestedAlarm, true); - if (infiniSleepController.infiniSleepSettings.naturalWake != true) { + if (!infiniSleepController.infiniSleepSettings.naturalWake) { wakeLock.Lock(); } } diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 7e5ce3738b..ed3d49e1a5 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -77,6 +77,9 @@ namespace Pinetime { lv_obj_t* label_sleep_cycles; lv_obj_t *btnSuggestedAlarm, *txtSuggestedAlarm, *iconSuggestedAlarm; + lv_obj_t *lblWakeMode, *btnWakeMode, *lblWakeModeValue, *lblCycles, *btnCycles, *lblCycleValue, *btnTestMotorGradual, + *lblMotorStrength, *btnMotorStrength, *lblMotorStrengthValue, *lblPushesToStop, *btnPushesToStop, *lblPushesToStopValue; + Widgets::PageIndicator pageIndicator1 = Widgets::PageIndicator(0, 3); Widgets::PageIndicator pageIndicator2 = Widgets::PageIndicator(1, 3); Widgets::PageIndicator pageIndicator3 = Widgets::PageIndicator(2, 3); From 860fcb63152b5338ca330ee466835640781bd99a Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 9 Dec 2024 11:09:45 -0600 Subject: [PATCH 104/191] Code Clean up removed some unused code. Didn't reduce RAM usage. --- .../infinisleep/InfiniSleepController.cpp | 128 +++++++++--------- .../infinisleep/InfiniSleepController.h | 56 ++------ src/displayapp/DisplayApp.cpp | 3 - src/displayapp/screens/Sleep.cpp | 7 +- 4 files changed, 79 insertions(+), 115 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 645f8a9083..b020fc1cea 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -70,7 +70,7 @@ void InfiniSleepController::UpdateTracker() { NRF_LOG_INFO("[InfiniSleepController] Updating tracker"); if (infiniSleepSettings.heartRateTracking) { - UpdateBPM(); + // UpdateBPM(); } systemTask->PushMessage(System::Messages::SleepTrackerUpdate); @@ -200,7 +200,7 @@ void InfiniSleepController::UpdateGradualWake() { // Calculate the period for the gradualWakeTimer if (infiniSleepSettings.graddualWake && gradualWakeStep > 0) { - int64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); + uint64_t gradualWakePeriod = ((SecondsToWakeAlarm() - gradualWakeSteps[-1 + gradualWakeStep])) * (configTICK_RATE_HZ); xTimerChangePeriod(gradualWakeTimer, gradualWakePeriod, 0); xTimerStart(gradualWakeTimer, 0); } else { @@ -216,70 +216,70 @@ void InfiniSleepController::StopAlerting() { /* Sleep Tracking Section */ -void InfiniSleepController::UpdateBPM() { - // Get the heart rate from the controller - prevBpm = bpm; - bpm = heartRateController.HeartRate(); - - if (prevBpm != 0) - rollingBpm = (rollingBpm + bpm) / 2; - else - rollingBpm = bpm; - - // Get the current time from DateTimeController - int hours = dateTimeController.Hours(); - int minutes = dateTimeController.Minutes(); - int seconds = dateTimeController.Seconds(); - - // Log the BPM and current time - NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); - - // Write data to CSV - // const int motion = 0; // Placeholder for motion data - // std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; - // WriteDataCSV(TRACKER_DATA_FILE_NAME, data, 1); -} - -void InfiniSleepController::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { - lfs_file_t file; - int err = fs.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error opening file: %d", err); - return; - } - - for (int i = 0; i < dataSize; ++i) { - int hours, minutes, seconds, bpm, motion; - std::tie(hours, minutes, seconds, bpm, motion) = data[i]; - char buffer[64]; - int len = snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d,%d,%d\n", hours, minutes, seconds, bpm, motion); - err = fs.FileWrite(&file, reinterpret_cast(buffer), len); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error writing to file: %d", err); - fs.FileClose(&file); - - return; - } - } - - fs.FileClose(&file); -} +// void InfiniSleepController::UpdateBPM() { +// // Get the heart rate from the controller +// prevBpm = bpm; +// bpm = heartRateController.HeartRate(); + +// if (prevBpm != 0) +// rollingBpm = (rollingBpm + bpm) / 2; +// else +// rollingBpm = bpm; + +// // Get the current time from DateTimeController +// int hours = dateTimeController.Hours(); +// int minutes = dateTimeController.Minutes(); +// int seconds = dateTimeController.Seconds(); + +// // Log the BPM and current time +// NRF_LOG_INFO("BPM: %d at %02d:%02d:%02d", rollingBpm, hours, minutes, seconds); + +// // Write data to CSV +// // const int motion = 0; // Placeholder for motion data +// // std::tuple data[1] = {std::make_tuple(hours, minutes, seconds, bpm, motion)}; +// // WriteDataCSV(TRACKER_DATA_FILE_NAME, data, 1); +// } + +// void InfiniSleepController::WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const { +// lfs_file_t file; +// int err = fs.FileOpen(&file, fileName, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND); +// if (err < 0) { +// // Handle error +// NRF_LOG_INFO("Error opening file: %d", err); +// return; +// } + +// for (int i = 0; i < dataSize; ++i) { +// int hours, minutes, seconds, bpm, motion; +// std::tie(hours, minutes, seconds, bpm, motion) = data[i]; +// char buffer[64]; +// int len = snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d,%d,%d\n", hours, minutes, seconds, bpm, motion); +// err = fs.FileWrite(&file, reinterpret_cast(buffer), len); +// if (err < 0) { +// // Handle error +// NRF_LOG_INFO("Error writing to file: %d", err); +// fs.FileClose(&file); + +// return; +// } +// } + +// fs.FileClose(&file); +// } // Clear data in CSV -void InfiniSleepController::ClearDataCSV(const char* filename) const { - lfs_file_t file; - int err = fs.FileOpen(&file, filename, LFS_O_WRONLY | LFS_O_TRUNC); - if (err < 0) { - // Handle error - NRF_LOG_INFO("Error opening file: %d", err); - return; - } - - fs.FileClose(&file); - NRF_LOG_INFO("CSV data cleared"); -} +// void InfiniSleepController::ClearDataCSV(const char* filename) const { +// lfs_file_t file; +// int err = fs.FileOpen(&file, filename, LFS_O_WRONLY | LFS_O_TRUNC); +// if (err < 0) { +// // Handle error +// NRF_LOG_INFO("Error opening file: %d", err); +// return; +// } + +// fs.FileClose(&file); +// NRF_LOG_INFO("CSV data cleared"); +// } /* Sleep Tracking Section End */ diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 14355679ce..183147d302 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -98,38 +98,6 @@ namespace Pinetime { void DisableTracker(); void UpdateTracker(); - bool BodyTrackingEnabled() const { - return infiniSleepSettings.bodyTracking; - } - - void SetBodyTrackingEnabled(bool enabled) { - infiniSleepSettings.bodyTracking = enabled; - } - - bool HeartRateTrackingEnabled() const { - return infiniSleepSettings.heartRateTracking; - } - - void SetHeartRateTrackingEnabled(bool enabled) { - infiniSleepSettings.heartRateTracking = enabled; - } - - bool GradualWakeEnabled() const { - return infiniSleepSettings.graddualWake; - } - - void SetGradualWakeEnabled(bool enabled) { - infiniSleepSettings.graddualWake = enabled; - } - - bool SmartAlarmEnabled() const { - return infiniSleepSettings.smartAlarm; - } - - void SetSmartAlarmEnabled(bool enabled) { - infiniSleepSettings.smartAlarm = enabled; - } - void SetSettingsChanged() { settingsChanged = true; } @@ -149,14 +117,12 @@ namespace Pinetime { WakeAlarmSettings wakeAlarm; // Dertermine the steps for the gradual wake alarm, the corresponding vibration durations determine the power of the vibration - static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds - static constexpr uint16_t gradualWakeVibrationDurations[9] = {1000, 1000, 900, 800, 800, 700, 700, 700, 500}; // In ms + static constexpr uint16_t gradualWakeSteps[9] = {30, 60, 90, 120, 180, 240, 300, 350, 600}; // In seconds - int8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex + uint8_t gradualWakeStep = 9; // used to keep track of which step to use, in position form not idex - uint16_t GetSleepCycles() { - uint16_t totalMinutes = GetTotalSleep(); - return (totalMinutes * 100 / infiniSleepSettings.sleepCycleDuration); + uint16_t GetSleepCycles() const { + return (GetTotalSleep() * 100 / infiniSleepSettings.sleepCycleDuration); } uint16_t GetTotalSleep() const { @@ -177,7 +143,7 @@ namespace Pinetime { return sleepMinutes; } - uint16_t GetSuggestedSleepTime() { + uint16_t GetSuggestedSleepTime() const { return infiniSleepSettings.desiredCycles * infiniSleepSettings.sleepCycleDuration; } @@ -230,10 +196,6 @@ namespace Pinetime { return dateTimeController.Minutes(); } - int bpm = 0; - int prevBpm = 0; - int rollingBpm = 0; - void UpdateBPM(); uint8_t GetGradualWakeStep() const { @@ -247,6 +209,10 @@ namespace Pinetime { bool isEnabled = false; bool settingsChanged = false; + // uint8_t bpm = 0; + // uint8_t prevBpm = 0; + // uint8_t rollingBpm = 0; + Controllers::DateTime& dateTimeController; Controllers::FS& fs; Controllers::HeartRateController& heartRateController; @@ -262,8 +228,8 @@ namespace Pinetime { void SavePrevSessionData() const; // For File IO - void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; - void ClearDataCSV(const char* fileName) const; + // void WriteDataCSV(const char* fileName, const std::tuple* data, int dataSize) const; + // void ClearDataCSV(const char* fileName) const; }; } diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index f69cd63268..cc69664109 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -357,9 +357,6 @@ void DisplayApp::Refresh() { if (infiniSleepController.IsEnabled()) { if (currentApp != Apps::Sleep) { LoadNewScreen(Apps::Sleep, DisplayApp::FullRefreshDirections::Up); - // Wait for the sleep app to load before moving on. - while (!lv_task_handler()) { - }; } } } diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index c47b7b9840..c4d4629a60 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -40,7 +40,6 @@ namespace { } } - Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, Controllers::Settings::ClockType clockType, System::SystemTask& systemTask, @@ -52,7 +51,7 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, clockType {clockType}, displayApp {displayApp} { - infiniSleepController.SetHeartRateTrackingEnabled(false); + infiniSleepController.infiniSleepSettings.heartRateTracking = false; infiniSleepController.SetSettingsChanged(); UpdateDisplay(); taskRefresh = lv_task_create(RefreshTaskCallback, 2000, LV_TASK_PRIO_MID, this); @@ -494,7 +493,9 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { infiniSleepController.infiniSleepSettings.graddualWake = true; } infiniSleepController.SetSettingsChanged(); - const char* mode = infiniSleepController.infiniSleepSettings.graddualWake ? "Grad." : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." : "Off"; + const char* mode = infiniSleepController.infiniSleepSettings.graddualWake ? "Grad." + : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." + : "Off"; lv_label_set_text_static(lv_obj_get_child(obj, nullptr), mode); return; } From 37f81ba609a80cb16d6bb75ba4a596bcf34f3897 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 9 Dec 2024 19:52:13 -0600 Subject: [PATCH 105/191] Added a both option for wake mode that allows for natural wake with pre vibrations added the similar ramping up effect to the natural wake alarm but with larger interval --- src/components/motor/MotorController.cpp | 16 ++++-- src/displayapp/screens/Sleep.cpp | 66 ++++++++++++++---------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index dd4ed64b29..8a12971725 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -108,15 +108,23 @@ void MotorController::StopWakeAlarm() { } void MotorController::StartNaturalWakeAlarm() { - SetMotorStrength((60 * infiniSleepMotorStrength) / 100); - RunForDuration(280); + wakeAlarmStrength = (80 * infiniSleepMotorStrength) / 100; + wakeAlarmDuration = 100; + SetMotorStrength(wakeAlarmStrength); + RunForDuration(wakeAlarmDuration); xTimerStart(naturalWakeAlarmVib, 0); } void MotorController::NaturalWakeAlarmRing(TimerHandle_t xTimer) { auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); - motorController->SetMotorStrength((60 * motorController->infiniSleepMotorStrength) / 100); - motorController->RunForDuration(280); + if (motorController->wakeAlarmStrength > (40 * motorController->infiniSleepMotorStrength) / 100) { + motorController->wakeAlarmStrength -= (30 * motorController->infiniSleepMotorStrength) / 100; + } + if (motorController->wakeAlarmDuration < 500) { + motorController->wakeAlarmDuration += 180; + } + motorController->SetMotorStrength(motorController->wakeAlarmStrength); + motorController->RunForDuration(motorController->wakeAlarmDuration); } void MotorController::StopNaturalWakeAlarm() { diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index c4d4629a60..a2df141aa1 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -91,6 +91,8 @@ void Sleep::UpdateDisplay() { return; } + lv_task_reset(taskRefresh); + // Clear the screen lv_obj_clean(lv_scr_act()); if (infiniSleepController.IsAlerting()) { @@ -199,12 +201,12 @@ void Sleep::DrawAlarmScreen() { // lv_label_set_text_static(txtSuggestedAlarm, "Use Sugg.\nAlarmTime"); txtSuggestedAlarm = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(txtSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -10); + lv_obj_align(txtSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -15, -13); lv_label_set_text_static(txtSuggestedAlarm, "Auto"); iconSuggestedAlarm = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(iconSuggestedAlarm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_obj_align(iconSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -50, -10); + lv_obj_align(iconSuggestedAlarm, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -50, -13); lv_label_set_text_static(iconSuggestedAlarm, Symbols::sun); enableSwitch = lv_switch_create(lv_scr_act(), nullptr); @@ -245,7 +247,7 @@ void Sleep::DrawInfoScreen() { // Total sleep time label_total_sleep = lv_label_create(lv_scr_act(), nullptr); - uint16_t totalMinutes = infiniSleepController.GetTotalSleep(); + const uint16_t totalMinutes = infiniSleepController.GetTotalSleep(); lv_label_set_text_fmt(label_total_sleep, "Time Asleep: %dh%dm", totalMinutes / 60, totalMinutes % 60); lv_obj_align(label_total_sleep, lv_scr_act(), LV_ALIGN_CENTER, 0, -60); @@ -310,8 +312,10 @@ void Sleep::DrawInfoScreen() { // Gradual Wake info label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.infiniSleepSettings.graddualWake) { - lv_label_set_text_static(label_gradual_wake, "Wake Mode: Gradual"); + if (infiniSleepController.infiniSleepSettings.graddualWake && infiniSleepController.infiniSleepSettings.naturalWake) { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Both"); + } else if (infiniSleepController.infiniSleepSettings.graddualWake) { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: PreWake"); } else if (infiniSleepController.infiniSleepSettings.naturalWake) { lv_label_set_text_static(label_gradual_wake, "Wake Mode: Natural"); } else { @@ -365,9 +369,11 @@ void Sleep::DrawSettingsScreen() { lv_obj_align(btnWakeMode, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 130, y_offset); btnWakeMode->user_data = this; lv_obj_set_event_cb(btnWakeMode, btnEventHandler); - const char* mode = infiniSleepController.infiniSleepSettings.graddualWake ? "Grad." - : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." - : "Off"; + const char* mode = (infiniSleepController.infiniSleepSettings.graddualWake && infiniSleepController.infiniSleepSettings.naturalWake) + ? "Both" + : infiniSleepController.infiniSleepSettings.graddualWake ? "Pre." + : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." + : "Off"; lblWakeModeValue = lv_label_create(btnWakeMode, nullptr); lv_label_set_text_static(lblWakeModeValue, mode); lv_obj_align(lblWakeModeValue, nullptr, LV_ALIGN_CENTER, 0, 0); @@ -464,13 +470,13 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } if (obj == btnSuggestedAlarm) { // Set the suggested time - uint16_t totalSuggestedMinutes = infiniSleepController.GetSuggestedSleepTime(); - uint8_t suggestedHours = totalSuggestedMinutes / 60; - uint8_t suggestedMinutes = totalSuggestedMinutes % 60; + const uint16_t totalSuggestedMinutes = infiniSleepController.GetSuggestedSleepTime(); + const uint8_t suggestedHours = totalSuggestedMinutes / 60; + const uint8_t suggestedMinutes = totalSuggestedMinutes % 60; // Time for alarm, current time + suggested sleep time - uint8_t alarmHour = (infiniSleepController.GetCurrentHour() + suggestedHours) % 24; - uint8_t alarmMinute = (infiniSleepController.GetCurrentMinute() + suggestedMinutes) % 60; + const uint8_t alarmHour = (infiniSleepController.GetCurrentHour() + suggestedHours) % 24; + const uint8_t alarmMinute = (infiniSleepController.GetCurrentMinute() + suggestedMinutes) % 60; infiniSleepController.SetWakeAlarmTime(alarmHour, alarmMinute); @@ -483,19 +489,25 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { return; } if (obj == btnWakeMode) { - if (infiniSleepController.infiniSleepSettings.graddualWake) { + if (infiniSleepController.infiniSleepSettings.graddualWake && infiniSleepController.infiniSleepSettings.naturalWake) { infiniSleepController.infiniSleepSettings.graddualWake = false; - infiniSleepController.infiniSleepSettings.naturalWake = true; - } else if (infiniSleepController.infiniSleepSettings.naturalWake) { infiniSleepController.infiniSleepSettings.naturalWake = false; + } else if (infiniSleepController.infiniSleepSettings.graddualWake) { infiniSleepController.infiniSleepSettings.graddualWake = false; + infiniSleepController.infiniSleepSettings.naturalWake = true; + } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + infiniSleepController.infiniSleepSettings.naturalWake = true; + infiniSleepController.infiniSleepSettings.graddualWake = true; } else if (!infiniSleepController.infiniSleepSettings.graddualWake && !infiniSleepController.infiniSleepSettings.naturalWake) { infiniSleepController.infiniSleepSettings.graddualWake = true; + infiniSleepController.infiniSleepSettings.naturalWake = false; } infiniSleepController.SetSettingsChanged(); - const char* mode = infiniSleepController.infiniSleepSettings.graddualWake ? "Grad." - : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." - : "Off"; + const char* mode = (infiniSleepController.infiniSleepSettings.graddualWake && infiniSleepController.infiniSleepSettings.naturalWake) + ? "Both" + : infiniSleepController.infiniSleepSettings.graddualWake ? "Pre." + : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." + : "Off"; lv_label_set_text_static(lv_obj_get_child(obj, nullptr), mode); return; } @@ -624,8 +636,8 @@ void Sleep::SnoozeWakeAlarm() { NRF_LOG_INFO("Snoozing alarm for %d minutes", SNOOZE_MINUTES); - uint16_t totalAlarmMinutes = infiniSleepController.GetCurrentHour() * 60 + infiniSleepController.GetCurrentMinute(); - uint16_t newSnoozeMinutes = totalAlarmMinutes + SNOOZE_MINUTES; + const uint16_t totalAlarmMinutes = infiniSleepController.GetCurrentHour() * 60 + infiniSleepController.GetCurrentMinute(); + const uint16_t newSnoozeMinutes = totalAlarmMinutes + SNOOZE_MINUTES; infiniSleepController.SetPreSnoozeTime(); infiniSleepController.isSnoozing = true; @@ -661,10 +673,10 @@ void Sleep::SetAlerting() { if (!infiniSleepController.infiniSleepSettings.naturalWake) { taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); } - if (infiniSleepController.infiniSleepSettings.graddualWake) { - motorController.StartWakeAlarm(); - } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + if (infiniSleepController.infiniSleepSettings.naturalWake) { motorController.StartNaturalWakeAlarm(); + } else { + motorController.StartWakeAlarm(); } if (!infiniSleepController.infiniSleepSettings.naturalWake) { wakeLock.Lock(); @@ -686,10 +698,10 @@ void Sleep::RedrawSetAlerting() { void Sleep::StopAlerting(bool setSwitch) { infiniSleepController.StopAlerting(); - if (infiniSleepController.infiniSleepSettings.graddualWake) { - motorController.StopWakeAlarm(); - } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + if (infiniSleepController.infiniSleepSettings.naturalWake) { motorController.StopNaturalWakeAlarm(); + } else { + motorController.StopWakeAlarm(); } if (setSwitch) { SetSwitchState(LV_ANIM_OFF); From 66aaaae8037e108766ba5621f107b2cf62112fc8 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 12 Dec 2024 18:49:02 -0600 Subject: [PATCH 106/191] Enabling tracker sets brightness to low and resets to previous brightness when stopped Also tweaked the Natural Wake Vibration a little. --- src/components/infinisleep/InfiniSleepController.cpp | 12 +++++++++--- src/components/infinisleep/InfiniSleepController.h | 6 +++++- src/components/motor/MotorController.cpp | 8 ++++++-- src/main.cpp | 4 +++- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index b020fc1cea..1e1a78cb2c 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -9,8 +9,9 @@ using namespace std::chrono_literals; InfiniSleepController::InfiniSleepController(Controllers::DateTime& dateTimeController, Controllers::FS& fs, - Controllers::HeartRateController& heartRateController) - : dateTimeController {dateTimeController}, fs {fs}, heartRateController {heartRateController} { + Controllers::HeartRateController& heartRateController, + Controllers::BrightnessController& brightnessController) + : dateTimeController {dateTimeController}, fs {fs}, heartRateController {heartRateController}, brightnessController {brightnessController} { } namespace { @@ -49,10 +50,14 @@ void InfiniSleepController::Init(System::SystemTask* systemTask) { NRF_LOG_INFO("[InfiniSleepController] Loaded wake alarm was enabled, scheduling"); ScheduleWakeAlarm(); } + + prevBrightnessLevel = brightnessController.Level(); } void InfiniSleepController::EnableTracker() { - DisableTracker(); + prevBrightnessLevel = brightnessController.Level(); + brightnessController.Set(BrightnessController::Levels::Low); + // DisableTracker(); NRF_LOG_INFO("[InfiniSleepController] Enabling tracker"); isEnabled = true; trackerUpdateTimer = @@ -61,6 +66,7 @@ void InfiniSleepController::EnableTracker() { } void InfiniSleepController::DisableTracker() { + brightnessController.Set(prevBrightnessLevel); NRF_LOG_INFO("[InfiniSleepController] Disabling tracker"); xTimerStop(trackerUpdateTimer, 0); isEnabled = false; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 183147d302..53cf0b0ac2 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -29,7 +29,8 @@ namespace Pinetime { public: InfiniSleepController(Controllers::DateTime& dateTimeCOntroller, Controllers::FS&, - Controllers::HeartRateController& heartRateController); + Controllers::HeartRateController& heartRateController, + Controllers::BrightnessController& brightnessController); void Init(System::SystemTask* systemTask); void SaveWakeAlarm(); @@ -169,6 +170,8 @@ namespace Pinetime { return infiniSleepSettings; } + BrightnessController::Levels prevBrightnessLevel; + bool ToggleTracker() { if (isEnabled) { prevSessionData.endTimeHours = GetCurrentHour(); @@ -216,6 +219,7 @@ namespace Pinetime { Controllers::DateTime& dateTimeController; Controllers::FS& fs; Controllers::HeartRateController& heartRateController; + Controllers::BrightnessController& brightnessController; System::SystemTask* systemTask = nullptr; TimerHandle_t wakeAlarmTimer; TimerHandle_t gradualWakeTimer; diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 8a12971725..d6c64bfd80 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -118,10 +118,14 @@ void MotorController::StartNaturalWakeAlarm() { void MotorController::NaturalWakeAlarmRing(TimerHandle_t xTimer) { auto* motorController = static_cast(pvTimerGetTimerID(xTimer)); if (motorController->wakeAlarmStrength > (40 * motorController->infiniSleepMotorStrength) / 100) { - motorController->wakeAlarmStrength -= (30 * motorController->infiniSleepMotorStrength) / 100; + motorController->wakeAlarmStrength -= (15 * motorController->infiniSleepMotorStrength) / 100; + } else { + motorController->wakeAlarmStrength += (30 * motorController->infiniSleepMotorStrength) / 100; } if (motorController->wakeAlarmDuration < 500) { - motorController->wakeAlarmDuration += 180; + motorController->wakeAlarmDuration += 90; + } else { + motorController->wakeAlarmDuration -= 90; } motorController->SetMotorStrength(motorController->wakeAlarmStrength); motorController->RunForDuration(motorController->wakeAlarmDuration); diff --git a/src/main.cpp b/src/main.cpp index 3efc6bb59d..f60f592c63 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,12 +105,14 @@ Pinetime::Drivers::Watchdog watchdog; Pinetime::Controllers::NotificationManager notificationManager; Pinetime::Controllers::MotionController motionController; Pinetime::Controllers::AlarmController alarmController {dateTimeController, fs}; -Pinetime::Controllers::InfiniSleepController infiniSleepController {dateTimeController, fs, heartRateController}; Pinetime::Controllers::TouchHandler touchHandler; Pinetime::Controllers::ButtonHandler buttonHandler; Pinetime::Controllers::BrightnessController brightnessController {}; +Pinetime::Controllers::InfiniSleepController infiniSleepController {dateTimeController, fs, heartRateController, brightnessController}; + + Pinetime::Applications::DisplayApp displayApp(lcd, touchPanel, batteryController, From 14d173fa46b59406ffc3a1626601593606daff7d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 12 Dec 2024 20:56:39 -0600 Subject: [PATCH 107/191] Opening app now sets lower brightness and restores when closing only if tracker disabled. --- src/components/infinisleep/InfiniSleepController.cpp | 3 --- src/components/infinisleep/InfiniSleepController.h | 4 ++++ src/displayapp/screens/Sleep.cpp | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index 1e1a78cb2c..acfd189d61 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -55,8 +55,6 @@ void InfiniSleepController::Init(System::SystemTask* systemTask) { } void InfiniSleepController::EnableTracker() { - prevBrightnessLevel = brightnessController.Level(); - brightnessController.Set(BrightnessController::Levels::Low); // DisableTracker(); NRF_LOG_INFO("[InfiniSleepController] Enabling tracker"); isEnabled = true; @@ -66,7 +64,6 @@ void InfiniSleepController::EnableTracker() { } void InfiniSleepController::DisableTracker() { - brightnessController.Set(prevBrightnessLevel); NRF_LOG_INFO("[InfiniSleepController] Disabling tracker"); xTimerStop(trackerUpdateTimer, 0); isEnabled = false; diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 53cf0b0ac2..c913abcb96 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -205,6 +205,10 @@ namespace Pinetime { return (9 - gradualWakeStep) + 1; } + BrightnessController& GetBrightnessController() { + return brightnessController; + } + private: bool isAlerting = false; bool isGradualWakeAlerting = false; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index a2df141aa1..b1e54550a0 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -59,6 +59,11 @@ Sleep::Sleep(Controllers::InfiniSleepController& infiniSleepController, lv_task_create(PressesToStopAlarmTimeoutCallback, PUSHES_TO_STOP_ALARM_TIMEOUT * 1000, LV_TASK_PRIO_MID, this); infiniSleepController.infiniSleepSettings.sleepCycleDuration = 90; infiniSleepController.SetSettingsChanged(); + + if (!infiniSleepController.IsEnabled()) { + infiniSleepController.prevBrightnessLevel = infiniSleepController.GetBrightnessController().Level(); + } + infiniSleepController.GetBrightnessController().Set(Controllers::BrightnessController::Levels::Low); } Sleep::~Sleep() { @@ -73,6 +78,9 @@ Sleep::~Sleep() { lv_obj_clean(lv_scr_act()); infiniSleepController.SaveWakeAlarm(); infiniSleepController.SaveInfiniSleepSettings(); + if (!infiniSleepController.IsEnabled()) { + infiniSleepController.GetBrightnessController().Set(infiniSleepController.prevBrightnessLevel); + } } void Sleep::DisableWakeAlarm() { From 152f0281b4fb4b3342674c165245539dfb707914 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 13 Dec 2024 13:06:30 -0600 Subject: [PATCH 108/191] Fixed bug where brightness isn't low when watch turning on from sleep. --- src/displayapp/DisplayApp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index cc69664109..1463bd2685 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -760,6 +760,10 @@ void DisplayApp::Register(Pinetime::Controllers::NavigationService* NavigationSe } void DisplayApp::ApplyBrightness() { + if (infiniSleepController.IsEnabled() || currentApp == Apps::Sleep) { + brightnessController.Set(Controllers::BrightnessController::Levels::Low); + return; + } auto brightness = settingsController.GetBrightness(); if (brightness != Controllers::BrightnessController::Levels::Low && brightness != Controllers::BrightnessController::Levels::Medium && brightness != Controllers::BrightnessController::Levels::High) { From 7d1cfaef821a5e2ca890240a203c46f32cacc719 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 16 Dec 2024 13:33:51 -0600 Subject: [PATCH 109/191] Updated SessionData struct and removed wakelock --- .../infinisleep/InfiniSleepController.h | 29 +++++++++++++------ src/displayapp/screens/Sleep.cpp | 12 ++++---- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index c913abcb96..7f48ff60ed 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -25,6 +25,20 @@ namespace Pinetime { } namespace Controllers { + namespace InfiniSleepControllerTypes { + // Struct for sessions + struct SessionData { + uint8_t day = 0; + uint8_t month = 0; + uint16_t year = 0; + + uint8_t startTimeHours = 0; + uint8_t startTimeMinutes = 0; + uint8_t endTimeHours = 0; + uint8_t endTimeMinutes = 0; + }; + } + class InfiniSleepController { public: InfiniSleepController(Controllers::DateTime& dateTimeCOntroller, @@ -51,15 +65,7 @@ namespace Pinetime { uint8_t preSnoozeMinutes = 255; uint8_t preSnnoozeHours = 255; - // Struct for sessions - struct SessionData { - uint8_t startTimeHours = 0; - uint8_t startTimeMinutes = 0; - uint8_t endTimeHours = 0; - uint8_t endTimeMinutes = 0; - }; - - SessionData prevSessionData; + InfiniSleepControllerTypes::SessionData prevSessionData; void SetPreSnoozeTime() { if (preSnoozeMinutes != 255 || preSnnoozeHours != 255) { @@ -180,8 +186,13 @@ namespace Pinetime { DisableTracker(); } else { // ClearDataCSV(TRACKER_DATA_FILE_NAME); + prevSessionData.endTimeHours = 255; + prevSessionData.endTimeMinutes = 255; prevSessionData.startTimeHours = GetCurrentHour(); prevSessionData.startTimeMinutes = GetCurrentMinute(); + prevSessionData.day = dateTimeController.Day(); + prevSessionData.month = static_cast(dateTimeController.Month()); + prevSessionData.year = dateTimeController.Year(); EnableTracker(); } return isEnabled; diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index b1e54550a0..9f2bcf9b7e 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -686,9 +686,9 @@ void Sleep::SetAlerting() { } else { motorController.StartWakeAlarm(); } - if (!infiniSleepController.infiniSleepSettings.naturalWake) { - wakeLock.Lock(); - } + // if (!infiniSleepController.infiniSleepSettings.naturalWake) { + // wakeLock.Lock(); + // } alreadyAlerting = true; } @@ -699,9 +699,9 @@ void Sleep::RedrawSetAlerting() { lv_obj_set_hidden(btnSuggestedAlarm, true); lv_obj_set_hidden(txtSuggestedAlarm, true); lv_obj_set_hidden(iconSuggestedAlarm, true); - if (!infiniSleepController.infiniSleepSettings.naturalWake) { - wakeLock.Lock(); - } + // if (!infiniSleepController.infiniSleepSettings.naturalWake) { + // wakeLock.Lock(); + // } } void Sleep::StopAlerting(bool setSwitch) { From 1892a90511ca4eea02491d61938a9b4cafcdb2eb Mon Sep 17 00:00:00 2001 From: cyberneel Date: Mon, 16 Dec 2024 21:24:37 -0600 Subject: [PATCH 110/191] Added total sleep minutes to SessionData --- .../infinisleep/InfiniSleepController.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 7f48ff60ed..3018a125c8 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -36,6 +36,8 @@ namespace Pinetime { uint8_t startTimeMinutes = 0; uint8_t endTimeHours = 0; uint8_t endTimeMinutes = 0; + + uint16_t totalSleepMinutes = 0; }; } @@ -182,10 +184,23 @@ namespace Pinetime { if (isEnabled) { prevSessionData.endTimeHours = GetCurrentHour(); prevSessionData.endTimeMinutes = GetCurrentMinute(); + + // Calculate total sleep time + uint16_t startTotalMinutes = prevSessionData.startTimeHours * 60 + prevSessionData.startTimeMinutes; + uint16_t endTotalMinutes = GetCurrentHour() * 60 + GetCurrentMinute(); + + // If end time is before start time, add 24 hours to end time (handle crossing midnight) + if (endTotalMinutes < startTotalMinutes) { + endTotalMinutes += 24 * 60; + } + + prevSessionData.totalSleepMinutes = endTotalMinutes - startTotalMinutes; + SavePrevSessionData(); DisableTracker(); } else { // ClearDataCSV(TRACKER_DATA_FILE_NAME); + prevSessionData.totalSleepMinutes = 0; prevSessionData.endTimeHours = 255; prevSessionData.endTimeMinutes = 255; prevSessionData.startTimeHours = GetCurrentHour(); From 1bfd33fbd12d997db50fe5fc6d72af990e89fa33 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Tue, 17 Dec 2024 09:23:20 -0600 Subject: [PATCH 111/191] Added a variable to ignore button press during certion actions. I think pressing the side button as the auto snooze function is running causes a crash. --- src/displayapp/screens/Sleep.cpp | 6 ++++-- src/displayapp/screens/Sleep.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 9f2bcf9b7e..21b5cb1aba 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -24,13 +24,15 @@ namespace { } void SnoozeAlarmTaskCallback(lv_task_t* task) { - auto* screen = static_cast(task->user_data); lv_task_set_prio(task, LV_TASK_PRIO_OFF); + auto* screen = static_cast(task->user_data); + screen->ignoreButtonPush = true; screen->StopAlerting(false); screen->UpdateDisplay(); screen->SnoozeWakeAlarm(); screen->displayState = Sleep::SleepDisplayState::Info; screen->UpdateDisplay(); + screen->ignoreButtonPush = false; } void PressesToStopAlarmTimeoutCallback(lv_task_t* task) { @@ -555,7 +557,7 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } bool Sleep::OnButtonPushed() { - if (infiniSleepController.IsAlerting()) { + if (infiniSleepController.IsAlerting() || ignoreButtonPush) { return true; } if (displayState != SleepDisplayState::Info) { diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index ed3d49e1a5..a38194775a 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -37,6 +37,8 @@ namespace Pinetime { Controllers::InfiniSleepController& infiniSleepController; + bool ignoreButtonPush = false; + private: System::WakeLock wakeLock; Controllers::MotorController& motorController; From cadd0f8777ac82c0b50373fc3a2b27d97dbea07e Mon Sep 17 00:00:00 2001 From: liamcharger Date: Thu, 19 Dec 2024 11:06:39 -0500 Subject: [PATCH 112/191] settings: vibrate on change of motor strength --- src/displayapp/screens/Sleep.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 21b5cb1aba..aafa5c2976 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -543,6 +543,7 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { infiniSleepController.SetSettingsChanged(); lv_label_set_text_fmt(lv_obj_get_child(obj, nullptr), "%d", value); motorController.infiniSleepMotorStrength = value; + motorController.GradualWakeBuzz(); return; } if (obj == btnPushesToStop) { From f09b548090a7198ca37bd40ebf70f7a53091878f Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 19 Dec 2024 11:41:30 -0600 Subject: [PATCH 113/191] Moved alerting logic, shouldn't change anything. --- src/displayapp/screens/Sleep.cpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 21b5cb1aba..b0789e4925 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -123,6 +123,17 @@ void Sleep::UpdateDisplay() { pageIndicator3.Create(); break; } + + if (alreadyAlerting) { + RedrawSetAlerting(); + return; + } + + if (infiniSleepController.IsAlerting()) { + SetAlerting(); + } else { + SetSwitchState(LV_ANIM_OFF); + } } void Sleep::DrawAlarmScreen() { @@ -228,17 +239,6 @@ void Sleep::DrawAlarmScreen() { lv_obj_set_style_local_bg_color(enableSwitch, LV_SWITCH_PART_BG, LV_STATE_DEFAULT, bgColor); UpdateWakeAlarmTime(); - - if (alreadyAlerting) { - RedrawSetAlerting(); - return; - } - - if (infiniSleepController.IsAlerting()) { - SetAlerting(); - } else { - SetSwitchState(LV_ANIM_OFF); - } } void Sleep::DrawInfoScreen() { @@ -688,9 +688,7 @@ void Sleep::SetAlerting() { } else { motorController.StartWakeAlarm(); } - // if (!infiniSleepController.infiniSleepSettings.naturalWake) { - // wakeLock.Lock(); - // } + wakeLock.Lock(); alreadyAlerting = true; } @@ -701,9 +699,7 @@ void Sleep::RedrawSetAlerting() { lv_obj_set_hidden(btnSuggestedAlarm, true); lv_obj_set_hidden(txtSuggestedAlarm, true); lv_obj_set_hidden(iconSuggestedAlarm, true); - // if (!infiniSleepController.infiniSleepSettings.naturalWake) { - // wakeLock.Lock(); - // } + wakeLock.Lock(); } void Sleep::StopAlerting(bool setSwitch) { From a3af01732b539afdfe4e815a88d0c3d4ce1fd833 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Thu, 19 Dec 2024 17:51:49 -0600 Subject: [PATCH 114/191] Bug fix and Changed Off to Normal. Bug was that the SetSwitchState was missing a check to make sure enableSwitch is available. --- src/components/infinisleep/InfiniSleepController.cpp | 12 +++++++++++- src/components/infinisleep/InfiniSleepController.h | 3 +++ src/displayapp/screens/Sleep.cpp | 12 ++++++------ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/components/infinisleep/InfiniSleepController.cpp b/src/components/infinisleep/InfiniSleepController.cpp index acfd189d61..106c3b5ca4 100644 --- a/src/components/infinisleep/InfiniSleepController.cpp +++ b/src/components/infinisleep/InfiniSleepController.cpp @@ -368,7 +368,17 @@ void InfiniSleepController::LoadPrevSessionData() { return; } - fs.FileRead(&prevSessionFile, reinterpret_cast(&prevSessionData), sizeof(prevSessionData)); + InfiniSleepControllerTypes::SessionData tmpSessionData; + + fs.FileRead(&prevSessionFile, reinterpret_cast(&tmpSessionData), sizeof(tmpSessionData)); fs.FileClose(&prevSessionFile); + + if (tmpSessionData.version != SESSION_DATA_VERSION) { + NRF_LOG_WARNING("[InfiniSleepController] Loaded previous session data has version %u instead of %u, discarding", + tmpSessionData.version, + SESSION_DATA_VERSION); + return; + } + prevSessionData = tmpSessionData; NRF_LOG_INFO("[InfiniSleepController] Loaded previous session data"); } \ No newline at end of file diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index 3018a125c8..c9dfacddeb 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -18,6 +18,7 @@ #define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes #define DESIRED_CYCLES 5 // desired number of sleep cycles #define PUSHES_TO_STOP_ALARM_TIMEOUT 2 // in seconds +#define SESSION_DATA_VERSION 1 // Version of the session data struct namespace Pinetime { namespace System { @@ -38,6 +39,8 @@ namespace Pinetime { uint8_t endTimeMinutes = 0; uint16_t totalSleepMinutes = 0; + + uint8_t version = SESSION_DATA_VERSION; }; } diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 95e086f74b..d1b435b75a 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -3,7 +3,7 @@ #include "displayapp/screens/Symbols.h" #include "displayapp/InfiniTimeTheme.h" #include "components/settings/Settings.h" -#include "components/alarm/AlarmController.h" +#include "components/infinisleep/InfiniSleepController.h" #include "components/motor/MotorController.h" #include "systemtask/SystemTask.h" @@ -131,7 +131,7 @@ void Sleep::UpdateDisplay() { if (infiniSleepController.IsAlerting()) { SetAlerting(); - } else { + } else if (displayState == SleepDisplayState::Alarm) { SetSwitchState(LV_ANIM_OFF); } } @@ -329,7 +329,7 @@ void Sleep::DrawInfoScreen() { } else if (infiniSleepController.infiniSleepSettings.naturalWake) { lv_label_set_text_static(label_gradual_wake, "Wake Mode: Natural"); } else { - lv_label_set_text_static(label_gradual_wake, "Wake Mode: Off"); + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Normal"); } lv_obj_align(label_gradual_wake, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); lv_obj_set_style_local_text_color(label_gradual_wake, @@ -383,7 +383,7 @@ void Sleep::DrawSettingsScreen() { ? "Both" : infiniSleepController.infiniSleepSettings.graddualWake ? "Pre." : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." - : "Off"; + : "Norm."; lblWakeModeValue = lv_label_create(btnWakeMode, nullptr); lv_label_set_text_static(lblWakeModeValue, mode); lv_obj_align(lblWakeModeValue, nullptr, LV_ALIGN_CENTER, 0, 0); @@ -517,7 +517,7 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { ? "Both" : infiniSleepController.infiniSleepSettings.graddualWake ? "Pre." : infiniSleepController.infiniSleepSettings.naturalWake ? "Nat." - : "Off"; + : "Norm."; lv_label_set_text_static(lv_obj_get_child(obj, nullptr), mode); return; } @@ -724,7 +724,7 @@ void Sleep::StopAlerting(bool setSwitch) { } void Sleep::SetSwitchState(lv_anim_enable_t anim) { - if (infiniSleepController.GetWakeAlarm().isEnabled) { + if (displayState == SleepDisplayState::Alarm && infiniSleepController.GetWakeAlarm().isEnabled) { lv_switch_on(enableSwitch, anim); } else { lv_switch_off(enableSwitch, anim); From ee73c340a60cfe0d41c731c392bf26480382c010 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 20 Dec 2024 13:11:55 -0600 Subject: [PATCH 115/191] Pressing side button while alarm alerting snoozes. --- src/displayapp/screens/Sleep.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index d1b435b75a..e11138ab82 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -558,7 +558,12 @@ void Sleep::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } bool Sleep::OnButtonPushed() { - if (infiniSleepController.IsAlerting() || ignoreButtonPush) { + if (ignoreButtonPush) { + return true; + } + // Side button to snooze + if (infiniSleepController.IsAlerting() && displayState == SleepDisplayState::Alarm) { + OnButtonEvent(btnSnooze, LV_EVENT_CLICKED); return true; } if (displayState != SleepDisplayState::Info) { From 0e0e1f564d65d612c9e5d9221cf584742970c46d Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 20 Dec 2024 13:19:24 -0600 Subject: [PATCH 116/191] Made changes to the SnoozeAlarmTaskCallback, it uses the existing code in the OnButtonEvent function. Also made sure to delete the task in some places. --- src/displayapp/screens/Sleep.cpp | 10 +++++----- src/displayapp/screens/Sleep.h | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index e11138ab82..f47b4c99e2 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -27,11 +27,7 @@ namespace { lv_task_set_prio(task, LV_TASK_PRIO_OFF); auto* screen = static_cast(task->user_data); screen->ignoreButtonPush = true; - screen->StopAlerting(false); - screen->UpdateDisplay(); - screen->SnoozeWakeAlarm(); - screen->displayState = Sleep::SleepDisplayState::Info; - screen->UpdateDisplay(); + screen->OnButtonEvent(screen->btnSnooze, LV_EVENT_CLICKED); screen->ignoreButtonPush = false; } @@ -709,6 +705,10 @@ void Sleep::RedrawSetAlerting() { } void Sleep::StopAlerting(bool setSwitch) { + if (taskSnoozeWakeAlarm != nullptr) { + lv_task_del(taskSnoozeWakeAlarm); + taskSnoozeWakeAlarm = nullptr; + } infiniSleepController.StopAlerting(); if (infiniSleepController.infiniSleepSettings.naturalWake) { motorController.StopNaturalWakeAlarm(); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index a38194775a..6376ca982e 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -39,13 +39,15 @@ namespace Pinetime { bool ignoreButtonPush = false; + lv_obj_t *btnSnooze; + private: System::WakeLock wakeLock; Controllers::MotorController& motorController; Controllers::Settings::ClockType clockType; DisplayApp& displayApp; - lv_obj_t *btnStop, *btnSnooze, *txtStop, *txtSnooze, /**btnRecur, *txtRecur,*/ *btnInfo, *enableSwitch; + lv_obj_t *btnStop, *txtStop, *txtSnooze, /**btnRecur, *txtRecur,*/ *btnInfo, *enableSwitch; lv_obj_t *trackerToggleBtn, *trackerToggleLabel; lv_obj_t* lblampm = nullptr; lv_obj_t* txtMessage = nullptr; From 7b8339ca967deb28c2bb1c309bf46ee04c3d68ad Mon Sep 17 00:00:00 2001 From: cyberneel Date: Fri, 20 Dec 2024 13:39:09 -0600 Subject: [PATCH 117/191] Added startTimeStamp to SessionData --- src/components/infinisleep/InfiniSleepController.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/infinisleep/InfiniSleepController.h b/src/components/infinisleep/InfiniSleepController.h index c9dfacddeb..9e2ff3fb8f 100644 --- a/src/components/infinisleep/InfiniSleepController.h +++ b/src/components/infinisleep/InfiniSleepController.h @@ -18,7 +18,7 @@ #define SLEEP_CYCLE_DURATION 90 // sleep cycle duration in minutes #define DESIRED_CYCLES 5 // desired number of sleep cycles #define PUSHES_TO_STOP_ALARM_TIMEOUT 2 // in seconds -#define SESSION_DATA_VERSION 1 // Version of the session data struct +#define SESSION_DATA_VERSION 2 // Version of the session data struct namespace Pinetime { namespace System { @@ -40,6 +40,8 @@ namespace Pinetime { uint16_t totalSleepMinutes = 0; + uint32_t startTimeStamp = 0; + uint8_t version = SESSION_DATA_VERSION; }; } @@ -211,6 +213,7 @@ namespace Pinetime { prevSessionData.day = dateTimeController.Day(); prevSessionData.month = static_cast(dateTimeController.Month()); prevSessionData.year = dateTimeController.Year(); + prevSessionData.startTimeStamp = dateTimeController.CurrentDateTime().time_since_epoch().count(); EnableTracker(); } return isEnabled; From 37351cfac591235b3c1e06f9c6f2998d4a8e9437 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sat, 21 Dec 2024 22:22:29 -0600 Subject: [PATCH 118/191] Added more checks in code --- src/displayapp/screens/Sleep.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index f47b4c99e2..22f96f194b 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -651,7 +651,9 @@ void Sleep::SnoozeWakeAlarm() { const uint16_t totalAlarmMinutes = infiniSleepController.GetCurrentHour() * 60 + infiniSleepController.GetCurrentMinute(); const uint16_t newSnoozeMinutes = totalAlarmMinutes + SNOOZE_MINUTES; - infiniSleepController.SetPreSnoozeTime(); + if (infiniSleepController.isSnoozing != true) { + infiniSleepController.SetPreSnoozeTime(); + } infiniSleepController.isSnoozing = true; infiniSleepController.SetWakeAlarmTime(newSnoozeMinutes / 60, newSnoozeMinutes % 60); @@ -683,6 +685,10 @@ void Sleep::SetAlerting() { lv_obj_set_hidden(iconSuggestedAlarm, true); NRF_LOG_INFO("Alarm is alerting"); if (!infiniSleepController.infiniSleepSettings.naturalWake) { + if (taskSnoozeWakeAlarm != nullptr) { + lv_task_del(taskSnoozeWakeAlarm); + taskSnoozeWakeAlarm = nullptr; + } taskSnoozeWakeAlarm = lv_task_create(SnoozeAlarmTaskCallback, 120 * 1000, LV_TASK_PRIO_MID, this); } if (infiniSleepController.infiniSleepSettings.naturalWake) { From 578f06e45dcdf7f07a94b79b950b9eded130a3b5 Mon Sep 17 00:00:00 2001 From: cyberneel Date: Sun, 22 Dec 2024 12:05:21 -0600 Subject: [PATCH 119/191] Showing wake mode on info screen only when alarm is active. Also applied code formatting. --- src/displayapp/screens/Sleep.cpp | 32 +++++++++++++++++--------------- src/displayapp/screens/Sleep.h | 2 +- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/displayapp/screens/Sleep.cpp b/src/displayapp/screens/Sleep.cpp index 22f96f194b..ccd1ea635a 100644 --- a/src/displayapp/screens/Sleep.cpp +++ b/src/displayapp/screens/Sleep.cpp @@ -316,22 +316,24 @@ void Sleep::DrawInfoScreen() { LV_STATE_DEFAULT, infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); - // Gradual Wake info - label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); - if (infiniSleepController.infiniSleepSettings.graddualWake && infiniSleepController.infiniSleepSettings.naturalWake) { - lv_label_set_text_static(label_gradual_wake, "Wake Mode: Both"); - } else if (infiniSleepController.infiniSleepSettings.graddualWake) { - lv_label_set_text_static(label_gradual_wake, "Wake Mode: PreWake"); - } else if (infiniSleepController.infiniSleepSettings.naturalWake) { - lv_label_set_text_static(label_gradual_wake, "Wake Mode: Natural"); - } else { - lv_label_set_text_static(label_gradual_wake, "Wake Mode: Normal"); + // Wake Mode info + if (infiniSleepController.GetWakeAlarm().isEnabled) { + label_gradual_wake = lv_label_create(lv_scr_act(), nullptr); + if (infiniSleepController.infiniSleepSettings.graddualWake && infiniSleepController.infiniSleepSettings.naturalWake) { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Both"); + } else if (infiniSleepController.infiniSleepSettings.graddualWake) { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: PreWake"); + } else if (infiniSleepController.infiniSleepSettings.naturalWake) { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Natural"); + } else { + lv_label_set_text_static(label_gradual_wake, "Wake Mode: Normal"); + } + lv_obj_align(label_gradual_wake, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); + lv_obj_set_style_local_text_color(label_gradual_wake, + LV_LABEL_PART_MAIN, + LV_STATE_DEFAULT, + infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); } - lv_obj_align(label_gradual_wake, lv_scr_act(), LV_ALIGN_CENTER, 0, 40); - lv_obj_set_style_local_text_color(label_gradual_wake, - LV_LABEL_PART_MAIN, - LV_STATE_DEFAULT, - infiniSleepController.IsEnabled() ? LV_COLOR_RED : LV_COLOR_WHITE); // Start/Stop button trackerToggleBtn = lv_btn_create(lv_scr_act(), nullptr); diff --git a/src/displayapp/screens/Sleep.h b/src/displayapp/screens/Sleep.h index 6376ca982e..13f8816798 100644 --- a/src/displayapp/screens/Sleep.h +++ b/src/displayapp/screens/Sleep.h @@ -39,7 +39,7 @@ namespace Pinetime { bool ignoreButtonPush = false; - lv_obj_t *btnSnooze; + lv_obj_t* btnSnooze; private: System::WakeLock wakeLock; From 2cdbfa58e7b1ede2d735fc9f086decb2184c4ce0 Mon Sep 17 00:00:00 2001 From: Jozef Mlich Date: Sat, 16 Dec 2023 15:45:13 +0100 Subject: [PATCH 120/191] Show alarm controller state in status icon --- src/displayapp/DisplayApp.cpp | 4 +++- src/displayapp/screens/ApplicationList.cpp | 3 +++ src/displayapp/screens/ApplicationList.h | 2 ++ src/displayapp/screens/Tile.cpp | 6 +++++- src/displayapp/screens/Tile.h | 1 + src/displayapp/screens/WatchFaceDigital.cpp | 3 ++- src/displayapp/screens/WatchFaceDigital.h | 3 +++ src/displayapp/screens/settings/QuickSettings.cpp | 5 +++-- src/displayapp/screens/settings/QuickSettings.h | 3 ++- src/displayapp/widgets/StatusIcons.cpp | 15 +++++++++++++-- src/displayapp/widgets/StatusIcons.h | 8 +++++++- 11 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 1463bd2685..64217c174d 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -566,6 +566,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio settingsController, batteryController, bleController, + alarmController, dateTimeController, filesystem, std::move(apps)); @@ -620,7 +621,8 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio brightnessController, motorController, settingsController, - bleController); + bleController, + alarmController); break; case Apps::Settings: currentScreen = std::make_unique(this, settingsController); diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp index 41735349da..fb46b41384 100644 --- a/src/displayapp/screens/ApplicationList.cpp +++ b/src/displayapp/screens/ApplicationList.cpp @@ -21,6 +21,7 @@ ApplicationList::ApplicationList(DisplayApp* app, Pinetime::Controllers::Settings& settingsController, const Pinetime::Controllers::Battery& batteryController, const Pinetime::Controllers::Ble& bleController, + const Pinetime::Controllers::AlarmController& alarmController, Controllers::DateTime& dateTimeController, Pinetime::Controllers::FS& filesystem, std::array&& apps) @@ -28,6 +29,7 @@ ApplicationList::ApplicationList(DisplayApp* app, settingsController {settingsController}, batteryController {batteryController}, bleController {bleController}, + alarmController {alarmController}, dateTimeController {dateTimeController}, filesystem {filesystem}, apps {std::move(apps)}, @@ -59,6 +61,7 @@ std::unique_ptr ApplicationList::CreateScreen(unsigned int screenNum) co settingsController, batteryController, bleController, + alarmController, dateTimeController, pageApps); } diff --git a/src/displayapp/screens/ApplicationList.h b/src/displayapp/screens/ApplicationList.h index 41a413af1a..4a57d7c034 100644 --- a/src/displayapp/screens/ApplicationList.h +++ b/src/displayapp/screens/ApplicationList.h @@ -18,6 +18,7 @@ namespace Pinetime { Pinetime::Controllers::Settings& settingsController, const Pinetime::Controllers::Battery& batteryController, const Pinetime::Controllers::Ble& bleController, + const Pinetime::Controllers::AlarmController& alarmController, Controllers::DateTime& dateTimeController, Pinetime::Controllers::FS& filesystem, std::array&& apps); @@ -32,6 +33,7 @@ namespace Pinetime { Controllers::Settings& settingsController; const Pinetime::Controllers::Battery& batteryController; const Pinetime::Controllers::Ble& bleController; + const Pinetime::Controllers::AlarmController& alarmController; Controllers::DateTime& dateTimeController; Pinetime::Controllers::FS& filesystem; std::array apps; diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index 7c392c59e5..7c585a4b97 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -29,9 +29,13 @@ Tile::Tile(uint8_t screenID, Controllers::Settings& settingsController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController, Controllers::DateTime& dateTimeController, std::array& applications) - : app {app}, dateTimeController {dateTimeController}, pageIndicator(screenID, numScreens), statusIcons(batteryController, bleController) { + : app {app}, + dateTimeController {dateTimeController}, + pageIndicator(screenID, numScreens), + statusIcons(batteryController, bleController, alarmController) { settingsController.SetAppMenu(screenID); diff --git a/src/displayapp/screens/Tile.h b/src/displayapp/screens/Tile.h index f1b86246ce..c16151d0e1 100644 --- a/src/displayapp/screens/Tile.h +++ b/src/displayapp/screens/Tile.h @@ -28,6 +28,7 @@ namespace Pinetime { Controllers::Settings& settingsController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController, Controllers::DateTime& dateTimeController, std::array& applications); diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index d944117dd7..3163c6e750 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -19,6 +19,7 @@ using namespace Pinetime::Applications::Screens; WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController, Controllers::NotificationManager& notificationManager, Controllers::Settings& settingsController, Controllers::HeartRateController& heartRateController, @@ -31,7 +32,7 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, heartRateController {heartRateController}, motionController {motionController}, weatherService {weatherService}, - statusIcons(batteryController, bleController) { + statusIcons(batteryController, bleController, alarmController) { statusIcons.Create(); diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 7bb713cbb8..3005cea56f 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -17,6 +17,7 @@ namespace Pinetime { class Settings; class Battery; class Ble; + class AlarmController; class NotificationManager; class HeartRateController; class MotionController; @@ -30,6 +31,7 @@ namespace Pinetime { WatchFaceDigital(Controllers::DateTime& dateTimeController, const Controllers::Battery& batteryController, const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController, Controllers::NotificationManager& notificationManager, Controllers::Settings& settingsController, Controllers::HeartRateController& heartRateController, @@ -84,6 +86,7 @@ namespace Pinetime { return new Screens::WatchFaceDigital(controllers.dateTimeController, controllers.batteryController, controllers.bleController, + controllers.alarmController, controllers.notificationManager, controllers.settingsController, controllers.heartRateController, diff --git a/src/displayapp/screens/settings/QuickSettings.cpp b/src/displayapp/screens/settings/QuickSettings.cpp index 0548488855..c5c3071aef 100644 --- a/src/displayapp/screens/settings/QuickSettings.cpp +++ b/src/displayapp/screens/settings/QuickSettings.cpp @@ -33,13 +33,14 @@ QuickSettings::QuickSettings(Pinetime::Applications::DisplayApp* app, Controllers::BrightnessController& brightness, Controllers::MotorController& motorController, Pinetime::Controllers::Settings& settingsController, - const Controllers::Ble& bleController) + const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController) : app {app}, dateTimeController {dateTimeController}, brightness {brightness}, motorController {motorController}, settingsController {settingsController}, - statusIcons(batteryController, bleController) { + statusIcons(batteryController, bleController, alarmController) { statusIcons.Create(); diff --git a/src/displayapp/screens/settings/QuickSettings.h b/src/displayapp/screens/settings/QuickSettings.h index 55da617629..87c126b7fa 100644 --- a/src/displayapp/screens/settings/QuickSettings.h +++ b/src/displayapp/screens/settings/QuickSettings.h @@ -23,7 +23,8 @@ namespace Pinetime { Controllers::BrightnessController& brightness, Controllers::MotorController& motorController, Pinetime::Controllers::Settings& settingsController, - const Controllers::Ble& bleController); + const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController); ~QuickSettings() override; diff --git a/src/displayapp/widgets/StatusIcons.cpp b/src/displayapp/widgets/StatusIcons.cpp index 423b53d97a..777731a59f 100644 --- a/src/displayapp/widgets/StatusIcons.cpp +++ b/src/displayapp/widgets/StatusIcons.cpp @@ -1,10 +1,13 @@ #include "displayapp/widgets/StatusIcons.h" #include "displayapp/screens/Symbols.h" +#include "components/alarm/AlarmController.h" using namespace Pinetime::Applications::Widgets; -StatusIcons::StatusIcons(const Controllers::Battery& batteryController, const Controllers::Ble& bleController) - : batteryIcon(true), batteryController {batteryController}, bleController {bleController} { +StatusIcons::StatusIcons(const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController) + : batteryIcon(true), batteryController {batteryController}, bleController {bleController}, alarmController {alarmController} { } void StatusIcons::Create() { @@ -20,6 +23,9 @@ void StatusIcons::Create() { batteryPlug = lv_label_create(container, nullptr); lv_label_set_text_static(batteryPlug, Screens::Symbols::plug); + alarmIcon = lv_label_create(container, nullptr); + lv_label_set_text_static(alarmIcon, Screens::Symbols::bell); + batteryIcon.Create(container); lv_obj_align(container, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); @@ -37,6 +43,11 @@ void StatusIcons::Update() { batteryIcon.SetBatteryPercentage(batteryPercent); } + alarmEnabled = alarmController.IsEnabled(); + if (alarmEnabled.IsUpdated()) { + lv_obj_set_hidden(alarmIcon, !alarmEnabled.Get()); + } + bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated() || bleRadioEnabled.IsUpdated()) { diff --git a/src/displayapp/widgets/StatusIcons.h b/src/displayapp/widgets/StatusIcons.h index 9e21d3add0..5524e996c5 100644 --- a/src/displayapp/widgets/StatusIcons.h +++ b/src/displayapp/widgets/StatusIcons.h @@ -5,6 +5,7 @@ #include "displayapp/screens/Screen.h" #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" +#include "components/alarm/AlarmController.h" #include "displayapp/screens/BatteryIcon.h" #include "utility/DirtyValue.h" @@ -13,7 +14,9 @@ namespace Pinetime { namespace Widgets { class StatusIcons { public: - StatusIcons(const Controllers::Battery& batteryController, const Controllers::Ble& bleController); + StatusIcons(const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + const Controllers::AlarmController& alarmController); void Align(); void Create(); @@ -27,13 +30,16 @@ namespace Pinetime { Screens::BatteryIcon batteryIcon; const Pinetime::Controllers::Battery& batteryController; const Controllers::Ble& bleController; + const Controllers::AlarmController& alarmController; Utility::DirtyValue batteryPercentRemaining {}; Utility::DirtyValue powerPresent {}; Utility::DirtyValue bleState {}; Utility::DirtyValue bleRadioEnabled {}; + Utility::DirtyValue alarmEnabled {}; lv_obj_t* bleIcon; + lv_obj_t* alarmIcon; lv_obj_t* batteryPlug; lv_obj_t* container; }; From 6e0da819314cb7db0fe6d00beb12dd86b5a46023 Mon Sep 17 00:00:00 2001 From: ljahn <36698527+ljahn@users.noreply.github.com> Date: Tue, 21 Jan 2025 09:10:41 +0100 Subject: [PATCH 121/191] Alarm: Simplify alarm alerting screen (#2211) Simplify alarm alerting screen and fix bug with alerting on time value change SetAlerting creates an lv_task to automatically call StopAlerting after one minute. This task will call an invalid function reference and lead to a crash under the following condition: All exit paths but the time value change (so not considering this fix) call StopAlerting themselves, which also terminates the lv_task. However, the value change callback only calls DisableAlarm, because its normal use case is for setting up an alarm, where you have to re-confirm enabling the alarm after every change you make. DisableAlarm still sets isAlerting in the alarmController to false, probably because someone thought a currently alerting but also disabled alarm makes no sense, this was introduced in a0cd439. That causes the destructor of Alarm to think there is nothing to do regarding the alerting when the alarm screen is dismissed. Therefore it does not call StopAlerting and the lv_task is left with an invalid function pointer, because Alarm does not exist anymore once the lv_task finally goes to call the callback function --- src/components/alarm/AlarmController.cpp | 1 - src/displayapp/screens/Alarm.cpp | 12 ++++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp index 7dbfb0e307..4ae42c0830 100644 --- a/src/components/alarm/AlarmController.cpp +++ b/src/components/alarm/AlarmController.cpp @@ -111,7 +111,6 @@ uint32_t AlarmController::SecondsToAlarm() const { void AlarmController::DisableAlarm() { xTimerStop(alarmTimer, 0); - isAlerting = false; if (alarm.isEnabled) { alarm.isEnabled = false; alarmChanged = true; diff --git a/src/displayapp/screens/Alarm.cpp b/src/displayapp/screens/Alarm.cpp index b1e673639a..4cf4392157 100644 --- a/src/displayapp/screens/Alarm.cpp +++ b/src/displayapp/screens/Alarm.cpp @@ -77,7 +77,7 @@ Alarm::Alarm(Controllers::AlarmController& alarmController, btnStop = lv_btn_create(lv_scr_act(), nullptr); btnStop->user_data = this; lv_obj_set_event_cb(btnStop, btnEventHandler); - lv_obj_set_size(btnStop, 115, 50); + lv_obj_set_size(btnStop, 240, 70); lv_obj_align(btnStop, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_set_style_local_bg_color(btnStop, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); txtStop = lv_label_create(btnStop, nullptr); @@ -203,6 +203,10 @@ void Alarm::UpdateAlarmTime() { void Alarm::SetAlerting() { lv_obj_set_hidden(enableSwitch, true); + lv_obj_set_hidden(btnRecur, true); + lv_obj_set_hidden(btnInfo, true); + hourCounter.HideControls(); + minuteCounter.HideControls(); lv_obj_set_hidden(btnStop, false); taskStopAlarm = lv_task_create(StopAlarmTaskCallback, pdMS_TO_TICKS(60 * 1000), LV_TASK_PRIO_MID, this); motorController.StartRinging(); @@ -218,8 +222,12 @@ void Alarm::StopAlerting() { taskStopAlarm = nullptr; } wakeLock.Release(); - lv_obj_set_hidden(enableSwitch, false); lv_obj_set_hidden(btnStop, true); + hourCounter.ShowControls(); + minuteCounter.ShowControls(); + lv_obj_set_hidden(btnInfo, false); + lv_obj_set_hidden(btnRecur, false); + lv_obj_set_hidden(enableSwitch, false); } void Alarm::SetSwitchState(lv_anim_enable_t anim) { From 8de2c2ae98c9b30054ffc2115f68be8509ba2c3a Mon Sep 17 00:00:00 2001 From: Jozef Mlich Date: Fri, 10 Jan 2025 09:06:11 +0100 Subject: [PATCH 122/191] Fixes #2219: use artifact v4 instead of v3 --- .github/workflows/format.yml | 2 +- .github/workflows/main.yml | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 71c05fa299..ceb37d5bdd 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -29,7 +29,7 @@ jobs: run: tests/test-format.sh - name: Upload patches - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: Patches diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 247bd4af6b..db93bb3fb7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -52,22 +52,22 @@ jobs: ref_name: ${{ github.head_ref || github.ref_name }} run: echo "REF_NAME=${ref_name//\//-}" >> $GITHUB_ENV - name: Upload DFU artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: InfiniTime DFU ${{ env.REF_NAME }} path: ./build/output/pinetime-mcuboot-app-dfu/* - name: Upload MCUBoot image artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: InfiniTime MCUBoot image ${{ env.REF_NAME }} path: ./build/output/pinetime-mcuboot-app-image-*.bin - name: Upload standalone ELF artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: InfiniTime image ${{ env.REF_NAME }} path: ./build/output/src/pinetime-app-*.out - name: Upload resources artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: InfiniTime resources ${{ env.REF_NAME }} path: ./build/output/infinitime-resources-*.zip @@ -108,7 +108,7 @@ jobs: cmake --build build_lv_sim - name: Upload simulator executable - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: infinisim-${{ env.REF_NAME }} path: build_lv_sim/infinisim @@ -208,7 +208,7 @@ jobs: EOF - name: Upload comment - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: comment path: comment From 29a78028c5f96ac6eb1730bdb59a138c12fc7eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Mart=C3=ADnez?= Date: Tue, 28 Jan 2025 20:57:07 +0100 Subject: [PATCH 123/191] Add "Run on InfiniEmu" link to pull requests (#2150) --- .github/workflows/main.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index db93bb3fb7..41f305b9ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,6 +22,8 @@ jobs: text_size: ${{ steps.output-sizes.outputs.text_size }} data_size: ${{ steps.output-sizes.outputs.data_size }} bss_size: ${{ steps.output-sizes.outputs.bss_size }} + firmware_artifact: ${{ steps.upload-firmware.outputs.artifact-id }} + resources_artifact: ${{ steps.upload-resources.outputs.artifact-id }} env: # InfiniTime sources are downloaded to the current directory. # Override SOURCES_DIR in build.sh @@ -63,11 +65,13 @@ jobs: path: ./build/output/pinetime-mcuboot-app-image-*.bin - name: Upload standalone ELF artifacts uses: actions/upload-artifact@v4 + id: upload-firmware with: name: InfiniTime image ${{ env.REF_NAME }} path: ./build/output/src/pinetime-app-*.out - name: Upload resources artifacts uses: actions/upload-artifact@v4 + id: upload-resources with: name: InfiniTime resources ${{ env.REF_NAME }} path: ./build/output/infinitime-resources-*.zip @@ -205,6 +209,8 @@ jobs: | text | ${{ needs.build-firmware.outputs.text_size }}B | ${{ steps.output-sizes-diff.outputs.text_diff }}B | | data | ${{ needs.build-firmware.outputs.data_size }}B | ${{ steps.output-sizes-diff.outputs.data_diff }}B | | bss | ${{ needs.build-firmware.outputs.bss_size }}B | ${{ steps.output-sizes-diff.outputs.bss_diff }}B | + + [Run in InfiniEmu](https://infiniemu.pipe01.net/?firmware=artifact://${{ github.repository }}/${{ needs.build-firmware.outputs.firmware_artifact }}&resources=artifact://${{ github.repository }}/${{ needs.build-firmware.outputs.resources_artifact }}) EOF - name: Upload comment From 333ca34b017f0917af18fedabb305c15d9108cac Mon Sep 17 00:00:00 2001 From: Titus <154823939+tituscmd@users.noreply.github.com> Date: Mon, 10 Feb 2025 20:28:20 +0100 Subject: [PATCH 124/191] Improve no notification text (#2238) Change the "No notification" text to "No notifications" --- src/displayapp/screens/Notifications.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 45f72f2e20..837c4683aa 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -246,8 +246,8 @@ namespace { Notifications::NotificationItem::NotificationItem(Pinetime::Controllers::AlertNotificationService& alertNotificationService, Pinetime::Controllers::MotorController& motorController) - : NotificationItem("Notification", - "No notification to display", + : NotificationItem("Notifications", + "No notifications to display", 0, Controllers::NotificationManager::Categories::Unknown, 0, From 9ff7c14cd59bb40551c00c888c66498fe14d7f2c Mon Sep 17 00:00:00 2001 From: Max Jakobitsch Date: Wed, 12 Feb 2025 00:43:10 +0100 Subject: [PATCH 125/191] Fix EOL related build issues on Windows (#2077) Prevent line endings from getting normalised to CRLF Co-authored-by: NeroBurner --- .gitattributes | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index 2257cac4e5..7adb0e69a6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,9 @@ # Set the default behavior, in case people don't have core.autocrlf set. -* text=auto +# Prevent build errors on non lf systems (like Windows), we need files with lf as newlines. +* text=auto eol=lf # Explicitly declare text files you want to always be normalized and converted -# to native line endings on checkout. +# to lf line endings on checkout. *.c text *.cpp text *.h text From d8fd80b048ff19b20b6f07f7c5e089b256a26af0 Mon Sep 17 00:00:00 2001 From: Steveis Date: Wed, 26 Feb 2025 23:16:20 +0000 Subject: [PATCH 126/191] Fix Infineat crash when charging with AOD (#2256) Optimise the battery animation to not use 100% CPU (which causes DisplayApp to spin forever with AOD) (DisplayApp also needs to be fixed in the future so it cannot spin infinitely) --- src/displayapp/screens/WatchFaceInfineat.cpp | 7 +++++-- src/displayapp/screens/WatchFaceInfineat.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/WatchFaceInfineat.cpp b/src/displayapp/screens/WatchFaceInfineat.cpp index 4c6fc196ac..40f2abbbbc 100644 --- a/src/displayapp/screens/WatchFaceInfineat.cpp +++ b/src/displayapp/screens/WatchFaceInfineat.cpp @@ -434,12 +434,15 @@ void WatchFaceInfineat::Refresh() { batteryPercentRemaining = batteryController.PercentRemaining(); isCharging = batteryController.IsCharging(); - if (batteryController.IsCharging()) { // Charging battery animation - chargingBatteryPercent += 1; + // Charging battery animation + if (batteryController.IsCharging() && (xTaskGetTickCount() - chargingAnimationTick > pdMS_TO_TICKS(150))) { + // Dividing 100 by the height gives the battery percentage required to shift the animation by 1 pixel + chargingBatteryPercent += 100 / lv_obj_get_height(logoPine); if (chargingBatteryPercent > 100) { chargingBatteryPercent = batteryPercentRemaining.Get(); } SetBatteryLevel(chargingBatteryPercent); + chargingAnimationTick = xTaskGetTickCount(); } else if (isCharging.IsUpdated() || batteryPercentRemaining.IsUpdated()) { chargingBatteryPercent = batteryPercentRemaining.Get(); SetBatteryLevel(chargingBatteryPercent); diff --git a/src/displayapp/screens/WatchFaceInfineat.h b/src/displayapp/screens/WatchFaceInfineat.h index 55c43f98e0..78d020f10b 100644 --- a/src/displayapp/screens/WatchFaceInfineat.h +++ b/src/displayapp/screens/WatchFaceInfineat.h @@ -47,6 +47,7 @@ namespace Pinetime { private: uint32_t savedTick = 0; uint8_t chargingBatteryPercent = 101; // not a mistake ;) + TickType_t chargingAnimationTick = 0; Utility::DirtyValue batteryPercentRemaining {}; Utility::DirtyValue isCharging {}; From 59cc6d4ce2b6155b73bdf2eb28503bc28e49318a Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Sun, 23 Feb 2025 15:39:27 +0000 Subject: [PATCH 127/191] Set build context directory in devcontainer.json Otherwise the default build context is the top level directory when building the dev container in JetBrain IDEs. VsCode seems to use the Dockerfile location as build context instead, meaning the container build works by default here. --- .devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer.json b/.devcontainer.json index 95a27dac74..813f92cc3a 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -2,7 +2,8 @@ // https://github.com/microsoft/vscode-dev-containers/tree/v0.154.2/containers/cpp { "build": { - "dockerfile": "docker/Dockerfile" + "dockerfile": "docker/Dockerfile", + "context": "docker", }, "customizations": { "vscode": { From ba868dd85cd649aad6190b365d73a643b14725da Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Wed, 26 Feb 2025 20:29:43 +0000 Subject: [PATCH 128/191] Install sudo and ninja in the dev container Dockerfile --- docker/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/Dockerfile b/docker/Dockerfile index e6d92aae96..cc63c343f5 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -15,11 +15,13 @@ RUN apt-get update -qq \ cmake \ git \ make \ + ninja-build \ nodejs \ python3 \ python3-pip \ python3-pil \ python-is-python3 \ + sudo \ tar \ unzip \ wget \ From 97ceb8b10466f62fd7ddbe9817f8fa901ccfbbc9 Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Sat, 1 Mar 2025 16:43:07 +0000 Subject: [PATCH 129/191] Add basic CMakePresets.json file Everything is set to work in the dev container by default. --- CMakePresets.json | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 CMakePresets.json diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..0cb47a4448 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,68 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 22, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "description": "Default build using devcontainer tools", + "generator": "Ninja", + "hidden": true, + "cacheVariables": { + "ARM_NONE_EABI_TOOLCHAIN_PATH": { + "type": "PATH", + "value": "/opt/gcc-arm-none-eabi-10.3-2021.10" + }, + "NRF5_SDK_PATH": { + "type": "PATH", + "value": "/opt/nRF5_SDK_15.3.0_59ac345" + }, + "BUILD_DFU": { + "type": "BOOL", + "value": "ON" + }, + "BUILD_RESOURCES": { + "type": "BOOL", + "value": "ON" + }, + "TARGET_DEVICE": { + "type": "STRING", + "value": "PINETIME" + } + } + }, + { + "name": "pinetime-debug", + "inherits": "base", + "displayName": "Pinetime Debug", + "description": "Debug build using Ninja", + "binaryDir": "build/debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug" + } + }, + { + "name": "pinetime-release", + "inherits": "base", + "displayName": "Pinetime Release", + "description": "Release build using Ninja", + "binaryDir": "build/release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release" + } + } + ], + "buildPresets": [ + { + "name": "pinetime-release", + "configurePreset": "pinetime-release" + }, + { + "name": "pinetime-debug", + "configurePreset": "pinetime-debug" + } + ] +} From 2b10d4b12e570702bec89a0bfc0063a000218604 Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Sat, 1 Mar 2025 16:43:19 +0000 Subject: [PATCH 130/191] Add build script --- build.sh | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 build.sh diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..78dc9178b0 --- /dev/null +++ b/build.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set euo -pipefail + +cmake --preset pinetime-release +cmake --build --preset pinetime-release From 7b32df9e6b040522789270d564c9d54458c78e78 Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Sat, 1 Mar 2025 19:50:04 +0000 Subject: [PATCH 131/191] Make vibration after timer ends more noticable Replace the single short vibration after timer ends with three ones with longer duration. The single short pulse was very easy to miss. --- src/displayapp/DisplayApp.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 64217c174d..1d0633632f 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -381,7 +381,11 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); } - motorController.RunForDuration(35); + motorController.RunForDuration(100); + vTaskDelay(pdMS_TO_TICKS(500)); + motorController.RunForDuration(100); + vTaskDelay(pdMS_TO_TICKS(500)); + motorController.RunForDuration(100); break; case Messages::AlarmTriggered: if (currentApp == Apps::Alarm) { From 939caf3dd145a73628888f819f3a1a19b015abe8 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 3 Dec 2022 23:09:24 +0100 Subject: [PATCH 132/191] add int calculator --- src/CMakeLists.txt | 1 + src/displayapp/DisplayApp.cpp | 1 + src/displayapp/screens/Calculator.cpp | 160 ++++++++++++++++++++++++++ src/displayapp/screens/Calculator.h | 31 +++++ 4 files changed, 193 insertions(+) create mode 100644 src/displayapp/screens/Calculator.cpp create mode 100644 src/displayapp/screens/Calculator.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f53c85817..7e03d66386 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -381,6 +381,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Metronome.cpp displayapp/screens/Motion.cpp displayapp/screens/Weather.cpp + displayapp/screens/Calculator.cpp displayapp/screens/FirmwareValidation.cpp displayapp/screens/ApplicationList.cpp displayapp/screens/Notifications.cpp diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 1d0633632f..1d82d17fbe 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -31,6 +31,7 @@ #include "displayapp/screens/PassKey.h" #include "displayapp/screens/Error.h" #include "displayapp/screens/Sleep.h" +#include "displayapp/screens/Calculator.h" #include "drivers/Cst816s.h" #include "drivers/St7789.h" diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp new file mode 100644 index 0000000000..8a9def68dd --- /dev/null +++ b/src/displayapp/screens/Calculator.cpp @@ -0,0 +1,160 @@ +#include "Calculator.h" +#include + + +using namespace Pinetime::Applications::Screens; + + +static void eventHandler(lv_obj_t* obj, lv_event_t event) { + auto app = static_cast(obj->user_data); + app->OnButtonEvent(obj, event); +} + +Calculator::~Calculator() { + lv_obj_clean(lv_scr_act()); +} + +static const char* buttonMap[] = { + "7", "8", "9", "<", "\n", + "4", "5", "6", "+-", "\n", + "1", "2", "3", "*/", "\n", + ".", "0", "=", "^", "" +}; + +Calculator::Calculator(DisplayApp* app) : Screen(app) { + resultLabel = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP); + lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT); + lv_label_set_text(resultLabel, "0"); + lv_obj_set_size(resultLabel, 190, 20); + lv_obj_set_pos(resultLabel, 10, 10); + + valueLabel = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_long_mode(valueLabel, LV_LABEL_LONG_CROP); + lv_label_set_align(valueLabel, LV_LABEL_ALIGN_RIGHT); + lv_label_set_text(valueLabel, "0"); + lv_obj_set_size(valueLabel, 190, 20); + lv_obj_set_pos(valueLabel, 10, 40); + + operationLabel = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(operationLabel, ""); + lv_obj_set_size(operationLabel, 20, 20); + lv_obj_set_pos(operationLabel, 210, 40); + + buttonMatrix = lv_btnmatrix_create(lv_scr_act(), nullptr); + buttonMatrix->user_data = this; + lv_obj_set_event_cb(buttonMatrix, eventHandler); + lv_btnmatrix_set_map(buttonMatrix, buttonMap); + lv_obj_set_size(buttonMatrix, 240, 180); + lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); +} + +void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { + if (event == LV_EVENT_CLICKED) { + if (obj == buttonMatrix) { + const char* buttonText = lv_btnmatrix_get_active_btn_text(obj); + + // we only compare the first char because it is enough + switch (*buttonText) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // *buttonText is the first char in buttonText + // "- '0'" results in the int value of the char + // *10 shifts the value one digit to the left so we can add the new digit + value = (value * 10) + (*buttonText - '0'); + break; + + case '.': + break; + + // for every operator we: + // - eval the current operator if value > 0 + // - then set the new operator + // - + and - as well as * and / cycle on the same button + case '+': + if (value != 0) { + Eval(); + } + if (operation == '+') { + operation = '-'; + } else { + operation = '+'; + } + break; + case '*': + if (value != 0) { + Eval(); + } + if (operation == '*') { + operation = '/'; + } else { + operation = '*'; + } + break; + case '^': + if (value != 0) { + Eval(); + } + operation = '^'; + break; + + case '<': + if (value > 0) { + value = 0; + } else { + result = 0; + } + operation = ' '; + break; + case '=': + Eval(); + operation = ' '; + break; + } + lv_label_set_text_fmt(valueLabel, "%d", value); + lv_label_set_text_fmt(resultLabel, "%d", result); + lv_label_set_text(operationLabel, &operation); + } + } +} + +void Calculator::Eval() { + switch (operation) { + case ' ': + case '=': + result = value; + value = 0; + break; + case '+': + result += value; + value = 0; + break; + case '-': + result -= value; + value = 0; + break; + case '*': + result *= value; + value = 0; + break; + case '/': + if (value != 0) { + result /= value; + value = 0; + } + break; + case '^': + result = pow(result, value); + value = 0; + break; + } + operation = ' '; +} diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h new file mode 100644 index 0000000000..c90b1b387a --- /dev/null +++ b/src/displayapp/screens/Calculator.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Screen.h" + + +namespace Pinetime { + namespace Applications { + namespace Screens { + class Calculator : public Screen { + public: + ~Calculator() override; + + Calculator(DisplayApp* app); + + void OnButtonEvent(lv_obj_t* obj, lv_event_t event); + + private: + lv_obj_t* buttonMatrix; + lv_obj_t* valueLabel; + lv_obj_t* resultLabel; + lv_obj_t* operationLabel; + + void Eval(); + + int value = 0; + int result = 0; + char operation = ' '; + }; + } + } +} From 8a9875731061e3e9c4e733c5aee551f0a4a4841f Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Sun, 4 Dec 2022 01:38:21 +0100 Subject: [PATCH 133/191] Fix comparison --- src/displayapp/screens/Calculator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 8a9def68dd..152a5748a3 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -107,7 +107,7 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { break; case '<': - if (value > 0) { + if (value != 0) { value = 0; } else { result = 0; From 7c5070b7511e1e6578c95801c50e0530ad7a8f5a Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 4 Dec 2022 13:10:01 +0100 Subject: [PATCH 134/191] add offset --- src/displayapp/screens/Calculator.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index c90b1b387a..2d12e68fff 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -22,8 +22,10 @@ namespace Pinetime { void Eval(); - int value = 0; - int result = 0; + static constexpr FIXED_POINT_OFFSET = 1000; + + long int value = 0; + long int result = 0; char operation = ' '; }; } From 3a9ec9985b1b29a4a458fcabc4a4141c48d83281 Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 4 Dec 2022 14:12:18 +0100 Subject: [PATCH 135/191] added fixed point numbers, pow is still broken --- src/displayapp/screens/Calculator.cpp | 56 ++++++++++++++++++++++----- src/displayapp/screens/Calculator.h | 3 +- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 152a5748a3..bd4908a47f 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -1,5 +1,6 @@ #include "Calculator.h" #include +#include using namespace Pinetime::Applications::Screens; @@ -25,19 +26,19 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { resultLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP); lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT); - lv_label_set_text(resultLabel, "0"); + lv_label_set_text_fmt(resultLabel, "%d", result); lv_obj_set_size(resultLabel, 190, 20); lv_obj_set_pos(resultLabel, 10, 10); valueLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(valueLabel, LV_LABEL_LONG_CROP); lv_label_set_align(valueLabel, LV_LABEL_ALIGN_RIGHT); - lv_label_set_text(valueLabel, "0"); + lv_label_set_text_fmt(valueLabel, "%d", value); lv_obj_set_size(valueLabel, 190, 20); lv_obj_set_pos(valueLabel, 10, 40); operationLabel = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(operationLabel, ""); + lv_label_set_text_static(operationLabel, &operation); lv_obj_set_size(operationLabel, 20, 20); lv_obj_set_pos(operationLabel, 210, 40); @@ -66,17 +67,32 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { case '7': case '8': case '9': + // if this is true, we already pressed the . button + if (offset < FIXED_POINT_OFFSET) { + value += offset * (*buttonText - '0'); + offset /= 10; + } else { + value *= 10; + value += offset * (*buttonText - '0'); + } // *buttonText is the first char in buttonText // "- '0'" results in the int value of the char - // *10 shifts the value one digit to the left so we can add the new digit - value = (value * 10) + (*buttonText - '0'); + NRF_LOG_INFO(". offset: %d", offset); + NRF_LOG_INFO(". value: %d", value); + NRF_LOG_INFO(". result: %d", result); break; case '.': + if (offset == FIXED_POINT_OFFSET) { + offset /= 10; + } + NRF_LOG_INFO(". offset: %d", offset); + NRF_LOG_INFO(". value: %d", value); + NRF_LOG_INFO(". result: %d", result); break; // for every operator we: - // - eval the current operator if value > 0 + // - eval the current operator if value > FIXED_POINT_OFFSET // - then set the new operator // - + and - as well as * and / cycle on the same button case '+': @@ -119,9 +135,23 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { operation = ' '; break; } - lv_label_set_text_fmt(valueLabel, "%d", value); - lv_label_set_text_fmt(resultLabel, "%d", result); - lv_label_set_text(operationLabel, &operation); + + // show values, spare . if no remainder + int valueRemainder = value % FIXED_POINT_OFFSET; + if (valueRemainder || offset < FIXED_POINT_OFFSET) { + lv_label_set_text_fmt(valueLabel, "%d.%d", value / FIXED_POINT_OFFSET, valueRemainder); + } else { + lv_label_set_text_fmt(valueLabel, "%d", value / FIXED_POINT_OFFSET); + } + int resultRemainder = result % FIXED_POINT_OFFSET; + if (resultRemainder) { + lv_label_set_text_fmt(resultLabel, "%d.%d", result / FIXED_POINT_OFFSET, resultRemainder); + } else { + lv_label_set_text_fmt(resultLabel, "%d", result / FIXED_POINT_OFFSET); + } + + // show operation + lv_label_set_text_static(operationLabel, &operation); } } } @@ -143,18 +173,24 @@ void Calculator::Eval() { break; case '*': result *= value; + // fixed point offset was multiplied too + result /= FIXED_POINT_OFFSET; value = 0; break; case '/': - if (value != 0) { + if (value != FIXED_POINT_OFFSET) { + // fixed point offset will be divided too + result *= FIXED_POINT_OFFSET; result /= value; value = 0; } break; + // TODO pow is totally broken with fixed point numbers case '^': result = pow(result, value); value = 0; break; } operation = ' '; + offset = FIXED_POINT_OFFSET; } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 2d12e68fff..b74ff7bd1a 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -22,7 +22,8 @@ namespace Pinetime { void Eval(); - static constexpr FIXED_POINT_OFFSET = 1000; + static constexpr int FIXED_POINT_OFFSET = 1000; + int offset = FIXED_POINT_OFFSET; long int value = 0; long int result = 0; From 8bb3d9b73d1483e0c818d09ba8e0495a3d9e53a7 Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 4 Dec 2022 15:51:56 +0100 Subject: [PATCH 136/191] added pow with floats --- src/displayapp/screens/Calculator.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index bd4908a47f..40ad565446 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -185,9 +185,18 @@ void Calculator::Eval() { value = 0; } break; - // TODO pow is totally broken with fixed point numbers + + // we use floats here because pow with fixed point numbers is weird case '^': - result = pow(result, value); + float tmp_value = (float)value; + tmp_value /= FIXED_POINT_OFFSET; + + float tmp_result = (float)result; + tmp_result /= FIXED_POINT_OFFSET; + + tmp_result = pow(tmp_result, tmp_value); + result = (long) (tmp_result * FIXED_POINT_OFFSET); + value = 0; break; } From df09603c62133cd44e875dedddba461a59f38a51 Mon Sep 17 00:00:00 2001 From: minacode Date: Mon, 5 Dec 2022 17:34:49 +0100 Subject: [PATCH 137/191] added calculator symbol --- src/displayapp/fonts/fonts.json | 2 +- src/displayapp/screens/Symbols.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 85e3269088..92a5b3f12f 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf06e, 0xf015, 0xf00c, 0xf0f3, 0xf522, 0xf743, 0xf236" + "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf00c, 0xf1ec, 0xf743, 0xf0f3, 0xf522, 0xf236" } ], "bpp": 1, diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index 6bd5f0efe7..a4ec474b80 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -40,6 +40,7 @@ namespace Pinetime { static constexpr const char* home = "\xEF\x80\x95"; static constexpr const char* sleep = "\xEE\xBD\x84"; static constexpr const char* bed = "\xEF\x88\xB6"; + static constexpr const char* calculator = "\xEF\x87\xAC"; // fontawesome_weathericons.c // static constexpr const char* sun = "\xEF\x86\x85"; From d0a1fdbc0fe7c1679683f5eb19ab8d37a083ffe3 Mon Sep 17 00:00:00 2001 From: minacode Date: Mon, 5 Dec 2022 17:35:26 +0100 Subject: [PATCH 138/191] fixes and cleanup --- src/displayapp/screens/Calculator.cpp | 77 ++++++++++++++++++--------- src/displayapp/screens/Calculator.h | 8 ++- 2 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 40ad565446..fc05136037 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -27,26 +27,27 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP); lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT); lv_label_set_text_fmt(resultLabel, "%d", result); - lv_obj_set_size(resultLabel, 190, 20); + lv_obj_set_size(resultLabel, 142, 20); lv_obj_set_pos(resultLabel, 10, 10); valueLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(valueLabel, LV_LABEL_LONG_CROP); lv_label_set_align(valueLabel, LV_LABEL_ALIGN_RIGHT); lv_label_set_text_fmt(valueLabel, "%d", value); - lv_obj_set_size(valueLabel, 190, 20); + lv_obj_set_size(valueLabel, 142, 20); lv_obj_set_pos(valueLabel, 10, 40); operationLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(operationLabel, &operation); lv_obj_set_size(operationLabel, 20, 20); - lv_obj_set_pos(operationLabel, 210, 40); + lv_obj_set_pos(operationLabel, 195, 40); buttonMatrix = lv_btnmatrix_create(lv_scr_act(), nullptr); buttonMatrix->user_data = this; lv_obj_set_event_cb(buttonMatrix, eventHandler); lv_btnmatrix_set_map(buttonMatrix, buttonMap); - lv_obj_set_size(buttonMatrix, 240, 180); + lv_obj_set_size(buttonMatrix, 238, 180); + lv_obj_set_style_local_pad_inner(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); } @@ -69,14 +70,16 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { case '9': // if this is true, we already pressed the . button if (offset < FIXED_POINT_OFFSET) { + // *buttonText is the first char in buttonText + // "- '0'" results in the int value of the char value += offset * (*buttonText - '0'); offset /= 10; } else { value *= 10; value += offset * (*buttonText - '0'); } - // *buttonText is the first char in buttonText - // "- '0'" results in the int value of the char + UpdateLabel(valueLabel, value); + NRF_LOG_INFO(". offset: %d", offset); NRF_LOG_INFO(". value: %d", value); NRF_LOG_INFO(". result: %d", result); @@ -86,6 +89,8 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (offset == FIXED_POINT_OFFSET) { offset /= 10; } + UpdateLabel(valueLabel, value); + NRF_LOG_INFO(". offset: %d", offset); NRF_LOG_INFO(". value: %d", value); NRF_LOG_INFO(". result: %d", result); @@ -104,6 +109,7 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } else { operation = '+'; } + lv_label_refr_text(operationLabel); break; case '*': if (value != 0) { @@ -114,45 +120,65 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } else { operation = '*'; } + lv_label_refr_text(operationLabel); break; case '^': if (value != 0) { Eval(); } operation = '^'; + lv_label_refr_text(operationLabel); break; case '<': + offset = FIXED_POINT_OFFSET; if (value != 0) { value = 0; } else { result = 0; + UpdateLabel(resultLabel, result); } + UpdateLabel(valueLabel, value); + operation = ' '; + lv_label_refr_text(operationLabel); break; case '=': Eval(); operation = ' '; + lv_label_refr_text(operationLabel); break; } - - // show values, spare . if no remainder - int valueRemainder = value % FIXED_POINT_OFFSET; - if (valueRemainder || offset < FIXED_POINT_OFFSET) { - lv_label_set_text_fmt(valueLabel, "%d.%d", value / FIXED_POINT_OFFSET, valueRemainder); - } else { - lv_label_set_text_fmt(valueLabel, "%d", value / FIXED_POINT_OFFSET); - } - int resultRemainder = result % FIXED_POINT_OFFSET; - if (resultRemainder) { - lv_label_set_text_fmt(resultLabel, "%d.%d", result / FIXED_POINT_OFFSET, resultRemainder); - } else { - lv_label_set_text_fmt(resultLabel, "%d", result / FIXED_POINT_OFFSET); } + } +} + +void Calculator::UpdateLabel(lv_obj_t* label, long int number) { + long int remainder = number % FIXED_POINT_OFFSET; + // remove sign from remainder + if (remainder < 0) { + remainder *= -1; + } - // show operation - lv_label_set_text_static(operationLabel, &operation); + // remove trailing zeros because its more beautiful + long int printRemainder = remainder; + while (printRemainder > 0 && printRemainder % 10 == 0) { + printRemainder /= 10; + } + + // we have to print a . and leading zeros in some cases + if (remainder || (offset < FIXED_POINT_OFFSET)) { + if (remainder == 0) { + lv_label_set_text_fmt(label, "%d.", number / FIXED_POINT_OFFSET); + } else if (remainder < 10) { + lv_label_set_text_fmt(label, "%d.00%d", number / FIXED_POINT_OFFSET, printRemainder); + } else if (remainder < 100) { + lv_label_set_text_fmt(label, "%d.0%d", number / FIXED_POINT_OFFSET, printRemainder); + } else { + lv_label_set_text_fmt(label, "%d.%d", number / FIXED_POINT_OFFSET, printRemainder); } + } else { + lv_label_set_text_fmt(label, "%d", number / FIXED_POINT_OFFSET); } } @@ -188,18 +214,21 @@ void Calculator::Eval() { // we use floats here because pow with fixed point numbers is weird case '^': - float tmp_value = (float)value; + float tmp_value = (float) value; tmp_value /= FIXED_POINT_OFFSET; - float tmp_result = (float)result; + float tmp_result = (float) result; tmp_result /= FIXED_POINT_OFFSET; tmp_result = pow(tmp_result, tmp_value); - result = (long) (tmp_result * FIXED_POINT_OFFSET); + result = (long int) (tmp_result * FIXED_POINT_OFFSET); value = 0; break; } operation = ' '; offset = FIXED_POINT_OFFSET; + + UpdateLabel(valueLabel, value); + UpdateLabel(resultLabel, result); } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index b74ff7bd1a..db1603b6f0 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -21,9 +21,13 @@ namespace Pinetime { lv_obj_t* operationLabel; void Eval(); + void UpdateLabel(lv_obj_t* label, long int number); - static constexpr int FIXED_POINT_OFFSET = 1000; - int offset = FIXED_POINT_OFFSET; + // offset is the current offset for new digits + // standard is FIXED_POINT_OFFSET for 3 decimal places + // after typing a . this gets divided by 10 with each input + static constexpr long int FIXED_POINT_OFFSET = 1000; + long int offset = FIXED_POINT_OFFSET; long int value = 0; long int result = 0; From 7ef407fc8a3519fac2f57f7c292b9844a005ed29 Mon Sep 17 00:00:00 2001 From: minacode Date: Wed, 7 Dec 2022 15:06:40 +0100 Subject: [PATCH 139/191] make buttons bigger --- src/displayapp/screens/Calculator.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index fc05136037..a392672cfe 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -27,20 +27,20 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP); lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT); lv_label_set_text_fmt(resultLabel, "%d", result); - lv_obj_set_size(resultLabel, 142, 20); - lv_obj_set_pos(resultLabel, 10, 10); + lv_obj_set_size(resultLabel, 145, 20); + lv_obj_set_pos(resultLabel, 10, 5); valueLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(valueLabel, LV_LABEL_LONG_CROP); lv_label_set_align(valueLabel, LV_LABEL_ALIGN_RIGHT); lv_label_set_text_fmt(valueLabel, "%d", value); - lv_obj_set_size(valueLabel, 142, 20); - lv_obj_set_pos(valueLabel, 10, 40); + lv_obj_set_size(valueLabel, 145, 20); + lv_obj_set_pos(valueLabel, 10, 35); operationLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(operationLabel, &operation); lv_obj_set_size(operationLabel, 20, 20); - lv_obj_set_pos(operationLabel, 195, 40); + lv_obj_set_pos(operationLabel, 203, 35); buttonMatrix = lv_btnmatrix_create(lv_scr_act(), nullptr); buttonMatrix->user_data = this; @@ -48,6 +48,10 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_btnmatrix_set_map(buttonMatrix, buttonMap); lv_obj_set_size(buttonMatrix, 238, 180); lv_obj_set_style_local_pad_inner(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); + lv_obj_set_style_local_pad_top(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); + lv_obj_set_style_local_pad_bottom(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); + lv_obj_set_style_local_pad_left(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); + lv_obj_set_style_local_pad_right(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); } From 53d9759d6954adf77419b52e2cb54fc440261e89 Mon Sep 17 00:00:00 2001 From: minacode Date: Wed, 7 Dec 2022 17:36:40 +0100 Subject: [PATCH 140/191] fixed number displays --- src/displayapp/screens/Calculator.cpp | 119 ++++++++++++++++++-------- src/displayapp/screens/Calculator.h | 5 +- 2 files changed, 86 insertions(+), 38 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index a392672cfe..29f7437c3d 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -38,7 +38,7 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_obj_set_pos(valueLabel, 10, 35); operationLabel = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(operationLabel, &operation); + lv_label_set_text_static(operationLabel, operation); lv_obj_set_size(operationLabel, 20, 20); lv_obj_set_pos(operationLabel, 203, 35); @@ -60,6 +60,10 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (obj == buttonMatrix) { const char* buttonText = lv_btnmatrix_get_active_btn_text(obj); + if (buttonText == nullptr) { + return; + } + // we only compare the first char because it is enough switch (*buttonText) { case '0': @@ -82,7 +86,7 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { value *= 10; value += offset * (*buttonText - '0'); } - UpdateLabel(valueLabel, value); + UpdateValueLabel(); NRF_LOG_INFO(". offset: %d", offset); NRF_LOG_INFO(". value: %d", value); @@ -93,7 +97,7 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (offset == FIXED_POINT_OFFSET) { offset /= 10; } - UpdateLabel(valueLabel, value); + UpdateValueLabel(); NRF_LOG_INFO(". offset: %d", offset); NRF_LOG_INFO(". value: %d", value); @@ -108,10 +112,10 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (value != 0) { Eval(); } - if (operation == '+') { - operation = '-'; + if (*operation == '+') { + *operation = '-'; } else { - operation = '+'; + *operation = '+'; } lv_label_refr_text(operationLabel); break; @@ -119,10 +123,10 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (value != 0) { Eval(); } - if (operation == '*') { - operation = '/'; + if (*operation == '*') { + *operation = '/'; } else { - operation = '*'; + *operation = '*'; } lv_label_refr_text(operationLabel); break; @@ -130,7 +134,7 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { if (value != 0) { Eval(); } - operation = '^'; + *operation = '^'; lv_label_refr_text(operationLabel); break; @@ -140,16 +144,16 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { value = 0; } else { result = 0; - UpdateLabel(resultLabel, result); + UpdateResultLabel(); } - UpdateLabel(valueLabel, value); + UpdateValueLabel(); - operation = ' '; + *operation = ' '; lv_label_refr_text(operationLabel); break; case '=': Eval(); - operation = ' '; + *operation = ' '; lv_label_refr_text(operationLabel); break; } @@ -157,37 +161,80 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } } -void Calculator::UpdateLabel(lv_obj_t* label, long int number) { - long int remainder = number % FIXED_POINT_OFFSET; - // remove sign from remainder - if (remainder < 0) { - remainder *= -1; +void Calculator::UpdateResultLabel() { + NRF_LOG_INFO("update result label"); + + long int integer = result / FIXED_POINT_OFFSET; + long int remainder = result % FIXED_POINT_OFFSET; + + // todo zero padding + if (remainder == 0) { + lv_label_set_text_fmt(resultLabel, "%ld", integer); + return; } - // remove trailing zeros because its more beautiful long int printRemainder = remainder; - while (printRemainder > 0 && printRemainder % 10 == 0) { + while ((printRemainder > 0) && (printRemainder % 10 == 0)) { + NRF_LOG_INFO("pr: %ld", printRemainder); printRemainder /= 10; } - // we have to print a . and leading zeros in some cases - if (remainder || (offset < FIXED_POINT_OFFSET)) { - if (remainder == 0) { - lv_label_set_text_fmt(label, "%d.", number / FIXED_POINT_OFFSET); - } else if (remainder < 10) { - lv_label_set_text_fmt(label, "%d.00%d", number / FIXED_POINT_OFFSET, printRemainder); - } else if (remainder < 100) { - lv_label_set_text_fmt(label, "%d.0%d", number / FIXED_POINT_OFFSET, printRemainder); - } else { - lv_label_set_text_fmt(label, "%d.%d", number / FIXED_POINT_OFFSET, printRemainder); + int padding = 0; + long int tmp = FIXED_POINT_OFFSET; + while (tmp > remainder) { + tmp /= 10; + padding++; + } + + lv_label_set_text_fmt( + resultLabel, + "%ld.%0*u", + integer, + padding, + printRemainder + ); +} + +void Calculator::UpdateValueLabel() { + long int integer = value / FIXED_POINT_OFFSET; + long int remainder = value % FIXED_POINT_OFFSET; + + long int printRemainder; + int padding; + + if (offset == 0) { + printRemainder = remainder; + padding = 3; + } else { + printRemainder = remainder / (10*offset); + padding = 0; + + // calculate the padding length as the length difference + // between FIXED_POINT_OFFSET and offset + long int tmp = FIXED_POINT_OFFSET / (10*offset); + while (tmp > 1) { + padding ++; + tmp /= 10; } + } + + if (offset == FIXED_POINT_OFFSET) { + lv_label_set_text_fmt(valueLabel, "%ld", integer); + } else if ((offset == FIXED_POINT_OFFSET / 10) && (remainder == 0)) { + lv_label_set_text_fmt(valueLabel, "%ld.", integer); } else { - lv_label_set_text_fmt(label, "%d", number / FIXED_POINT_OFFSET); + lv_label_set_text_fmt( + valueLabel, + "%ld.%0*u", + integer, + padding, + printRemainder + ); } } void Calculator::Eval() { - switch (operation) { + switch (*operation) { case ' ': case '=': result = value; @@ -230,9 +277,9 @@ void Calculator::Eval() { value = 0; break; } - operation = ' '; + *operation = ' '; offset = FIXED_POINT_OFFSET; - UpdateLabel(valueLabel, value); - UpdateLabel(resultLabel, result); + UpdateValueLabel(); + UpdateResultLabel(); } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index db1603b6f0..5bcec86a47 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -21,7 +21,8 @@ namespace Pinetime { lv_obj_t* operationLabel; void Eval(); - void UpdateLabel(lv_obj_t* label, long int number); + void UpdateValueLabel(); + void UpdateResultLabel(); // offset is the current offset for new digits // standard is FIXED_POINT_OFFSET for 3 decimal places @@ -31,7 +32,7 @@ namespace Pinetime { long int value = 0; long int result = 0; - char operation = ' '; + char operation[2] {" "}; }; } } From 7b988308943ba8ba8a86b43c32cde7e3d6c2d253 Mon Sep 17 00:00:00 2001 From: minacode Date: Thu, 8 Dec 2022 20:43:47 +0100 Subject: [PATCH 141/191] format --- src/displayapp/screens/Calculator.cpp | 33 +++++---------------- src/displayapp/screens/Calculator.h | 41 +++++++++++++-------------- 2 files changed, 27 insertions(+), 47 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 29f7437c3d..5153afa573 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -2,10 +2,8 @@ #include #include - using namespace Pinetime::Applications::Screens; - static void eventHandler(lv_obj_t* obj, lv_event_t event) { auto app = static_cast(obj->user_data); app->OnButtonEvent(obj, event); @@ -15,12 +13,7 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* buttonMap[] = { - "7", "8", "9", "<", "\n", - "4", "5", "6", "+-", "\n", - "1", "2", "3", "*/", "\n", - ".", "0", "=", "^", "" -}; +static const char* buttonMap[] = {"7", "8", "9", "<", "\n", "4", "5", "6", "+-", "\n", "1", "2", "3", "*/", "\n", ".", "0", "=", "^", ""}; Calculator::Calculator(DisplayApp* app) : Screen(app) { resultLabel = lv_label_create(lv_scr_act(), nullptr); @@ -186,13 +179,7 @@ void Calculator::UpdateResultLabel() { padding++; } - lv_label_set_text_fmt( - resultLabel, - "%ld.%0*u", - integer, - padding, - printRemainder - ); + lv_label_set_text_fmt(resultLabel, "%ld.%0*u", integer, padding, printRemainder); } void Calculator::UpdateValueLabel() { @@ -201,19 +188,19 @@ void Calculator::UpdateValueLabel() { long int printRemainder; int padding; - + if (offset == 0) { printRemainder = remainder; padding = 3; } else { - printRemainder = remainder / (10*offset); + printRemainder = remainder / (10 * offset); padding = 0; // calculate the padding length as the length difference // between FIXED_POINT_OFFSET and offset - long int tmp = FIXED_POINT_OFFSET / (10*offset); + long int tmp = FIXED_POINT_OFFSET / (10 * offset); while (tmp > 1) { - padding ++; + padding++; tmp /= 10; } } @@ -223,13 +210,7 @@ void Calculator::UpdateValueLabel() { } else if ((offset == FIXED_POINT_OFFSET / 10) && (remainder == 0)) { lv_label_set_text_fmt(valueLabel, "%ld.", integer); } else { - lv_label_set_text_fmt( - valueLabel, - "%ld.%0*u", - integer, - padding, - printRemainder - ); + lv_label_set_text_fmt(valueLabel, "%ld.%0*u", integer, padding, printRemainder); } } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 5bcec86a47..52ff6d4ba7 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -2,37 +2,36 @@ #include "Screen.h" - namespace Pinetime { namespace Applications { namespace Screens { class Calculator : public Screen { - public: - ~Calculator() override; + public: + ~Calculator() override; - Calculator(DisplayApp* app); + Calculator(DisplayApp* app); - void OnButtonEvent(lv_obj_t* obj, lv_event_t event); + void OnButtonEvent(lv_obj_t* obj, lv_event_t event); - private: - lv_obj_t* buttonMatrix; - lv_obj_t* valueLabel; - lv_obj_t* resultLabel; - lv_obj_t* operationLabel; + private: + lv_obj_t* buttonMatrix; + lv_obj_t* valueLabel; + lv_obj_t* resultLabel; + lv_obj_t* operationLabel; - void Eval(); - void UpdateValueLabel(); - void UpdateResultLabel(); + void Eval(); + void UpdateValueLabel(); + void UpdateResultLabel(); - // offset is the current offset for new digits - // standard is FIXED_POINT_OFFSET for 3 decimal places - // after typing a . this gets divided by 10 with each input - static constexpr long int FIXED_POINT_OFFSET = 1000; - long int offset = FIXED_POINT_OFFSET; + // offset is the current offset for new digits + // standard is FIXED_POINT_OFFSET for 3 decimal places + // after typing a . this gets divided by 10 with each input + static constexpr long int FIXED_POINT_OFFSET = 1000; + long int offset = FIXED_POINT_OFFSET; - long int value = 0; - long int result = 0; - char operation[2] {" "}; + long int value = 0; + long int result = 0; + char operation[2] {" "}; }; } } From ea121a7e5f9471cd0421708d55c901d0ee9368c5 Mon Sep 17 00:00:00 2001 From: minacode Date: Fri, 9 Dec 2022 17:57:35 +0100 Subject: [PATCH 142/191] changed long int to int64_t --- src/displayapp/screens/Calculator.cpp | 47 ++++++++++++++------------- src/displayapp/screens/Calculator.h | 4 +-- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 5153afa573..228dbadbc1 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -1,5 +1,6 @@ #include "Calculator.h" #include +#include #include using namespace Pinetime::Applications::Screens; @@ -19,14 +20,14 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { resultLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP); lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT); - lv_label_set_text_fmt(resultLabel, "%d", result); + lv_label_set_text_fmt(resultLabel, "%" PRId64, result); lv_obj_set_size(resultLabel, 145, 20); lv_obj_set_pos(resultLabel, 10, 5); valueLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(valueLabel, LV_LABEL_LONG_CROP); lv_label_set_align(valueLabel, LV_LABEL_ALIGN_RIGHT); - lv_label_set_text_fmt(valueLabel, "%d", value); + lv_label_set_text_fmt(valueLabel, "%" PRId64, value); lv_obj_set_size(valueLabel, 145, 20); lv_obj_set_pos(valueLabel, 10, 35); @@ -81,9 +82,9 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } UpdateValueLabel(); - NRF_LOG_INFO(". offset: %d", offset); - NRF_LOG_INFO(". value: %d", value); - NRF_LOG_INFO(". result: %d", result); + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); break; case '.': @@ -92,9 +93,9 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } UpdateValueLabel(); - NRF_LOG_INFO(". offset: %d", offset); - NRF_LOG_INFO(". value: %d", value); - NRF_LOG_INFO(". result: %d", result); + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); break; // for every operator we: @@ -157,36 +158,36 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { void Calculator::UpdateResultLabel() { NRF_LOG_INFO("update result label"); - long int integer = result / FIXED_POINT_OFFSET; - long int remainder = result % FIXED_POINT_OFFSET; + int64_t integer = result / FIXED_POINT_OFFSET; + int64_t remainder = result % FIXED_POINT_OFFSET; // todo zero padding if (remainder == 0) { - lv_label_set_text_fmt(resultLabel, "%ld", integer); + lv_label_set_text_fmt(resultLabel, "%" PRId64, integer); return; } - long int printRemainder = remainder; + int64_t printRemainder = remainder; while ((printRemainder > 0) && (printRemainder % 10 == 0)) { - NRF_LOG_INFO("pr: %ld", printRemainder); + NRF_LOG_INFO("pr: %" PRId64, printRemainder); printRemainder /= 10; } int padding = 0; - long int tmp = FIXED_POINT_OFFSET; + int64_t tmp = FIXED_POINT_OFFSET; while (tmp > remainder) { tmp /= 10; padding++; } - lv_label_set_text_fmt(resultLabel, "%ld.%0*u", integer, padding, printRemainder); + lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*u", integer, padding, printRemainder); } void Calculator::UpdateValueLabel() { - long int integer = value / FIXED_POINT_OFFSET; - long int remainder = value % FIXED_POINT_OFFSET; + int64_t integer = value / FIXED_POINT_OFFSET; + int64_t remainder = value % FIXED_POINT_OFFSET; - long int printRemainder; + int64_t printRemainder; int padding; if (offset == 0) { @@ -198,7 +199,7 @@ void Calculator::UpdateValueLabel() { // calculate the padding length as the length difference // between FIXED_POINT_OFFSET and offset - long int tmp = FIXED_POINT_OFFSET / (10 * offset); + int64_t tmp = FIXED_POINT_OFFSET / (10 * offset); while (tmp > 1) { padding++; tmp /= 10; @@ -206,11 +207,11 @@ void Calculator::UpdateValueLabel() { } if (offset == FIXED_POINT_OFFSET) { - lv_label_set_text_fmt(valueLabel, "%ld", integer); + lv_label_set_text_fmt(valueLabel, "%" PRId64, integer); } else if ((offset == FIXED_POINT_OFFSET / 10) && (remainder == 0)) { - lv_label_set_text_fmt(valueLabel, "%ld.", integer); + lv_label_set_text_fmt(valueLabel, "%" PRId64 ".", integer); } else { - lv_label_set_text_fmt(valueLabel, "%ld.%0*u", integer, padding, printRemainder); + lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*u", integer, padding, printRemainder); } } @@ -253,7 +254,7 @@ void Calculator::Eval() { tmp_result /= FIXED_POINT_OFFSET; tmp_result = pow(tmp_result, tmp_value); - result = (long int) (tmp_result * FIXED_POINT_OFFSET); + result = (int64_t) (tmp_result * FIXED_POINT_OFFSET); value = 0; break; diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 52ff6d4ba7..cd97744c19 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -29,8 +29,8 @@ namespace Pinetime { static constexpr long int FIXED_POINT_OFFSET = 1000; long int offset = FIXED_POINT_OFFSET; - long int value = 0; - long int result = 0; + int64_t value = 0; + int64_t result = 0; char operation[2] {" "}; }; } From a5a99e16032a2199834017bc82a5ba63b0cb65c4 Mon Sep 17 00:00:00 2001 From: minacode Date: Fri, 9 Dec 2022 18:14:24 +0100 Subject: [PATCH 143/191] change float to double --- src/displayapp/screens/Calculator.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 228dbadbc1..c3b119f32e 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -247,14 +247,15 @@ void Calculator::Eval() { // we use floats here because pow with fixed point numbers is weird case '^': - float tmp_value = (float) value; + double tmp_value = (double) value; tmp_value /= FIXED_POINT_OFFSET; - float tmp_result = (float) result; + double tmp_result = (double) result; tmp_result /= FIXED_POINT_OFFSET; tmp_result = pow(tmp_result, tmp_value); - result = (int64_t) (tmp_result * FIXED_POINT_OFFSET); + tmp_result *= FIXED_POINT_OFFSET; + result = (int64_t) tmp_result; value = 0; break; From 7dbf6da5124443ca2c2f12267fe98f937bb62012 Mon Sep 17 00:00:00 2001 From: minacode Date: Mon, 19 Dec 2022 17:42:45 +0100 Subject: [PATCH 144/191] fixed crashes --- src/displayapp/screens/Calculator.cpp | 17 ++++++++--------- src/displayapp/screens/Calculator.h | 4 ++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index c3b119f32e..025d078287 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -167,13 +167,13 @@ void Calculator::UpdateResultLabel() { return; } - int64_t printRemainder = remainder; + int64_t printRemainder = remainder < 0 ? -remainder : remainder; while ((printRemainder > 0) && (printRemainder % 10 == 0)) { NRF_LOG_INFO("pr: %" PRId64, printRemainder); printRemainder /= 10; } - int padding = 0; + uint8_t padding = 0; int64_t tmp = FIXED_POINT_OFFSET; while (tmp > remainder) { tmp /= 10; @@ -187,14 +187,13 @@ void Calculator::UpdateValueLabel() { int64_t integer = value / FIXED_POINT_OFFSET; int64_t remainder = value % FIXED_POINT_OFFSET; - int64_t printRemainder; - int padding; + int64_t printRemainder = remainder < 0 ? -remainder : remainder; + uint8_t padding; if (offset == 0) { - printRemainder = remainder; padding = 3; } else { - printRemainder = remainder / (10 * offset); + printRemainder /= (10 * offset); padding = 0; // calculate the padding length as the length difference @@ -247,15 +246,15 @@ void Calculator::Eval() { // we use floats here because pow with fixed point numbers is weird case '^': - double tmp_value = (double) value; + double tmp_value = static_cast(value); tmp_value /= FIXED_POINT_OFFSET; - double tmp_result = (double) result; + double tmp_result = static_cast(result); tmp_result /= FIXED_POINT_OFFSET; tmp_result = pow(tmp_result, tmp_value); tmp_result *= FIXED_POINT_OFFSET; - result = (int64_t) tmp_result; + result = static_cast(tmp_result); value = 0; break; diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index cd97744c19..3a6f9ae4e8 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -26,8 +26,8 @@ namespace Pinetime { // offset is the current offset for new digits // standard is FIXED_POINT_OFFSET for 3 decimal places // after typing a . this gets divided by 10 with each input - static constexpr long int FIXED_POINT_OFFSET = 1000; - long int offset = FIXED_POINT_OFFSET; + static constexpr int64_t FIXED_POINT_OFFSET = 1000; + int64_t offset = FIXED_POINT_OFFSET; int64_t value = 0; int64_t result = 0; From 6abc42e31b334cd956463d930b49d861cbe5f8ee Mon Sep 17 00:00:00 2001 From: minacode Date: Mon, 19 Dec 2022 23:06:47 +0100 Subject: [PATCH 145/191] WIP: refactored the prints --- src/displayapp/screens/Calculator.cpp | 62 +++++++++++++-------------- src/displayapp/screens/Calculator.h | 24 +++++++++-- 2 files changed, 50 insertions(+), 36 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 025d078287..7ebcc829a2 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -156,31 +156,27 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } void Calculator::UpdateResultLabel() { - NRF_LOG_INFO("update result label"); - int64_t integer = result / FIXED_POINT_OFFSET; int64_t remainder = result % FIXED_POINT_OFFSET; - // todo zero padding if (remainder == 0) { lv_label_set_text_fmt(resultLabel, "%" PRId64, integer); return; } - int64_t printRemainder = remainder < 0 ? -remainder : remainder; - while ((printRemainder > 0) && (printRemainder % 10 == 0)) { - NRF_LOG_INFO("pr: %" PRId64, printRemainder); - printRemainder /= 10; + if (remainder < 0) { + remainder = -remainder; } - uint8_t padding = 0; - int64_t tmp = FIXED_POINT_OFFSET; - while (tmp > remainder) { - tmp /= 10; - padding++; + uint8_t min_width = N_DECIMALS; + + // cut "0"-digits on the right + while ((remainder > 0) && (remainder % 10 == 0)) { + remainder /= 10; + min_width--; } - lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*u", integer, padding, printRemainder); + lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, remainder); } void Calculator::UpdateValueLabel() { @@ -188,29 +184,31 @@ void Calculator::UpdateValueLabel() { int64_t remainder = value % FIXED_POINT_OFFSET; int64_t printRemainder = remainder < 0 ? -remainder : remainder; - uint8_t padding; - if (offset == 0) { - padding = 3; - } else { - printRemainder /= (10 * offset); - padding = 0; - - // calculate the padding length as the length difference - // between FIXED_POINT_OFFSET and offset - int64_t tmp = FIXED_POINT_OFFSET / (10 * offset); - while (tmp > 1) { - padding++; - tmp /= 10; - } + uint8_t min_width = 0; + int64_t tmp_offset = offset; + + // TODO there has to be a simpler way to do this + if (tmp_offset == 0) { + tmp_offset = 1; + min_width = 1; + } + while (tmp_offset < FIXED_POINT_OFFSET) { + tmp_offset *= 10; + min_width++; + } + min_width--; + + for (uint8_t i = min_width; i < N_DECIMALS; i++) { + printRemainder /= 10; } if (offset == FIXED_POINT_OFFSET) { lv_label_set_text_fmt(valueLabel, "%" PRId64, integer); - } else if ((offset == FIXED_POINT_OFFSET / 10) && (remainder == 0)) { + } else if ((offset == (FIXED_POINT_OFFSET / 10)) && (remainder == 0)) { lv_label_set_text_fmt(valueLabel, "%" PRId64 ".", integer); } else { - lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*u", integer, padding, printRemainder); + lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, printRemainder); } } @@ -247,13 +245,13 @@ void Calculator::Eval() { // we use floats here because pow with fixed point numbers is weird case '^': double tmp_value = static_cast(value); - tmp_value /= FIXED_POINT_OFFSET; + tmp_value /= static_cast(FIXED_POINT_OFFSET); double tmp_result = static_cast(result); - tmp_result /= FIXED_POINT_OFFSET; + tmp_result /= static_cast(FIXED_POINT_OFFSET); tmp_result = pow(tmp_result, tmp_value); - tmp_result *= FIXED_POINT_OFFSET; + tmp_result *= static_cast(FIXED_POINT_OFFSET); result = static_cast(tmp_result); value = 0; diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 3a6f9ae4e8..dac520cf89 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -2,6 +2,17 @@ #include "Screen.h" +namespace { + int64_t constexpr powi(int64_t base, uint8_t exponent) { + int64_t value = 1; + while (exponent) { + value *= base; + exponent--; + } + return value; + } +} + namespace Pinetime { namespace Applications { namespace Screens { @@ -23,14 +34,19 @@ namespace Pinetime { void UpdateValueLabel(); void UpdateResultLabel(); - // offset is the current offset for new digits - // standard is FIXED_POINT_OFFSET for 3 decimal places - // after typing a . this gets divided by 10 with each input - static constexpr int64_t FIXED_POINT_OFFSET = 1000; + // change this if you want to change the number of decimals + static constexpr uint8_t N_DECIMALS = 4; + // this is the constant default offset + static constexpr int64_t FIXED_POINT_OFFSET = powi(10, N_DECIMALS); + // this is the current offset, may wary after pressing '.' int64_t offset = FIXED_POINT_OFFSET; int64_t value = 0; int64_t result = 0; + // this has length 2 because it must be a string + // because we also use it as the buffer for the operationLabel + // the second char is always \0 + // we only care about the first char char operation[2] {" "}; }; } From c48dfe4b4392f1d3990650f4d104bed24f0b9cf0 Mon Sep 17 00:00:00 2001 From: minacode Date: Tue, 20 Dec 2022 19:30:07 +0100 Subject: [PATCH 146/191] set value bounds and checks --- src/displayapp/screens/Calculator.cpp | 24 ++++++++++++++++++++++-- src/displayapp/screens/Calculator.h | 6 ++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 7ebcc829a2..b99abf0672 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -76,7 +76,7 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { // "- '0'" results in the int value of the char value += offset * (*buttonText - '0'); offset /= 10; - } else { + } else if (value <= MAX_VALUE / 10) { value *= 10; value += offset * (*buttonText - '0'); } @@ -220,21 +220,41 @@ void Calculator::Eval() { value = 0; break; case '+': + // check for overflow + if (((result > 0) && (value > (MAX_VALUE - result))) || + ((result < 0) && (value < (MIN_VALUE - result)))) { + break; + } + result += value; value = 0; break; case '-': + // check for overflow + if (((result < 0) && (value > (MAX_VALUE + result))) || + ((result > 0) && (value < (MIN_VALUE + result)))) { + break; + } + result -= value; value = 0; break; case '*': + // check for overflow + // while dividing we eliminate the fixed point offset + // therefore we have to multiply it again for the comparison with value + if (((result != 0) && (value > (FIXED_POINT_OFFSET * (MAX_VALUE / result)))) || + ((result != 0) && (value < (FIXED_POINT_OFFSET * (MIN_VALUE / result))))) { + break; + } + result *= value; // fixed point offset was multiplied too result /= FIXED_POINT_OFFSET; value = 0; break; case '/': - if (value != FIXED_POINT_OFFSET) { + if (value != 0) { // fixed point offset will be divided too result *= FIXED_POINT_OFFSET; result /= value; diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index dac520cf89..593cbc216a 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -41,6 +41,12 @@ namespace Pinetime { // this is the current offset, may wary after pressing '.' int64_t offset = FIXED_POINT_OFFSET; + // the screen can show 12 chars + // but two are needed for '.' and '-' + static constexpr uint8_t MAX_DIGITS = 10; + static constexpr int64_t MAX_VALUE = powi(10, MAX_DIGITS) - 1; + static constexpr int64_t MIN_VALUE = -MAX_VALUE; + int64_t value = 0; int64_t result = 0; // this has length 2 because it must be a string From 0b8d205e45cdbba220e97d290e4f85f051f0f2b2 Mon Sep 17 00:00:00 2001 From: minacode Date: Tue, 20 Dec 2022 20:03:49 +0100 Subject: [PATCH 147/191] add backspace button --- src/displayapp/fonts/fonts.json | 2 +- src/displayapp/screens/Calculator.cpp | 36 ++++++++++++++++++++++----- src/displayapp/screens/Symbols.h | 1 + 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 92a5b3f12f..7e34eeff51 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -7,7 +7,7 @@ }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", - "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf00c, 0xf1ec, 0xf743, 0xf0f3, 0xf522, 0xf236" + "range": "0xf294, 0xf242, 0xf54b, 0xf21e, 0xf1e6, 0xf017, 0xf129, 0xf03a, 0xf185, 0xf560, 0xf001, 0xf3fd, 0xf1fc, 0xf45d, 0xf59f, 0xf5a0, 0xf027, 0xf028, 0xf6a9, 0xf04b, 0xf04c, 0xf048, 0xf051, 0xf095, 0xf3dd, 0xf04d, 0xf2f2, 0xf024, 0xf252, 0xf569, 0xf201, 0xf06e, 0xf015, 0xf00c, 0xf1ec, 0xf743, 0xf55a, 0xf0f3, 0xf522, 0xf236" } ], "bpp": 1, diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index b99abf0672..43922f64e6 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -1,7 +1,8 @@ -#include "Calculator.h" #include #include #include +#include "Calculator.h" +#include "Symbols.h" using namespace Pinetime::Applications::Screens; @@ -14,7 +15,7 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* buttonMap[] = {"7", "8", "9", "<", "\n", "4", "5", "6", "+-", "\n", "1", "2", "3", "*/", "\n", ".", "0", "=", "^", ""}; +static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+-", "\n", "1", "2", "3", "*/", "\n", ".", "0", "=", "^", ""}; Calculator::Calculator(DisplayApp* app) : Screen(app) { resultLabel = lv_label_create(lv_scr_act(), nullptr); @@ -132,15 +133,38 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { lv_label_refr_text(operationLabel); break; - case '<': - offset = FIXED_POINT_OFFSET; + // this is a little hacky because it matches only the first char + case Symbols::backspace[0]: if (value != 0) { - value = 0; + // delete one value digit + + if (offset < FIXED_POINT_OFFSET) { + if (offset == 0) { + offset = 1; + } else { + offset *= 10; + } + } else { + value /= 10; + } + + if (offset < FIXED_POINT_OFFSET) { + value -= value % (10 * offset); + } else { + value -= value % offset; + } + + UpdateValueLabel(); } else { + // reset the result + result = 0; UpdateResultLabel(); } - UpdateValueLabel(); + + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); *operation = ' '; lv_label_refr_text(operationLabel); diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index a4ec474b80..01e2c40e6c 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -41,6 +41,7 @@ namespace Pinetime { static constexpr const char* sleep = "\xEE\xBD\x84"; static constexpr const char* bed = "\xEF\x88\xB6"; static constexpr const char* calculator = "\xEF\x87\xAC"; + static constexpr const char* backspace = "\xEF\x95\x9A"; // fontawesome_weathericons.c // static constexpr const char* sun = "\xEF\x86\x85"; From 57834eb6dc8c93f2f6858bbf199e945bfdfa8805 Mon Sep 17 00:00:00 2001 From: minacode Date: Tue, 20 Dec 2022 20:27:51 +0100 Subject: [PATCH 148/191] WIP: = repeats calculation --- src/displayapp/screens/Calculator.cpp | 53 +++++++++++++++++++-------- src/displayapp/screens/Calculator.h | 1 + 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 43922f64e6..3a08fa84d7 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -106,36 +106,57 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { case '+': if (value != 0) { Eval(); + ResetInput(); + + UpdateValueLabel(); + UpdateResultLabel(); } + if (*operation == '+') { *operation = '-'; } else { *operation = '+'; } + lv_label_refr_text(operationLabel); break; + case '*': if (value != 0) { Eval(); + ResetInput(); + + UpdateValueLabel(); + UpdateResultLabel(); } + if (*operation == '*') { *operation = '/'; } else { *operation = '*'; } + lv_label_refr_text(operationLabel); break; + case '^': if (value != 0) { Eval(); + ResetInput(); + + UpdateValueLabel(); + UpdateResultLabel(); } *operation = '^'; + lv_label_refr_text(operationLabel); break; // this is a little hacky because it matches only the first char case Symbols::backspace[0]: - if (value != 0) { + if (*operation != ' ') { + *operation = ' '; + } else if (value != 0) { // delete one value digit if (offset < FIXED_POINT_OFFSET) { @@ -171,14 +192,21 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { break; case '=': Eval(); - *operation = ' '; - lv_label_refr_text(operationLabel); + + UpdateValueLabel(); + UpdateResultLabel(); break; } } } } +void Calculator::ResetInput() { + value = 0; + offset = FIXED_POINT_OFFSET; + *operation = ' '; +} + void Calculator::UpdateResultLabel() { int64_t integer = result / FIXED_POINT_OFFSET; int64_t remainder = result % FIXED_POINT_OFFSET; @@ -236,13 +264,13 @@ void Calculator::UpdateValueLabel() { } } +// update the result based on value and operation void Calculator::Eval() { switch (*operation) { case ' ': - case '=': result = value; - value = 0; break; + case '+': // check for overflow if (((result > 0) && (value > (MAX_VALUE - result))) || @@ -251,7 +279,6 @@ void Calculator::Eval() { } result += value; - value = 0; break; case '-': // check for overflow @@ -261,7 +288,6 @@ void Calculator::Eval() { } result -= value; - value = 0; break; case '*': // check for overflow @@ -275,19 +301,17 @@ void Calculator::Eval() { result *= value; // fixed point offset was multiplied too result /= FIXED_POINT_OFFSET; - value = 0; break; case '/': if (value != 0) { // fixed point offset will be divided too result *= FIXED_POINT_OFFSET; result /= value; - value = 0; } break; // we use floats here because pow with fixed point numbers is weird - case '^': + case '^': { double tmp_value = static_cast(value); tmp_value /= static_cast(FIXED_POINT_OFFSET); @@ -297,13 +321,10 @@ void Calculator::Eval() { tmp_result = pow(tmp_result, tmp_value); tmp_result *= static_cast(FIXED_POINT_OFFSET); result = static_cast(tmp_result); + break; + } - value = 0; + default: break; } - *operation = ' '; - offset = FIXED_POINT_OFFSET; - - UpdateValueLabel(); - UpdateResultLabel(); } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 593cbc216a..90e2b4a2e1 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -31,6 +31,7 @@ namespace Pinetime { lv_obj_t* operationLabel; void Eval(); + void ResetInput(); void UpdateValueLabel(); void UpdateResultLabel(); From f9833414b5e0828a78f1c0702221dce520a53833 Mon Sep 17 00:00:00 2001 From: minacode Date: Tue, 20 Dec 2022 20:44:50 +0100 Subject: [PATCH 149/191] format --- src/displayapp/screens/Calculator.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 3a08fa84d7..61e41452d6 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -15,7 +15,8 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+-", "\n", "1", "2", "3", "*/", "\n", ".", "0", "=", "^", ""}; +static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+-", "\n", "1", "2", "3", "*/", "\n", ".", "0", + "=", "^", ""}; Calculator::Calculator(DisplayApp* app) : Screen(app) { resultLabel = lv_label_create(lv_scr_act(), nullptr); @@ -273,8 +274,7 @@ void Calculator::Eval() { case '+': // check for overflow - if (((result > 0) && (value > (MAX_VALUE - result))) || - ((result < 0) && (value < (MIN_VALUE - result)))) { + if (((result > 0) && (value > (MAX_VALUE - result))) || ((result < 0) && (value < (MIN_VALUE - result)))) { break; } @@ -282,8 +282,7 @@ void Calculator::Eval() { break; case '-': // check for overflow - if (((result < 0) && (value > (MAX_VALUE + result))) || - ((result > 0) && (value < (MIN_VALUE + result)))) { + if (((result < 0) && (value > (MAX_VALUE + result))) || ((result > 0) && (value < (MIN_VALUE + result)))) { break; } From bae299d954fb6309ca98431fc22570d94412878e Mon Sep 17 00:00:00 2001 From: minacode Date: Tue, 20 Dec 2022 22:50:23 +0100 Subject: [PATCH 150/191] fix offset bug from backspace --- src/displayapp/screens/Calculator.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 61e41452d6..6f8596ca86 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -176,6 +176,10 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { value -= value % offset; } + if ((value == 0) && (offset < FIXED_POINT_OFFSET)) { + offset = FIXED_POINT_OFFSET; + } + UpdateValueLabel(); } else { // reset the result @@ -191,6 +195,7 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { *operation = ' '; lv_label_refr_text(operationLabel); break; + case '=': Eval(); From 40262fa5bf3eec0b76f7f307cfa315a78baa59ca Mon Sep 17 00:00:00 2001 From: minacode Date: Wed, 21 Dec 2022 00:57:23 +0100 Subject: [PATCH 151/191] fix backspace for zeros --- src/displayapp/screens/Calculator.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 6f8596ca86..eaffbf7d57 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -176,10 +176,9 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { value -= value % offset; } - if ((value == 0) && (offset < FIXED_POINT_OFFSET)) { - offset = FIXED_POINT_OFFSET; - } - + UpdateValueLabel(); + } else if (offset < FIXED_POINT_OFFSET) { + offset *= 10; UpdateValueLabel(); } else { // reset the result From 2db56c93367bb7ca4156c2d00db7a8a42af6f1e6 Mon Sep 17 00:00:00 2001 From: minacode Date: Wed, 21 Dec 2022 16:00:04 +0100 Subject: [PATCH 152/191] colored current button --- src/displayapp/screens/Calculator.cpp | 275 +++++++++++++------------- src/displayapp/screens/Calculator.h | 1 + 2 files changed, 144 insertions(+), 132 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index eaffbf7d57..e39fe4e6c4 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -48,161 +48,172 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_obj_set_style_local_pad_bottom(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_left(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_right(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_FOCUSED, LV_COLOR_BLUE); lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); } void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { - if (event == LV_EVENT_CLICKED) { - if (obj == buttonMatrix) { - const char* buttonText = lv_btnmatrix_get_active_btn_text(obj); + if (obj == buttonMatrix) { + if ((event == LV_EVENT_PRESSED) || (event == LV_EVENT_PRESSING)) { + uint16_t activeButton = lv_btnmatrix_get_active_btn(buttonMatrix); + lv_btnmatrix_set_focused_btn(buttonMatrix, activeButton); + } + if (event == LV_EVENT_RELEASED) { + HandleInput(); + lv_btnmatrix_set_focused_btn(buttonMatrix, LV_BTNMATRIX_BTN_NONE); + } + } +} + + +void Calculator::HandleInput() { + const char* buttonText = lv_btnmatrix_get_active_btn_text(buttonMatrix); - if (buttonText == nullptr) { - return; + if (buttonText == nullptr) { + return; + } + + // we only compare the first char because it is enough + switch (*buttonText) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // if this is true, we already pressed the . button + if (offset < FIXED_POINT_OFFSET) { + // *buttonText is the first char in buttonText + // "- '0'" results in the int value of the char + value += offset * (*buttonText - '0'); + offset /= 10; + } else if (value <= MAX_VALUE / 10) { + value *= 10; + value += offset * (*buttonText - '0'); } + UpdateValueLabel(); - // we only compare the first char because it is enough - switch (*buttonText) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - // if this is true, we already pressed the . button - if (offset < FIXED_POINT_OFFSET) { - // *buttonText is the first char in buttonText - // "- '0'" results in the int value of the char - value += offset * (*buttonText - '0'); - offset /= 10; - } else if (value <= MAX_VALUE / 10) { - value *= 10; - value += offset * (*buttonText - '0'); - } - UpdateValueLabel(); + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); + break; - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); - break; + case '.': + if (offset == FIXED_POINT_OFFSET) { + offset /= 10; + } + UpdateValueLabel(); - case '.': - if (offset == FIXED_POINT_OFFSET) { - offset /= 10; - } - UpdateValueLabel(); - - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); - break; - - // for every operator we: - // - eval the current operator if value > FIXED_POINT_OFFSET - // - then set the new operator - // - + and - as well as * and / cycle on the same button - case '+': - if (value != 0) { - Eval(); - ResetInput(); - - UpdateValueLabel(); - UpdateResultLabel(); - } + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); + break; - if (*operation == '+') { - *operation = '-'; - } else { - *operation = '+'; - } + // for every operator we: + // - eval the current operator if value > FIXED_POINT_OFFSET + // - then set the new operator + // - + and - as well as * and / cycle on the same button + case '+': + if (value != 0) { + Eval(); + ResetInput(); - lv_label_refr_text(operationLabel); - break; + UpdateValueLabel(); + UpdateResultLabel(); + } - case '*': - if (value != 0) { - Eval(); - ResetInput(); + if (*operation == '+') { + *operation = '-'; + } else { + *operation = '+'; + } - UpdateValueLabel(); - UpdateResultLabel(); - } + lv_label_refr_text(operationLabel); + break; - if (*operation == '*') { - *operation = '/'; - } else { - *operation = '*'; - } + case '*': + if (value != 0) { + Eval(); + ResetInput(); - lv_label_refr_text(operationLabel); - break; + UpdateValueLabel(); + UpdateResultLabel(); + } - case '^': - if (value != 0) { - Eval(); - ResetInput(); + if (*operation == '*') { + *operation = '/'; + } else { + *operation = '*'; + } - UpdateValueLabel(); - UpdateResultLabel(); - } - *operation = '^'; - - lv_label_refr_text(operationLabel); - break; - - // this is a little hacky because it matches only the first char - case Symbols::backspace[0]: - if (*operation != ' ') { - *operation = ' '; - } else if (value != 0) { - // delete one value digit - - if (offset < FIXED_POINT_OFFSET) { - if (offset == 0) { - offset = 1; - } else { - offset *= 10; - } - } else { - value /= 10; - } - - if (offset < FIXED_POINT_OFFSET) { - value -= value % (10 * offset); - } else { - value -= value % offset; - } - - UpdateValueLabel(); - } else if (offset < FIXED_POINT_OFFSET) { - offset *= 10; - UpdateValueLabel(); - } else { - // reset the result + lv_label_refr_text(operationLabel); + break; - result = 0; - UpdateResultLabel(); - } + case '^': + if (value != 0) { + Eval(); + ResetInput(); - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); + UpdateValueLabel(); + UpdateResultLabel(); + } + *operation = '^'; - *operation = ' '; - lv_label_refr_text(operationLabel); - break; + lv_label_refr_text(operationLabel); + break; - case '=': - Eval(); + // this is a little hacky because it matches only the first char + case Symbols::backspace[0]: + if (*operation != ' ') { + *operation = ' '; + } else if (value != 0) { + // delete one value digit - UpdateValueLabel(); - UpdateResultLabel(); - break; + if (offset < FIXED_POINT_OFFSET) { + if (offset == 0) { + offset = 1; + } else { + offset *= 10; + } + } else { + value /= 10; + } + + if (offset < FIXED_POINT_OFFSET) { + value -= value % (10 * offset); + } else { + value -= value % offset; + } + + UpdateValueLabel(); + } else if (offset < FIXED_POINT_OFFSET) { + offset *= 10; + UpdateValueLabel(); + } else { + // reset the result + + result = 0; + UpdateResultLabel(); } - } + + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); + + *operation = ' '; + lv_label_refr_text(operationLabel); + break; + + case '=': + Eval(); + + UpdateValueLabel(); + UpdateResultLabel(); + break; } } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 90e2b4a2e1..0f68199e2d 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -32,6 +32,7 @@ namespace Pinetime { void Eval(); void ResetInput(); + void HandleInput(); void UpdateValueLabel(); void UpdateResultLabel(); From 083fea0d8cd3b11b57a504a6a61ca5d591e2a8d9 Mon Sep 17 00:00:00 2001 From: minacode Date: Wed, 21 Dec 2022 16:04:34 +0100 Subject: [PATCH 153/191] format --- src/displayapp/screens/Calculator.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index e39fe4e6c4..5acd6a6dac 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -65,7 +65,6 @@ void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { } } - void Calculator::HandleInput() { const char* buttonText = lv_btnmatrix_get_active_btn_text(buttonMatrix); From 70cfced63680111415c6859d69cb20dc57f4a1b7 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 31 Dec 2022 12:54:03 +0100 Subject: [PATCH 154/191] save changes --- src/displayapp/screens/Calculator.cpp | 77 ++++++++++++++++----------- src/displayapp/screens/Calculator.h | 1 + 2 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 5acd6a6dac..3fac476a0b 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -84,6 +84,10 @@ void Calculator::HandleInput() { case '7': case '8': case '9': + if (equalSignPressed) { + ResetInput(); + } + // if this is true, we already pressed the . button if (offset < FIXED_POINT_OFFSET) { // *buttonText is the first char in buttonText @@ -94,7 +98,6 @@ void Calculator::HandleInput() { value *= 10; value += offset * (*buttonText - '0'); } - UpdateValueLabel(); NRF_LOG_INFO(". offset: %" PRId64, offset); NRF_LOG_INFO(". value: %" PRId64, value); @@ -102,10 +105,13 @@ void Calculator::HandleInput() { break; case '.': + if (equalSignPressed) { + ResetInput(); + } + if (offset == FIXED_POINT_OFFSET) { offset /= 10; } - UpdateValueLabel(); NRF_LOG_INFO(". offset: %" PRId64, offset); NRF_LOG_INFO(". value: %" PRId64, value); @@ -117,12 +123,13 @@ void Calculator::HandleInput() { // - then set the new operator // - + and - as well as * and / cycle on the same button case '+': + if (equalSignPressed) { + ResetInput(); + } + if (value != 0) { Eval(); ResetInput(); - - UpdateValueLabel(); - UpdateResultLabel(); } if (*operation == '+') { @@ -130,17 +137,16 @@ void Calculator::HandleInput() { } else { *operation = '+'; } - - lv_label_refr_text(operationLabel); break; case '*': + if (equalSignPressed) { + ResetInput(); + } + if (value != 0) { Eval(); ResetInput(); - - UpdateValueLabel(); - UpdateResultLabel(); } if (*operation == '*') { @@ -148,30 +154,30 @@ void Calculator::HandleInput() { } else { *operation = '*'; } - - lv_label_refr_text(operationLabel); break; case '^': + if (equalSignPressed) { + ResetInput(); + } + if (value != 0) { Eval(); ResetInput(); - - UpdateValueLabel(); - UpdateResultLabel(); } *operation = '^'; - - lv_label_refr_text(operationLabel); break; // this is a little hacky because it matches only the first char case Symbols::backspace[0]: + if (equalSignPressed) { + ResetInput(); + } + if (*operation != ' ') { *operation = ' '; } else if (value != 0) { // delete one value digit - if (offset < FIXED_POINT_OFFSET) { if (offset == 0) { offset = 1; @@ -181,22 +187,16 @@ void Calculator::HandleInput() { } else { value /= 10; } - if (offset < FIXED_POINT_OFFSET) { value -= value % (10 * offset); } else { value -= value % offset; } - - UpdateValueLabel(); } else if (offset < FIXED_POINT_OFFSET) { offset *= 10; - UpdateValueLabel(); } else { // reset the result - result = 0; - UpdateResultLabel(); } NRF_LOG_INFO(". offset: %" PRId64, offset); @@ -204,22 +204,24 @@ void Calculator::HandleInput() { NRF_LOG_INFO(". result: %" PRId64, result); *operation = ' '; - lv_label_refr_text(operationLabel); break; case '=': + equalSignPressed = true; Eval(); - - UpdateValueLabel(); - UpdateResultLabel(); break; } + + UpdateValueLabel(); + UpdateResultLabel(); + lv_label_refr_text(operationLabel); } void Calculator::ResetInput() { value = 0; offset = FIXED_POINT_OFFSET; *operation = ' '; + equalSignPressed = false; } void Calculator::UpdateResultLabel() { @@ -316,11 +318,14 @@ void Calculator::Eval() { result /= FIXED_POINT_OFFSET; break; case '/': - if (value != 0) { - // fixed point offset will be divided too - result *= FIXED_POINT_OFFSET; - result /= value; + // check for zero division + if (value == 0) { + break; } + + // fixed point offset will be divided too + result *= FIXED_POINT_OFFSET; + result /= value; break; // we use floats here because pow with fixed point numbers is weird @@ -331,6 +336,14 @@ void Calculator::Eval() { double tmp_result = static_cast(result); tmp_result /= static_cast(FIXED_POINT_OFFSET); + // check for overflow + // result^value > MAX_VALUE iff + // log2(result^value) > log2(MAX_VALUE) iff + // value * log2(result) > log2(MAX_VALUE) + if ((value * log2(result)) > log2(MAX_VALUE)) { + break; + } + tmp_result = pow(tmp_result, tmp_value); tmp_result *= static_cast(FIXED_POINT_OFFSET); result = static_cast(tmp_result); diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 0f68199e2d..a2223bd216 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -56,6 +56,7 @@ namespace Pinetime { // the second char is always \0 // we only care about the first char char operation[2] {" "}; + bool equalSignPressed = false; }; } } From 6d6fec550040970c6dd04f884715a7d9fc24acb0 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 31 Dec 2022 14:13:26 +0100 Subject: [PATCH 155/191] fixed various issues --- src/displayapp/screens/Calculator.cpp | 197 ++++++++++++++++---------- src/displayapp/screens/Calculator.h | 18 ++- 2 files changed, 133 insertions(+), 82 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 3fac476a0b..36bfba6bb8 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -15,7 +15,7 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+-", "\n", "1", "2", "3", "*/", "\n", ".", "0", +static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", ".", "0", "=", "^", ""}; Calculator::Calculator(DisplayApp* app) : Screen(app) { @@ -23,21 +23,16 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP); lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT); lv_label_set_text_fmt(resultLabel, "%" PRId64, result); - lv_obj_set_size(resultLabel, 145, 20); + lv_obj_set_size(resultLabel, 200, 20); lv_obj_set_pos(resultLabel, 10, 5); valueLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(valueLabel, LV_LABEL_LONG_CROP); lv_label_set_align(valueLabel, LV_LABEL_ALIGN_RIGHT); lv_label_set_text_fmt(valueLabel, "%" PRId64, value); - lv_obj_set_size(valueLabel, 145, 20); + lv_obj_set_size(valueLabel, 200, 20); lv_obj_set_pos(valueLabel, 10, 35); - operationLabel = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(operationLabel, operation); - lv_obj_set_size(operationLabel, 20, 20); - lv_obj_set_pos(operationLabel, 203, 35); - buttonMatrix = lv_btnmatrix_create(lv_scr_act(), nullptr); buttonMatrix->user_data = this; lv_obj_set_event_cb(buttonMatrix, eventHandler); @@ -50,6 +45,10 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_obj_set_style_local_pad_right(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_FOCUSED, LV_COLOR_BLUE); lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + lv_obj_set_style_local_bg_opa(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_OPA_COVER); + lv_obj_set_style_local_bg_grad_stop(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, 128); + lv_obj_set_style_local_bg_main_stop(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, 128); } void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { @@ -72,6 +71,11 @@ void Calculator::HandleInput() { return; } + if ((equalSignPressed && (*buttonText != '=')) || (error != Error::None)) { + ResetInput(); + UpdateOperation(); + } + // we only compare the first char because it is enough switch (*buttonText) { case '0': @@ -84,10 +88,6 @@ void Calculator::HandleInput() { case '7': case '8': case '9': - if (equalSignPressed) { - ResetInput(); - } - // if this is true, we already pressed the . button if (offset < FIXED_POINT_OFFSET) { // *buttonText is the first char in buttonText @@ -105,10 +105,6 @@ void Calculator::HandleInput() { break; case '.': - if (equalSignPressed) { - ResetInput(); - } - if (offset == FIXED_POINT_OFFSET) { offset /= 10; } @@ -123,60 +119,57 @@ void Calculator::HandleInput() { // - then set the new operator // - + and - as well as * and / cycle on the same button case '+': - if (equalSignPressed) { - ResetInput(); - } - if (value != 0) { Eval(); ResetInput(); } - if (*operation == '+') { - *operation = '-'; - } else { - *operation = '+'; + switch (operation) { + case '+': + operation = '-'; + break; + case '-': + operation = ' '; + break; + default: + operation = '+'; + break; } + UpdateOperation(); break; case '*': - if (equalSignPressed) { - ResetInput(); - } - if (value != 0) { Eval(); ResetInput(); } - if (*operation == '*') { - *operation = '/'; - } else { - *operation = '*'; + switch (operation) { + case '*': + operation = '/'; + break; + case '/': + operation = ' '; + break; + default: + operation = '*'; + break; } + UpdateOperation(); break; case '^': - if (equalSignPressed) { - ResetInput(); - } - if (value != 0) { Eval(); ResetInput(); } - *operation = '^'; + operation = '^'; + UpdateOperation(); break; // this is a little hacky because it matches only the first char case Symbols::backspace[0]: - if (equalSignPressed) { - ResetInput(); - } - - if (*operation != ' ') { - *operation = ' '; - } else if (value != 0) { + if (value != 0) { // delete one value digit if (offset < FIXED_POINT_OFFSET) { if (offset == 0) { @@ -193,7 +186,11 @@ void Calculator::HandleInput() { value -= value % offset; } } else if (offset < FIXED_POINT_OFFSET) { - offset *= 10; + if (offset == 0) { + offset = 1; + } else { + offset *= 10; + } } else { // reset the result result = 0; @@ -203,7 +200,7 @@ void Calculator::HandleInput() { NRF_LOG_INFO(". value: %" PRId64, value); NRF_LOG_INFO(". result: %" PRId64, result); - *operation = ' '; + operation = ' '; break; case '=': @@ -211,17 +208,50 @@ void Calculator::HandleInput() { Eval(); break; } - + UpdateValueLabel(); UpdateResultLabel(); - lv_label_refr_text(operationLabel); +} + +void Calculator::UpdateOperation() { + lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); + lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); + lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); + + if (operation == '+') { + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); + } else if (operation == '-') { + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); + } + if (operation == '*') { + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); + } else if (operation == '/') { + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); + } else if (operation == '^') { + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_NONE); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); + } } void Calculator::ResetInput() { value = 0; offset = FIXED_POINT_OFFSET; - *operation = ' '; + operation = ' '; equalSignPressed = false; + error = Error::None; } void Calculator::UpdateResultLabel() { @@ -249,41 +279,53 @@ void Calculator::UpdateResultLabel() { } void Calculator::UpdateValueLabel() { - int64_t integer = value / FIXED_POINT_OFFSET; - int64_t remainder = value % FIXED_POINT_OFFSET; + switch (error) { + case Error::TooLarge: + lv_label_set_text_static(valueLabel, "too large"); + break; + case Error::ZeroDivision: + lv_label_set_text_static(valueLabel, "zero division"); + break; + case Error::None: + default: { + int64_t integer = value / FIXED_POINT_OFFSET; + int64_t remainder = value % FIXED_POINT_OFFSET; - int64_t printRemainder = remainder < 0 ? -remainder : remainder; + int64_t printRemainder = remainder < 0 ? -remainder : remainder; - uint8_t min_width = 0; - int64_t tmp_offset = offset; + uint8_t min_width = 0; + int64_t tmp_offset = offset; - // TODO there has to be a simpler way to do this - if (tmp_offset == 0) { - tmp_offset = 1; - min_width = 1; - } - while (tmp_offset < FIXED_POINT_OFFSET) { - tmp_offset *= 10; - min_width++; - } - min_width--; + // TODO there has to be a simpler way to do this + if (tmp_offset == 0) { + tmp_offset = 1; + min_width = 1; + } + while (tmp_offset < FIXED_POINT_OFFSET) { + tmp_offset *= 10; + min_width++; + } + min_width--; - for (uint8_t i = min_width; i < N_DECIMALS; i++) { - printRemainder /= 10; - } + for (uint8_t i = min_width; i < N_DECIMALS; i++) { + printRemainder /= 10; + } - if (offset == FIXED_POINT_OFFSET) { - lv_label_set_text_fmt(valueLabel, "%" PRId64, integer); - } else if ((offset == (FIXED_POINT_OFFSET / 10)) && (remainder == 0)) { - lv_label_set_text_fmt(valueLabel, "%" PRId64 ".", integer); - } else { - lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, printRemainder); + if (offset == FIXED_POINT_OFFSET) { + lv_label_set_text_fmt(valueLabel, "%" PRId64, integer); + } else if ((offset == (FIXED_POINT_OFFSET / 10)) && (remainder == 0)) { + lv_label_set_text_fmt(valueLabel, "%" PRId64 ".", integer); + } else { + lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, printRemainder); + } + } + break; } } // update the result based on value and operation void Calculator::Eval() { - switch (*operation) { + switch (operation) { case ' ': result = value; break; @@ -291,6 +333,7 @@ void Calculator::Eval() { case '+': // check for overflow if (((result > 0) && (value > (MAX_VALUE - result))) || ((result < 0) && (value < (MIN_VALUE - result)))) { + error = Error::TooLarge; break; } @@ -299,6 +342,7 @@ void Calculator::Eval() { case '-': // check for overflow if (((result < 0) && (value > (MAX_VALUE + result))) || ((result > 0) && (value < (MIN_VALUE + result)))) { + error = Error::TooLarge; break; } @@ -310,6 +354,7 @@ void Calculator::Eval() { // therefore we have to multiply it again for the comparison with value if (((result != 0) && (value > (FIXED_POINT_OFFSET * (MAX_VALUE / result)))) || ((result != 0) && (value < (FIXED_POINT_OFFSET * (MIN_VALUE / result))))) { + error = Error::TooLarge; break; } @@ -320,6 +365,7 @@ void Calculator::Eval() { case '/': // check for zero division if (value == 0) { + error = Error::ZeroDivision; break; } @@ -340,7 +386,8 @@ void Calculator::Eval() { // result^value > MAX_VALUE iff // log2(result^value) > log2(MAX_VALUE) iff // value * log2(result) > log2(MAX_VALUE) - if ((value * log2(result)) > log2(MAX_VALUE)) { + if ((tmp_value * log2(std::abs(tmp_result))) > log2(static_cast(MAX_VALUE))) { + error = Error::TooLarge; break; } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index a2223bd216..00cefdb3e4 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -28,13 +28,13 @@ namespace Pinetime { lv_obj_t* buttonMatrix; lv_obj_t* valueLabel; lv_obj_t* resultLabel; - lv_obj_t* operationLabel; void Eval(); void ResetInput(); void HandleInput(); void UpdateValueLabel(); void UpdateResultLabel(); + void UpdateOperation(); // change this if you want to change the number of decimals static constexpr uint8_t N_DECIMALS = 4; @@ -45,18 +45,22 @@ namespace Pinetime { // the screen can show 12 chars // but two are needed for '.' and '-' - static constexpr uint8_t MAX_DIGITS = 10; + static constexpr uint8_t MAX_DIGITS = 15; static constexpr int64_t MAX_VALUE = powi(10, MAX_DIGITS) - 1; static constexpr int64_t MIN_VALUE = -MAX_VALUE; int64_t value = 0; int64_t result = 0; - // this has length 2 because it must be a string - // because we also use it as the buffer for the operationLabel - // the second char is always \0 - // we only care about the first char - char operation[2] {" "}; + char operation = ' '; bool equalSignPressed = false; + + enum Error { + TooLarge, + ZeroDivision, + None, + }; + + Error error = Error::None; }; } } From 63b9d8111d85f94efc37288e16596095f6f665a2 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 31 Dec 2022 14:29:13 +0100 Subject: [PATCH 156/191] reset value after copy to result --- src/displayapp/screens/Calculator.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 36bfba6bb8..6b7a6349a7 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -206,6 +206,12 @@ void Calculator::HandleInput() { case '=': equalSignPressed = true; Eval(); + // If the operation is ' ' then we move the value to the result. + // We reset the input after this. + // This seems more convenient. + if (operation == ' ') { + ResetInput(); + } break; } From fe0dd5050ee61bb2d63ee78fcbbdb97a8d0cc655 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 31 Dec 2022 14:29:51 +0100 Subject: [PATCH 157/191] format --- src/displayapp/screens/Calculator.cpp | 9 ++++----- src/displayapp/screens/Calculator.h | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 6b7a6349a7..2fc7d1fe34 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -45,7 +45,7 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_obj_set_style_local_pad_right(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_FOCUSED, LV_COLOR_BLUE); lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); - + lv_obj_set_style_local_bg_opa(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_OPA_COVER); lv_obj_set_style_local_bg_grad_stop(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, 128); lv_obj_set_style_local_bg_main_stop(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, 128); @@ -214,7 +214,7 @@ void Calculator::HandleInput() { } break; } - + UpdateValueLabel(); UpdateResultLabel(); } @@ -324,8 +324,7 @@ void Calculator::UpdateValueLabel() { } else { lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, printRemainder); } - } - break; + } break; } } @@ -389,7 +388,7 @@ void Calculator::Eval() { tmp_result /= static_cast(FIXED_POINT_OFFSET); // check for overflow - // result^value > MAX_VALUE iff + // result^value > MAX_VALUE iff // log2(result^value) > log2(MAX_VALUE) iff // value * log2(result) > log2(MAX_VALUE) if ((tmp_value * log2(std::abs(tmp_result))) > log2(static_cast(MAX_VALUE))) { diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 00cefdb3e4..d9554429b0 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -59,7 +59,7 @@ namespace Pinetime { ZeroDivision, None, }; - + Error error = Error::None; }; } From cea56b824e74247cb0f652598f2ce9e422242079 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 31 Dec 2022 14:40:49 +0100 Subject: [PATCH 158/191] format and tidy --- src/displayapp/screens/Calculator.cpp | 8 ++++---- src/displayapp/screens/Calculator.h | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 2fc7d1fe34..4ef66c7bc1 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -219,7 +219,7 @@ void Calculator::HandleInput() { UpdateResultLabel(); } -void Calculator::UpdateOperation() { +void Calculator::UpdateOperation() const { lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); @@ -260,7 +260,7 @@ void Calculator::ResetInput() { error = Error::None; } -void Calculator::UpdateResultLabel() { +void Calculator::UpdateResultLabel() const { int64_t integer = result / FIXED_POINT_OFFSET; int64_t remainder = result % FIXED_POINT_OFFSET; @@ -381,10 +381,10 @@ void Calculator::Eval() { // we use floats here because pow with fixed point numbers is weird case '^': { - double tmp_value = static_cast(value); + auto tmp_value = static_cast(value); tmp_value /= static_cast(FIXED_POINT_OFFSET); - double tmp_result = static_cast(result); + auto tmp_result = static_cast(result); tmp_result /= static_cast(FIXED_POINT_OFFSET); // check for overflow diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index d9554429b0..4a6969c3de 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -25,16 +25,16 @@ namespace Pinetime { void OnButtonEvent(lv_obj_t* obj, lv_event_t event); private: - lv_obj_t* buttonMatrix; - lv_obj_t* valueLabel; - lv_obj_t* resultLabel; + lv_obj_t* buttonMatrix {}; + lv_obj_t* valueLabel {}; + lv_obj_t* resultLabel {}; void Eval(); void ResetInput(); void HandleInput(); void UpdateValueLabel(); - void UpdateResultLabel(); - void UpdateOperation(); + void UpdateResultLabel() const; + void UpdateOperation() const; // change this if you want to change the number of decimals static constexpr uint8_t N_DECIMALS = 4; From 89c01e6ba93f9fd3b789e11779e97c36ddda7da5 Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 1 Jan 2023 02:04:32 +0100 Subject: [PATCH 159/191] add power operation toggle --- src/displayapp/screens/Calculator.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 4ef66c7bc1..7340e483d3 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -163,7 +163,12 @@ void Calculator::HandleInput() { Eval(); ResetInput(); } - operation = '^'; + + if (operation == '^') { + operation = ' '; + } else { + operation = '^'; + } UpdateOperation(); break; From ac15ee8dd7fc246d8497d0c6df4bd690c28f9881 Mon Sep 17 00:00:00 2001 From: minacode Date: Thu, 5 Jan 2023 21:44:05 +0100 Subject: [PATCH 160/191] checked buttons cleanup --- src/displayapp/screens/Calculator.cpp | 63 +++++++++++++++------------ 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 7340e483d3..e486fa4cb1 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -37,6 +37,7 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { buttonMatrix->user_data = this; lv_obj_set_event_cb(buttonMatrix, eventHandler); lv_btnmatrix_set_map(buttonMatrix, buttonMap); + lv_btnmatrix_set_one_check(buttonMatrix, true); lv_obj_set_size(buttonMatrix, 238, 180); lv_obj_set_style_local_pad_inner(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_top(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); @@ -225,35 +226,39 @@ void Calculator::HandleInput() { } void Calculator::UpdateOperation() const { - lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); - lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); - lv_btnmatrix_clear_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); - - if (operation == '+') { - lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); - lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); - } else if (operation == '-') { - lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); - lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); - } - if (operation == '*') { - lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); - lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); - } else if (operation == '/') { - lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); - lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); - } else if (operation == '^') { - lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_NONE); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); - lv_btnmatrix_set_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); + switch (operation) { + case '+': + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); + break; + case '-': + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); + break; + case '*': + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); + break; + case '/': + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); + break; + case '^': + lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_NONE); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_btnmatrix_set_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); + break; + default: + lv_btnmatrix_clear_btn_ctrl_all(buttonMatrix, LV_BTNMATRIX_CTRL_CHECK_STATE); + break; } } From 1556a9cd48ca61737112d2f9a937b96ab7ae9bfe Mon Sep 17 00:00:00 2001 From: minacode Date: Thu, 5 Jan 2023 21:47:18 +0100 Subject: [PATCH 161/191] removed swiping --- src/displayapp/screens/Calculator.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index e486fa4cb1..6193c74da0 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -44,7 +44,6 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_obj_set_style_local_pad_bottom(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_left(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_right(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_FOCUSED, LV_COLOR_BLUE); lv_obj_align(buttonMatrix, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_obj_set_style_local_bg_opa(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_OPA_COVER); @@ -53,15 +52,8 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { } void Calculator::OnButtonEvent(lv_obj_t* obj, lv_event_t event) { - if (obj == buttonMatrix) { - if ((event == LV_EVENT_PRESSED) || (event == LV_EVENT_PRESSING)) { - uint16_t activeButton = lv_btnmatrix_get_active_btn(buttonMatrix); - lv_btnmatrix_set_focused_btn(buttonMatrix, activeButton); - } - if (event == LV_EVENT_RELEASED) { - HandleInput(); - lv_btnmatrix_set_focused_btn(buttonMatrix, LV_BTNMATRIX_BTN_NONE); - } + if ((obj == buttonMatrix) && (event == LV_EVENT_PRESSED)) { + HandleInput(); } } From 901bdb0fddb8a8f194c44a0c9ecd88235bb3fb02 Mon Sep 17 00:00:00 2001 From: minacode Date: Thu, 5 Jan 2023 22:03:54 +0100 Subject: [PATCH 162/191] add better colors --- src/displayapp/InfiniTimeTheme.h | 1 + src/displayapp/screens/Calculator.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 0690b09912..9ceb08771e 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -8,6 +8,7 @@ namespace Colors { static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0); static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff); static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0); + static constexpr lv_color_t deepOrange = LV_COLOR_MAKE(0xff, 0x40, 0x0); static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38); diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 6193c74da0..8efc0ee5e9 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -2,6 +2,7 @@ #include #include #include "Calculator.h" +#include "displayapp/InfiniTimeTheme.h" #include "Symbols.h" using namespace Pinetime::Applications::Screens; @@ -39,6 +40,7 @@ Calculator::Calculator(DisplayApp* app) : Screen(app) { lv_btnmatrix_set_map(buttonMatrix, buttonMap); lv_btnmatrix_set_one_check(buttonMatrix, true); lv_obj_set_size(buttonMatrix, 238, 180); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_style_local_pad_inner(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_top(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); lv_obj_set_style_local_pad_bottom(buttonMatrix, LV_BTNMATRIX_PART_BG, LV_STATE_DEFAULT, 1); @@ -221,31 +223,31 @@ void Calculator::UpdateOperation() const { switch (operation) { case '+': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); break; case '-': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 7, LV_BTNMATRIX_CTRL_CHECK_STATE); break; case '*': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); break; case '/': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_HOR); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_GRAY); - lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::bgAlt); + lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); break; case '^': lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_NONE); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_COLOR_RED); + lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); break; default: From ec8b5060e80e6234ce8a629e92a1c986d552f345 Mon Sep 17 00:00:00 2001 From: Finlay Davidson Date: Mon, 9 Jan 2023 00:57:42 +0100 Subject: [PATCH 163/191] Remove power operation in calculator app Also shuffles bottom row around a bit, and adds a unary minus button. Also fixes issue where the colours on the operator buttons aren't wiped when the backspace button is pressed. --- src/displayapp/screens/Calculator.cpp | 52 +++++---------------------- 1 file changed, 8 insertions(+), 44 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 8efc0ee5e9..1e03d4fa1d 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -16,8 +16,8 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", ".", "0", - "=", "^", ""}; +static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", + "(-)", "=", ""}; Calculator::Calculator(DisplayApp* app) : Screen(app) { resultLabel = lv_label_create(lv_scr_act(), nullptr); @@ -99,6 +99,11 @@ void Calculator::HandleInput() { NRF_LOG_INFO(". result: %" PRId64, result); break; + // unary minus + case '(': + value = -value; + break; + case '.': if (offset == FIXED_POINT_OFFSET) { offset /= 10; @@ -153,20 +158,6 @@ void Calculator::HandleInput() { UpdateOperation(); break; - case '^': - if (value != 0) { - Eval(); - ResetInput(); - } - - if (operation == '^') { - operation = ' '; - } else { - operation = '^'; - } - UpdateOperation(); - break; - // this is a little hacky because it matches only the first char case Symbols::backspace[0]: if (value != 0) { @@ -201,6 +192,7 @@ void Calculator::HandleInput() { NRF_LOG_INFO(". result: %" PRId64, result); operation = ' '; + UpdateOperation(); break; case '=': @@ -245,11 +237,6 @@ void Calculator::UpdateOperation() const { lv_obj_set_style_local_bg_grad_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); lv_btnmatrix_set_btn_ctrl(buttonMatrix, 11, LV_BTNMATRIX_CTRL_CHECK_STATE); break; - case '^': - lv_obj_set_style_local_bg_grad_dir(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, LV_GRAD_DIR_NONE); - lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_CHECKED, Colors::deepOrange); - lv_btnmatrix_set_btn_ctrl(buttonMatrix, 15, LV_BTNMATRIX_CTRL_CHECK_STATE); - break; default: lv_btnmatrix_clear_btn_ctrl_all(buttonMatrix, LV_BTNMATRIX_CTRL_CHECK_STATE); break; @@ -383,29 +370,6 @@ void Calculator::Eval() { result /= value; break; - // we use floats here because pow with fixed point numbers is weird - case '^': { - auto tmp_value = static_cast(value); - tmp_value /= static_cast(FIXED_POINT_OFFSET); - - auto tmp_result = static_cast(result); - tmp_result /= static_cast(FIXED_POINT_OFFSET); - - // check for overflow - // result^value > MAX_VALUE iff - // log2(result^value) > log2(MAX_VALUE) iff - // value * log2(result) > log2(MAX_VALUE) - if ((tmp_value * log2(std::abs(tmp_result))) > log2(static_cast(MAX_VALUE))) { - error = Error::TooLarge; - break; - } - - tmp_result = pow(tmp_result, tmp_value); - tmp_result *= static_cast(FIXED_POINT_OFFSET); - result = static_cast(tmp_result); - break; - } - default: break; } From 4a604dbec577111b6e3d13130e24698b77633ffd Mon Sep 17 00:00:00 2001 From: minacode Date: Mon, 9 Jan 2023 09:19:46 +0100 Subject: [PATCH 164/191] format --- src/displayapp/screens/Calculator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 1e03d4fa1d..9bb735be82 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -16,8 +16,8 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* buttonMap[] = {"7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", - "(-)", "=", ""}; +static const char* buttonMap[] = { + "7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", "(-)", "=", ""}; Calculator::Calculator(DisplayApp* app) : Screen(app) { resultLabel = lv_label_create(lv_scr_act(), nullptr); From 770cf85f461eb51068577ff117976e86a6435a2c Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 29 Jan 2023 23:34:59 +0100 Subject: [PATCH 165/191] fixed negative number input Instead of always adding the new digit it now gets multipled with a sign, based on whether value is negative or not. Thus, the addition becomes a subtraction for negative numbers. --- src/displayapp/screens/Calculator.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 9bb735be82..b4cc003f51 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -82,22 +82,25 @@ void Calculator::HandleInput() { case '6': case '7': case '8': - case '9': + case '9': { + // *buttonText is the first char in buttonText + // "- '0'" results in the int value of the char + auto digit = (*buttonText) - '0'; + auto sign = (value < 0) ? -1 : 1; + // if this is true, we already pressed the . button if (offset < FIXED_POINT_OFFSET) { - // *buttonText is the first char in buttonText - // "- '0'" results in the int value of the char - value += offset * (*buttonText - '0'); + value += sign * offset * digit; offset /= 10; } else if (value <= MAX_VALUE / 10) { value *= 10; - value += offset * (*buttonText - '0'); + value += sign * offset * digit; } NRF_LOG_INFO(". offset: %" PRId64, offset); NRF_LOG_INFO(". value: %" PRId64, value); NRF_LOG_INFO(". result: %" PRId64, result); - break; + } break; // unary minus case '(': From ca0241f6c037802b97ac39528d88f094a0396304 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 4 Mar 2023 15:23:34 +0100 Subject: [PATCH 166/191] changes --- src/displayapp/screens/Calculator.cpp | 6 +++--- src/displayapp/screens/Calculator.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index b4cc003f51..44d0875282 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -347,12 +347,12 @@ void Calculator::Eval() { result -= value; break; - case '*': + case '*': // check for overflow // while dividing we eliminate the fixed point offset // therefore we have to multiply it again for the comparison with value - if (((result != 0) && (value > (FIXED_POINT_OFFSET * (MAX_VALUE / result)))) || - ((result != 0) && (value < (FIXED_POINT_OFFSET * (MIN_VALUE / result))))) { + // we also assume here that MAX_VALUE == -MIN_VALUE + if ((result != 0) && (std::abs(value) > (FIXED_POINT_OFFSET * (MAX_VALUE / std::abs(result))))) { error = Error::TooLarge; break; } diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 4a6969c3de..f657613067 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -47,6 +47,7 @@ namespace Pinetime { // but two are needed for '.' and '-' static constexpr uint8_t MAX_DIGITS = 15; static constexpr int64_t MAX_VALUE = powi(10, MAX_DIGITS) - 1; + // this is assumed in the multiplication overflow! static constexpr int64_t MIN_VALUE = -MAX_VALUE; int64_t value = 0; From 5b41ae454b2203b4eef00e2d7576e58a530106d3 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 4 Mar 2023 17:01:03 +0100 Subject: [PATCH 167/191] fix after rebase --- src/displayapp/InfiniTimeTheme.h | 1 - src/displayapp/screens/Calculator.cpp | 2 +- src/displayapp/screens/Calculator.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 9ceb08771e..0690b09912 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -8,7 +8,6 @@ namespace Colors { static constexpr lv_color_t green = LV_COLOR_MAKE(0x0, 0xb0, 0x0); static constexpr lv_color_t blue = LV_COLOR_MAKE(0x0, 0x50, 0xff); static constexpr lv_color_t lightGray = LV_COLOR_MAKE(0xb0, 0xb0, 0xb0); - static constexpr lv_color_t deepOrange = LV_COLOR_MAKE(0xff, 0x40, 0x0); static constexpr lv_color_t bg = LV_COLOR_MAKE(0x5d, 0x69, 0x7e); static constexpr lv_color_t bgAlt = LV_COLOR_MAKE(0x38, 0x38, 0x38); diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 44d0875282..8b1b5a7dbd 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -19,7 +19,7 @@ Calculator::~Calculator() { static const char* buttonMap[] = { "7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", "(-)", "=", ""}; -Calculator::Calculator(DisplayApp* app) : Screen(app) { +Calculator::Calculator() { resultLabel = lv_label_create(lv_scr_act(), nullptr); lv_label_set_long_mode(resultLabel, LV_LABEL_LONG_CROP); lv_label_set_align(resultLabel, LV_LABEL_ALIGN_RIGHT); diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index f657613067..1751386108 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -20,7 +20,7 @@ namespace Pinetime { public: ~Calculator() override; - Calculator(DisplayApp* app); + Calculator(); void OnButtonEvent(lv_obj_t* obj, lv_event_t event); From 6597fb8c8482617627d7e2b9d48511183c1aefa3 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 4 Mar 2023 17:05:12 +0100 Subject: [PATCH 168/191] format --- src/displayapp/screens/Calculator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 8b1b5a7dbd..fddb0db216 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -347,7 +347,7 @@ void Calculator::Eval() { result -= value; break; - case '*': + case '*': // check for overflow // while dividing we eliminate the fixed point offset // therefore we have to multiply it again for the comparison with value From 389fcb57ace7e15136cf0aef2d6c80d8d349e12b Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 4 Mar 2023 17:22:59 +0100 Subject: [PATCH 169/191] fixed display of negative numbers smaller than 0 --- src/displayapp/screens/Calculator.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index fddb0db216..e5d3881082 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -105,6 +105,11 @@ void Calculator::HandleInput() { // unary minus case '(': value = -value; + + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); + break; case '.': @@ -207,6 +212,11 @@ void Calculator::HandleInput() { if (operation == ' ') { ResetInput(); } + + NRF_LOG_INFO(". offset: %" PRId64, offset); + NRF_LOG_INFO(". value: %" PRId64, value); + NRF_LOG_INFO(". result: %" PRId64, result); + break; } @@ -257,6 +267,7 @@ void Calculator::ResetInput() { void Calculator::UpdateResultLabel() const { int64_t integer = result / FIXED_POINT_OFFSET; int64_t remainder = result % FIXED_POINT_OFFSET; + bool negative = (remainder < 0); if (remainder == 0) { lv_label_set_text_fmt(resultLabel, "%" PRId64, integer); @@ -275,7 +286,11 @@ void Calculator::UpdateResultLabel() const { min_width--; } - lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, remainder); + if ((integer == 0) && negative) { + lv_label_set_text_fmt(resultLabel, "-0.%0*" PRId64, min_width, remainder); + } else { + lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, remainder); + } } void Calculator::UpdateValueLabel() { @@ -290,6 +305,7 @@ void Calculator::UpdateValueLabel() { default: { int64_t integer = value / FIXED_POINT_OFFSET; int64_t remainder = value % FIXED_POINT_OFFSET; + bool negative = (remainder < 0); int64_t printRemainder = remainder < 0 ? -remainder : remainder; @@ -311,7 +327,9 @@ void Calculator::UpdateValueLabel() { printRemainder /= 10; } - if (offset == FIXED_POINT_OFFSET) { + if ((integer == 0) && negative) { + lv_label_set_text_fmt(valueLabel, "-0.%0*" PRId64, min_width, printRemainder); + } else if (offset == FIXED_POINT_OFFSET) { lv_label_set_text_fmt(valueLabel, "%" PRId64, integer); } else if ((offset == (FIXED_POINT_OFFSET / 10)) && (remainder == 0)) { lv_label_set_text_fmt(valueLabel, "%" PRId64 ".", integer); From 206adc86f5bae6687e76e00fc772c4fc58c25576 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Sun, 12 Nov 2023 20:04:13 +0100 Subject: [PATCH 170/191] only remove the operator if the value is zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: SuIƓng N. --- src/displayapp/screens/Calculator.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index e5d3881082..a311ee0fb4 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -199,8 +199,10 @@ void Calculator::HandleInput() { NRF_LOG_INFO(". value: %" PRId64, value); NRF_LOG_INFO(". result: %" PRId64, result); - operation = ' '; - UpdateOperation(); + if (value == 0) { + operation = ' '; + UpdateOperation(); + } break; case '=': From ede3db6dbe602ac17f2ddd5ee299f17e61cabbcf Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 12 Nov 2023 19:58:52 +0100 Subject: [PATCH 171/191] lower maximum number size and number of digits This is necessary to ensure correct calculations. Themaximum int64 has 19 digits. Therefore, 18 digits are safe to use. But in order to calculate exact multiplication we need twice the number of digits after the comma, so I decided to go with 12 digits before the comman and 3 after it. --- src/displayapp/screens/Calculator.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 1751386108..2111c29828 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -37,7 +37,7 @@ namespace Pinetime { void UpdateOperation() const; // change this if you want to change the number of decimals - static constexpr uint8_t N_DECIMALS = 4; + static constexpr uint8_t N_DECIMALS = 3; // this is the constant default offset static constexpr int64_t FIXED_POINT_OFFSET = powi(10, N_DECIMALS); // this is the current offset, may wary after pressing '.' @@ -45,7 +45,7 @@ namespace Pinetime { // the screen can show 12 chars // but two are needed for '.' and '-' - static constexpr uint8_t MAX_DIGITS = 15; + static constexpr uint8_t MAX_DIGITS = 12; static constexpr int64_t MAX_VALUE = powi(10, MAX_DIGITS) - 1; // this is assumed in the multiplication overflow! static constexpr int64_t MIN_VALUE = -MAX_VALUE; From 051ae2ad7a2c227d3dfed4b2413c113d2e1e0075 Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 10 Dec 2023 18:24:20 +0100 Subject: [PATCH 172/191] update to optional apps This commit updates the codebase to use the new interface for compile-time optional apps. --- src/displayapp/screens/Calculator.h | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 2111c29828..dcfc65feba 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -1,6 +1,9 @@ #pragma once -#include "Screen.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/Apps.h" +#include "displayapp/Controllers.h" +#include "Symbols.h" namespace { int64_t constexpr powi(int64_t base, uint8_t exponent) { @@ -64,5 +67,14 @@ namespace Pinetime { Error error = Error::None; }; } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::Calculator; + static constexpr const char* icon = Screens::Symbols::calculator; + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::Calculator(); + }; + }; } } From 4c2da3b0a732729a0bad87235a6aee7fd757d05e Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 10 Dec 2023 18:36:00 +0100 Subject: [PATCH 173/191] fix build and format warnings --- src/displayapp/screens/Calculator.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index dcfc65feba..3b23a8a674 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -72,7 +72,8 @@ namespace Pinetime { struct AppTraits { static constexpr Apps app = Apps::Calculator; static constexpr const char* icon = Screens::Symbols::calculator; - static Screens::Screen* Create(AppControllers& controllers) { + + static Screens::Screen* Create(AppControllers& /* controllers */) { return new Screens::Calculator(); }; }; From 242abf3d7d5ba86946d6454a1d875ed0bed43bbf Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 13 Jan 2024 21:39:11 +0100 Subject: [PATCH 174/191] reduce heap size --- src/FreeRTOSConfig.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index d877705a70..930ec7644b 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,6 +62,7 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) +#define configTOTAL_HEAP_SIZE (1024 * 35) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 From 04364d9a83d498813eafc9e2bc3759d88521e3b2 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 13 Jan 2024 21:39:48 +0100 Subject: [PATCH 175/191] implement new CMake interface --- src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 1 + src/displayapp/screens/Calculator.h | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 499f43accb..0598bf7974 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -27,6 +27,7 @@ namespace Pinetime { StopWatch, Metronome, Motion, + Calculator, Steps, Dice, Weather, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 7d8879a4e8..b278c1568f 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -13,6 +13,7 @@ else () set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Calculator") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Weather") set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Sleep") #set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Motion") diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 3b23a8a674..99d86e7531 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -1,7 +1,7 @@ #pragma once #include "displayapp/screens/Screen.h" -#include "displayapp/Apps.h" +#include "displayapp/apps/Apps.h" #include "displayapp/Controllers.h" #include "Symbols.h" From 35df4da0676788d97b74284edf2ead84b2236c71 Mon Sep 17 00:00:00 2001 From: minacode Date: Tue, 16 Jul 2024 15:39:34 +0200 Subject: [PATCH 176/191] set heap size to 39 --- src/FreeRTOSConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 930ec7644b..4696e386f0 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,7 +62,7 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) -#define configTOTAL_HEAP_SIZE (1024 * 35) +#define configTOTAL_HEAP_SIZE (1024 * 39) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 From 3285ebe6b4348b6e5badc3f72e291817386e9efc Mon Sep 17 00:00:00 2001 From: minacode Date: Tue, 16 Jul 2024 15:40:08 +0200 Subject: [PATCH 177/191] remove TODO --- src/displayapp/screens/Calculator.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index a311ee0fb4..81bf2f623c 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -314,7 +314,6 @@ void Calculator::UpdateValueLabel() { uint8_t min_width = 0; int64_t tmp_offset = offset; - // TODO there has to be a simpler way to do this if (tmp_offset == 0) { tmp_offset = 1; min_width = 1; From db946ae8a865e28d630dd56869fe8fa3d63f4410 Mon Sep 17 00:00:00 2001 From: minacode Date: Sat, 31 Aug 2024 18:14:13 +0200 Subject: [PATCH 178/191] add const I dont 100% understand, how it works, but this seems to reduce the amount of needed memory, such that we do not have to reduce the size in the FreeRTOS config. --- src/FreeRTOSConfig.h | 2 +- src/displayapp/screens/Calculator.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 4696e386f0..67c33a34cc 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,7 +62,7 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) -#define configTOTAL_HEAP_SIZE (1024 * 39) +#define configTOTAL_HEAP_SIZE (1024 * 40) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 81bf2f623c..15651df70f 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -16,7 +16,7 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* buttonMap[] = { +static const char* const buttonMap[] = { "7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", "(-)", "=", ""}; Calculator::Calculator() { @@ -37,7 +37,7 @@ Calculator::Calculator() { buttonMatrix = lv_btnmatrix_create(lv_scr_act(), nullptr); buttonMatrix->user_data = this; lv_obj_set_event_cb(buttonMatrix, eventHandler); - lv_btnmatrix_set_map(buttonMatrix, buttonMap); + lv_btnmatrix_set_map(buttonMatrix, const_cast(buttonMap)); lv_btnmatrix_set_one_check(buttonMatrix, true); lv_obj_set_size(buttonMatrix, 238, 180); lv_obj_set_style_local_bg_color(buttonMatrix, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, Colors::bgAlt); From 9700b3386fa1e0b2eb1d71330e04a5f972cd284b Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 1 Sep 2024 22:00:10 +0200 Subject: [PATCH 179/191] add constexpr --- src/displayapp/screens/Calculator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 15651df70f..9143ccf565 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -16,7 +16,7 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -static const char* const buttonMap[] = { +constexpr const char* const buttonMap[] = { "7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", "(-)", "=", ""}; Calculator::Calculator() { From f431121e088b61fe3b05b80295b38241cec2ac41 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Tue, 3 Sep 2024 03:03:32 +0200 Subject: [PATCH 180/191] Remove const Because it is redundant --- src/displayapp/screens/Calculator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 9143ccf565..5f51b88dbd 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -16,7 +16,7 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -constexpr const char* const buttonMap[] = { +constexpr char* const buttonMap[] = { "7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", "(-)", "=", ""}; Calculator::Calculator() { From f0bbbe3229ebcf79d0c953479b85c0388a16d2cc Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 24 Nov 2024 13:57:49 +0100 Subject: [PATCH 181/191] fix compile error by making the button labels even more const --- src/displayapp/screens/Calculator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 5f51b88dbd..9143ccf565 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -16,7 +16,7 @@ Calculator::~Calculator() { lv_obj_clean(lv_scr_act()); } -constexpr char* const buttonMap[] = { +constexpr const char* const buttonMap[] = { "7", "8", "9", Symbols::backspace, "\n", "4", "5", "6", "+ -", "\n", "1", "2", "3", "* /", "\n", "0", ".", "(-)", "=", ""}; Calculator::Calculator() { From ab7dac84d0bb967f52dd9913870dc98963afb0f7 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Sun, 24 Nov 2024 16:39:44 +0100 Subject: [PATCH 182/191] fix typo Co-authored-by: mark9064 <30447455+mark9064@users.noreply.github.com> --- src/displayapp/screens/Calculator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 99d86e7531..6888fba265 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -43,7 +43,7 @@ namespace Pinetime { static constexpr uint8_t N_DECIMALS = 3; // this is the constant default offset static constexpr int64_t FIXED_POINT_OFFSET = powi(10, N_DECIMALS); - // this is the current offset, may wary after pressing '.' + // this is the current offset, may vary after pressing '.' int64_t offset = FIXED_POINT_OFFSET; // the screen can show 12 chars From fc4bb83bf2d1258befb8b7e6e6194ab7572ec841 Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 24 Nov 2024 18:38:16 +0100 Subject: [PATCH 183/191] explain number of digits --- src/displayapp/screens/Calculator.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index 6888fba265..d7d66054f9 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -40,6 +40,8 @@ namespace Pinetime { void UpdateOperation() const; // change this if you want to change the number of decimals + // keep in mind, that we only have 12 digits in total (see MAX_DIGITS) + // due to the fixed point implementation static constexpr uint8_t N_DECIMALS = 3; // this is the constant default offset static constexpr int64_t FIXED_POINT_OFFSET = powi(10, N_DECIMALS); From 7204dfb2e7386affc8112f96fecbc0e44d7dbcec Mon Sep 17 00:00:00 2001 From: minacode Date: Sun, 24 Nov 2024 18:40:11 +0100 Subject: [PATCH 184/191] remove logging --- src/displayapp/screens/Calculator.cpp | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 9143ccf565..fd312a725a 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -1,6 +1,5 @@ #include #include -#include #include "Calculator.h" #include "displayapp/InfiniTimeTheme.h" #include "Symbols.h" @@ -96,30 +95,17 @@ void Calculator::HandleInput() { value *= 10; value += sign * offset * digit; } - - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); } break; // unary minus case '(': value = -value; - - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); - break; case '.': if (offset == FIXED_POINT_OFFSET) { offset /= 10; } - - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); break; // for every operator we: @@ -195,10 +181,6 @@ void Calculator::HandleInput() { result = 0; } - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); - if (value == 0) { operation = ' '; UpdateOperation(); @@ -214,11 +196,6 @@ void Calculator::HandleInput() { if (operation == ' ') { ResetInput(); } - - NRF_LOG_INFO(". offset: %" PRId64, offset); - NRF_LOG_INFO(". value: %" PRId64, value); - NRF_LOG_INFO(". result: %" PRId64, result); - break; } From 6106e15057f7e69c94126232291ae1a936975c25 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Sat, 7 Dec 2024 17:52:58 +0100 Subject: [PATCH 185/191] Specify auto types --- src/displayapp/screens/Calculator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index fd312a725a..36474d4eeb 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -84,8 +84,8 @@ void Calculator::HandleInput() { case '9': { // *buttonText is the first char in buttonText // "- '0'" results in the int value of the char - auto digit = (*buttonText) - '0'; - auto sign = (value < 0) ? -1 : 1; + uint8_t digit = (*buttonText) - '0'; + int8_t sign = (value < 0) ? -1 : 1; // if this is true, we already pressed the . button if (offset < FIXED_POINT_OFFSET) { From b98536e268faab1631ec67da7f342bbd3f4387e0 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Sat, 7 Dec 2024 17:58:28 +0100 Subject: [PATCH 186/191] Change variables to camel case --- src/displayapp/screens/Calculator.cpp | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 36474d4eeb..7c759584d3 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -257,18 +257,18 @@ void Calculator::UpdateResultLabel() const { remainder = -remainder; } - uint8_t min_width = N_DECIMALS; + uint8_t minWidth = N_DECIMALS; // cut "0"-digits on the right while ((remainder > 0) && (remainder % 10 == 0)) { remainder /= 10; - min_width--; + minWidth--; } if ((integer == 0) && negative) { - lv_label_set_text_fmt(resultLabel, "-0.%0*" PRId64, min_width, remainder); + lv_label_set_text_fmt(resultLabel, "-0.%0*" PRId64, minWidth, remainder); } else { - lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, remainder); + lv_label_set_text_fmt(resultLabel, "%" PRId64 ".%0*" PRId64, integer, minWidth, remainder); } } @@ -288,31 +288,31 @@ void Calculator::UpdateValueLabel() { int64_t printRemainder = remainder < 0 ? -remainder : remainder; - uint8_t min_width = 0; - int64_t tmp_offset = offset; + uint8_t minWidth = 0; + int64_t tmpOffset = offset; - if (tmp_offset == 0) { - tmp_offset = 1; - min_width = 1; + if (tmpOffset == 0) { + tmpOffset = 1; + minWidth = 1; } - while (tmp_offset < FIXED_POINT_OFFSET) { - tmp_offset *= 10; - min_width++; + while (tmpOffset < FIXED_POINT_OFFSET) { + tmpOffset *= 10; + minWidth++; } - min_width--; + minWidth--; - for (uint8_t i = min_width; i < N_DECIMALS; i++) { + for (uint8_t i = minWidth; i < N_DECIMALS; i++) { printRemainder /= 10; } if ((integer == 0) && negative) { - lv_label_set_text_fmt(valueLabel, "-0.%0*" PRId64, min_width, printRemainder); + lv_label_set_text_fmt(valueLabel, "-0.%0*" PRId64, minWidth, printRemainder); } else if (offset == FIXED_POINT_OFFSET) { lv_label_set_text_fmt(valueLabel, "%" PRId64, integer); } else if ((offset == (FIXED_POINT_OFFSET / 10)) && (remainder == 0)) { lv_label_set_text_fmt(valueLabel, "%" PRId64 ".", integer); } else { - lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*" PRId64, integer, min_width, printRemainder); + lv_label_set_text_fmt(valueLabel, "%" PRId64 ".%0*" PRId64, integer, minWidth, printRemainder); } } break; } From df03059494963dc1af2a71b3a691bd467e86e7d8 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Sat, 7 Dec 2024 18:00:32 +0100 Subject: [PATCH 187/191] Rename equalSignPressed to equalSignPressedBefore --- src/displayapp/screens/Calculator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/Calculator.cpp b/src/displayapp/screens/Calculator.cpp index 7c759584d3..a1f093830c 100644 --- a/src/displayapp/screens/Calculator.cpp +++ b/src/displayapp/screens/Calculator.cpp @@ -65,7 +65,7 @@ void Calculator::HandleInput() { return; } - if ((equalSignPressed && (*buttonText != '=')) || (error != Error::None)) { + if ((equalSignPressedBefore && (*buttonText != '=')) || (error != Error::None)) { ResetInput(); UpdateOperation(); } @@ -188,7 +188,7 @@ void Calculator::HandleInput() { break; case '=': - equalSignPressed = true; + equalSignPressedBefore = true; Eval(); // If the operation is ' ' then we move the value to the result. // We reset the input after this. @@ -239,7 +239,7 @@ void Calculator::ResetInput() { value = 0; offset = FIXED_POINT_OFFSET; operation = ' '; - equalSignPressed = false; + equalSignPressedBefore = false; error = Error::None; } From 9619c759500f2c917d3f5f2fb687c7cfbd45fcd5 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Sat, 7 Dec 2024 18:01:25 +0100 Subject: [PATCH 188/191] Update header --- src/displayapp/screens/Calculator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index d7d66054f9..d71b7a83b2 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -58,7 +58,7 @@ namespace Pinetime { int64_t value = 0; int64_t result = 0; char operation = ' '; - bool equalSignPressed = false; + bool equalSignPressedBefore = false; enum Error { TooLarge, From e0af268a3cfc1a4975cebf8990d975d2e66e8f01 Mon Sep 17 00:00:00 2001 From: Max Friedrich Date: Mon, 9 Dec 2024 20:07:59 +0100 Subject: [PATCH 189/191] fix constexpr position Co-authored-by: mark9064 <30447455+mark9064@users.noreply.github.com> --- src/displayapp/screens/Calculator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/screens/Calculator.h b/src/displayapp/screens/Calculator.h index d71b7a83b2..9971f275a4 100644 --- a/src/displayapp/screens/Calculator.h +++ b/src/displayapp/screens/Calculator.h @@ -6,7 +6,7 @@ #include "Symbols.h" namespace { - int64_t constexpr powi(int64_t base, uint8_t exponent) { + constexpr int64_t powi(int64_t base, uint8_t exponent) { int64_t value = 1; while (exponent) { value *= base; From 21b6908e87838a516ee52c7831dcf55452753b9b Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Sat, 1 Mar 2025 20:51:13 +0000 Subject: [PATCH 190/191] Set sudo password for developer user in dev container This makes it possible to do live changes in a running container and debug issues there before adding to Dockerfile. --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index cc63c343f5..9f3f26374c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -64,8 +64,8 @@ RUN bash -c "source /opt/build.sh; GetNrfSdk;" # McuBoot RUN bash -c "source /opt/build.sh; GetMcuBoot;" -# Add the infinitime user for connecting devcontainer -RUN adduser infinitime +# Add the infinitime user with sudo password "it" for developing in devcontainer +RUN adduser infinitime && echo "infinitime:it" | chpasswd && usermod -aG sudo infinitime # Configure Git to accept the /sources directory as safe RUN git config --global --add safe.directory /sources From 85bdbd8fbcd5e272442d51c33740246892a3933e Mon Sep 17 00:00:00 2001 From: Darius Arnold Date: Sat, 1 Mar 2025 20:56:23 +0000 Subject: [PATCH 191/191] Add option to enable ccache to build - Add ENABLE_CCACHE flag to cmake - Install ccache in dev container - Always enable caching in CMakePresets.json --- CMakeLists.txt | 4 ++++ CMakePresets.json | 4 ++++ cmake/ccache.cmake | 14 ++++++++++++++ docker/Dockerfile | 1 + 4 files changed, 23 insertions(+) create mode 100644 cmake/ccache.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3250982d6a..6e0fbe3d4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,10 @@ if(BUILD_RESOURCES) set(BUILD_RESOURCES true) endif() +if(ENABLE_CCACHE) + include(cmake/ccache.cmake) +endif() + set(TARGET_DEVICE "PINETIME" CACHE STRING "Target device") set_property(CACHE TARGET_DEVICE PROPERTY STRINGS PINETIME MOY_TFK5 MOY_TIN5 MOY_TON5 MOY_UNK) diff --git a/CMakePresets.json b/CMakePresets.json index 0cb47a4448..3d94774fd6 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -31,6 +31,10 @@ "TARGET_DEVICE": { "type": "STRING", "value": "PINETIME" + }, + "ENABLE_CCACHE": { + "type": "BOOL", + "value": true } } }, diff --git a/cmake/ccache.cmake b/cmake/ccache.cmake new file mode 100644 index 0000000000..e9dccaa9ed --- /dev/null +++ b/cmake/ccache.cmake @@ -0,0 +1,14 @@ +find_program(CCACHE_EXECUTABLE ccache) + +if (CCACHE_EXECUTABLE) + message(STATUS "Activating ccache compiler cache.") + set(ccacheEnv + CCACHE_SLOPPINESS=pch_defines + ) + foreach (lang IN ITEMS C CXX) + set(CMAKE_${lang}_COMPILER_LAUNCHER + ${CMAKE_COMMAND} -E env ${ccacheEnv} ${CCACHE_EXECUTABLE} + ) + endforeach () + message(WARNING "Ccache could not be activated because ccache executable was not found.") +endif () diff --git a/docker/Dockerfile b/docker/Dockerfile index 9f3f26374c..95df5a64b8 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -12,6 +12,7 @@ RUN apt-get update -qq \ # x86_64 / generic packages bash \ build-essential \ + ccache \ cmake \ git \ make \