From 77f465dea3984e6942c3a738e4ced4f6b5ef48c3 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Mon, 8 Jan 2024 10:02:45 -0500 Subject: [PATCH 1/2] timer: Add ringing The timer app issues a short buzz once and then disappears. There is no trace left that the timer finished or how long ago. This change makes the motor start ringing and presents a timer counter. --- src/components/motor/MotorController.cpp | 4 +++ src/components/motor/MotorController.h | 1 + src/components/timer/Timer.cpp | 8 +++--- src/displayapp/DisplayApp.cpp | 2 +- src/displayapp/screens/Timer.cpp | 31 +++++++++++++++++++++--- src/displayapp/screens/Timer.h | 8 ++++-- 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index 4e392416..d3bd2cf3 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -34,6 +34,10 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(PinMap::Motor); } +bool MotorController::IsRinging() { + return (xTimerIsTimerActive(longVib) == pdTRUE); +} + 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 6dea6d1f..ab8c956e 100644 --- a/src/components/motor/MotorController.h +++ b/src/components/motor/MotorController.h @@ -15,6 +15,7 @@ namespace Pinetime { void RunForDuration(uint8_t motorDuration); void StartRinging(); void StopRinging(); + bool IsRinging(); private: static void Ring(TimerHandle_t xTimer); diff --git a/src/components/timer/Timer.cpp b/src/components/timer/Timer.cpp index 279178cd..b3c4417a 100644 --- a/src/components/timer/Timer.cpp +++ b/src/components/timer/Timer.cpp @@ -12,11 +12,13 @@ void Timer::StartTimer(std::chrono::milliseconds duration) { } std::chrono::milliseconds Timer::GetTimeRemaining() { + TickType_t remainingTime = 0; if (IsRunning()) { - TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount(); - return std::chrono::milliseconds(remainingTime * 1000 / configTICK_RATE_HZ); + remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount(); + } else { + remainingTime = xTaskGetTickCount() - xTimerGetExpiryTime(timer); } - return std::chrono::milliseconds(0); + return std::chrono::milliseconds(remainingTime * 1000 / configTICK_RATE_HZ); } void Timer::StopTimer() { diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 3fd34b3a..01bb1d6c 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -270,7 +270,7 @@ void DisplayApp::Refresh() { } else { LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); } - motorController.RunForDuration(35); + motorController.StartRinging(); break; case Messages::AlarmTriggered: if (currentApp == Apps::Alarm) { diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index a1ede6be..f0b48f8d 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -17,7 +17,8 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) { } } -Timer::Timer(Controllers::Timer& timerController) : timer {timerController} { +Timer::Timer(Controllers::Timer& timerController, Controllers::MotorController& motorController) + : timer {timerController}, motorController {motorController} { 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); @@ -62,7 +63,9 @@ Timer::Timer(Controllers::Timer& timerController) : timer {timerController} { txtPlayPause = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0); - if (timer.IsRunning()) { + if (motorController.IsRinging()) { + SetTimerRinging(); + } else if (timer.IsRunning()) { SetTimerRunning(); } else { SetTimerStopped(); @@ -103,7 +106,12 @@ void Timer::UpdateMask() { } void Timer::Refresh() { - if (timer.IsRunning()) { + if (motorController.IsRinging()) { + SetTimerRinging(); + auto secondsElapsed = std::chrono::duration_cast(timer.GetTimeRemaining()); + minuteCounter.SetValue(secondsElapsed.count() / 60); + secondCounter.SetValue(secondsElapsed.count() % 60); + } else if (timer.IsRunning()) { auto secondsRemaining = std::chrono::duration_cast(timer.GetTimeRemaining()); minuteCounter.SetValue(secondsRemaining.count() / 60); secondCounter.SetValue(secondsRemaining.count() % 60); @@ -123,16 +131,31 @@ void Timer::SetTimerRunning() { minuteCounter.HideControls(); secondCounter.HideControls(); lv_label_set_text_static(txtPlayPause, "Pause"); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); } void Timer::SetTimerStopped() { minuteCounter.ShowControls(); secondCounter.ShowControls(); lv_label_set_text_static(txtPlayPause, "Start"); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); +} + +void Timer::SetTimerRinging() { + minuteCounter.HideControls(); + secondCounter.HideControls(); + lv_label_set_text_static(txtPlayPause, "Reset"); + lv_obj_set_style_local_bg_color(btnPlayPause, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); + if (ringTime == 0) { + ringTime = xTaskGetTickCount(); + } } void Timer::ToggleRunning() { - if (timer.IsRunning()) { + if (motorController.IsRinging()) { + motorController.StopRinging(); + Reset(); + } else if (timer.IsRunning()) { auto secondsRemaining = std::chrono::duration_cast(timer.GetTimeRemaining()); minuteCounter.SetValue(secondsRemaining.count() / 60); secondCounter.SetValue(secondsRemaining.count() % 60); diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index 409cae1c..99f3a016 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -2,6 +2,7 @@ #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" +#include "components/motor/MotorController.h" #include "systemtask/SystemTask.h" #include "displayapp/LittleVgl.h" #include "displayapp/widgets/Counter.h" @@ -14,7 +15,7 @@ namespace Pinetime::Applications { namespace Screens { class Timer : public Screen { public: - Timer(Controllers::Timer& timerController); + Timer(Controllers::Timer& timerController, Controllers::MotorController& motorController); ~Timer() override; void Refresh() override; void Reset(); @@ -25,8 +26,10 @@ namespace Pinetime::Applications { private: void SetTimerRunning(); void SetTimerStopped(); + void SetTimerRinging(); void UpdateMask(); Pinetime::Controllers::Timer& timer; + Pinetime::Controllers::MotorController& motorController; lv_obj_t* btnPlayPause; lv_obj_t* txtPlayPause; @@ -43,6 +46,7 @@ namespace Pinetime::Applications { bool buttonPressing = false; lv_coord_t maskPosition = 0; TickType_t pressTime = 0; + TickType_t ringTime = 0; }; } @@ -52,7 +56,7 @@ namespace Pinetime::Applications { static constexpr const char* icon = Screens::Symbols::hourGlass; static Screens::Screen* Create(AppControllers& controllers) { - return new Screens::Timer(controllers.timer); + return new Screens::Timer(controllers.timer, controllers.motorController); }; }; } From 4542055faf5d85afc3de3b544fc3e1dc7dc3550c Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Mon, 15 Jan 2024 11:50:54 -0500 Subject: [PATCH 2/2] timer: Stop buzzing after 10 seconds Also reset timer after 1 minute. --- src/displayapp/DisplayApp.cpp | 9 ++++++--- src/displayapp/screens/Timer.cpp | 15 ++++++++++++--- src/displayapp/screens/Timer.h | 3 ++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 01bb1d6c..cbf1912e 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -263,12 +263,15 @@ void DisplayApp::Refresh() { if (state != States::Running) { PushMessageToSystemTask(System::Messages::GoToRunning); } + // Load timer app if not loaded + if (currentApp != Apps::Timer) { + LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); + } + // Once loaded, set the timer to ringing mode if (currentApp == Apps::Timer) { lv_disp_trig_activity(nullptr); auto* timer = static_cast(currentScreen.get()); - timer->Reset(); - } else { - LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); + timer->SetTimerRinging(); } motorController.StartRinging(); break; diff --git a/src/displayapp/screens/Timer.cpp b/src/displayapp/screens/Timer.cpp index f0b48f8d..dbfaeff5 100644 --- a/src/displayapp/screens/Timer.cpp +++ b/src/displayapp/screens/Timer.cpp @@ -106,11 +106,18 @@ void Timer::UpdateMask() { } void Timer::Refresh() { - if (motorController.IsRinging()) { - SetTimerRinging(); + if (isRinging) { auto secondsElapsed = std::chrono::duration_cast(timer.GetTimeRemaining()); minuteCounter.SetValue(secondsElapsed.count() / 60); secondCounter.SetValue(secondsElapsed.count() % 60); + // Stop buzzing after 10 seconds, but continue the counter + if (motorController.IsRinging() && secondsElapsed.count() > 10) { + motorController.StopRinging(); + } + // Reset timer after 1 minute + if (secondsElapsed.count() > 60) { + Reset(); + } } else if (timer.IsRunning()) { auto secondsRemaining = std::chrono::duration_cast(timer.GetTimeRemaining()); minuteCounter.SetValue(secondsRemaining.count() / 60); @@ -135,6 +142,7 @@ void Timer::SetTimerRunning() { } void Timer::SetTimerStopped() { + isRinging = false; minuteCounter.ShowControls(); secondCounter.ShowControls(); lv_label_set_text_static(txtPlayPause, "Start"); @@ -142,6 +150,7 @@ void Timer::SetTimerStopped() { } void Timer::SetTimerRinging() { + isRinging = true; minuteCounter.HideControls(); secondCounter.HideControls(); lv_label_set_text_static(txtPlayPause, "Reset"); @@ -152,7 +161,7 @@ void Timer::SetTimerRinging() { } void Timer::ToggleRunning() { - if (motorController.IsRinging()) { + if (isRinging) { motorController.StopRinging(); Reset(); } else if (timer.IsRunning()) { diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index 99f3a016..62ae96a7 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -22,11 +22,11 @@ namespace Pinetime::Applications { void ToggleRunning(); void ButtonPressed(); void MaskReset(); + void SetTimerRinging(); private: void SetTimerRunning(); void SetTimerStopped(); - void SetTimerRinging(); void UpdateMask(); Pinetime::Controllers::Timer& timer; Pinetime::Controllers::MotorController& motorController; @@ -44,6 +44,7 @@ namespace Pinetime::Applications { Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76); bool buttonPressing = false; + bool isRinging = false; lv_coord_t maskPosition = 0; TickType_t pressTime = 0; TickType_t ringTime = 0;