diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e727b2b0ce..89a85f6890 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -482,6 +482,7 @@ list(APPEND SOURCE_FILES components/motor/MotorController.cpp components/settings/Settings.cpp components/timer/TimerController.cpp + components/stopwatch/StopWatchController.cpp components/alarm/AlarmController.cpp components/fs/FS.cpp drivers/Cst816s.cpp @@ -552,6 +553,7 @@ list(APPEND RECOVERY_SOURCE_FILES components/settings/Settings.cpp components/timer/TimerController.cpp components/alarm/AlarmController.cpp + components/stopwatch/StopWatchController.cpp drivers/Cst816s.cpp FreeRTOS/port.c FreeRTOS/port_cmsis_systick.c @@ -660,6 +662,7 @@ set(INCLUDE_FILES components/settings/Settings.h components/timer/TimerController.h components/alarm/AlarmController.h + components/stopwatch/StopWatchController.h drivers/Cst816s.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h diff --git a/src/components/stopwatch/StopWatchController.cpp b/src/components/stopwatch/StopWatchController.cpp new file mode 100644 index 0000000000..adbc091524 --- /dev/null +++ b/src/components/stopwatch/StopWatchController.cpp @@ -0,0 +1,103 @@ +#include "StopWatchController.h" +#include +#include + +using namespace Pinetime::Controllers; + +namespace { + TickType_t calculateDelta(const TickType_t startTime, const TickType_t currentTime) { + TickType_t delta = 0; + // Take care of overflow + if (startTime > currentTime) { + delta = 0xffffffff - startTime; + delta += (currentTime + 1); + } else { + delta = currentTime - startTime; + } + return delta; + } +} + +StopWatch::StopWatch() { + clear(); +} + +// State Change + +void StopWatch::start(TickType_t start) { + currentState = StopWatchStates::Running; + startTime = start; +} + +void StopWatch::pause(TickType_t end) { + currentState = StopWatchStates::Paused; + timeElapsedPreviously += calculateDelta(startTime, end); +} + +void StopWatch::clear() { + currentState = StopWatchStates::Cleared; + timeElapsedPreviously = 0; + + for (int i = 0; i < LAP_CAPACITY; i++) { + laps[i].count = 0; + laps[i].time = 0; + } + lapCount = 0; + lapHead = 0; +} + +// Lap + +void StopWatch::pushLap(TickType_t lapEnd) { + laps[lapHead].time = lapEnd; + laps[lapHead].count = lapCount + 1; + lapCount += 1; + lapHead = lapCount % LAP_CAPACITY; +} + +int StopWatch::getLapNum() { + if (lapCount < LAP_CAPACITY) + return lapCount; + else + return LAP_CAPACITY; +} + +int StopWatch::getLapCount() { + return lapCount; +} + +int wrap(int index) { + return ((index % LAP_CAPACITY) + LAP_CAPACITY) % LAP_CAPACITY; +} + +LapInfo_t* StopWatch::lastLap(int lap) { + if (lap >= LAP_CAPACITY || lap > lapCount || lapCount == 0) { + // Return "empty" LapInfo_t + return &emptyLapInfo; + } + // Index backwards + int index = wrap(lapHead - lap); + return &laps[index]; +} + +// Data acess + +TickType_t StopWatch::getStart() { + return startTime; +} + +TickType_t StopWatch::getElapsedPreviously() { + return timeElapsedPreviously; +} + +bool StopWatch::isRunning() { + return currentState == StopWatchStates::Running; +} + +bool StopWatch::isCleared() { + return currentState == StopWatchStates::Cleared; +} + +bool StopWatch::isPaused() { + return currentState == StopWatchStates::Paused; +} diff --git a/src/components/stopwatch/StopWatchController.h b/src/components/stopwatch/StopWatchController.h new file mode 100644 index 0000000000..d1198f1de7 --- /dev/null +++ b/src/components/stopwatch/StopWatchController.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include "FreeRTOS.h" + +#define LAP_CAPACITY 2 + +namespace Pinetime { + namespace System { + class SystemTask; + } + namespace Controllers { + + enum class StopWatchStates { Cleared, Running, Paused }; + + struct LapInfo_t { + int count = 0; // Used to label the lap + TickType_t time = 0; // delta time from beginning of stopwatch + }; + + class StopWatch { + public: + StopWatch(); + + // StopWatch functionality and data + void start(TickType_t start); + void pause(TickType_t end); + void clear(); + + TickType_t getStart(); + TickType_t getElapsedPreviously(); + + // Lap functionality + + /// Only the latest laps are stored, the lap count is saved until reset + void pushLap(TickType_t lapEnd); + + /// Returns actual count of stored laps + int getLapNum(); + + /// Returns lapCount + int getLapCount(); + + /// Indexes into lap history, with 0 being the latest lap. + /// If the lap is unavailable, count and time will be 0. If there is a + /// real value, count should be above 0 + LapInfo_t* lastLap(int lap = 0); + + bool isRunning(); + bool isCleared(); + bool isPaused(); + + private: + // Current state of stopwatch + StopWatchStates currentState = StopWatchStates::Cleared; + // Start time of current duration + TickType_t startTime = 0; + // How much time was elapsed before current duration + TickType_t timeElapsedPreviously = 0; + // Stores lap times + LapInfo_t laps[LAP_CAPACITY]; + LapInfo_t emptyLapInfo = {.count = 0, .time = 0}; + int lapCount = 0; + int lapHead = 0; + }; + } +} diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 38ce930ae0..aebbda032a 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -10,6 +10,7 @@ #include "components/ble/NotificationManager.h" #include "components/motion/MotionController.h" #include "components/motor/MotorController.h" +#include "components/stopwatch/StopWatchController.h" #include "displayapp/screens/ApplicationList.h" #include "displayapp/screens/Brightness.h" #include "displayapp/screens/Clock.h" @@ -95,6 +96,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::StopWatch& stopWatchController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, lvgl {lvgl}, @@ -110,6 +112,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, motionController {motionController}, timerController {timerController}, alarmController {alarmController}, + stopWatchController {stopWatchController}, touchHandler {touchHandler} { } @@ -424,7 +427,7 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::StopWatch: - currentScreen = std::make_unique(this, *systemTask); + currentScreen = std::make_unique(this, *systemTask, dateTimeController, stopWatchController, batteryController); break; case Apps::Twos: currentScreen = std::make_unique(this); diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 39fe631455..1839f29193 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -16,6 +16,7 @@ #include "components/timer/TimerController.h" #include "components/alarm/AlarmController.h" #include "touchhandler/TouchHandler.h" +#include "components/stopwatch/StopWatchController.h" #include "displayapp/Messages.h" #include "BootErrors.h" @@ -36,6 +37,7 @@ namespace Pinetime { class HeartRateController; class MotionController; class TouchHandler; + class StopWatch; } namespace System { @@ -61,6 +63,7 @@ namespace Pinetime { Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::StopWatch& stopWatchController, Pinetime::Controllers::TouchHandler& touchHandler); void Start(System::BootErrors error); void PushMessage(Display::Messages msg); @@ -87,6 +90,7 @@ namespace Pinetime { Pinetime::Controllers::MotionController& motionController; Pinetime::Controllers::TimerController& timerController; Pinetime::Controllers::AlarmController& alarmController; + Pinetime::Controllers::StopWatch& stopWatchController; Pinetime::Controllers::TouchHandler& touchHandler; Pinetime::Controllers::FirmwareValidator validator; diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index fd7017a451..e293b561f3 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -23,6 +23,7 @@ DisplayApp::DisplayApp(Drivers::St7789& lcd, Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::StopWatch& stopWatchController, Pinetime::Controllers::TouchHandler& touchHandler) : lcd {lcd}, bleController {bleController} { diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 86e956d133..47d8cd2d79 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -34,6 +34,7 @@ namespace Pinetime { class MotorController; class TimerController; class AlarmController; + class StopWatch; } namespace System { @@ -57,6 +58,7 @@ namespace Pinetime { Pinetime::Controllers::MotionController& motionController, Pinetime::Controllers::TimerController& timerController, Pinetime::Controllers::AlarmController& alarmController, + Pinetime::Controllers::StopWatch& stopWatchController, Pinetime::Controllers::TouchHandler& touchHandler); void Start(); void Start(Pinetime::System::BootErrors){ Start(); }; diff --git a/src/displayapp/screens/StopWatch.cpp b/src/displayapp/screens/StopWatch.cpp index a260d29310..fb88aff723 100644 --- a/src/displayapp/screens/StopWatch.cpp +++ b/src/displayapp/screens/StopWatch.cpp @@ -6,6 +6,7 @@ #include "projdefs.h" #include "FreeRTOSConfig.h" #include "task.h" +#include "BatteryIcon.h" #include @@ -45,28 +46,33 @@ static void stop_lap_event_handler(lv_obj_t* obj, lv_event_t event) { stopWatch->stopLapBtnEventHandler(event); } -StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) +StopWatch::StopWatch(DisplayApp* app, + System::SystemTask& systemTask, + Controllers::DateTime& dateTimeController, + Controllers::StopWatch& stopWatchController, + Controllers::Battery& batteryController) : Screen(app), systemTask {systemTask}, - currentState {States::Init}, - startTime {}, - oldTimeElapsed {}, - currentTimeSeparated {}, - lapBuffer {}, - lapNr {} { + dateTimeController {dateTimeController}, + stopWatchController {stopWatchController}, + batteryController {batteryController}, + timeElapsed {}, + currentTimeSeparated {} { + // Running time time = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_font(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_76); lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); lv_label_set_text(time, "00:00"); lv_obj_align(time, lv_scr_act(), LV_ALIGN_CENTER, 0, -45); + // Create millisecond label msecTime = lv_label_create(lv_scr_act(), nullptr); - // lv_obj_set_style_local_text_font(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); lv_label_set_text(msecTime, "00"); lv_obj_align(msecTime, lv_scr_act(), LV_ALIGN_CENTER, 0, 3); + // Create play/pause button btnPlayPause = lv_btn_create(lv_scr_act(), nullptr); btnPlayPause->user_data = this; lv_obj_set_event_cb(btnPlayPause, play_pause_event_handler); @@ -76,6 +82,7 @@ StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) txtPlayPause = lv_label_create(btnPlayPause, nullptr); lv_label_set_text(txtPlayPause, Symbols::play); + // Create stop/lap button btnStopLap = lv_btn_create(lv_scr_act(), nullptr); btnStopLap->user_data = this; lv_obj_set_event_cb(btnStopLap, stop_lap_event_handler); @@ -89,19 +96,53 @@ StopWatch::StopWatch(DisplayApp* app, System::SystemTask& systemTask) lv_obj_set_state(btnStopLap, LV_STATE_DISABLED); lv_obj_set_state(txtStopLap, LV_STATE_DISABLED); + // Create first lap text label lapOneText = lv_label_create(lv_scr_act(), nullptr); - // lv_obj_set_style_local_text_font(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); lv_obj_set_style_local_text_color(lapOneText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_obj_align(lapOneText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 30); lv_label_set_text(lapOneText, ""); + // Create second lap text label lapTwoText = lv_label_create(lv_scr_act(), nullptr); - // lv_obj_set_style_local_text_font(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); lv_obj_set_style_local_text_color(lapTwoText, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_obj_align(lapTwoText, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 50, 55); lv_label_set_text(lapTwoText, ""); + // Create Date time label + dateTime = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_fmt(dateTime, "%02i:%02i", dateTimeController.Hours(), dateTimeController.Minutes()); + lv_label_set_align(dateTime, LV_LABEL_ALIGN_CENTER); + lv_obj_align(dateTime, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + lv_obj_set_style_local_text_color(dateTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + + // Battery + batteryIcon = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryController.PercentRemaining())); + lv_obj_align(batteryIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, -8, 0); + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + + // Figure out what the current state of the stopwatch is and select the correct display + if (stopWatchController.isCleared()) { + displayCleared(); + } else { + // Add laps if there are any + if (stopWatchController.getLapCount() > 0) { + updateLaps(); + } + + if (stopWatchController.isRunning()) { + displayRunning(); + } else if (stopWatchController.isPaused()) { + displayPaused(); + currentTimeSeparated = convertTicksToTimeSegments(stopWatchController.getElapsedPreviously()); + + lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs); + lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths); + lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT); + lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT); + } + } } StopWatch::~StopWatch() { @@ -110,9 +151,7 @@ StopWatch::~StopWatch() { lv_obj_clean(lv_scr_act()); } -void StopWatch::reset() { - currentState = States::Init; - oldTimeElapsed = 0; +void StopWatch::displayCleared() { lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); @@ -121,40 +160,54 @@ void StopWatch::reset() { lv_label_set_text(lapOneText, ""); lv_label_set_text(lapTwoText, ""); - lapBuffer.clearBuffer(); - lapNr = 0; + lv_obj_set_state(btnStopLap, LV_STATE_DISABLED); lv_obj_set_state(txtStopLap, LV_STATE_DISABLED); } -void StopWatch::start() { +void StopWatch::displayRunning() { lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT); lv_obj_set_state(txtStopLap, LV_STATE_DEFAULT); lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GREEN); lv_label_set_text(txtPlayPause, Symbols::pause); lv_label_set_text(txtStopLap, Symbols::lapsFlag); - startTime = xTaskGetTickCount(); - currentState = States::Running; + systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); } -void StopWatch::pause() { - startTime = 0; - // Store the current time elapsed in cache - oldTimeElapsed += timeElapsed; - currentState = States::Halted; - lv_label_set_text(txtPlayPause, Symbols::play); - lv_label_set_text(txtStopLap, Symbols::stop); +void StopWatch::displayPaused() { + lv_obj_set_state(btnStopLap, LV_STATE_DEFAULT); + lv_obj_set_style_local_text_color(time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_obj_set_style_local_text_color(msecTime, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); + + lv_label_set_text(txtPlayPause, Symbols::play); + lv_label_set_text(txtStopLap, Symbols::stop); + systemTask.PushMessage(Pinetime::System::Messages::EnableSleeping); } +void StopWatch::updateLaps() { + Pinetime::Controllers::LapInfo_t* lap1 = stopWatchController.lastLap(); + Pinetime::Controllers::LapInfo_t* lap2 = stopWatchController.lastLap(1); + + if (lap1->count != 0) { + TimeSeparated_t laptime = convertTicksToTimeSegments(lap1->time); + lv_label_set_text_fmt(lapOneText, "#%2d %2d:%02d.%02d", lap1->count, laptime.mins, laptime.secs, laptime.hundredths); + } + if (lap2->count != 0) { + TimeSeparated_t laptime = convertTicksToTimeSegments(lap2->time); + lv_label_set_text_fmt(lapTwoText, "#%2d %2d:%02d.%02d", lap2->count, laptime.mins, laptime.secs, laptime.hundredths); + } +} + void StopWatch::Refresh() { - if (currentState == States::Running) { - timeElapsed = calculateDelta(startTime, xTaskGetTickCount()); - currentTimeSeparated = convertTicksToTimeSegments((oldTimeElapsed + timeElapsed)); + lv_label_set_text_fmt(dateTime, "%02i:%02i", dateTimeController.Hours(), dateTimeController.Minutes()); + lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryController.PercentRemaining())); + if (stopWatchController.isRunning()) { + timeElapsed = calculateDelta(stopWatchController.getStart(), xTaskGetTickCount()); + currentTimeSeparated = convertTicksToTimeSegments((stopWatchController.getElapsedPreviously() + timeElapsed)); lv_label_set_text_fmt(time, "%02d:%02d", currentTimeSeparated.mins, currentTimeSeparated.secs); lv_label_set_text_fmt(msecTime, "%02d", currentTimeSeparated.hundredths); @@ -165,12 +218,12 @@ void StopWatch::playPauseBtnEventHandler(lv_event_t event) { if (event != LV_EVENT_CLICKED) { return; } - if (currentState == States::Init) { - start(); - } else if (currentState == States::Running) { - pause(); - } else if (currentState == States::Halted) { - start(); + if (stopWatchController.isCleared() || stopWatchController.isPaused()) { + stopWatchController.start(xTaskGetTickCount()); + displayRunning(); + } else if (stopWatchController.isRunning()) { + stopWatchController.pause(xTaskGetTickCount()); + displayPaused(); } } @@ -179,25 +232,14 @@ void StopWatch::stopLapBtnEventHandler(lv_event_t event) { return; } // If running, then this button is used to save laps - if (currentState == States::Running) { - lapBuffer.addLaps(currentTimeSeparated); - lapNr++; - if (lapBuffer[1]) { - lv_label_set_text_fmt( - lapOneText, "#%2d %2d:%02d.%02d", (lapNr - 1), lapBuffer[1]->mins, lapBuffer[1]->secs, lapBuffer[1]->hundredths); - } - if (lapBuffer[0]) { - lv_label_set_text_fmt(lapTwoText, "#%2d %2d:%02d.%02d", lapNr, lapBuffer[0]->mins, lapBuffer[0]->secs, lapBuffer[0]->hundredths); - } - } else if (currentState == States::Halted) { - reset(); - } -} - -bool StopWatch::OnButtonPushed() { - if (currentState == States::Running) { - pause(); - return true; + if (stopWatchController.isRunning()) { + TickType_t currentTime = + stopWatchController.getElapsedPreviously() + calculateDelta(stopWatchController.getStart(), xTaskGetTickCount()); + stopWatchController.pushLap(currentTime); + + updateLaps(); + } else if (stopWatchController.isPaused()) { + stopWatchController.clear(); + displayCleared(); } - return false; } diff --git a/src/displayapp/screens/StopWatch.h b/src/displayapp/screens/StopWatch.h index 0720a5868d..67f985066a 100644 --- a/src/displayapp/screens/StopWatch.h +++ b/src/displayapp/screens/StopWatch.h @@ -3,6 +3,9 @@ #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" #include "displayapp/LittleVgl.h" +#include "components/stopwatch/StopWatchController.h" +#include "components/battery/BatteryController.h" +#include "displayapp/LittleVgl.h" #include "FreeRTOS.h" #include "portmacro_cmsis.h" @@ -12,78 +15,40 @@ namespace Pinetime::Applications::Screens { - enum class States { Init, Running, Halted }; - struct TimeSeparated_t { int mins; int secs; int hundredths; }; - // A simple buffer to hold the latest two laps - template struct LapTextBuffer_t { - LapTextBuffer_t() : buffer {}, currentSize {}, capacity {N}, head {-1} { - } - - void addLaps(const TimeSeparated_t& timeVal) { - head++; - head %= capacity; - buffer[head] = timeVal; - - if (currentSize < capacity) { - currentSize++; - } - } - - void clearBuffer() { - buffer = {}; - currentSize = 0; - head = -1; - } - - TimeSeparated_t* operator[](std::size_t idx) { - // Sanity check for out-of-bounds - if (idx >= 0 && idx < capacity) { - if (idx < currentSize) { - // This transformation is to ensure that head is always pointing to index 0. - const auto transformed_idx = (head - idx) % capacity; - return (&buffer[transformed_idx]); - } - } - return nullptr; - } - - private: - std::array buffer; - uint8_t currentSize; - uint8_t capacity; - int8_t head; - }; - class StopWatch : public Screen { public: - StopWatch(DisplayApp* app, System::SystemTask& systemTask); + StopWatch(DisplayApp* app, + System::SystemTask& systemTask, + Controllers::DateTime& dateTimeController, + Controllers::StopWatch& stopWatchController, + Controllers::Battery& batteryController); ~StopWatch() override; void Refresh() override; void playPauseBtnEventHandler(lv_event_t event); void stopLapBtnEventHandler(lv_event_t event); - bool OnButtonPushed() override; - void reset(); - void start(); - void pause(); + void displayCleared(); + void displayRunning(); + void displayPaused(); + void updateLaps(); private: Pinetime::System::SystemTask& systemTask; + Controllers::DateTime& dateTimeController; + Controllers::StopWatch& stopWatchController; + Controllers::Battery& batteryController; + TickType_t timeElapsed; - States currentState; - TickType_t startTime; - TickType_t oldTimeElapsed; TimeSeparated_t currentTimeSeparated; // Holds Mins, Secs, millisecs - LapTextBuffer_t<2> lapBuffer; - int lapNr = 0; - lv_obj_t *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap; + + lv_obj_t *dateTime, *time, *msecTime, *btnPlayPause, *btnStopLap, *txtPlayPause, *txtStopLap, *batteryIcon; lv_obj_t *lapOneText, *lapTwoText; lv_task_t* taskRefresh; diff --git a/src/main.cpp b/src/main.cpp index 53f78ce8a1..3353e53b76 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,6 +36,7 @@ #include "components/motor/MotorController.h" #include "components/datetime/DateTimeController.h" #include "components/heartrate/HeartRateController.h" +#include "components/stopwatch/StopWatchController.h" #include "components/fs/FS.h" #include "drivers/Spi.h" #include "drivers/SpiMaster.h" @@ -107,6 +108,7 @@ Pinetime::Drivers::WatchdogView watchdogView(watchdog); Pinetime::Controllers::NotificationManager notificationManager; Pinetime::Controllers::MotionController motionController; Pinetime::Controllers::TimerController timerController; +Pinetime::Controllers::StopWatch stopWatchController; Pinetime::Controllers::AlarmController alarmController {dateTimeController}; Pinetime::Controllers::TouchHandler touchHandler(touchPanel, lvgl); Pinetime::Controllers::ButtonHandler buttonHandler; @@ -129,6 +131,7 @@ Pinetime::Applications::DisplayApp displayApp(lcd, motionController, timerController, alarmController, + stopWatchController, touchHandler); Pinetime::System::SystemTask systemTask(spi, @@ -142,6 +145,7 @@ Pinetime::System::SystemTask systemTask(spi, dateTimeController, timerController, alarmController, + stopWatchController, watchdog, notificationManager, motorController, @@ -156,7 +160,7 @@ Pinetime::System::SystemTask systemTask(spi, touchHandler, buttonHandler); -/* Variable Declarations for variables in noinit SRAM +/* Variable Declarations for variables in noinit SRAM Increment NoInit_MagicValue upon adding variables to this area */ extern uint32_t __start_noinit_data; @@ -165,7 +169,6 @@ static constexpr uint32_t NoInit_MagicValue = 0xDEAD0000; uint32_t NoInit_MagicWord __attribute__((section(".noinit"))); std::chrono::time_point NoInit_BackUpTime __attribute__((section(".noinit"))); - void nrfx_gpiote_evt_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { if (pin == Pinetime::PinMap::Cst816sIrq) { systemTask.OnTouchEvent(); @@ -324,12 +327,11 @@ int main(void) { // retrieve version stored by bootloader Pinetime::BootloaderVersion::SetVersion(NRF_TIMER2->CC[0]); - if (NoInit_MagicWord == NoInit_MagicValue) { dateTimeController.SetCurrentTime(NoInit_BackUpTime); } else { - //Clear Memory to known state - memset(&__start_noinit_data,0,(uintptr_t)&__stop_noinit_data-(uintptr_t)&__start_noinit_data); + // Clear Memory to known state + memset(&__start_noinit_data, 0, (uintptr_t) &__stop_noinit_data - (uintptr_t) &__start_noinit_data); NoInit_MagicWord = NoInit_MagicValue; } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 1120b80d05..2e29e259e5 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -65,6 +65,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, Controllers::DateTime& dateTimeController, Controllers::TimerController& timerController, Controllers::AlarmController& alarmController, + Controllers::StopWatch& stopWatchController, Drivers::Watchdog& watchdog, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::MotorController& motorController, @@ -89,6 +90,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, dateTimeController {dateTimeController}, timerController {timerController}, alarmController {alarmController}, + stopWatchController {stopWatchController}, watchdog {watchdog}, notificationManager {notificationManager}, motorController {motorController}, @@ -193,7 +195,8 @@ void SystemTask::Work() { nrfx_gpiote_in_event_enable(PinMap::Button, true); // Touchscreen - nrf_gpio_cfg_sense_input(PinMap::Cst816sIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low); + nrf_gpio_cfg_sense_input( + PinMap::Cst816sIrq, (nrf_gpio_pin_pull_t) GPIO_PIN_CNF_PULL_Pullup, (nrf_gpio_pin_sense_t) GPIO_PIN_CNF_SENSE_Low); pinConfig.skip_gpio_setup = true; pinConfig.hi_accuracy = false; diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index e2e6de7f66..9c1e75f39c 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -18,6 +18,7 @@ #include "components/motor/MotorController.h" #include "components/timer/TimerController.h" #include "components/alarm/AlarmController.h" +#include "components/stopwatch/StopWatchController.h" #include "components/fs/FS.h" #include "touchhandler/TouchHandler.h" #include "buttonhandler/ButtonHandler.h" @@ -63,6 +64,7 @@ namespace Pinetime { Controllers::DateTime& dateTimeController, Controllers::TimerController& timerController, Controllers::AlarmController& alarmController, + Controllers::StopWatch& stopWatchController, Drivers::Watchdog& watchdog, Pinetime::Controllers::NotificationManager& notificationManager, Pinetime::Controllers::MotorController& motorController, @@ -108,6 +110,7 @@ namespace Pinetime { Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::TimerController& timerController; Pinetime::Controllers::AlarmController& alarmController; + Pinetime::Controllers::StopWatch& stopWatchController; QueueHandle_t systemTasksMsgQueue; std::atomic isSleeping {false}; std::atomic isGoingToSleep {false};