This commit is contained in:
tausen 2024-08-10 00:04:09 +02:00 committed by GitHub
commit 32aa22af4f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 182 additions and 52 deletions

View file

@ -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

View file

@ -3,26 +3,57 @@
using namespace Pinetime::Controllers;
Timer::Timer(void* const timerData, TimerCallbackFunction_t timerCallbackFunction) {
pausedAtTimer = std::chrono::seconds(0);
state = Stopped;
timer = xTimerCreate("Timer", 1, pdFALSE, timerData, timerCallbackFunction);
}
void Timer::StartTimer(std::chrono::milliseconds duration) {
xTimerChangePeriod(timer, pdMS_TO_TICKS(duration.count()), 0);
xTimerStart(timer, 0);
}
std::chrono::milliseconds Timer::GetTimeRemaining() {
if (IsRunning()) {
TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount();
const TickType_t remainingTime = xTimerGetExpiryTime(timer) - xTaskGetTickCount();
return std::chrono::milliseconds(remainingTime * 1000 / configTICK_RATE_HZ);
}
if (state == Paused)
return pausedAtTimer;
return std::chrono::milliseconds(0);
}
void Timer::StopTimer() {
xTimerStop(timer, 0);
Timer::TimerState Timer::GetState() {
return state;
}
void Timer::Start(const std::chrono::milliseconds duration) {
TimerStart(duration);
state = Running;
}
void Timer::Stop() {
TimerStop();
state = Stopped;
}
void Timer::Pause() {
pausedAtTimer = GetTimeRemaining();
TimerStop();
state = Paused;
}
void Timer::Resume() {
TimerStart(pausedAtTimer);
state = Running;
}
bool Timer::IsRunning() {
return (xTimerIsTimerActive(timer) == pdTRUE);
};
void Timer::TimerStart(const std::chrono::milliseconds duration) {
xTimerChangePeriod(timer, pdMS_TO_TICKS(duration.count()), 0);
xTimerStart(timer, 0);
}
void Timer::TimerStop() {
xTimerStop(timer, 0);
}

View file

@ -11,16 +11,30 @@ namespace Pinetime {
public:
Timer(void* timerData, TimerCallbackFunction_t timerCallbackFunction);
void StartTimer(std::chrono::milliseconds duration);
void Start(const std::chrono::milliseconds duration);
void StopTimer();
void Stop();
void Pause();
void Resume();
std::chrono::milliseconds GetTimeRemaining();
bool IsRunning();
typedef enum TimerState { Running, Stopped, Paused } TimerState;
TimerState GetState();
private:
TimerHandle_t timer;
std::chrono::milliseconds pausedAtTimer;
TimerState state;
bool IsRunning();
void TimerStart(const std::chrono::milliseconds duration);
void TimerStop();
};
}
}

View file

@ -333,11 +333,12 @@ void DisplayApp::Refresh() {
}
if (currentApp == Apps::Timer) {
lv_disp_trig_activity(nullptr);
auto* timer = static_cast<Screens::Timer*>(currentScreen.get());
timer->Reset();
} else {
LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up);
}
Screens::Timer* timer;
timer = static_cast<Screens::Timer*>(currentScreen.get());
timer->Stop();
motorController.RunForDuration(35);
break;
case Messages::AlarmTriggered:

View file

@ -6,6 +6,8 @@
using namespace Pinetime::Applications::Screens;
static std::chrono::milliseconds lastTimerSetting;
static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
auto* screen = static_cast<Timer*>(obj->user_data);
if (event == LV_EVENT_PRESSED) {
@ -17,6 +19,11 @@ static void btnEventHandler(lv_obj_t* obj, lv_event_t event) {
}
}
static void counterChangeHandler(void *timerScreen) {
Timer* timer = (Timer*)timerScreen;
lastTimerSetting = timer->GetCounters();
}
Timer::Timer(Controllers::Timer& timerController) : timer {timerController} {
lv_obj_t* colonLabel = lv_label_create(lv_scr_act(), nullptr);
@ -29,6 +36,8 @@ Timer::Timer(Controllers::Timer& timerController) : timer {timerController} {
secondCounter.Create();
lv_obj_align(minuteCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_align(secondCounter.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0);
minuteCounter.SetValueChangedEventCallback(this, counterChangeHandler);
secondCounter.SetValueChangedEventCallback(this, counterChangeHandler);
highlightObjectMask = lv_objmask_create(lv_scr_act(), nullptr);
lv_obj_set_size(highlightObjectMask, 240, 50);
@ -60,12 +69,20 @@ Timer::Timer(Controllers::Timer& timerController) : timer {timerController} {
lv_obj_set_size(btnPlayPause, LV_HOR_RES, 50);
txtPlayPause = lv_label_create(lv_scr_act(), nullptr);
lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0);
if (timer.IsRunning()) {
SetTimerRunning();
} else {
SetTimerStopped();
switch (timer.GetState()) {
case Controllers::Timer::TimerState::Stopped:
SetCounters(lastTimerSetting);
SetInterfaceStopped();
break;
case Controllers::Timer::TimerState::Running:
SetCounters(timer.GetTimeRemaining());
SetInterfaceRunning();
break;
case Controllers::Timer::TimerState::Paused:
SetCounters(timer.GetTimeRemaining());
SetInterfacePaused();
break;
}
taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this);
@ -76,6 +93,11 @@ Timer::~Timer() {
lv_obj_clean(lv_scr_act());
}
void Timer::SetButtonText(const char* text) {
lv_label_set_text_static(txtPlayPause, text);
lv_obj_align(txtPlayPause, btnPlayPause, LV_ALIGN_CENTER, 0, 0);
}
void Timer::ButtonPressed() {
pressTime = xTaskGetTickCount();
buttonPressing = true;
@ -83,15 +105,40 @@ 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 (!timer.IsRunning()) {
lv_label_set_text_static(txtPlayPause, "Start");
switch (timer.GetState()) {
case Controllers::Timer::TimerState::Stopped:
SetButtonText("Start");
break;
case Controllers::Timer::TimerState::Running:
SetButtonText("Pause");
break;
case Controllers::Timer::TimerState::Paused:
SetButtonText("Resume");
break;
}
maskPosition = 0;
UpdateMask();
}
void Timer::HandleHold() {
if (timer.GetState() == Controllers::Timer::TimerState::Stopped) {
SetButtonText("Reset");
} else {
SetButtonText("Stop");
}
maskPosition += 15;
if (maskPosition > 240) {
HandleLongPress();
} else {
UpdateMask();
}
}
void Timer::UpdateMask() {
lv_draw_mask_line_param_t maskLine;
@ -102,52 +149,81 @@ void Timer::UpdateMask() {
lv_objmask_update_mask(btnObjectMask, btnMask, &maskLine);
}
void Timer::Refresh() {
if (timer.IsRunning()) {
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
minuteCounter.SetValue(secondsRemaining.count() / 60);
secondCounter.SetValue(secondsRemaining.count() % 60);
} else if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
lv_label_set_text_static(txtPlayPause, "Reset");
maskPosition += 15;
if (maskPosition > 240) {
MaskReset();
void Timer::HandleLongPress() {
if (timer.GetState() == Controllers::Timer::TimerState::Stopped) {
Reset();
} else {
UpdateMask();
Stop();
}
MaskReset();
}
void Timer::Refresh() {
if (timer.GetState() == Controllers::Timer::TimerState::Running) {
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
SetCounters(secondsRemaining);
} else {
if (buttonPressing && xTaskGetTickCount() > pressTime + pdMS_TO_TICKS(150)) {
HandleHold();
}
}
}
void Timer::SetTimerRunning() {
void Timer::SetInterfaceRunning() {
minuteCounter.HideControls();
secondCounter.HideControls();
lv_label_set_text_static(txtPlayPause, "Pause");
SetButtonText("Pause");
}
void Timer::SetTimerStopped() {
void Timer::SetInterfacePaused() {
minuteCounter.HideControls();
secondCounter.HideControls();
SetButtonText("Resume");
}
void Timer::SetInterfaceStopped() {
minuteCounter.ShowControls();
secondCounter.ShowControls();
lv_label_set_text_static(txtPlayPause, "Start");
SetButtonText("Start");
}
void Timer::SetCounters(const std::chrono::milliseconds& duration) {
SetCounters(std::chrono::duration_cast<std::chrono::seconds>(duration));
}
void Timer::SetCounters(const std::chrono::seconds& duration) {
minuteCounter.SetValue(duration.count() / 60);
secondCounter.SetValue(duration.count() % 60);
}
std::chrono::seconds Timer::GetCounters() {
return std::chrono::minutes(minuteCounter.GetValue()) + std::chrono::seconds(secondCounter.GetValue());
}
void Timer::ToggleRunning() {
if (timer.IsRunning()) {
auto secondsRemaining = std::chrono::duration_cast<std::chrono::seconds>(timer.GetTimeRemaining());
minuteCounter.SetValue(secondsRemaining.count() / 60);
secondCounter.SetValue(secondsRemaining.count() % 60);
timer.StopTimer();
SetTimerStopped();
} else if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
auto timerDuration = std::chrono::minutes(minuteCounter.GetValue()) + std::chrono::seconds(secondCounter.GetValue());
timer.StartTimer(timerDuration);
if (timer.GetState() == Controllers::Timer::TimerState::Stopped) {
if (secondCounter.GetValue() + minuteCounter.GetValue() > 0) {
timer.Start(GetCounters());
Refresh();
SetTimerRunning();
SetInterfaceRunning();
}
} else if (timer.GetState() == Controllers::Timer::TimerState::Running) {
timer.Pause();
SetInterfacePaused();
} else { // Paused
timer.Resume();
SetInterfaceRunning();
}
}
void Timer::Reset() {
minuteCounter.SetValue(0);
secondCounter.SetValue(0);
SetTimerStopped();
lastTimerSetting = std::chrono::seconds(0);
Stop();
}
void Timer::Stop() {
timer.Stop();
SetCounters(lastTimerSetting);
SetInterfaceStopped();
}

View file

@ -17,15 +17,23 @@ namespace Pinetime::Applications {
Timer(Controllers::Timer& timerController);
~Timer() override;
void Refresh() override;
void Stop();
void Reset();
void ToggleRunning();
void ButtonPressed();
void MaskReset();
std::chrono::seconds GetCounters();
private:
void SetTimerRunning();
void SetTimerStopped();
void SetInterfaceRunning();
void SetInterfacePaused();
void SetInterfaceStopped();
void HandleHold();
void UpdateMask();
void HandleLongPress();
void SetCounters(const std::chrono::milliseconds& duration);
void SetCounters(const std::chrono::seconds& duration);
void SetButtonText(const char* text);
Pinetime::Controllers::Timer& timer;
lv_obj_t* btnPlayPause;