Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions src/components/timer/TimerController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,30 @@ void TimerController::Init(Pinetime::System::SystemTask* systemTask) {
void TimerController::StartTimer(uint32_t duration) {
xTimerChangePeriod(timer, pdMS_TO_TICKS(duration), 0);
xTimerStart(timer, 0);
state = TimerState::Running;
}

uint32_t TimerController::GetTimeRemaining() {
if (IsRunning()) {
TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount();
return (remainingTime * 1000 / configTICK_RATE_HZ);
uint32_t TimerController::GetTimeRemainingMs() {
TickType_t remainingTime = 0;
switch (state) {
case TimerState::Stopped:
break;
case TimerState::Running:
remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount();
break;
case TimerState::Finished:
remainingTime = xTaskGetTickCount() - xTimerGetExpiryTime(timer);
break;
}
return 0;
return (remainingTime * 1000 / configTICK_RATE_HZ);
}

void TimerController::StopTimer() {
xTimerStop(timer, 0);
}

bool TimerController::IsRunning() {
return (xTimerIsTimerActive(timer) == pdTRUE);
state = TimerState::Stopped;
}

void TimerController::OnTimerEnd() {
state = TimerState::Finished;
systemTask->PushMessage(System::Messages::OnTimerDone);
}
11 changes: 8 additions & 3 deletions src/components/timer/TimerController.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@ namespace Pinetime {

void StopTimer();

uint32_t GetTimeRemaining();

bool IsRunning();
uint32_t GetTimeRemainingMs();

void OnTimerEnd();

enum class TimerState { Stopped, Running, Finished };

TimerState State() const {
return state;
}

private:
System::SystemTask* systemTask = nullptr;
TimerHandle_t timer;
TimerState state = TimerState::Stopped;
};
}
}
9 changes: 7 additions & 2 deletions src/displayapp/DisplayApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,15 @@ void DisplayApp::Refresh() {
case Messages::NewNotification:
LoadNewScreen(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down);
break;
case Messages::GoToClock:
if (currentApp != Apps::Clock) {
LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None);
}
break;
case Messages::TimerDone:
if (currentApp == Apps::Timer) {
auto* timer = static_cast<Screens::Timer*>(currentScreen.get());
timer->Reset();
timer->SetTimerFinished();
} else {
LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up);
}
Expand Down Expand Up @@ -396,7 +401,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio
Screens::Notifications::Modes::Preview);
break;
case Apps::Timer:
currentScreen = std::make_unique<Screens::Timer>(this, timerController);
currentScreen = std::make_unique<Screens::Timer>(this, timerController, *systemTask);
break;
case Apps::Alarm:
currentScreen = std::make_unique<Screens::Alarm>(this, alarmController, settingsController.GetClockType(), *systemTask);
Expand Down
1 change: 1 addition & 0 deletions src/displayapp/Messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace Pinetime {
enum class Messages : uint8_t {
GoToSleep,
GoToRunning,
GoToClock,
UpdateDateTime,
UpdateBleConnection,
TouchEvent,
Expand Down
126 changes: 104 additions & 22 deletions src/displayapp/screens/Timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include <lvgl/lvgl.h>

using namespace Pinetime::Applications::Screens;
using Pinetime::Controllers::TimerController;

#define TIMER_RING_DURATION_MSEC (10 * 1000)

static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<Timer*>(obj->user_data);
Expand All @@ -17,9 +20,14 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
}
}

Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) : Screen(app), timerController {timerController} {
static void StopRingingTaskCallback(lv_task_t* task) {
auto* screen = static_cast<Timer*>(task->user_data);
screen->StopRinging();
}

lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr);
Timer::Timer(DisplayApp* app, TimerController& timerController, System::SystemTask& systemTask)
: Screen(app), timerController {timerController}, systemTask {systemTask} {
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_obj_set_style_local_text_color(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE);
lv_label_set_text_static(colonLabel, ":");
Expand Down Expand Up @@ -62,10 +70,16 @@ Timer::Timer(DisplayApp* app, Controllers::TimerController& timerController) : S
txtPlayPause = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0);

if (timerController.IsRunning()) {
SetTimerRunning();
} else {
SetTimerStopped();
switch (timerController.State()) {
case TimerController::TimerState::Running:
SetTimerRunning();
break;
case TimerController::TimerState::Stopped:
SetTimerStopped();
break;
case TimerController::TimerState::Finished:
SetTimerFinished();
break;
}

taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
Expand All @@ -84,9 +98,11 @@ void Timer::ButtonPressed() {
void Timer::MaskReset() {
buttonPressing = false;
// A click event is processed before a release event,
// so the release event would override the "Pause" text without this check
if (!timerController.IsRunning()) {
// so the release event would override the text without this check
if (timerController.State() == TimerController::TimerState::Stopped) {
lv_label_set_text_static(txtPlayPause, "Start");
} else if (timerController.State() == TimerController::TimerState::Finished) {
lv_label_set_text_static(txtPlayPause, "Stop");
}
maskPosition = 0;
UpdateMask();
Expand All @@ -103,45 +119,100 @@ void Timer::UpdateMask() {
}

void Timer::Refresh() {
if (timerController.IsRunning()) {
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
if (timerController.State() != TimerController::TimerState::Stopped) {
// Update counters if running or finished
uint32_t seconds = timerController.GetTimeRemainingMs() / 1000;
minuteCounter.SetValue(seconds / 60);
secondCounter.SetValue(seconds % 60);
} else if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
}
if (timerController.State() != TimerController::TimerState::Running && buttonPressing &&
xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
// Support long-pressing the button if stopped or finished
lv_label_set_text_static(txtPlayPause, "Reset");
maskPosition += 15;
if (maskPosition > 240) {
MaskReset();
Reset();
if (timerController.State() == TimerController::TimerState::Stopped) {
Reset();
} else {
StopRinging();
timerController.StopTimer();
systemTask.PushMessage(System::Messages::GoToClock);
}
} else {
UpdateMask();
}
}
}

void Timer::UpdateColor() {
lv_color_t color = timerController.State() == TimerController::TimerState::Finished ? LV_COLOR_RED : LV_COLOR_WHITE;
lv_obj_set_style_local_text_color(colonLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color);
minuteCounter.SetTextColor(color);
secondCounter.SetTextColor(color);
}

void Timer::SetTimerRunning() {
minuteCounter.HideControls();
secondCounter.HideControls();
lv_label_set_text_static(txtPlayPause, "Pause");
MaskReset();
UpdateColor();
}

void Timer::SetTimerFinished() {
minuteCounter.HideControls();
secondCounter.HideControls();
lv_label_set_text_static(txtPlayPause, "Stop");
UpdateColor();
uint32_t msecRemaining = timerController.GetTimeRemainingMs();
if (msecRemaining < TIMER_RING_DURATION_MSEC) {
taskStopRinging =
lv_task_create(StopRingingTaskCallback, pdMS_TO_TICKS(TIMER_RING_DURATION_MSEC - msecRemaining), LV_TASK_PRIO_MID, this);
systemTask.PushMessage(System::Messages::DisableSleeping);
}
}

bool Timer::StopRinging() {
if (taskStopRinging == nullptr) {
return false;
}
lv_task_del(taskStopRinging);
taskStopRinging = nullptr;
systemTask.PushMessage(System::Messages::StopRinging);
systemTask.PushMessage(System::Messages::EnableSleeping);
return true;
}

void Timer::SetTimerStopped() {
minuteCounter.ShowControls();
secondCounter.ShowControls();
lv_label_set_text_static(txtPlayPause, "Start");
UpdateColor();
}

void Timer::ToggleRunning() {
if (timerController.IsRunning()) {
uint32_t seconds = timerController.GetTimeRemaining() / 1000;
minuteCounter.SetValue(seconds / 60);
secondCounter.SetValue(seconds % 60);
timerController.StopTimer();
SetTimerStopped();
} else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
timerController.StartTimer((secondCounter.GetValue() + minuteCounter.GetValue() * 60) * 1000);
Refresh();
SetTimerRunning();
switch (timerController.State()) {
case TimerController::TimerState::Running: {
uint32_t seconds = timerController.GetTimeRemainingMs() / 1000;
minuteCounter.SetValue(seconds / 60);
secondCounter.SetValue(seconds % 60);
}
timerController.StopTimer();
SetTimerStopped();
break;
case TimerController::TimerState::Finished:
StopRinging();
timerController.StopTimer();
Reset();
break;
case TimerController::TimerState::Stopped:
if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
timerController.StartTimer((secondCounter.GetValue() + minuteCounter.GetValue() * 60) * 1000);
Refresh();
SetTimerRunning();
}
break;
}
}

Expand All @@ -150,3 +221,14 @@ void Timer::Reset() {
secondCounter.SetValue(0);
SetTimerStopped();
}

bool Timer::OnButtonPushed() {
return StopRinging();
}

bool Timer::OnTouchEvent(TouchEvents event) {
if (event == TouchEvents::SwipeDown) {
StopRinging();
}
return false;
}
10 changes: 9 additions & 1 deletion src/displayapp/screens/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,25 @@
namespace Pinetime::Applications::Screens {
class Timer : public Screen {
public:
Timer(DisplayApp* app, Controllers::TimerController& timerController);
Timer(DisplayApp* app, Controllers::TimerController& timerController, System::SystemTask& systemTask);
~Timer() override;
void Refresh() override;
void Reset();
void ToggleRunning();
void ButtonPressed();
void MaskReset();
void SetTimerFinished();
bool StopRinging();
bool OnButtonPushed() override;
bool OnTouchEvent(TouchEvents event) override;

private:
void SetTimerRunning();
void SetTimerStopped();
void UpdateMask();
void UpdateColor();
Controllers::TimerController& timerController;
System::SystemTask& systemTask;

lv_obj_t* btnPlayPause;
lv_obj_t* txtPlayPause;
Expand All @@ -36,7 +42,9 @@ namespace Pinetime::Applications::Screens {

lv_task_t* taskRefresh;
Widgets::Counter minuteCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
lv_obj_t* colonLabel;
Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76);
lv_task_t* taskStopRinging = nullptr;

bool buttonPressing = false;
lv_coord_t maskPosition = 0;
Expand Down
4 changes: 4 additions & 0 deletions src/displayapp/widgets/Counter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ void Counter::SetValueChangedEventCallback(void* userData, void (*handler)(void*
this->ValueChangedHandler = handler;
}

void Counter::SetTextColor(lv_color_t color) {
lv_obj_set_style_local_text_color(number, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color);
}

void Counter::Create() {
counterContainer = lv_obj_create(lv_scr_act(), nullptr);
lv_obj_set_style_local_bg_color(counterContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt);
Expand Down
1 change: 1 addition & 0 deletions src/displayapp/widgets/Counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace Pinetime {
void EnableMonthMode();
void SetMax(int newMax);
void SetValueChangedEventCallback(void* userData, void (*handler)(void* userData));
void SetTextColor(lv_color_t color);

int GetValue() const {
return value;
Expand Down
1 change: 1 addition & 0 deletions src/systemtask/Messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Pinetime {
enum class Messages : uint8_t {
GoToSleep,
GoToRunning,
GoToClock,
TouchWakeUp,
OnNewTime,
OnNewNotification,
Expand Down
8 changes: 7 additions & 1 deletion src/systemtask/SystemTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ void SystemTask::Work() {
alarmController.ScheduleAlarm();
}
break;
case Messages::GoToClock:
if (state == SystemTaskState::Sleeping) {
GoToRunning();
}
displayApp.PushMessage(Pinetime::Applications::Display::Messages::GoToClock);
break;
case Messages::OnNewNotification:
if (settingsController.GetNotificationStatus() == Pinetime::Controllers::Settings::Notification::On) {
if (state == SystemTaskState::Sleeping) {
Expand All @@ -295,7 +301,7 @@ void SystemTask::Work() {
if (state == SystemTaskState::Sleeping) {
GoToRunning();
}
motorController.RunForDuration(35);
motorController.StartRinging();
displayApp.PushMessage(Pinetime::Applications::Display::Messages::TimerDone);
break;
case Messages::SetOffAlarm:
Expand Down