From 12acef6a71602c1f8425202560209355da1ce97b Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sat, 6 Jan 2024 10:49:26 +0100 Subject: [PATCH 01/67] apps: restore default apps ordering in CMake Restore the default list of apps to compile. The ordering was changed in the changeset to make the app-list configurable through a CMake-variable in https://github.com/InfiniTimeOrg/InfiniTime/pull/1928 In the process have one app per line to create the default app list in CMake. This makes git diffs easer and more readable. --- src/displayapp/apps/CMakeLists.txt | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index ddf95171..3544443a 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -1,7 +1,20 @@ if(DEFINED ENABLE_USERAPPS) set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware") else () - set(USERAPP_TYPES "Apps::Navigation, Apps::StopWatch, Apps::Alarm, Apps::Timer, Apps::Steps, Apps::HeartRate, Apps::Music, Apps::Paint, Apps::Paddle, Apps::Twos, Apps::Metronome" CACHE STRING "List of user apps to build into the firmware") + set(DEFAULT_USER_APP_TYPES "Apps::StopWatch") + set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Alarm") + 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::Twos") + 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::Motion") + set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") endif () add_library(infinitime_apps INTERFACE) From 22f6d4a40b6715b436f5eb3bf8524fa955eccd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sun, 24 Dec 2023 11:44:37 +0100 Subject: [PATCH 02/67] Watch face selection using CMake The list of watch face to build into the firmware is now set by CMake (-DENABLE_WATCHFACES). Fix SettingWatchFace : convert to index to/from WatchFace when needed. --- src/displayapp/DisplayApp.cpp | 5 ++- src/displayapp/apps/Apps.h.in | 7 +--- src/displayapp/apps/CMakeLists.txt | 6 +++ .../screens/settings/SettingWatchFace.cpp | 42 ++++++++++++++++--- .../screens/settings/SettingWatchFace.h | 10 ++++- 5 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 2792009f..938d1179 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -489,10 +489,11 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio currentScreen = std::make_unique(this, settingsController); break; case Apps::SettingWatchFace: { - std::array items; + std::array items; int i = 0; for (const auto& userWatchFace : userWatchFaces) { - items[i++] = Screens::CheckboxList::Item {userWatchFace.name, userWatchFace.isAvailable(controllers.filesystem)}; + items[i++] = + Screens::SettingWatchFace::Item {userWatchFace.name, userWatchFace.watchFace, userWatchFace.isAvailable(controllers.filesystem)}; } currentScreen = std::make_unique(this, std::move(items), settingsController, filesystem); } break; diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 11fe17b5..e6e8d7dc 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -71,12 +71,7 @@ namespace Pinetime { static constexpr size_t Count = sizeof...(Ws); }; - using UserWatchFaceTypes = WatchFaceTypeList; + using UserWatchFaceTypes = WatchFaceTypeList<@WATCHFACE_TYPES@>; static_assert(UserWatchFaceTypes::Count >= 1); } diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 3544443a..4f0e4c49 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -17,6 +17,12 @@ else () set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") endif () +if(DEFINED ENABLE_WATCHFACES) + set(WATCHFACE_TYPES ${ENABLE_WATCHFACES} CACHE STRING "List of watch faces to build into the firmware") +else() + set(WATCHFACE_TYPES "WatchFace::Digital, WatchFace::Analog, WatchFace::PineTimeStyle, WatchFace::Terminal, WatchFace::Infineat, WatchFace::CasioStyleG7710" CACHE STRING "List of watch faces to build into the firmware") +endif() + add_library(infinitime_apps INTERFACE) target_sources(infinitime_apps INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/Apps.h") target_include_directories(infinitime_apps INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/") diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index f052573c..e01e9f84 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -9,6 +9,37 @@ using namespace Pinetime::Applications::Screens; constexpr const char* SettingWatchFace::title; constexpr const char* SettingWatchFace::symbol; +namespace { + uint32_t IndexOf(const std::array& watchfaces, + Pinetime::Applications::WatchFace watchface) { + size_t index = 0; + auto found = std::find_if(watchfaces.begin(), + watchfaces.end(), + [&index, &watchface](const Pinetime::Applications::Screens::SettingWatchFace::Item& item) { + const bool result = item.watchface == watchface; + if (!result) { + index++; + } + return result; + }); + if (found == watchfaces.end()) { + index = 0; + } + + return index; + } + + Pinetime::Applications::WatchFace IndexToWatchFace(const std::array& watchfaces, + size_t index) { + if (index >= watchfaces.size()) { + return watchfaces[0].watchface; + } + return watchfaces[index].watchface; + } +} + auto SettingWatchFace::CreateScreenList() const { std::array()>, nScreens> screens; for (size_t i = 0; i < screens.size(); i++) { @@ -20,7 +51,7 @@ auto SettingWatchFace::CreateScreenList() const { } SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, - std::array&& watchfaceItems, + std::array&& watchfaceItems, Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::FS& filesystem) : app {app}, @@ -44,7 +75,8 @@ std::unique_ptr SettingWatchFace::CreateScreen(unsigned int screenNum) c if (i + (screenNum * settingsPerScreen) >= watchfaceItems.size()) { watchfacesOnThisScreen[i] = {"", false}; } else { - watchfacesOnThisScreen[i] = watchfaceItems[i + (screenNum * settingsPerScreen)]; + auto& item = watchfaceItems[i + (screenNum * settingsPerScreen)]; + watchfacesOnThisScreen[i] = Screens::CheckboxList::Item {item.name, item.enabled}; } } @@ -53,9 +85,9 @@ std::unique_ptr SettingWatchFace::CreateScreen(unsigned int screenNum) c nScreens, title, symbol, - static_cast(settingsController.GetWatchFace()), - [&settings = settingsController](uint32_t index) { - settings.SetWatchFace(static_cast(index)); + static_cast(IndexOf(watchfaceItems, settingsController.GetWatchFace())), + [this, &settings = settingsController](uint32_t index) { + settings.SetWatchFace(IndexToWatchFace(watchfaceItems, index)); settings.SaveSettings(); }, watchfacesOnThisScreen); diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index 66559c73..4c75b0ab 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -19,8 +19,14 @@ namespace Pinetime { class SettingWatchFace : public Screen { public: + struct Item { + const char* name; + WatchFace watchface; + bool enabled; + }; + SettingWatchFace(DisplayApp* app, - std::array&& watchfaceItems, + std::array&& watchfaceItems, Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::FS& filesystem); ~SettingWatchFace() override; @@ -33,7 +39,7 @@ namespace Pinetime { std::unique_ptr CreateScreen(unsigned int screenNum) const; static constexpr int settingsPerScreen = 4; - std::array watchfaceItems; + std::array watchfaceItems; static constexpr int nScreens = UserWatchFaceTypes::Count > 0 ? (UserWatchFaceTypes ::Count - 1) / settingsPerScreen + 1 : 1; Controllers::Settings& settingsController; From 72c992c84e44ac9a6dd8c53055a00ca801bf9ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sat, 30 Dec 2023 20:46:36 +0100 Subject: [PATCH 03/67] Watch face selection using CMake Update Apps.md to mention the selection of watchfaces using Cmake. --- doc/code/Apps.md | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/doc/code/Apps.md b/doc/code/Apps.md index 6ca84481..ca7d8bc2 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -35,18 +35,20 @@ that will call the method `Refresh()` periodically. ## App types -There are basically 2 types of applications : **system** apps and **user** apps. +There are basically 3 types of applications : **system** apps and **user** apps and **watchfaces**. **System** applications are always built into InfiniTime, and InfiniTime cannot work properly without those apps. The watchfaces, settings, notifications and the application launcher are examples of such system applications. **User** applications are optionally built into the firmware. They extend the functionalities of the system. -The distinction between **system** and **user** applications allows for more flexibility and customization. -This allows to easily select which user applications must be built into the firmware +**Watchfaces** are very similar to the **user** apps, they are optional, but at least one must be built into the firmware. + +The distinction between **system** apps, **user** apps and watchfaces allows for more flexibility and customization. +This allows to easily select which user applications and watchfaces must be built into the firmware without overflowing the system memory. -## Apps initialization +## Apps and watchfaces initialization Apps are created by `DisplayApp` in `DisplayApp::LoadScreen()`. This method simply call the creates an instance of the class that corresponds to the app specified in parameters. @@ -55,6 +57,8 @@ The constructor of **system** apps is called directly. If the application is a * the corresponding `AppDescription` is first retrieved from `userApps` and then the function `create` is called to create an instance of the app. +Watchfaces are handled in a very similar way than the **user** apps : they are created by `DisplayApp` in the method `DisplayApp::LoadScreen()` when the application type is `Apps::Clock`. + ## User application selection at build time The list of user applications is generated at build time by the `consteval` function `CreateAppDescriptions()` @@ -85,6 +89,32 @@ struct AppTraits { This array `userApps` is used by `DisplayApp` to create the applications and the `AppLauncher` to list all available applications. +## Watchface selection at build time + +The list of available watchface is also generated at build time by the `consteval` +function `CreateWatchFaceDescriptions()` in `UserApps.h` in the same way as the **user** apps. +Watchfaces must declare a `WatchFaceTraits` so that the corresponding `WatchFaceDescription` can be generated. +Here is an example of `WatchFaceTraits`: +```c++ + template <> + struct WatchFaceTraits { + static constexpr WatchFace watchFace = WatchFace::Analog; + static constexpr const char* name = "Analog face"; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::WatchFaceAnalog(controllers.dateTimeController, + controllers.batteryController, + controllers.bleController, + controllers.notificationManager, + controllers.settingsController); + }; + + static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { + return true; + } + }; +``` + ## Creating your own app A minimal user app could look like this: @@ -168,6 +198,14 @@ Ex : build the firmware with 3 user application : Alarm, Timer and MyApp (the ap $ cmake ... -DENABLE_USERAPPS="Apps::Alarm, Apps::Timer, Apps::MyApp" ... ``` +Similarly, the list of watchfaces is also generated by CMake, so you need to add the variable `ENABLE_WATCHFACES` to the command line of CMake. It must be set with the list of watchfaces that will be built into the firmware. + +Ex: build the firmware with 3 watchfaces : Analog, PineTimeStyle and Infineat: + +```cmake +$ cmake ... -DENABLE_WATCHFACES="WatchFace::Analog,WatchFace::PineTimeStyle,WatchFace::Infineat" ... +``` + You should now be able to [build](../buildAndProgram.md) the firmware and flash it to your PineTime. Yay! From 25b3e2461db0b27de9546452c45921983e4b8d35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sat, 6 Jan 2024 11:28:48 +0100 Subject: [PATCH 04/67] CMake watch faces selection Improve wording and replace "watchface" by "watch face" in Apps.md. Improve CMake readability regarding watch face selection Co-authored-by: Reinhold Gschweicher --- doc/code/Apps.md | 25 +++++++++++++------------ src/displayapp/apps/CMakeLists.txt | 8 +++++++- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/doc/code/Apps.md b/doc/code/Apps.md index ca7d8bc2..d97eff4b 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -35,20 +35,20 @@ that will call the method `Refresh()` periodically. ## App types -There are basically 3 types of applications : **system** apps and **user** apps and **watchfaces**. +There are basically 3 types of applications : **system** apps and **user** apps and **watch faces**. **System** applications are always built into InfiniTime, and InfiniTime cannot work properly without those apps. -The watchfaces, settings, notifications and the application launcher are examples of such system applications. +The watch faces, settings, notifications and the application launcher are examples of such system applications. **User** applications are optionally built into the firmware. They extend the functionalities of the system. -**Watchfaces** are very similar to the **user** apps, they are optional, but at least one must be built into the firmware. +**Watch faces** are very similar to the **user** apps, they are optional, but at least one must be built into the firmware. -The distinction between **system** apps, **user** apps and watchfaces allows for more flexibility and customization. -This allows to easily select which user applications and watchfaces must be built into the firmware +The distinction between **system** apps, **user** apps and watch faces allows for more flexibility and customization. +This allows to easily select which user applications and watch faces must be built into the firmware without overflowing the system memory. -## Apps and watchfaces initialization +## Apps and watch faces initialization Apps are created by `DisplayApp` in `DisplayApp::LoadScreen()`. This method simply call the creates an instance of the class that corresponds to the app specified in parameters. @@ -57,7 +57,7 @@ The constructor of **system** apps is called directly. If the application is a * the corresponding `AppDescription` is first retrieved from `userApps` and then the function `create` is called to create an instance of the app. -Watchfaces are handled in a very similar way than the **user** apps : they are created by `DisplayApp` in the method `DisplayApp::LoadScreen()` when the application type is `Apps::Clock`. +Watch faces are handled in a very similar way as the **user** apps : they are created by `DisplayApp` in the method `DisplayApp::LoadScreen()` when the application type is `Apps::Clock`. ## User application selection at build time @@ -89,11 +89,11 @@ struct AppTraits { This array `userApps` is used by `DisplayApp` to create the applications and the `AppLauncher` to list all available applications. -## Watchface selection at build time +## Watch face selection at build time -The list of available watchface is also generated at build time by the `consteval` +The list of available watch faces is also generated at build time by the `consteval` function `CreateWatchFaceDescriptions()` in `UserApps.h` in the same way as the **user** apps. -Watchfaces must declare a `WatchFaceTraits` so that the corresponding `WatchFaceDescription` can be generated. +Watch faces must declare a `WatchFaceTraits` so that the corresponding `WatchFaceDescription` can be generated. Here is an example of `WatchFaceTraits`: ```c++ template <> @@ -198,9 +198,10 @@ Ex : build the firmware with 3 user application : Alarm, Timer and MyApp (the ap $ cmake ... -DENABLE_USERAPPS="Apps::Alarm, Apps::Timer, Apps::MyApp" ... ``` -Similarly, the list of watchfaces is also generated by CMake, so you need to add the variable `ENABLE_WATCHFACES` to the command line of CMake. It must be set with the list of watchfaces that will be built into the firmware. +Similarly, the list of watch faces is also generated by CMake, so you need to add the variable `ENABLE_WATCHFACES` to the command line of CMake. +It must be set with the comma separated list of watch faces that will be built into the firmware. -Ex: build the firmware with 3 watchfaces : Analog, PineTimeStyle and Infineat: +Ex: build the firmware with 3 watch faces : Analog, PineTimeStyle and Infineat: ```cmake $ cmake ... -DENABLE_WATCHFACES="WatchFace::Analog,WatchFace::PineTimeStyle,WatchFace::Infineat" ... diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 4f0e4c49..a531bdff 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -20,7 +20,13 @@ endif () if(DEFINED ENABLE_WATCHFACES) set(WATCHFACE_TYPES ${ENABLE_WATCHFACES} CACHE STRING "List of watch faces to build into the firmware") else() - set(WATCHFACE_TYPES "WatchFace::Digital, WatchFace::Analog, WatchFace::PineTimeStyle, WatchFace::Terminal, WatchFace::Infineat, WatchFace::CasioStyleG7710" CACHE STRING "List of watch faces to build into the firmware") + set(DEFAULT_WATCHFACE_TYPES "WatchFace::Digital") + 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") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710") + set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware") endif() add_library(infinitime_apps INTERFACE) From 6505336d60157923fd738723e2432b12e26203e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sat, 6 Jan 2024 14:28:34 +0100 Subject: [PATCH 05/67] CMake watch faces selection Documentation : watch faces are not system apps anymore. Co-authored-by: FintasticMan --- doc/code/Apps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/code/Apps.md b/doc/code/Apps.md index d97eff4b..b325fe98 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -38,7 +38,7 @@ that will call the method `Refresh()` periodically. There are basically 3 types of applications : **system** apps and **user** apps and **watch faces**. **System** applications are always built into InfiniTime, and InfiniTime cannot work properly without those apps. -The watch faces, settings, notifications and the application launcher are examples of such system applications. +Settings, notifications and the application launcher are examples of such system applications. **User** applications are optionally built into the firmware. They extend the functionalities of the system. From ecf2f564f7a0884b6acdfdf5530abe2b98cb9aa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Milants?= Date: Sat, 6 Jan 2024 15:21:29 +0100 Subject: [PATCH 06/67] Set version to 1.14.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e3a033d..9b5669b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose Debug or Release") -project(pinetime VERSION 1.13.0 LANGUAGES C CXX ASM) +project(pinetime VERSION 1.14.0 LANGUAGES C CXX ASM) set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 20) From ab8e267e2861f33750a1320bdcf39db03134dd1b Mon Sep 17 00:00:00 2001 From: FintasticMan Date: Tue, 3 Jan 2023 16:25:55 +0000 Subject: [PATCH 07/67] hook: Update pre-commit git hook --- hooks/pre-commit | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/hooks/pre-commit b/hooks/pre-commit index 5e10aa19..9247f8a8 100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit @@ -1,25 +1,8 @@ -#!/bin/bash -if clang-format --version | grep -q 'version 11\.'; then - CLANG_FORMAT_EXECUTABLE="clang-format" -else - CLANG_FORMAT_EXECUTABLE="clang-format-11" -fi +#!/bin/sh -if ! command -v $CLANG_FORMAT_EXECUTABLE &> /dev/null -then - echo $CLANG_FORMAT_EXECUTABLE does not exist, make sure to install it - exit 1 -fi +changedFiles="$(git clang-format --extensions cpp,h --style file --staged -q --diffstat -- ':!src/FreeRTOS' ':!src/libs')" +git clang-format --extensions cpp,h --style file --staged -q -- ':!src/FreeRTOS' ':!src/libs' -for FILE in $(git diff --cached --name-only) -do - if [[ "$FILE" =~ src/[A-Za-z0-9\ \-]+*\.(c|h|cpp|cc)$ ]]; then - echo Autoformatting $FILE with $CLANG_FORMAT_EXECUTABLE - $CLANG_FORMAT_EXECUTABLE -style=file -i -- $FILE - git add -- $FILE - elif [[ "$FILE" =~ src/(components|displayapp|drivers|heartratetask|logging|systemtask)/.*\.(c|h|cpp|cc)$ ]]; then - echo Autoformatting $FILE with $CLANG_FORMAT_EXECUTABLE - $CLANG_FORMAT_EXECUTABLE -style=file -i -- $FILE - git add -- $FILE - fi +echo "$changedFiles" | head -n -1 | cut -d ' ' -f 1 | while read -r file; do + git add -- "$file" done From c634a4e3b44f0d1b020be2bbb52ac57fb4f8772d Mon Sep 17 00:00:00 2001 From: FintasticMan Date: Mon, 9 Jan 2023 23:46:53 +0100 Subject: [PATCH 08/67] hook: Use clang-format with highest version --- hooks/pre-commit | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/hooks/pre-commit b/hooks/pre-commit index 9247f8a8..e03b4217 100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit @@ -1,8 +1,27 @@ #!/bin/sh -changedFiles="$(git clang-format --extensions cpp,h --style file --staged -q --diffstat -- ':!src/FreeRTOS' ':!src/libs')" -git clang-format --extensions cpp,h --style file --staged -q -- ':!src/FreeRTOS' ':!src/libs' +minVersion="14.0.0" -echo "$changedFiles" | head -n -1 | cut -d ' ' -f 1 | while read -r file; do +for file in $(find $(echo "$PATH" | tr ':' ' ') -maxdepth 1 -type f -executable -name 'git-clang-format*'); do + curName="$(basename "$file" | sed 's/^git-//')" + curVersion="$("$curName" --version | cut -d ' ' -f 3)" + + if [ "$(printf '%s\n' "$curVersion" "$version" "$minVersion" | sort -V | tail -n 1)" = "$curVersion" ]; then + name="$curName" + version="$curVersion" + fi +done + +if [ -z "$name" ]; then + echo "Could not find a suitable clang-format installation. Install clang-format that includes the git-clang-format script, with at least version $minVersion" + exit 1 +fi + +args='-q --extensions cpp,h --style file --staged -- :!src/FreeRTOS :!src/libs' + +changedFiles="$(git "$name" --diffstat $args)" +git "$name" $args + +echo "$changedFiles" | head -n -1 | cut -d ' ' -f 2 | while read -r file; do git add -- "$file" done From 0503248a258d64e195c8ecbf701ea36ba1e642cb Mon Sep 17 00:00:00 2001 From: FintasticMan Date: Thu, 16 Nov 2023 12:13:29 +0100 Subject: [PATCH 09/67] hook: Find correct clang-format version better --- hooks/pre-commit | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/hooks/pre-commit b/hooks/pre-commit index e03b4217..60a01e34 100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit @@ -1,23 +1,29 @@ #!/bin/sh +name="clang-format" + +if [ -z "$(command -v "git-$name")" ]; then + name="$(basename -a $(find $(echo "$PATH" | tr ':' ' ') -maxdepth 1 -type f -executable -name 'git-clang-format*') | sort | tail -n 1 | sed 's/^git-//')" +fi + minVersion="14.0.0" -for file in $(find $(echo "$PATH" | tr ':' ' ') -maxdepth 1 -type f -executable -name 'git-clang-format*'); do - curName="$(basename "$file" | sed 's/^git-//')" - curVersion="$("$curName" --version | cut -d ' ' -f 3)" +for file in $(find $(echo "$PATH" | tr ':' ' ') -maxdepth 1 -type f -executable -name 'clang-format*'); do + curBin="$file" + curVersion="$("$curBin" --version | cut -d ' ' -f 3)" if [ "$(printf '%s\n' "$curVersion" "$version" "$minVersion" | sort -V | tail -n 1)" = "$curVersion" ]; then - name="$curName" + bin="$curBin" version="$curVersion" fi done -if [ -z "$name" ]; then +if [ -z "$name" ] || [ -z "$bin" ]; then echo "Could not find a suitable clang-format installation. Install clang-format that includes the git-clang-format script, with at least version $minVersion" exit 1 fi -args='-q --extensions cpp,h --style file --staged -- :!src/FreeRTOS :!src/libs' +args="--binary $bin -q --extensions cpp,h --style file --staged -- :!src/FreeRTOS :!src/libs" changedFiles="$(git "$name" --diffstat $args)" git "$name" $args From 264b5bed43d5a703df20c1e305f394a15e9d2484 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Sun, 14 Jan 2024 16:37:26 -0500 Subject: [PATCH 10/67] WatchFacePineTimeStyle: Fix conditional in weather display (#1965) Since returning a valid weather is always considered an updated value, if the current weather is empty, the face will attempt to display the temperature and icon as empty values, rather than clearing the labels. --- src/displayapp/screens/WatchFacePineTimeStyle.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.cpp b/src/displayapp/screens/WatchFacePineTimeStyle.cpp index 296323d3..e56031f7 100644 --- a/src/displayapp/screens/WatchFacePineTimeStyle.cpp +++ b/src/displayapp/screens/WatchFacePineTimeStyle.cpp @@ -540,7 +540,6 @@ void WatchFacePineTimeStyle::Refresh() { } currentWeather = weatherService.Current(); - if (currentWeather.IsUpdated()) { auto optCurrentWeather = currentWeather.Get(); if (optCurrentWeather) { @@ -551,12 +550,10 @@ void WatchFacePineTimeStyle::Refresh() { temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); lv_label_set_text_fmt(temperature, "%d°", temp); lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); - lv_obj_realign(temperature); - lv_obj_realign(weatherIcon); + } else { + lv_label_set_text(temperature, "--"); + lv_label_set_text(weatherIcon, Symbols::ban); } - } else { - lv_label_set_text(temperature, "--"); - lv_label_set_text(weatherIcon, Symbols::ban); lv_obj_realign(temperature); lv_obj_realign(weatherIcon); } From 034d83fe6baf1ab3875a34f8cee387e24410a824 Mon Sep 17 00:00:00 2001 From: Lennart Jahn Date: Sat, 13 Jan 2024 14:05:04 +0100 Subject: [PATCH 11/67] Split declaration and implementation of GetSymbol --- src/CMakeLists.txt | 1 + src/displayapp/screens/WeatherSymbols.cpp | 36 +++++++++++++++++++++++ src/displayapp/screens/WeatherSymbols.h | 35 +--------------------- 3 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 src/displayapp/screens/WeatherSymbols.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8b27c19d..1b3de51c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -394,6 +394,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Error.cpp displayapp/screens/Alarm.cpp displayapp/screens/Styles.cpp + displayapp/screens/WeatherSymbols.cpp displayapp/Colors.cpp displayapp/widgets/Counter.cpp displayapp/widgets/PageIndicator.cpp diff --git a/src/displayapp/screens/WeatherSymbols.cpp b/src/displayapp/screens/WeatherSymbols.cpp new file mode 100644 index 00000000..a7749541 --- /dev/null +++ b/src/displayapp/screens/WeatherSymbols.cpp @@ -0,0 +1,36 @@ +#include "displayapp/screens/WeatherSymbols.h" + +const char* Pinetime::Applications::Screens::Symbols::GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon) { + switch (icon) { + case Pinetime::Controllers::SimpleWeatherService::Icons::Sun: + return Symbols::sun; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun: + return Symbols::cloudSun; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds: + return Symbols::cloud; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::BrokenClouds: + return Symbols::cloudMeatball; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::Thunderstorm: + return Symbols::bolt; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::Snow: + return Symbols::snowflake; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::CloudShowerHeavy: + return Symbols::cloudShowersHeavy; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain: + return Symbols::cloudSunRain; + break; + case Pinetime::Controllers::SimpleWeatherService::Icons::Smog: + return Symbols::smog; + break; + default: + return Symbols::ban; + break; + } +} diff --git a/src/displayapp/screens/WeatherSymbols.h b/src/displayapp/screens/WeatherSymbols.h index 99ce3887..93453b4e 100644 --- a/src/displayapp/screens/WeatherSymbols.h +++ b/src/displayapp/screens/WeatherSymbols.h @@ -6,40 +6,7 @@ namespace Pinetime { namespace Applications { namespace Screens { namespace Symbols { - const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon) { - switch (icon) { - case Pinetime::Controllers::SimpleWeatherService::Icons::Sun: - return Symbols::sun; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun: - return Symbols::cloudSun; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds: - return Symbols::cloud; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::BrokenClouds: - return Symbols::cloudMeatball; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::Thunderstorm: - return Symbols::bolt; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::Snow: - return Symbols::snowflake; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::CloudShowerHeavy: - return Symbols::cloudShowersHeavy; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain: - return Symbols::cloudSunRain; - break; - case Pinetime::Controllers::SimpleWeatherService::Icons::Smog: - return Symbols::smog; - break; - default: - return Symbols::ban; - break; - } - } + const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon); } } } From a481af06cff915ca37deb5b967433480612186aa Mon Sep 17 00:00:00 2001 From: Reinhold Gschweicher Date: Sun, 21 Jan 2024 21:23:35 +0100 Subject: [PATCH 12/67] lv_img_conv: support other modes like 'P' Support other image modes like `P`, which uses 8 bits per pixel and a color palette to save space. Luckily the Pillow module can do the mode conversion for us. Fixes: https://github.com/InfiniTimeOrg/InfiniTime/issues/1985 --- src/resources/lv_img_conv.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/resources/lv_img_conv.py b/src/resources/lv_img_conv.py index 04765462..4c6b84e3 100755 --- a/src/resources/lv_img_conv.py +++ b/src/resources/lv_img_conv.py @@ -101,6 +101,13 @@ def main(): img = Image.open(img_path) img_height = img.height img_width = img.width + if args.color_format == "CF_TRUE_COLOR_ALPHA" and img.mode != "RGBA": + # support pictures stored in other formats like with a color palette 'P' + # see: https://pillow.readthedocs.io/en/stable/handbook/concepts.html#modes + img = img.convert(mode="RGBA") + elif args.color_format == "CF_INDEXED_1_BIT" and img.mode != "L": + # for CF_INDEXED_1_BIT we need just a grayscale value per pixel + img = img.convert(mode="L") if args.color_format == "CF_TRUE_COLOR_ALPHA" and args.binary_format == "ARGB8888": buf = bytearray(img_height*img_width*4) # 4 bytes (32 bit) per pixel for y in range(img_height): @@ -140,7 +147,7 @@ def main(): for y in range(img_height): for x in range(img_width): - c, a = img.getpixel((x,y)) + c = img.getpixel((x,y)) p = w * y + (x >> 3) + 8 # +8 for the palette buf[p] |= (c & 0x1) << (7 - (x & 0x7)) # write palette information, for indexed-1-bit we need palette with two values From a40168a9d7f13891c541055b167a315eb752cf1d Mon Sep 17 00:00:00 2001 From: Yusuf Ebrahim <45940010+yusufmte@users.noreply.github.com> Date: Tue, 23 Jan 2024 03:45:52 -0500 Subject: [PATCH 13/67] New dice-rolling app: InfiniDice! (#1326) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add new App `Dice.h` to randomly roll the dice(s). The number of dice can range from 1-9 (default 1), and the sides can range from d2-d99 (default d2). To have a haptic feedback we make Dice vibrate on roll. Regarding the use of C++ `` library: There are known problems with `rand()` and `srand()` (see https://en.cppreference.com/w/cpp/numeric/random/rand) and the `` library is preferred for this reason. The function used from `` also avoids a very rare bias that would occur using `rand()` and modulo, when `RAND_MAX` is not a multiple of `d` and the initially generated number falls in the last "short" segment. This commit also updates the seed to derive entropy (via `seed_seq`) from a mix of the system tick count and the x,y,z components of the PineTime motion controller -- taking inspiration from and with credit to @w4tsn (https://github.com/InfiniTimeOrg/InfiniTime/pull/1199) Thanks for suggestions: * in Dice, when rolling 1d2, also show "HEADS" or "TAILS" -- suggestion by @medeyko * ui adjustments and result realignment -- suggestion by @Boteium --------- Co-authored-by: NeroBurner Co-authored-by: Riku Isokoski Co-authored-by: Paul Weiß <45500341+Poohl@users.noreply.github.com> Co-authored-by: FintasticMan --- src/CMakeLists.txt | 2 + src/displayapp/DisplayApp.cpp | 1 + src/displayapp/UserApps.h | 1 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 1 + src/displayapp/fonts/fonts.json | 2 +- src/displayapp/screens/Dice.cpp | 199 +++++++++++++++++++++++++++++ src/displayapp/screens/Dice.h | 61 +++++++++ src/displayapp/screens/Symbols.h | 1 + 9 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 src/displayapp/screens/Dice.cpp create mode 100644 src/displayapp/screens/Dice.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1b3de51c..0f872f46 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -390,6 +390,7 @@ list(APPEND SOURCE_FILES displayapp/screens/BatteryInfo.cpp displayapp/screens/Steps.cpp displayapp/screens/Timer.cpp + displayapp/screens/Dice.cpp displayapp/screens/PassKey.cpp displayapp/screens/Error.cpp displayapp/screens/Alarm.cpp @@ -609,6 +610,7 @@ set(INCLUDE_FILES displayapp/screens/Metronome.h displayapp/screens/Motion.h displayapp/screens/Timer.h + displayapp/screens/Dice.h displayapp/screens/Alarm.h displayapp/Colors.h displayapp/widgets/Counter.h diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 938d1179..e5329b2d 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -26,6 +26,7 @@ #include "displayapp/screens/FlashLight.h" #include "displayapp/screens/BatteryInfo.h" #include "displayapp/screens/Steps.h" +#include "displayapp/screens/Dice.h" #include "displayapp/screens/PassKey.h" #include "displayapp/screens/Error.h" diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index 0307035a..67bbfa7d 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -3,6 +3,7 @@ #include "Controllers.h" #include "displayapp/screens/Alarm.h" +#include "displayapp/screens/Dice.h" #include "displayapp/screens/Timer.h" #include "displayapp/screens/Twos.h" #include "displayapp/screens/Tile.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index e6e8d7dc..77d3b366 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -27,6 +27,7 @@ namespace Pinetime { Metronome, Motion, Steps, + Dice, PassKey, QuickSettings, Settings, diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index a531bdff..51c08595 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -10,6 +10,7 @@ else () 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") diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index ead5239e..d9127dea 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, 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, 0xf522, 0xf743" } ], "bpp": 1, diff --git a/src/displayapp/screens/Dice.cpp b/src/displayapp/screens/Dice.cpp new file mode 100644 index 00000000..302c5f3f --- /dev/null +++ b/src/displayapp/screens/Dice.cpp @@ -0,0 +1,199 @@ +#include "displayapp/screens/Dice.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/Symbols.h" +#include "components/settings/Settings.h" +#include "components/motor/MotorController.h" +#include "components/motion/MotionController.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + lv_obj_t* MakeLabel(lv_font_t* font, + lv_color_t color, + lv_label_long_mode_t longMode, + uint8_t width, + lv_label_align_t labelAlignment, + const char* text, + lv_obj_t* reference, + lv_align_t alignment, + int8_t x, + int8_t y) { + lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font); + lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color); + lv_label_set_long_mode(label, longMode); + if (width != 0) { + lv_obj_set_width(label, width); + } + lv_label_set_align(label, labelAlignment); + lv_label_set_text(label, text); + lv_obj_align(label, reference, alignment, x, y); + return label; + } + + void btnRollEventHandler(lv_obj_t* obj, lv_event_t event) { + auto* screen = static_cast(obj->user_data); + if (event == LV_EVENT_CLICKED) { + screen->Roll(); + } + } +} + +Dice::Dice(Controllers::MotionController& motionController, + Controllers::MotorController& motorController, + Controllers::Settings& settingsController) + : motorController {motorController}, motionController {motionController}, settingsController {settingsController} { + std::seed_seq sseq {static_cast(xTaskGetTickCount()), + static_cast(motionController.X()), + static_cast(motionController.Y()), + static_cast(motionController.Z())}; + gen.seed(sseq); + + lv_obj_t* nCounterLabel = MakeLabel(&jetbrains_mono_bold_20, + LV_COLOR_WHITE, + LV_LABEL_LONG_EXPAND, + 0, + LV_LABEL_ALIGN_CENTER, + "count", + lv_scr_act(), + LV_ALIGN_IN_TOP_LEFT, + 0, + 0); + + lv_obj_t* dCounterLabel = MakeLabel(&jetbrains_mono_bold_20, + LV_COLOR_WHITE, + LV_LABEL_LONG_EXPAND, + 0, + LV_LABEL_ALIGN_CENTER, + "sides", + nCounterLabel, + LV_ALIGN_OUT_RIGHT_MID, + 20, + 0); + + nCounter.Create(); + lv_obj_align(nCounter.GetObject(), nCounterLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); + nCounter.SetValue(1); + + dCounter.Create(); + lv_obj_align(dCounter.GetObject(), dCounterLabel, LV_ALIGN_OUT_BOTTOM_MID, 0, 10); + dCounter.SetValue(6); + + std::uniform_int_distribution<> distrib(0, resultColors.size() - 1); + currentColorIndex = distrib(gen); + + resultTotalLabel = MakeLabel(&jetbrains_mono_42, + resultColors[currentColorIndex], + LV_LABEL_LONG_BREAK, + 120, + LV_LABEL_ALIGN_CENTER, + "", + lv_scr_act(), + LV_ALIGN_IN_TOP_RIGHT, + 11, + 38); + resultIndividualLabel = MakeLabel(&jetbrains_mono_bold_20, + resultColors[currentColorIndex], + LV_LABEL_LONG_BREAK, + 90, + LV_LABEL_ALIGN_CENTER, + "", + resultTotalLabel, + LV_ALIGN_OUT_BOTTOM_MID, + 0, + 10); + + Roll(); + openingRoll = false; + + btnRoll = lv_btn_create(lv_scr_act(), nullptr); + btnRoll->user_data = this; + lv_obj_set_event_cb(btnRoll, btnRollEventHandler); + lv_obj_set_size(btnRoll, 240, 50); + lv_obj_align(btnRoll, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); + + btnRollLabel = MakeLabel(&jetbrains_mono_bold_20, + LV_COLOR_WHITE, + LV_LABEL_LONG_EXPAND, + 0, + LV_LABEL_ALIGN_CENTER, + Symbols::dice, + btnRoll, + LV_ALIGN_CENTER, + 0, + 0); + + // Spagetti code in motion controller: it only updates the shake speed when shake to wake is on... + enableShakeForDice = !settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake); + if (enableShakeForDice) { + settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::Shake, true); + } + refreshTask = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); +} + +Dice::~Dice() { + // reset the shake to wake mode. + if (enableShakeForDice) { + settingsController.setWakeUpMode(Pinetime::Controllers::Settings::WakeUpMode::Shake, false); + enableShakeForDice = false; + } + lv_task_del(refreshTask); + lv_obj_clean(lv_scr_act()); +} + +void Dice::Refresh() { + // we only reset the hysteresis when at rest + if (motionController.CurrentShakeSpeed() >= settingsController.GetShakeThreshold()) { + if (currentRollHysteresis <= 0) { + // this timestamp is used for the screen timeout + lv_disp_get_next(NULL)->last_activity_time = lv_tick_get(); + + Roll(); + } + } else if (currentRollHysteresis > 0) + --currentRollHysteresis; +} + +void Dice::Roll() { + uint8_t resultIndividual; + uint16_t resultTotal = 0; + std::uniform_int_distribution<> distrib(1, dCounter.GetValue()); + + lv_label_set_text(resultIndividualLabel, ""); + + if (nCounter.GetValue() == 1) { + resultTotal = distrib(gen); + if (dCounter.GetValue() == 2) { + switch (resultTotal) { + case 1: + lv_label_set_text(resultIndividualLabel, "HEADS"); + break; + case 2: + lv_label_set_text(resultIndividualLabel, "TAILS"); + break; + } + } + } else { + for (uint8_t i = 0; i < nCounter.GetValue(); i++) { + resultIndividual = distrib(gen); + resultTotal += resultIndividual; + lv_label_ins_text(resultIndividualLabel, LV_LABEL_POS_LAST, std::to_string(resultIndividual).c_str()); + if (i < (nCounter.GetValue() - 1)) { + lv_label_ins_text(resultIndividualLabel, LV_LABEL_POS_LAST, "+"); + } + } + } + + lv_label_set_text_fmt(resultTotalLabel, "%d", resultTotal); + if (openingRoll == false) { + motorController.RunForDuration(30); + NextColor(); + currentRollHysteresis = rollHysteresis; + } +} + +void Dice::NextColor() { + currentColorIndex = (currentColorIndex + 1) % resultColors.size(); + lv_obj_set_style_local_text_color(resultTotalLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, resultColors[currentColorIndex]); + lv_obj_set_style_local_text_color(resultIndividualLabel, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, resultColors[currentColorIndex]); +} diff --git a/src/displayapp/screens/Dice.h b/src/displayapp/screens/Dice.h new file mode 100644 index 00000000..da91657d --- /dev/null +++ b/src/displayapp/screens/Dice.h @@ -0,0 +1,61 @@ +#pragma once + +#include "displayapp/apps/Apps.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/widgets/Counter.h" +#include "displayapp/Controllers.h" +#include "Symbols.h" + +#include +#include + +namespace Pinetime { + namespace Applications { + namespace Screens { + class Dice : public Screen { + public: + Dice(Controllers::MotionController& motionController, + Controllers::MotorController& motorController, + Controllers::Settings& settingsController); + ~Dice() override; + void Roll(); + void Refresh() override; + + private: + lv_obj_t* btnRoll; + lv_obj_t* btnRollLabel; + lv_obj_t* resultTotalLabel; + lv_obj_t* resultIndividualLabel; + lv_task_t* refreshTask; + bool enableShakeForDice = false; + + std::mt19937 gen; + + std::array resultColors = {LV_COLOR_YELLOW, LV_COLOR_MAGENTA, LV_COLOR_AQUA}; + uint8_t currentColorIndex; + void NextColor(); + + Widgets::Counter nCounter = Widgets::Counter(1, 9, jetbrains_mono_42); + Widgets::Counter dCounter = Widgets::Counter(2, 99, jetbrains_mono_42); + + bool openingRoll = true; + uint8_t currentRollHysteresis = 0; + static constexpr uint8_t rollHysteresis = 10; + + Controllers::MotorController& motorController; + Controllers::MotionController& motionController; + Controllers::Settings& settingsController; + }; + } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::Dice; + static constexpr const char* icon = Screens::Symbols::dice; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::Dice(controllers.motionController, controllers.motorController, controllers.settingsController); + }; + }; + } +} diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index 549ea04f..4434194b 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -34,6 +34,7 @@ namespace Pinetime { static constexpr const char* hourGlass = "\xEF\x89\x92"; static constexpr const char* lapsFlag = "\xEF\x80\xA4"; static constexpr const char* drum = "\xEF\x95\xA9"; + static constexpr const char* dice = "\xEF\x94\xA2"; static constexpr const char* eye = "\xEF\x81\xAE"; static constexpr const char* home = "\xEF\x80\x95"; static constexpr const char* sleep = "\xEE\xBD\x84"; From 074df0526fb1b6b6a18a4a28416837c122fbef8b Mon Sep 17 00:00:00 2001 From: apilat Date: Wed, 29 Jun 2022 13:06:30 +0100 Subject: [PATCH 14/67] Keep updating motion during sleep when Bluetooth is on --- src/systemtask/SystemTask.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index b245e392..f8c2c00f 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -417,8 +417,9 @@ void SystemTask::UpdateMotion() { return; } - if (state == SystemTaskState::Sleeping && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) || - settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake))) { + if (state == SystemTaskState::Sleeping && + !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) || + settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) || bleController.IsConnected())) { return; } From a6cd3679eb1219865a215d0600c9703b198f9157 Mon Sep 17 00:00:00 2001 From: apilat Date: Thu, 30 Jun 2022 15:52:57 +0100 Subject: [PATCH 15/67] Only inhibit sleep if motion notifications are enabled, not just Bluetooth --- src/components/ble/MotionService.cpp | 4 ++++ src/components/ble/MotionService.h | 1 + src/components/motion/MotionController.h | 4 ++++ src/systemtask/SystemTask.cpp | 6 +++--- 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/components/ble/MotionService.cpp b/src/components/ble/MotionService.cpp index 029be894..1626a5bf 100644 --- a/src/components/ble/MotionService.cpp +++ b/src/components/ble/MotionService.cpp @@ -120,3 +120,7 @@ void MotionService::UnsubscribeNotification(uint16_t attributeHandle) { else if (attributeHandle == motionValuesHandle) motionValuesNoficationEnabled = false; } + +bool MotionService::IsMotionNotificationSubscribed() const { + return motionValuesNoficationEnabled; +} diff --git a/src/components/ble/MotionService.h b/src/components/ble/MotionService.h index e15cffe3..acc91e8d 100644 --- a/src/components/ble/MotionService.h +++ b/src/components/ble/MotionService.h @@ -21,6 +21,7 @@ namespace Pinetime { void SubscribeNotification(uint16_t attributeHandle); void UnsubscribeNotification(uint16_t attributeHandle); + bool IsMotionNotificationSubscribed() const; private: NimbleController& nimble; diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h index 0aa7823e..b2e7e7fe 100644 --- a/src/components/motion/MotionController.h +++ b/src/components/motion/MotionController.h @@ -62,6 +62,10 @@ namespace Pinetime { this->service = service; } + Pinetime::Controllers::MotionService* GetService() const { + return service; + } + private: uint32_t nbSteps = 0; uint32_t currentTripSteps = 0; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index f8c2c00f..246e7cec 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -417,9 +417,9 @@ void SystemTask::UpdateMotion() { return; } - if (state == SystemTaskState::Sleeping && - !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) || - settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) || bleController.IsConnected())) { + if (state == SystemTaskState::Sleeping && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) || + settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake) || + motionController.GetService()->IsMotionNotificationSubscribed())) { return; } From 2135e12b338b651f3c3ed4511428d68b9727e6f6 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Tue, 23 Jan 2024 17:39:28 -0500 Subject: [PATCH 16/67] WatchFaceDigital: Add weather display If weather is available, display the cloud icon and temperature. --- src/displayapp/screens/WatchFaceDigital.cpp | 39 ++++++++++++++++++++- src/displayapp/screens/WatchFaceDigital.h | 12 +++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index ca53691b..0a7da2fd 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -4,11 +4,13 @@ #include #include "displayapp/screens/NotificationIcon.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/screens/WeatherSymbols.h" #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "components/ble/NotificationManager.h" #include "components/heartrate/HeartRateController.h" #include "components/motion/MotionController.h" +#include "components/ble/SimpleWeatherService.h" #include "components/settings/Settings.h" using namespace Pinetime::Applications::Screens; @@ -19,13 +21,15 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, Controllers::NotificationManager& notificationManager, Controllers::Settings& settingsController, Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController) + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weatherService) : currentDateTime {{}}, dateTimeController {dateTimeController}, notificationManager {notificationManager}, settingsController {settingsController}, heartRateController {heartRateController}, motionController {motionController}, + weatherService {weatherService}, statusIcons(batteryController, bleController) { statusIcons.Create(); @@ -35,6 +39,18 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + weatherIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); + lv_label_set_text(weatherIcon, ""); + lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 0); + lv_obj_set_auto_realign(weatherIcon, true); + + temperature = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_label_set_text(temperature, ""); + lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 0); + label_date = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); @@ -153,4 +169,25 @@ void WatchFaceDigital::Refresh() { lv_obj_realign(stepValue); lv_obj_realign(stepIcon); } + + currentWeather = weatherService.Current(); + if (currentWeather.IsUpdated()) { + auto optCurrentWeather = currentWeather.Get(); + if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature; + char tempUnit = 'C'; + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); + tempUnit = 'F'; + } + temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); + lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); + } else { + lv_label_set_text_static(temperature, ""); + lv_label_set_text(weatherIcon, ""); + } + lv_obj_realign(temperature); + lv_obj_realign(weatherIcon); + } } diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index a4664792..3ff78c8a 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -6,6 +6,7 @@ #include #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" +#include "components/ble/SimpleWeatherService.h" #include "components/ble/BleController.h" #include "displayapp/widgets/StatusIcons.h" #include "utility/DirtyValue.h" @@ -32,7 +33,8 @@ namespace Pinetime { Controllers::NotificationManager& notificationManager, Controllers::Settings& settingsController, Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController); + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weather); ~WatchFaceDigital() override; void Refresh() override; @@ -50,6 +52,8 @@ namespace Pinetime { Utility::DirtyValue heartbeat {}; Utility::DirtyValue heartbeatRunning {}; Utility::DirtyValue notificationState {}; + Utility::DirtyValue> currentWeather {}; + using days = std::chrono::duration>; // TODO: days is standard in c++20 Utility::DirtyValue> currentDate; @@ -61,12 +65,15 @@ namespace Pinetime { lv_obj_t* stepIcon; lv_obj_t* stepValue; lv_obj_t* notificationIcon; + lv_obj_t* weatherIcon; + lv_obj_t* temperature; Controllers::DateTime& dateTimeController; Controllers::NotificationManager& notificationManager; Controllers::Settings& settingsController; Controllers::HeartRateController& heartRateController; Controllers::MotionController& motionController; + Controllers::SimpleWeatherService& weatherService; lv_task_t* taskRefresh; Widgets::StatusIcons statusIcons; @@ -85,7 +92,8 @@ namespace Pinetime { controllers.notificationManager, controllers.settingsController, controllers.heartRateController, - controllers.motionController); + controllers.motionController, + *controllers.weatherController); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { From 44be356dc2dc6b4b7b0df8e3e12d41751cc315d3 Mon Sep 17 00:00:00 2001 From: kieranc Date: Wed, 7 Feb 2024 08:46:09 +0100 Subject: [PATCH 17/67] navigation: Missing character for font --- src/displayapp/fonts/fonts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index d9127dea..57341245 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -18,7 +18,7 @@ "sources": [ { "file": "JetBrainsMono-Regular.ttf", - "range": "0x25, 0x2b, 0x2d, 0x30-0x3a, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74" + "range": "0x25, 0x2b, 0x2d, 0x2e, 0x30-0x3a, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74" } ], "bpp": 1, From 2db920599eec192f794c96fcaeb7376ea3325adb Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Sat, 10 Feb 2024 13:24:46 -0500 Subject: [PATCH 18/67] SimpleWeatherService: Add forecast operator overrides (#2011) Any screen that relies on DirtyValue to display up-to-date forecast data would require the struct to provide an operator override for comparison. --- src/components/ble/SimpleWeatherService.cpp | 13 +++++++++++++ src/components/ble/SimpleWeatherService.h | 4 ++++ 2 files changed, 17 insertions(+) diff --git a/src/components/ble/SimpleWeatherService.cpp b/src/components/ble/SimpleWeatherService.cpp index d545d45b..146152f8 100644 --- a/src/components/ble/SimpleWeatherService.cpp +++ b/src/components/ble/SimpleWeatherService.cpp @@ -158,3 +158,16 @@ bool SimpleWeatherService::CurrentWeather::operator==(const SimpleWeatherService this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature && std::strcmp(this->location.data(), other.location.data()) == 0; } + +bool SimpleWeatherService::Forecast::Day::operator==(const SimpleWeatherService::Forecast::Day& other) const { + return this->iconId == other.iconId && this->maxTemperature == other.maxTemperature && this->minTemperature == other.maxTemperature; +} + +bool SimpleWeatherService::Forecast::operator==(const SimpleWeatherService::Forecast& other) const { + for (int i = 0; i < this->nbDays; i++) { + if (this->days[i] != other.days[i]) { + return false; + } + } + return this->timestamp == other.timestamp && this->nbDays == other.nbDays; +} diff --git a/src/components/ble/SimpleWeatherService.h b/src/components/ble/SimpleWeatherService.h index cec2bb8b..4bbefcfc 100644 --- a/src/components/ble/SimpleWeatherService.h +++ b/src/components/ble/SimpleWeatherService.h @@ -96,9 +96,13 @@ namespace Pinetime { int16_t minTemperature; int16_t maxTemperature; Icons iconId; + + bool operator==(const Day& other) const; }; std::array days; + + bool operator==(const Forecast& other) const; }; std::optional Current() const; From 4c274421d9bcf5f903e307f1fd61e52174362975 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Fri, 9 Feb 2024 00:04:31 +0000 Subject: [PATCH 19/67] Remove GFX (and unused GFX dependencies) --- src/CMakeLists.txt | 2 - src/components/gfx/Gfx.cpp | 196 ---------------------------- src/components/gfx/Gfx.h | 62 --------- src/displayapp/DisplayAppRecovery.h | 1 - src/drivers/St7789.cpp | 21 --- src/drivers/St7789.h | 2 - src/recoveryLoader.cpp | 3 - 7 files changed, 287 deletions(-) delete mode 100644 src/components/gfx/Gfx.cpp delete mode 100644 src/components/gfx/Gfx.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f872f46..8d0b792c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -542,7 +542,6 @@ list(APPEND RECOVERY_SOURCE_FILES systemtask/SystemTask.cpp systemtask/SystemMonitor.cpp drivers/TwiMaster.cpp - components/gfx/Gfx.cpp components/rle/RleDecoder.cpp components/heartrate/HeartRateController.cpp heartratetask/HeartRateTask.cpp @@ -572,7 +571,6 @@ list(APPEND RECOVERYLOADER_SOURCE_FILES components/rle/RleDecoder.cpp - components/gfx/Gfx.cpp drivers/St7789.cpp components/brightness/BrightnessController.cpp diff --git a/src/components/gfx/Gfx.cpp b/src/components/gfx/Gfx.cpp deleted file mode 100644 index baa6486a..00000000 --- a/src/components/gfx/Gfx.cpp +++ /dev/null @@ -1,196 +0,0 @@ -#include "components/gfx/Gfx.h" -#include "drivers/St7789.h" -using namespace Pinetime::Components; - -Gfx::Gfx(Pinetime::Drivers::St7789& lcd) : lcd {lcd} { -} - -void Gfx::Init() { -} - -void Gfx::ClearScreen() { - SetBackgroundColor(0x0000); - - state.remainingIterations = 240 + 1; - state.currentIteration = 0; - state.busy = true; - state.action = Action::FillRectangle; - state.taskToNotify = xTaskGetCurrentTaskHandle(); - - lcd.DrawBuffer(0, 0, width, height, reinterpret_cast(buffer), width * 2); - WaitTransferFinished(); -} - -void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint16_t color) { - SetBackgroundColor(color); - - state.remainingIterations = h; - state.currentIteration = 0; - state.busy = true; - state.action = Action::FillRectangle; - state.color = color; - state.taskToNotify = xTaskGetCurrentTaskHandle(); - - lcd.DrawBuffer(x, y, w, h, reinterpret_cast(buffer), width * 2); - - WaitTransferFinished(); -} - -void Gfx::FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b) { - state.remainingIterations = h; - state.currentIteration = 0; - state.busy = true; - state.action = Action::FillRectangle; - state.color = 0x00; - state.taskToNotify = xTaskGetCurrentTaskHandle(); - - lcd.DrawBuffer(x, y, w, h, reinterpret_cast(b), width * 2); - - WaitTransferFinished(); -} - -void Gfx::DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap) { - if (y > (height - p_font->height)) { - // Not enough space to write even single char. - return; - } - - uint8_t current_x = x; - uint8_t current_y = y; - - for (size_t i = 0; text[i] != '\0'; i++) { - if (text[i] == '\n') { - current_x = x; - current_y += p_font->height + p_font->height / 10; - } else { - DrawChar(p_font, (uint8_t) text[i], ¤t_x, current_y, color); - } - - uint8_t char_idx = text[i] - p_font->startChar; - uint16_t char_width = text[i] == ' ' ? (p_font->height / 2) : p_font->charInfo[char_idx].widthBits; - - if (current_x > (width - char_width)) { - if (wrap) { - current_x = x; - current_y += p_font->height + p_font->height / 10; - } else { - break; - } - - if (y > (height - p_font->height)) { - break; - } - } - } -} - -void Gfx::DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color) { - uint8_t char_idx = c - font->startChar; - uint16_t bytes_in_line = CEIL_DIV(font->charInfo[char_idx].widthBits, 8); - uint16_t bg = 0x0000; - - if (c == ' ') { - *x += font->height / 2; - return; - } - - // Build first line - for (uint16_t j = 0; j < bytes_in_line; j++) { - for (uint8_t k = 0; k < 8; k++) { - if ((1 << (7 - k)) & font->data[font->charInfo[char_idx].offset + j]) { - buffer[(j * 8) + k] = color; - } else { - buffer[(j * 8) + k] = bg; - } - } - } - - state.remainingIterations = font->height + 0; - state.currentIteration = 0; - state.busy = true; - state.action = Action::DrawChar; - state.font = const_cast(font); - state.character = c; - state.color = color; - state.taskToNotify = xTaskGetCurrentTaskHandle(); - - lcd.DrawBuffer(*x, y, bytes_in_line * 8, font->height, reinterpret_cast(&buffer), bytes_in_line * 8 * 2); - WaitTransferFinished(); - - *x += font->charInfo[char_idx].widthBits + font->spacePixels; -} - -void Gfx::pixel_draw(uint8_t x, uint8_t y, uint16_t color) { - lcd.DrawPixel(x, y, color); -} - -void Gfx::Sleep() { - lcd.Sleep(); -} - -void Gfx::Wakeup() { - lcd.Wakeup(); -} - -void Gfx::SetBackgroundColor(uint16_t color) { - for (int i = 0; i < width; i++) { - buffer[i] = color; - } -} - -bool Gfx::GetNextBuffer(uint8_t** data, size_t& size) { - if (!state.busy) - return false; - state.remainingIterations = state.remainingIterations - 1; - if (state.remainingIterations == 0) { - state.busy = false; - NotifyEndOfTransfer(state.taskToNotify); - return false; - } - - if (state.action == Action::FillRectangle) { - *data = reinterpret_cast(buffer); - size = width * 2; - } else if (state.action == Action::DrawChar) { - uint16_t bg = 0x0000; - uint8_t char_idx = state.character - state.font->startChar; - uint16_t bytes_in_line = CEIL_DIV(state.font->charInfo[char_idx].widthBits, 8); - - for (uint16_t j = 0; j < bytes_in_line; j++) { - for (uint8_t k = 0; k < 8; k++) { - if ((1 << (7 - k)) & state.font->data[state.font->charInfo[char_idx].offset + ((state.currentIteration + 1) * bytes_in_line) + j]) { - buffer[(j * 8) + k] = state.color; - } else { - buffer[(j * 8) + k] = bg; - } - } - } - - *data = reinterpret_cast(buffer); - size = bytes_in_line * 8 * 2; - } - - state.currentIteration = state.currentIteration + 1; - - return true; -} - -void Gfx::NotifyEndOfTransfer(TaskHandle_t task) { - if (task != nullptr) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - vTaskNotifyGiveFromISR(task, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - } -} - -void Gfx::WaitTransferFinished() const { - ulTaskNotifyTake(pdTRUE, 500); -} - -void Gfx::SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines) { - lcd.VerticalScrollDefinition(topFixedLines, scrollLines, bottomFixedLines); -} - -void Gfx::SetScrollStartLine(uint16_t line) { - lcd.VerticalScrollStartAddress(line); -} diff --git a/src/components/gfx/Gfx.h b/src/components/gfx/Gfx.h deleted file mode 100644 index 17c248f7..00000000 --- a/src/components/gfx/Gfx.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include "drivers/BufferProvider.h" - -namespace Pinetime { - namespace Drivers { - class St7789; - } - - namespace Components { - class Gfx : public Pinetime::Drivers::BufferProvider { - public: - explicit Gfx(Drivers::St7789& lcd); - void Init(); - void ClearScreen(); - void DrawString(uint8_t x, uint8_t y, uint16_t color, const char* text, const FONT_INFO* p_font, bool wrap); - void DrawChar(const FONT_INFO* font, uint8_t c, uint8_t* x, uint8_t y, uint16_t color); - void FillRectangle(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint16_t color); - void FillRectangle(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t* b); - void SetScrollArea(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines); - void SetScrollStartLine(uint16_t line); - - void Sleep(); - void Wakeup(); - bool GetNextBuffer(uint8_t** buffer, size_t& size) override; - void pixel_draw(uint8_t x, uint8_t y, uint16_t color); - - private: - static constexpr uint8_t width = 240; - static constexpr uint8_t height = 240; - - enum class Action { None, FillRectangle, DrawChar }; - - struct State { - State() : busy {false}, action {Action::None}, remainingIterations {0}, currentIteration {0} { - } - - volatile bool busy; - volatile Action action; - volatile uint16_t remainingIterations; - volatile uint16_t currentIteration; - volatile FONT_INFO* font; - volatile uint16_t color; - volatile uint8_t character; - volatile TaskHandle_t taskToNotify = nullptr; - }; - - volatile State state; - - uint16_t buffer[width]; // 1 line buffer - Drivers::St7789& lcd; - - void SetBackgroundColor(uint16_t color); - void WaitTransferFinished() const; - void NotifyEndOfTransfer(TaskHandle_t task); - }; - } -} diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 3a5c78d9..c1bf6243 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -5,7 +5,6 @@ #include #include #include -#include "components/gfx/Gfx.h" #include "drivers/Cst816s.h" #include #include diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index 17d14ce6..e583aac8 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -140,16 +140,6 @@ void St7789::DisplayOff() { nrf_delay_ms(500); } -void St7789::VerticalScrollDefinition(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines) { - WriteCommand(static_cast(Commands::VerticalScrollDefinition)); - WriteData(topFixedLines >> 8u); - WriteData(topFixedLines & 0x00ffu); - WriteData(scrollLines >> 8u); - WriteData(scrollLines & 0x00ffu); - WriteData(bottomFixedLines >> 8u); - WriteData(bottomFixedLines & 0x00ffu); -} - void St7789::VerticalScrollStartAddress(uint16_t line) { verticalScrollingStartAddress = line; WriteCommand(static_cast(Commands::VerticalScrollStartAddress)); @@ -160,17 +150,6 @@ void St7789::VerticalScrollStartAddress(uint16_t line) { void St7789::Uninit() { } -void St7789::DrawPixel(uint16_t x, uint16_t y, uint32_t color) { - if (x >= Width || y >= Height) { - return; - } - - SetAddrWindow(x, y, x + 1, y + 1); - - nrf_gpio_pin_set(pinDataCommand); - WriteSpi(reinterpret_cast(&color), 2); -} - void St7789::DrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t* data, size_t size) { SetAddrWindow(x, y, x + width - 1, y + height - 1); nrf_gpio_pin_set(pinDataCommand); diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 68e1da44..b00bee03 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -16,9 +16,7 @@ namespace Pinetime { void Init(); void Uninit(); - void DrawPixel(uint16_t x, uint16_t y, uint32_t color); - void VerticalScrollDefinition(uint16_t topFixedLines, uint16_t scrollLines, uint16_t bottomFixedLines); void VerticalScrollStartAddress(uint16_t line); void DrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t* data, size_t size); diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index 723977e3..a0b4d784 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -48,7 +47,6 @@ Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn}; Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand, Pinetime::PinMap::LcdReset}; -Pinetime::Components::Gfx gfx {lcd}; Pinetime::Controllers::BrightnessController brightnessController; void DisplayProgressBar(uint8_t percent, uint16_t color); @@ -92,7 +90,6 @@ void Process(void* /*instance*/) { spiNorFlash.Wakeup(); brightnessController.Init(); lcd.Init(); - gfx.Init(); NRF_LOG_INFO("Display logo") DisplayLogo(); From a49dc15a6e29022606289a02573cf567dad04114 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Thu, 1 Feb 2024 17:01:34 -0500 Subject: [PATCH 20/67] WatchFaceDigital: Move weather widget away from status icons The weather widget is too high and could overlap the status icons. Moving it to match the rest of the face avoids this issue and makes it align with the rest of the theme. --- src/displayapp/screens/WatchFaceDigital.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index 0a7da2fd..afe00fa5 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -40,16 +40,16 @@ WatchFaceDigital::WatchFaceDigital(Controllers::DateTime& dateTimeController, lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); weatherIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); lv_label_set_text(weatherIcon, ""); - lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 0); + lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 50); lv_obj_set_auto_realign(weatherIcon, true); temperature = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); lv_label_set_text(temperature, ""); - lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 0); + lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 50); label_date = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); From c2c53bc6abdcc0a81df860101df51ebfc43df308 Mon Sep 17 00:00:00 2001 From: Graham Jones Date: Sun, 11 Feb 2024 19:46:26 +0000 Subject: [PATCH 21/67] bma421: Change acceleration values to 'binary milli-G' units Co-authored-by: FintasticMan --- doc/MotionService.md | 2 ++ src/displayapp/screens/Motion.cpp | 8 ++++---- src/drivers/Bma421.cpp | 22 ++++++++++++++++++++-- src/drivers/Bma421.h | 1 + 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/doc/MotionService.md b/doc/MotionService.md index 429794ac..58c7e836 100644 --- a/doc/MotionService.md +++ b/doc/MotionService.md @@ -21,3 +21,5 @@ The current raw motion values. This is a 3 `int16_t` array: - [0] : X - [1] : Y - [2] : Z + +The three motion values are in units of "binary milli-g", where 1g is represented by a value of 1024. diff --git a/src/displayapp/screens/Motion.cpp b/src/displayapp/screens/Motion.cpp index 87c55eea..ecbed317 100644 --- a/src/displayapp/screens/Motion.cpp +++ b/src/displayapp/screens/Motion.cpp @@ -53,9 +53,9 @@ void Motion::Refresh() { lv_label_set_text_fmt(labelStep, "Steps %lu", motionController.NbSteps()); lv_label_set_text_fmt(label, - "X #FF0000 %d# Y #00B000 %d# Z #FFFF00 %d#", - motionController.X() / 0x10, - motionController.Y() / 0x10, - motionController.Z() / 0x10); + "X #FF0000 %d# Y #00B000 %d# Z #FFFF00 %d# mg", + motionController.X(), + motionController.Y(), + motionController.Z()); lv_obj_align(label, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10); } diff --git a/src/drivers/Bma421.cpp b/src/drivers/Bma421.cpp index 84d76ab3..aff62b8d 100644 --- a/src/drivers/Bma421.cpp +++ b/src/drivers/Bma421.cpp @@ -22,6 +22,16 @@ namespace { void user_delay(uint32_t period_us, void* /*intf_ptr*/) { nrf_delay_us(period_us); } + + // Scale factors to convert accelerometer counts to milli-g + // from datasheet: https://files.pine64.org/doc/datasheet/pinetime/BST-BMA421-FL000.pdf + // The array index to use is stored in accel_conf.range + constexpr int16_t accelScaleFactors[] = { + [BMA4_ACCEL_RANGE_2G] = 1024, // LSB/g +/- 2g range + [BMA4_ACCEL_RANGE_4G] = 512, // LSB/g +/- 4g range + [BMA4_ACCEL_RANGE_8G] = 256, // LSB/g +/- 8g range + [BMA4_ACCEL_RANGE_16G] = 128 // LSB/g +/- 16g range + }; } Bma421::Bma421(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, deviceAddress {twiAddress} { @@ -74,7 +84,6 @@ void Bma421::Init() { if (ret != BMA4_OK) return; - struct bma4_accel_config accel_conf; accel_conf.odr = BMA4_OUTPUT_DATA_RATE_100HZ; accel_conf.range = BMA4_ACCEL_RANGE_2G; accel_conf.bandwidth = BMA4_ACCEL_NORMAL_AVG4; @@ -102,8 +111,17 @@ void Bma421::Write(uint8_t registerAddress, const uint8_t* data, size_t size) { Bma421::Values Bma421::Process() { if (not isOk) return {}; + struct bma4_accel rawData; struct bma4_accel data; - bma4_read_accel_xyz(&data, &bma); + bma4_read_accel_xyz(&rawData, &bma); + + // Scale the measured ADC counts to units of 'binary milli-g' + // where 1g = 1024 'binary milli-g' units. + // See https://github.com/InfiniTimeOrg/InfiniTime/pull/1950 for + // discussion of why we opted for scaling to 1024 rather than 1000. + data.x = 1024 * rawData.x / accelScaleFactors[accel_conf.range]; + data.y = 1024 * rawData.y / accelScaleFactors[accel_conf.range]; + data.z = 1024 * rawData.z / accelScaleFactors[accel_conf.range]; uint32_t steps = 0; bma423_step_counter_output(&steps, &bma); diff --git a/src/drivers/Bma421.h b/src/drivers/Bma421.h index fb832514..5269f62b 100644 --- a/src/drivers/Bma421.h +++ b/src/drivers/Bma421.h @@ -41,6 +41,7 @@ namespace Pinetime { TwiMaster& twiMaster; uint8_t deviceAddress = 0x18; struct bma4_dev bma; + struct bma4_accel_config accel_conf; // Store the device configuration for later reference. bool isOk = false; bool isResetOk = false; DeviceTypes deviceType = DeviceTypes::Unknown; From fa1af55a45fb277db71b6654ebe610a4d1bc7961 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Mon, 12 Feb 2024 10:08:40 -0500 Subject: [PATCH 22/67] Alarm: Replace clock icon with bell --- src/displayapp/fonts/fonts.json | 2 +- src/displayapp/screens/Alarm.h | 2 +- src/displayapp/screens/Symbols.h | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 57341245..a3132504 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, 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" } ], "bpp": 1, diff --git a/src/displayapp/screens/Alarm.h b/src/displayapp/screens/Alarm.h index 993d65d1..444102cb 100644 --- a/src/displayapp/screens/Alarm.h +++ b/src/displayapp/screens/Alarm.h @@ -69,7 +69,7 @@ namespace Pinetime { template <> struct AppTraits { static constexpr Apps app = Apps::Alarm; - static constexpr const char* icon = Screens::Symbols::clock; + static constexpr const char* icon = Screens::Symbols::bell; static Screens::Screen* Create(AppControllers& controllers) { return new Screens::Alarm(controllers.alarmController, diff --git a/src/displayapp/screens/Symbols.h b/src/displayapp/screens/Symbols.h index 4434194b..bd958b28 100644 --- a/src/displayapp/screens/Symbols.h +++ b/src/displayapp/screens/Symbols.h @@ -11,6 +11,7 @@ namespace Pinetime { static constexpr const char* plug = "\xEF\x87\xA6"; static constexpr const char* shoe = "\xEF\x95\x8B"; static constexpr const char* clock = "\xEF\x80\x97"; + static constexpr const char* bell = "\xEF\x83\xB3"; static constexpr const char* info = "\xEF\x84\xA9"; static constexpr const char* list = "\xEF\x80\xBA"; static constexpr const char* sun = "\xEF\x86\x85"; From 93d7da16919a213404f00cbb26a630722b63d6f7 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Tue, 13 Feb 2024 01:20:46 +0000 Subject: [PATCH 23/67] Fix OOB flash write when DFU interrupted If a DFU is restarted, the write indices aren't reset causing the image to be written out of bounds. The CRC check prevents the faulty image from booting but LittleFS still gets nuked. --- src/components/ble/DfuService.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/ble/DfuService.cpp b/src/components/ble/DfuService.cpp index 1f06b69e..b3f2ff10 100644 --- a/src/components/ble/DfuService.cpp +++ b/src/components/ble/DfuService.cpp @@ -357,6 +357,8 @@ void DfuService::DfuImage::Init(size_t chunkSize, size_t totalSize, uint16_t exp this->totalSize = totalSize; this->expectedCrc = expectedCrc; this->ready = true; + totalWriteIndex = 0; + bufferWriteIndex = 0; } void DfuService::DfuImage::Append(uint8_t* data, size_t size) { From b0a0afdd4b30a663e1651e63be1549f33fdefb7b Mon Sep 17 00:00:00 2001 From: Tim Teichmann Date: Sun, 28 Jan 2024 09:46:56 +0100 Subject: [PATCH 24/67] README: Make hex and UTF-8 code consistent for the chosen example --- src/displayapp/fonts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/displayapp/fonts/README.md b/src/displayapp/fonts/README.md index bcc2d49c..20fb4a43 100644 --- a/src/displayapp/fonts/README.md +++ b/src/displayapp/fonts/README.md @@ -16,7 +16,7 @@ - Define the new symbols in `src/displayapp/screens/Symbols.h`: ``` -static constexpr const char* newSymbol = "\xEF\x86\x85"; +static constexpr const char* newSymbol = "\xEF\x99\x81"; ``` ### the config file format: From 5d971690cb7fcf51e0215a9eda16136607cf1851 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Mon, 12 Feb 2024 15:59:40 -0500 Subject: [PATCH 25/67] DateTimeController: Make DayOfWeekShortToStringLow static This allows it to be used outside of the current datetime context and makes it consistent with the MonthShortToStringLow function. --- src/components/datetime/DateTimeController.cpp | 4 ++-- src/components/datetime/DateTimeController.h | 2 +- src/displayapp/screens/WatchFaceInfineat.cpp | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index 8d4a834e..f0ccb5e5 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -115,8 +115,8 @@ const char* DateTime::MonthShortToStringLow(Months month) { return MonthsStringLow[static_cast(month)]; } -const char* DateTime::DayOfWeekShortToStringLow() const { - return DaysStringShortLow[static_cast(DayOfWeek())]; +const char* DateTime::DayOfWeekShortToStringLow(Days day) { + return DaysStringShortLow[static_cast(day)]; } void DateTime::Register(Pinetime::System::SystemTask* systemTask) { diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h index 0bf6ac2a..f719df7d 100644 --- a/src/components/datetime/DateTimeController.h +++ b/src/components/datetime/DateTimeController.h @@ -122,7 +122,7 @@ namespace Pinetime { const char* MonthShortToString() const; const char* DayOfWeekShortToString() const; static const char* MonthShortToStringLow(Months month); - const char* DayOfWeekShortToStringLow() const; + static const char* DayOfWeekShortToStringLow(Days day); std::chrono::time_point CurrentDateTime() const { return currentDateTime; diff --git a/src/displayapp/screens/WatchFaceInfineat.cpp b/src/displayapp/screens/WatchFaceInfineat.cpp index 3308303d..c643f3bd 100644 --- a/src/displayapp/screens/WatchFaceInfineat.cpp +++ b/src/displayapp/screens/WatchFaceInfineat.cpp @@ -426,7 +426,8 @@ void WatchFaceInfineat::Refresh() { currentDate = std::chrono::time_point_cast(currentDateTime.Get()); if (currentDate.IsUpdated()) { uint8_t day = dateTimeController.Day(); - lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(), day); + Controllers::DateTime::Days dayOfWeek = dateTimeController.DayOfWeek(); + lv_label_set_text_fmt(labelDate, "%s %02d", dateTimeController.DayOfWeekShortToStringLow(dayOfWeek), day); lv_obj_realign(labelDate); } } From f422929d8cd0877c56e55d285f3ab3cc1223ea96 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Wed, 31 Jan 2024 17:41:39 -0500 Subject: [PATCH 26/67] weather: Add new app with forecast --- src/CMakeLists.txt | 1 + src/displayapp/DisplayApp.cpp | 1 + src/displayapp/apps/Apps.h.in | 4 +- src/displayapp/apps/CMakeLists.txt | 2 +- src/displayapp/fonts/fonts.json | 4 +- src/displayapp/screens/Weather.cpp | 156 ++++++++++++++++++++++ src/displayapp/screens/Weather.h | 56 ++++++++ src/displayapp/screens/WeatherSymbols.cpp | 25 ++++ src/displayapp/screens/WeatherSymbols.h | 1 + 9 files changed, 245 insertions(+), 5 deletions(-) create mode 100644 src/displayapp/screens/Weather.cpp create mode 100644 src/displayapp/screens/Weather.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8d0b792c..fd8ece62 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -379,6 +379,7 @@ list(APPEND SOURCE_FILES displayapp/screens/Navigation.cpp displayapp/screens/Metronome.cpp displayapp/screens/Motion.cpp + displayapp/screens/Weather.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 e5329b2d..f3f0bd93 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -27,6 +27,7 @@ #include "displayapp/screens/BatteryInfo.h" #include "displayapp/screens/Steps.h" #include "displayapp/screens/Dice.h" +#include "displayapp/screens/Weather.h" #include "displayapp/screens/PassKey.h" #include "displayapp/screens/Error.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 77d3b366..2104a267 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -28,6 +28,7 @@ namespace Pinetime { Motion, Steps, Dice, + Weather, PassKey, QuickSettings, Settings, @@ -41,8 +42,7 @@ namespace Pinetime { SettingChimes, SettingShakeThreshold, SettingBluetooth, - Error, - Weather + Error }; enum class WatchFace : uint8_t { diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index 51c08595..d7858760 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -13,7 +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::Weather") + 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") endif () diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index a3132504..41c383c0 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -18,7 +18,7 @@ "sources": [ { "file": "JetBrainsMono-Regular.ttf", - "range": "0x25, 0x2b, 0x2d, 0x2e, 0x30-0x3a, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74" + "range": "0x25, 0x2b, 0x2d, 0x2e, 0x30-0x3a, 0x43, 0x46, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74, 0xb0" } ], "bpp": 1, @@ -28,7 +28,7 @@ "sources": [ { "file": "JetBrainsMono-Light.ttf", - "range": "0x25, 0x2D, 0x2F, 0x30-0x3a" + "range": "0x25, 0x2D, 0x2F, 0x30-0x3a, 0x43, 0x46, 0xb0" } ], "bpp": 1, diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp new file mode 100644 index 00000000..d5bdf127 --- /dev/null +++ b/src/displayapp/screens/Weather.cpp @@ -0,0 +1,156 @@ +#include "displayapp/screens/Weather.h" +#include +#include "components/ble/SimpleWeatherService.h" +#include "components/datetime/DateTimeController.h" +#include "components/settings/Settings.h" +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/WeatherSymbols.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Screens; + +Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService) + : settingsController {settingsController}, weatherService {weatherService} { + + temperature = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_font(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_42); + lv_label_set_text(temperature, "---"); + lv_obj_align(temperature, nullptr, LV_ALIGN_CENTER, 0, -30); + lv_obj_set_auto_realign(temperature, true); + + minTemperature = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(minTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); + lv_label_set_text(minTemperature, ""); + lv_obj_align(minTemperature, temperature, LV_ALIGN_OUT_LEFT_MID, -10, 0); + lv_obj_set_auto_realign(minTemperature, true); + + maxTemperature = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(maxTemperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::bg); + lv_label_set_text(maxTemperature, ""); + lv_obj_align(maxTemperature, temperature, LV_ALIGN_OUT_RIGHT_MID, 10, 0); + lv_obj_set_auto_realign(maxTemperature, true); + + condition = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(condition, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); + lv_label_set_text(condition, ""); + lv_obj_align(condition, temperature, LV_ALIGN_OUT_TOP_MID, 0, -10); + lv_obj_set_auto_realign(condition, true); + + 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_set_style_local_text_font(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); + lv_label_set_text(icon, ""); + lv_obj_align(icon, condition, LV_ALIGN_OUT_TOP_MID, 0, 0); + lv_obj_set_auto_realign(icon, true); + + forecast = lv_table_create(lv_scr_act(), nullptr); + lv_table_set_col_cnt(forecast, Controllers::SimpleWeatherService::MaxNbForecastDays); + lv_table_set_row_cnt(forecast, 4); + // LV_TABLE_PART_CELL1: Default table style + lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, Colors::lightGray); + lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, 6); + // LV_TABLE_PART_CELL2: Condition icon + lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_font(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, &fontawesome_weathericons); + lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, 6); + + lv_obj_align(forecast, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + + for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { + lv_table_set_col_width(forecast, i, 48); + lv_table_set_cell_type(forecast, 1, i, LV_TABLE_PART_CELL2); + lv_table_set_cell_align(forecast, 0, i, LV_LABEL_ALIGN_RIGHT); + lv_table_set_cell_align(forecast, 1, i, LV_LABEL_ALIGN_RIGHT); + lv_table_set_cell_align(forecast, 2, i, LV_LABEL_ALIGN_RIGHT); + lv_table_set_cell_align(forecast, 3, i, LV_LABEL_ALIGN_RIGHT); + } + + taskRefresh = lv_task_create(RefreshTaskCallback, 1000, LV_TASK_PRIO_MID, this); + Refresh(); +} + +Weather::~Weather() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); +} + +void Weather::Refresh() { + currentWeather = weatherService.Current(); + if (currentWeather.IsUpdated()) { + auto optCurrentWeather = currentWeather.Get(); + if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature; + int16_t minTemp = optCurrentWeather->minTemperature; + int16_t maxTemp = optCurrentWeather->maxTemperature; + lv_color_t color = Colors::orange; + if (temp <= 0) { // freezing + color = Colors::blue; + } else if (temp <= 400) { // ice danger + color = LV_COLOR_CYAN; + } else if (temp >= 2700) { // hot + color = Colors::deepOrange; + } + char tempUnit = 'C'; + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); + minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp); + maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp); + tempUnit = 'F'; + } + temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); + maxTemp = maxTemp / 100 + (maxTemp % 100 >= 50 ? 1 : 0); + minTemp = minTemp / 100 + (minTemp % 100 >= 50 ? 1 : 0); + lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId)); + lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId)); + lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color); + lv_label_set_text_fmt(minTemperature, "%d°", minTemp); + lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); + } else { + lv_label_set_text(icon, ""); + lv_label_set_text(condition, ""); + lv_label_set_text(temperature, "---"); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_label_set_text(minTemperature, ""); + lv_label_set_text(maxTemperature, ""); + } + } + + currentForecast = weatherService.GetForecast(); + if (currentForecast.IsUpdated()) { + auto optCurrentForecast = currentForecast.Get(); + if (optCurrentForecast) { + std::tm localTime = *std::localtime(reinterpret_cast(&optCurrentForecast->timestamp)); + + for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { + int16_t maxTemp = optCurrentForecast->days[i].maxTemperature; + int16_t minTemp = optCurrentForecast->days[i].minTemperature; + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp); + minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp); + } + uint8_t wday = localTime.tm_wday + i + 1; + if (wday > 7) { + wday -= 7; + } + maxTemp = maxTemp / 100 + (maxTemp % 100 >= 50 ? 1 : 0); + minTemp = minTemp / 100 + (minTemp % 100 >= 50 ? 1 : 0); + const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast(wday)); + lv_table_set_cell_value(forecast, 0, i, dayOfWeek); + lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i].iconId)); + lv_table_set_cell_value_fmt(forecast, 2, i, "%d", maxTemp); + lv_table_set_cell_value_fmt(forecast, 3, i, "%d", minTemp); + } + } else { + for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { + lv_table_set_cell_value(forecast, 0, i, ""); + lv_table_set_cell_value(forecast, 1, i, ""); + lv_table_set_cell_value(forecast, 2, i, ""); + lv_table_set_cell_value(forecast, 3, i, ""); + } + } + } +} diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h new file mode 100644 index 00000000..6975311e --- /dev/null +++ b/src/displayapp/screens/Weather.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/ble/SimpleWeatherService.h" +#include "displayapp/apps/Apps.h" +#include "displayapp/Controllers.h" +#include "Symbols.h" +#include "utility/DirtyValue.h" + +namespace Pinetime { + + namespace Controllers { + class Settings; + } + + namespace Applications { + namespace Screens { + + class Weather : public Screen { + public: + Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService); + ~Weather() override; + + void Refresh() override; + + private: + Controllers::Settings& settingsController; + Controllers::SimpleWeatherService& weatherService; + + Utility::DirtyValue> currentWeather {}; + Utility::DirtyValue> currentForecast {}; + + lv_obj_t* icon; + lv_obj_t* condition; + lv_obj_t* temperature; + lv_obj_t* minTemperature; + lv_obj_t* maxTemperature; + lv_obj_t* forecast; + + lv_task_t* taskRefresh; + }; + } + + template <> + struct AppTraits { + static constexpr Apps app = Apps::Weather; + static constexpr const char* icon = Screens::Symbols::cloudSunRain; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::Weather(controllers.settingsController, *controllers.weatherController); + }; + }; + } +} diff --git a/src/displayapp/screens/WeatherSymbols.cpp b/src/displayapp/screens/WeatherSymbols.cpp index a7749541..de66312f 100644 --- a/src/displayapp/screens/WeatherSymbols.cpp +++ b/src/displayapp/screens/WeatherSymbols.cpp @@ -34,3 +34,28 @@ const char* Pinetime::Applications::Screens::Symbols::GetSymbol(const Pinetime:: break; } } + +const char* Pinetime::Applications::Screens::Symbols::GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon) { + switch (icon) { + case Pinetime::Controllers::SimpleWeatherService::Icons::Sun: + return "Clear sky"; + case Pinetime::Controllers::SimpleWeatherService::Icons::CloudsSun: + return "Few clouds"; + case Pinetime::Controllers::SimpleWeatherService::Icons::Clouds: + return "Scattered clouds"; + case Pinetime::Controllers::SimpleWeatherService::Icons::BrokenClouds: + return "Broken clouds"; + case Pinetime::Controllers::SimpleWeatherService::Icons::CloudShowerHeavy: + return "Shower rain"; + case Pinetime::Controllers::SimpleWeatherService::Icons::CloudSunRain: + return "Rain"; + case Pinetime::Controllers::SimpleWeatherService::Icons::Thunderstorm: + return "Thunderstorm"; + case Pinetime::Controllers::SimpleWeatherService::Icons::Snow: + return "Snow"; + case Pinetime::Controllers::SimpleWeatherService::Icons::Smog: + return "Mist"; + default: + return ""; + } +} diff --git a/src/displayapp/screens/WeatherSymbols.h b/src/displayapp/screens/WeatherSymbols.h index 93453b4e..f3eeed55 100644 --- a/src/displayapp/screens/WeatherSymbols.h +++ b/src/displayapp/screens/WeatherSymbols.h @@ -7,6 +7,7 @@ namespace Pinetime { namespace Screens { namespace Symbols { const char* GetSymbol(const Pinetime::Controllers::SimpleWeatherService::Icons icon); + const char* GetCondition(const Pinetime::Controllers::SimpleWeatherService::Icons icon); } } } From 1857b02efa6607694849036eeba6f6c995f1b447 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Fri, 2 Feb 2024 16:54:40 -0500 Subject: [PATCH 27/67] weather: Colorize forecast temperatures --- src/displayapp/screens/Weather.cpp | 54 +++++++++++++++++++++++++----- src/libs/lv_conf.h | 4 ++- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index d5bdf127..b4e9ab9f 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -9,6 +9,30 @@ using namespace Pinetime::Applications::Screens; +namespace { + lv_color_t TemperatureColor(int16_t temperature) { + if (temperature <= 0) { // freezing + return Colors::blue; + } else if (temperature <= 400) { // ice + return LV_COLOR_CYAN; + } else if (temperature >= 2700) { // hot + return Colors::deepOrange; + } + return Colors::orange; // normal + } + + uint8_t TemperatureStyle(int16_t temperature) { + if (temperature <= 0) { // freezing + return LV_TABLE_PART_CELL3; + } else if (temperature <= 400) { // ice + return LV_TABLE_PART_CELL4; + } else if (temperature >= 2700) { // hot + return LV_TABLE_PART_CELL6; + } + return LV_TABLE_PART_CELL5; // normal + } +} + Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService) : settingsController {settingsController}, weatherService {weatherService} { @@ -56,6 +80,22 @@ Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleW lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_obj_set_style_local_text_font(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, &fontawesome_weathericons); lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, 6); + // LV_TABLE_PART_CELL3: Freezing + lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, Colors::blue); + lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, 6); + // LV_TABLE_PART_CELL4: Ice + lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_CYAN); + lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, 6); + // LV_TABLE_PART_CELL5: Normal + lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, Colors::orange); + lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, 6); + // LV_TABLE_PART_CELL6: Hot + lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, LV_COLOR_BLACK); + lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, Colors::deepOrange); + lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, 6); lv_obj_align(forecast, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); @@ -85,14 +125,7 @@ void Weather::Refresh() { int16_t temp = optCurrentWeather->temperature; int16_t minTemp = optCurrentWeather->minTemperature; int16_t maxTemp = optCurrentWeather->maxTemperature; - lv_color_t color = Colors::orange; - if (temp <= 0) { // freezing - color = Colors::blue; - } else if (temp <= 400) { // ice danger - color = LV_COLOR_CYAN; - } else if (temp >= 2700) { // hot - color = Colors::deepOrange; - } + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, TemperatureColor(temp)); char tempUnit = 'C'; if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); @@ -106,7 +139,6 @@ void Weather::Refresh() { lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId)); lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId)); lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); - lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, color); lv_label_set_text_fmt(minTemperature, "%d°", minTemp); lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); } else { @@ -128,6 +160,8 @@ void Weather::Refresh() { for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { int16_t maxTemp = optCurrentForecast->days[i].maxTemperature; int16_t minTemp = optCurrentForecast->days[i].minTemperature; + lv_table_set_cell_type(forecast, 2, i, TemperatureStyle(maxTemp)); + lv_table_set_cell_type(forecast, 3, i, TemperatureStyle(minTemp)); if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp); minTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(minTemp); @@ -150,6 +184,8 @@ void Weather::Refresh() { lv_table_set_cell_value(forecast, 1, i, ""); lv_table_set_cell_value(forecast, 2, i, ""); lv_table_set_cell_value(forecast, 3, i, ""); + lv_table_set_cell_type(forecast, 2, i, LV_TABLE_PART_CELL1); + lv_table_set_cell_type(forecast, 3, i, LV_TABLE_PART_CELL1); } } } diff --git a/src/libs/lv_conf.h b/src/libs/lv_conf.h index e96778ec..c23647f2 100644 --- a/src/libs/lv_conf.h +++ b/src/libs/lv_conf.h @@ -729,7 +729,9 @@ typedef void* lv_obj_user_data_t; #define LV_USE_TABLE 1 #if LV_USE_TABLE #define LV_TABLE_COL_MAX 12 -#define LV_TABLE_CELL_STYLE_CNT 5 +#define LV_TABLE_CELL_STYLE_CNT 6 +#define LV_TABLE_PART_CELL5 5 +#define LV_TABLE_PART_CELL6 6 #endif From 68ae335a97230fb1f00bf508648dc784cd4e0ba2 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Sat, 10 Feb 2024 13:26:47 -0500 Subject: [PATCH 28/67] weather: Pad forecast temperatures This ensures temperatures are correctly aligned with one another --- src/displayapp/screens/Weather.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index b4e9ab9f..5d5ab6d4 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -74,38 +74,32 @@ Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleW // LV_TABLE_PART_CELL1: Default table style lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, Colors::lightGray); - lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL1, LV_STATE_DEFAULT, 6); // LV_TABLE_PART_CELL2: Condition icon lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_obj_set_style_local_text_font(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, &fontawesome_weathericons); - lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL2, LV_STATE_DEFAULT, 6); // LV_TABLE_PART_CELL3: Freezing lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, Colors::blue); - lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL3, LV_STATE_DEFAULT, 6); // LV_TABLE_PART_CELL4: Ice lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, LV_COLOR_CYAN); - lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL4, LV_STATE_DEFAULT, 6); // LV_TABLE_PART_CELL5: Normal lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, Colors::orange); - lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL5, LV_STATE_DEFAULT, 6); // LV_TABLE_PART_CELL6: Hot lv_obj_set_style_local_border_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_obj_set_style_local_text_color(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, Colors::deepOrange); - lv_obj_set_style_local_pad_right(forecast, LV_TABLE_PART_CELL6, LV_STATE_DEFAULT, 6); lv_obj_align(forecast, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { lv_table_set_col_width(forecast, i, 48); lv_table_set_cell_type(forecast, 1, i, LV_TABLE_PART_CELL2); - lv_table_set_cell_align(forecast, 0, i, LV_LABEL_ALIGN_RIGHT); - lv_table_set_cell_align(forecast, 1, i, LV_LABEL_ALIGN_RIGHT); - lv_table_set_cell_align(forecast, 2, i, LV_LABEL_ALIGN_RIGHT); - lv_table_set_cell_align(forecast, 3, i, LV_LABEL_ALIGN_RIGHT); + lv_table_set_cell_align(forecast, 0, i, LV_LABEL_ALIGN_CENTER); + lv_table_set_cell_align(forecast, 1, i, LV_LABEL_ALIGN_CENTER); + lv_table_set_cell_align(forecast, 2, i, LV_LABEL_ALIGN_CENTER); + lv_table_set_cell_align(forecast, 3, i, LV_LABEL_ALIGN_CENTER); } taskRefresh = lv_task_create(RefreshTaskCallback, 1000, LV_TASK_PRIO_MID, this); @@ -175,8 +169,19 @@ void Weather::Refresh() { const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast(wday)); lv_table_set_cell_value(forecast, 0, i, dayOfWeek); lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i].iconId)); - lv_table_set_cell_value_fmt(forecast, 2, i, "%d", maxTemp); - lv_table_set_cell_value_fmt(forecast, 3, i, "%d", minTemp); + // Pad cells based on the largest number of digits on each column + char maxPadding[3] = " "; + char minPadding[3] = " "; + int diff = snprintf(nullptr, 0, "%d", maxTemp) - snprintf(nullptr, 0, "%d", minTemp); + if (diff <= 0) { + maxPadding[-diff] = '\0'; + minPadding[0] = '\0'; + } else { + maxPadding[0] = '\0'; + minPadding[diff] = '\0'; + } + lv_table_set_cell_value_fmt(forecast, 2, i, "%s%d", maxPadding, maxTemp); + lv_table_set_cell_value_fmt(forecast, 3, i, "%s%d", minPadding, minTemp); } } else { for (int i = 0; i < Controllers::SimpleWeatherService::MaxNbForecastDays; i++) { From 6ab512a6b6f83255f5798d0ccf574ee7ca1f287d Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Mon, 12 Feb 2024 16:32:52 -0500 Subject: [PATCH 29/67] weather: Define function to round and render temperature --- src/displayapp/screens/Weather.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 5d5ab6d4..5321b7cc 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -31,6 +31,10 @@ namespace { } return LV_TABLE_PART_CELL5; // normal } + + int16_t RoundTemperature(int16_t temp) { + return temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); + } } Weather::Weather(Controllers::Settings& settingsController, Controllers::SimpleWeatherService& weatherService) @@ -127,14 +131,11 @@ void Weather::Refresh() { maxTemp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(maxTemp); tempUnit = 'F'; } - temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); - maxTemp = maxTemp / 100 + (maxTemp % 100 >= 50 ? 1 : 0); - minTemp = minTemp / 100 + (minTemp % 100 >= 50 ? 1 : 0); lv_label_set_text(icon, Symbols::GetSymbol(optCurrentWeather->iconId)); lv_label_set_text(condition, Symbols::GetCondition(optCurrentWeather->iconId)); - lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); - lv_label_set_text_fmt(minTemperature, "%d°", minTemp); - lv_label_set_text_fmt(maxTemperature, "%d°", maxTemp); + lv_label_set_text_fmt(temperature, "%d°%c", RoundTemperature(temp), tempUnit); + lv_label_set_text_fmt(minTemperature, "%d°", RoundTemperature(minTemp)); + lv_label_set_text_fmt(maxTemperature, "%d°", RoundTemperature(maxTemp)); } else { lv_label_set_text(icon, ""); lv_label_set_text(condition, ""); @@ -164,8 +165,8 @@ void Weather::Refresh() { if (wday > 7) { wday -= 7; } - maxTemp = maxTemp / 100 + (maxTemp % 100 >= 50 ? 1 : 0); - minTemp = minTemp / 100 + (minTemp % 100 >= 50 ? 1 : 0); + maxTemp = RoundTemperature(maxTemp); + minTemp = RoundTemperature(minTemp); const char* dayOfWeek = Controllers::DateTime::DayOfWeekShortToStringLow(static_cast(wday)); lv_table_set_cell_value(forecast, 0, i, dayOfWeek); lv_table_set_cell_value(forecast, 1, i, Symbols::GetSymbol(optCurrentForecast->days[i].iconId)); From 004b2bf3a019fa63e18b0b2d5bd912ebf82c8c76 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Wed, 21 Feb 2024 14:49:46 -0500 Subject: [PATCH 30/67] README: Fix broken URLs --- README.md | 2 +- bootloader/ota-dfu-python/README.md | 4 ++-- src/drivers/Hrs3300.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8d612360..e4f6707f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![InfiniTime logo](doc/logo/infinitime-logo-small.jpg "InfiniTime Logo") -Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/pinetime/) with many features, written in modern C++. +Fast open-source firmware for the [PineTime smartwatch](https://pine64.org/devices/pinetime/) with many features, written in modern C++. ## New to InfiniTime? diff --git a/bootloader/ota-dfu-python/README.md b/bootloader/ota-dfu-python/README.md index c38e597a..c18da8bb 100644 --- a/bootloader/ota-dfu-python/README.md +++ b/bootloader/ota-dfu-python/README.md @@ -7,9 +7,9 @@ My own contribution is little more than a brute force conversion to python3. It is sparsely tested so there are likely to be a few remaining bytes versus string bugs remaining in the places I didn't test . I used it primarily as part of -[wasp-os](https://github.com/daniel-thompson/wasp-os) as a way to +[wasp-os](https://github.com/wasp-os/wasp-os) as a way to deliver OTA updates to nRF52-based smart watches, especially the -[Pine64 PineTime](https://www.pine64.org/pinetime/). +[Pine64 PineTime](https://pine64.org/devices/pinetime/). ## What does it do? diff --git a/src/drivers/Hrs3300.cpp b/src/drivers/Hrs3300.cpp index 7dfd301c..33889b6f 100644 --- a/src/drivers/Hrs3300.cpp +++ b/src/drivers/Hrs3300.cpp @@ -19,7 +19,7 @@ namespace { } /** Driver for the HRS3300 heart rate sensor. - * Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/drivers/hrs3300.py + * Original implementation from wasp-os : https://github.com/wasp-os/wasp-os/blob/master/wasp/drivers/hrs3300.py * * Experimentaly derived changes to improve signal/noise (see comments below) - Ceimour */ From 70f6604878e58ce7d052825cf44e960b263309d4 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:33:31 +0000 Subject: [PATCH 31/67] Fix chimes --- src/systemtask/SystemTask.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 246e7cec..5a885f17 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -342,8 +342,12 @@ void SystemTask::Work() { if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::Hours && alarmController.State() != AlarmController::AlarmState::Alerting) { + // if sleeping, we can't send a chime to displayApp yet (SPI flash switched off) + // request running first and repush the chime message if (state == SystemTaskState::Sleeping) { GoToRunning(); + PushMessage(msg); + } else { displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime); } } @@ -353,8 +357,12 @@ void SystemTask::Work() { if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep && settingsController.GetChimeOption() == Controllers::Settings::ChimesOption::HalfHours && alarmController.State() != AlarmController::AlarmState::Alerting) { + // if sleeping, we can't send a chime to displayApp yet (SPI flash switched off) + // request running first and repush the chime message if (state == SystemTaskState::Sleeping) { GoToRunning(); + PushMessage(msg); + } else { displayApp.PushMessage(Pinetime::Applications::Display::Messages::Chime); } } From 636af4d33da215f33ae09b6ae4c5e7195aaa356e Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:38:20 +0000 Subject: [PATCH 32/67] Simplify ISR task wake checks The macro checks the variable, so we don't need to check it ourselves --- src/displayapp/DisplayApp.cpp | 4 +--- src/displayapp/DisplayAppRecovery.cpp | 8 ++------ src/heartratetask/HeartRateTask.cpp | 5 +---- src/systemtask/SystemTask.cpp | 5 +---- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index f3f0bd93..c1008be0 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -561,9 +561,7 @@ void DisplayApp::PushMessage(Messages msg) { if (in_isr()) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken == pdTRUE) { - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - } + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } else { TickType_t timeout = portMAX_DELAY; // Make xQueueSend() non-blocking if the message is a Notification message. We do this to avoid diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index c4bd5766..002ee3bd 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -110,13 +110,9 @@ void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) { } void DisplayApp::PushMessage(Display::Messages msg) { - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { - /* Actual macro used here is port specific. */ - // TODO : should I do something here? - } + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void DisplayApp::Register(Pinetime::System::SystemTask* /*systemTask*/) { diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index 414cdf2c..9d82d11e 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -103,10 +103,7 @@ void HeartRateTask::Work() { void HeartRateTask::PushMessage(HeartRateTask::Messages msg) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(messageQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { - /* Actual macro used here is port specific. */ - // TODO : should I do something here? - } + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void HeartRateTask::StartMeasurement() { diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 5a885f17..e3d40d35 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -512,10 +512,7 @@ void SystemTask::PushMessage(System::Messages msg) { if (in_isr()) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken == pdTRUE) { - /* Actual macro used here is port specific. */ - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - } + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } else { xQueueSend(systemTasksMsgQueue, &msg, portMAX_DELAY); } From f2df0c45ef17f5a6180ecd21654c74506d7d7dd8 Mon Sep 17 00:00:00 2001 From: FintasticMan Date: Mon, 12 Feb 2024 11:37:34 +0100 Subject: [PATCH 33/67] lowersleep: Improve algorithm by checking wrist angle Inspired by https://github.com/InfiniTimeOrg/InfiniTime/pull/827#issuecomment-1881580414. --- src/components/motion/MotionController.cpp | 24 ++++++++++++++++------ src/components/motion/MotionController.h | 8 +++++--- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/components/motion/MotionController.cpp b/src/components/motion/MotionController.cpp index d28378d5..72507ac5 100644 --- a/src/components/motion/MotionController.cpp +++ b/src/components/motion/MotionController.cpp @@ -40,15 +40,15 @@ void MotionController::Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps) service->OnNewStepCountValue(nbSteps); } - if (service != nullptr && (this->x != x || yHistory[0] != y || zHistory[0] != z)) { + if (service != nullptr && (xHistory[0] != x || yHistory[0] != y || zHistory[0] != z)) { service->OnNewMotionValues(x, y, z); } lastTime = time; time = xTaskGetTickCount(); - lastX = this->x; - this->x = x; + xHistory++; + xHistory[0] = x; yHistory++; yHistory[0] = y; zHistory++; @@ -67,20 +67,26 @@ MotionController::AccelStats MotionController::GetAccelStats() const { AccelStats stats; for (uint8_t i = 0; i < AccelStats::numHistory; i++) { + stats.xMean += xHistory[histSize - i]; stats.yMean += yHistory[histSize - i]; stats.zMean += zHistory[histSize - i]; + stats.prevXMean += xHistory[1 + i]; stats.prevYMean += yHistory[1 + i]; stats.prevZMean += zHistory[1 + i]; } + stats.xMean /= AccelStats::numHistory; stats.yMean /= AccelStats::numHistory; stats.zMean /= AccelStats::numHistory; + stats.prevXMean /= AccelStats::numHistory; stats.prevYMean /= AccelStats::numHistory; stats.prevZMean /= AccelStats::numHistory; for (uint8_t i = 0; i < AccelStats::numHistory; i++) { + stats.xVariance += (xHistory[histSize - i] - stats.xMean) * (xHistory[histSize - i] - stats.xMean); stats.yVariance += (yHistory[histSize - i] - stats.yMean) * (yHistory[histSize - i] - stats.yMean); stats.zVariance += (zHistory[histSize - i] - stats.zMean) * (zHistory[histSize - i] - stats.zMean); } + stats.xVariance /= AccelStats::numHistory; stats.yVariance /= AccelStats::numHistory; stats.zVariance /= AccelStats::numHistory; @@ -93,7 +99,7 @@ bool MotionController::ShouldRaiseWake() const { constexpr int16_t yThresh = -64; constexpr int16_t rollDegreesThresh = -45; - if (x < -xThresh || x > xThresh) { + if (std::abs(stats.xMean) > xThresh) { return false; } @@ -107,8 +113,9 @@ bool MotionController::ShouldRaiseWake() const { bool MotionController::ShouldShakeWake(uint16_t thresh) { /* Currently Polling at 10hz, If this ever goes faster scalar and EMA might need adjusting */ - int32_t speed = - std::abs(zHistory[0] - zHistory[histSize - 1] + (yHistory[0] - yHistory[histSize - 1]) / 2 + (x - lastX) / 4) * 100 / (time - lastTime); + int32_t speed = std::abs(zHistory[0] - zHistory[histSize - 1] + (yHistory[0] - yHistory[histSize - 1]) / 2 + + (xHistory[0] - xHistory[histSize - 1]) / 4) * + 100 / (time - lastTime); // (.2 * speed) + ((1 - .2) * accumulatedSpeed); accumulatedSpeed = speed / 5 + accumulatedSpeed * 4 / 5; @@ -116,6 +123,11 @@ bool MotionController::ShouldShakeWake(uint16_t thresh) { } bool MotionController::ShouldLowerSleep() const { + if ((stats.xMean > 887 && DegreesRolled(stats.xMean, stats.zMean, stats.prevXMean, stats.prevZMean) > 30) || + (stats.xMean < -887 && DegreesRolled(stats.xMean, stats.zMean, stats.prevXMean, stats.prevZMean) < -30)) { + return true; + } + if (stats.yMean < 724 || DegreesRolled(stats.yMean, stats.zMean, stats.prevYMean, stats.prevZMean) < 30) { return false; } diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h index b2e7e7fe..be0241d3 100644 --- a/src/components/motion/MotionController.h +++ b/src/components/motion/MotionController.h @@ -21,7 +21,7 @@ namespace Pinetime { void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps); int16_t X() const { - return x; + return xHistory[0]; } int16_t Y() const { @@ -76,11 +76,14 @@ namespace Pinetime { struct AccelStats { static constexpr uint8_t numHistory = 2; + int16_t xMean = 0; int16_t yMean = 0; int16_t zMean = 0; + int16_t prevXMean = 0; int16_t prevYMean = 0; int16_t prevZMean = 0; + uint32_t xVariance = 0; uint32_t yVariance = 0; uint32_t zVariance = 0; }; @@ -89,9 +92,8 @@ namespace Pinetime { AccelStats stats = {}; - int16_t lastX = 0; - int16_t x = 0; static constexpr uint8_t histSize = 8; + Utility::CircularBuffer xHistory = {}; Utility::CircularBuffer yHistory = {}; Utility::CircularBuffer zHistory = {}; int32_t accumulatedSpeed = 0; From 3b4b5a51639016a87ef7309475f2ca83807804cf Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Fri, 9 Feb 2024 08:22:47 -0500 Subject: [PATCH 34/67] ApplicationList: Reset app menu screen when loading watch face This prevents the application list from loading in the last used screen and instead goes back to the first screen whenever the watch face is loaded. Fixes #2006 --- src/displayapp/DisplayApp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index c1008be0..9c7d87b2 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -446,6 +446,7 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio else { currentScreen.reset(userWatchFaces[0].create(controllers)); } + settingsController.SetAppMenu(0); } break; case Apps::Error: currentScreen = std::make_unique(bootError); From 4d86a3c6c16291be756a94197f73a5ad57a9a0af Mon Sep 17 00:00:00 2001 From: Ritvik Date: Wed, 21 Feb 2024 20:43:04 -0500 Subject: [PATCH 35/67] Fix conflicts of min and max from stl_algo.h (included from atomic) --- src/components/ble/HeartRateService.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ble/HeartRateService.h b/src/components/ble/HeartRateService.h index 72632c96..3f32fd09 100644 --- a/src/components/ble/HeartRateService.h +++ b/src/components/ble/HeartRateService.h @@ -2,9 +2,9 @@ #define min // workaround: nimble's min/max macros conflict with libstdc++ #define max #include -#include #undef max #undef min +#include namespace Pinetime { namespace Controllers { From 9aa0bc8ecf382245e3d874fed5cbc699921d05d4 Mon Sep 17 00:00:00 2001 From: adumelie Date: Thu, 14 Mar 2024 14:55:06 +0100 Subject: [PATCH 36/67] Fix and update documentation Fixed missing colon typo in template for minimal app example Updated reference to Apps enum after file move --- doc/code/Apps.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/code/Apps.md b/doc/code/Apps.md index b325fe98..1c8f8da1 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -140,7 +140,7 @@ namespace Pinetime { } template <> - struct AppTraits { + struct AppTraits { static constexpr Apps app = Apps::MyApp; static constexpr const char* icon = Screens::Symbol::myApp; static Screens::Screens* Create(AppController& controllers) { @@ -176,7 +176,7 @@ Now we have our very own app, but InfiniTime does not know about it yet. The first step is to include your `MyApp.cpp` (or any new cpp files for that matter) in the compilation by adding it to [CMakeLists.txt](/CMakeLists.txt). The next step to making it launch-able is to give your app an id. -To do this, add an entry in the enum class `Pinetime::Applications::Apps` ([displayapp/Apps.h](/src/displayapp/Apps.h)). +To do this, add an entry in the enum class `Pinetime::Applications::Apps` ([displayapp/apps/Apps.h](/src/displayapp/apps/Apps.h.in)). Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"` to the file [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp). From 4c9d5332c70958d13c9b52ebcf3cf3af771422dd Mon Sep 17 00:00:00 2001 From: adumelie Date: Thu, 14 Mar 2024 16:38:08 +0100 Subject: [PATCH 37/67] Typo in code example --- doc/code/Apps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/code/Apps.md b/doc/code/Apps.md index 1c8f8da1..b0698b2b 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -143,7 +143,7 @@ namespace Pinetime { struct AppTraits { static constexpr Apps app = Apps::MyApp; static constexpr const char* icon = Screens::Symbol::myApp; - static Screens::Screens* Create(AppController& controllers) { + static Screens::Screen* Create(AppController& controllers) { return new Screens::MyApp(); } }; From ef384722782e66cae62a32c894e39f27ef28ca4a Mon Sep 17 00:00:00 2001 From: adumelie Date: Thu, 14 Mar 2024 16:39:36 +0100 Subject: [PATCH 38/67] More typos in code example --- doc/code/Apps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/code/Apps.md b/doc/code/Apps.md index b0698b2b..bf71eab4 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -142,7 +142,7 @@ namespace Pinetime { template <> struct AppTraits { static constexpr Apps app = Apps::MyApp; - static constexpr const char* icon = Screens::Symbol::myApp; + static constexpr const char* icon = Screens::Symbols::myApp; static Screens::Screen* Create(AppController& controllers) { return new Screens::MyApp(); } From 14c627090340de9748af3d971a18f7d218e8c6db Mon Sep 17 00:00:00 2001 From: adumelie Date: Thu, 14 Mar 2024 16:41:17 +0100 Subject: [PATCH 39/67] Typo in example code --- doc/code/Apps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/code/Apps.md b/doc/code/Apps.md index bf71eab4..44c4ed65 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -143,7 +143,7 @@ namespace Pinetime { struct AppTraits { static constexpr Apps app = Apps::MyApp; static constexpr const char* icon = Screens::Symbols::myApp; - static Screens::Screen* Create(AppController& controllers) { + static Screens::Screen* Create(AppControllers& controllers) { return new Screens::MyApp(); } }; From 7dbb8f54c6bb645ea72c6350dde87e29ad1d14b0 Mon Sep 17 00:00:00 2001 From: FintasticMan Date: Mon, 12 Feb 2024 13:01:22 +0100 Subject: [PATCH 40/67] chrono: Resolve TODOs related to C++20 chrono feats --- src/displayapp/screens/WatchFaceAnalog.cpp | 2 +- src/displayapp/screens/WatchFaceAnalog.h | 3 +-- src/displayapp/screens/WatchFaceCasioStyleG7710.cpp | 2 +- src/displayapp/screens/WatchFaceCasioStyleG7710.h | 3 +-- src/displayapp/screens/WatchFaceDigital.cpp | 2 +- src/displayapp/screens/WatchFaceDigital.h | 3 +-- src/displayapp/screens/WatchFaceInfineat.cpp | 2 +- src/displayapp/screens/WatchFaceInfineat.h | 3 +-- src/displayapp/screens/WatchFaceTerminal.cpp | 2 +- src/displayapp/screens/WatchFaceTerminal.h | 3 +-- 10 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 2b27ad64..80a1c8b9 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -256,7 +256,7 @@ void WatchFaceAnalog::Refresh() { if (currentDateTime.IsUpdated()) { UpdateClock(); - currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); if (currentDate.IsUpdated()) { lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); } diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index 89ad4e13..2eee657e 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -43,8 +43,7 @@ namespace Pinetime { Utility::DirtyValue bleState {}; Utility::DirtyValue> currentDateTime; Utility::DirtyValue notificationState {false}; - using days = std::chrono::duration>; // TODO: days is standard in c++20 - Utility::DirtyValue> currentDate; + Utility::DirtyValue> currentDate; lv_obj_t* minor_scales; lv_obj_t* major_scales; diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp index 72bfaaa3..c695f852 100644 --- a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp +++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp @@ -244,7 +244,7 @@ void WatchFaceCasioStyleG7710::Refresh() { } lv_obj_realign(label_time); - currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); if (currentDate.IsUpdated()) { const char* weekNumberFormat = "%V"; diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.h b/src/displayapp/screens/WatchFaceCasioStyleG7710.h index f10e931c..0f46a692 100644 --- a/src/displayapp/screens/WatchFaceCasioStyleG7710.h +++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.h @@ -51,8 +51,7 @@ namespace Pinetime { Utility::DirtyValue heartbeat {}; Utility::DirtyValue heartbeatRunning {}; Utility::DirtyValue notificationState {}; - using days = std::chrono::duration>; // TODO: days is standard in c++20 - Utility::DirtyValue> currentDate; + Utility::DirtyValue> currentDate; lv_point_t line_icons_points[3] {{0, 5}, {117, 5}, {122, 0}}; lv_point_t line_day_of_week_number_points[4] {{0, 0}, {100, 0}, {95, 95}, {0, 95}}; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index afe00fa5..2e00ee98 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -125,7 +125,7 @@ void WatchFaceDigital::Refresh() { lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); } - currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); if (currentDate.IsUpdated()) { uint16_t year = dateTimeController.Year(); uint8_t day = dateTimeController.Day(); diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 3ff78c8a..78232c1e 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -54,8 +54,7 @@ namespace Pinetime { Utility::DirtyValue notificationState {}; Utility::DirtyValue> currentWeather {}; - using days = std::chrono::duration>; // TODO: days is standard in c++20 - Utility::DirtyValue> currentDate; + Utility::DirtyValue> currentDate; lv_obj_t* label_time; lv_obj_t* label_time_ampm; diff --git a/src/displayapp/screens/WatchFaceInfineat.cpp b/src/displayapp/screens/WatchFaceInfineat.cpp index c643f3bd..4c6fc196 100644 --- a/src/displayapp/screens/WatchFaceInfineat.cpp +++ b/src/displayapp/screens/WatchFaceInfineat.cpp @@ -423,7 +423,7 @@ void WatchFaceInfineat::Refresh() { lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0); } - currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); if (currentDate.IsUpdated()) { uint8_t day = dateTimeController.Day(); Controllers::DateTime::Days dayOfWeek = dateTimeController.DayOfWeek(); diff --git a/src/displayapp/screens/WatchFaceInfineat.h b/src/displayapp/screens/WatchFaceInfineat.h index 32c08f18..55c43f98 100644 --- a/src/displayapp/screens/WatchFaceInfineat.h +++ b/src/displayapp/screens/WatchFaceInfineat.h @@ -55,8 +55,7 @@ namespace Pinetime { Utility::DirtyValue> currentDateTime {}; Utility::DirtyValue stepCount {}; Utility::DirtyValue notificationState {}; - using days = std::chrono::duration>; // TODO: days is standard in c++20 - Utility::DirtyValue> currentDate; + Utility::DirtyValue> currentDate; // Lines making up the side cover lv_obj_t* lineBattery; diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 72383729..96d77741 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -125,7 +125,7 @@ void WatchFaceTerminal::Refresh() { lv_label_set_text_fmt(label_time, "[TIME]#11cc55 %02d:%02d:%02d", hour, minute, second); } - currentDate = std::chrono::time_point_cast(currentDateTime.Get()); + currentDate = std::chrono::time_point_cast(currentDateTime.Get()); if (currentDate.IsUpdated()) { uint16_t year = dateTimeController.Year(); Controllers::DateTime::Months month = dateTimeController.Month(); diff --git a/src/displayapp/screens/WatchFaceTerminal.h b/src/displayapp/screens/WatchFaceTerminal.h index ce22005f..bf460866 100644 --- a/src/displayapp/screens/WatchFaceTerminal.h +++ b/src/displayapp/screens/WatchFaceTerminal.h @@ -45,8 +45,7 @@ namespace Pinetime { Utility::DirtyValue heartbeat {}; Utility::DirtyValue heartbeatRunning {}; Utility::DirtyValue notificationState {}; - using days = std::chrono::duration>; // TODO: days is standard in c++20 - Utility::DirtyValue> currentDate; + Utility::DirtyValue> currentDate; lv_obj_t* label_time; lv_obj_t* label_date; From 4ca211289004f6270b69c2fab88d1143f3e7dc3d Mon Sep 17 00:00:00 2001 From: JF Date: Fri, 15 Mar 2024 09:20:19 +0100 Subject: [PATCH 41/67] Emit the message BleRadioEnableToggle to DisplayApp only if the enable state of the radio has actually changed. (#2037) This fixes an issue where the BLE connected logo would disappear when opening and closing the BLE setting (without changing it) while InfiniTime was already connected to a companion app. Co-authored-by: JustScott --- src/displayapp/screens/settings/SettingBluetooth.cpp | 6 +++--- src/displayapp/screens/settings/SettingBluetooth.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/settings/SettingBluetooth.cpp b/src/displayapp/screens/settings/SettingBluetooth.cpp index 82c3dee1..e4dc695c 100644 --- a/src/displayapp/screens/settings/SettingBluetooth.cpp +++ b/src/displayapp/screens/settings/SettingBluetooth.cpp @@ -36,17 +36,19 @@ namespace { SettingBluetooth::SettingBluetooth(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) : app {app}, + settings {settingsController}, checkboxList( 0, 1, "Bluetooth", Symbols::bluetooth, settingsController.GetBleRadioEnabled() ? 0 : 1, - [&settings = settingsController](uint32_t index) { + [this](uint32_t index) { const bool priorMode = settings.GetBleRadioEnabled(); const bool newMode = options[index].radioEnabled; if (newMode != priorMode) { settings.SetBleRadioEnabled(newMode); + this->app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle); } }, CreateOptionArray()) { @@ -54,6 +56,4 @@ SettingBluetooth::SettingBluetooth(Pinetime::Applications::DisplayApp* app, Pine SettingBluetooth::~SettingBluetooth() { lv_obj_clean(lv_scr_act()); - // Pushing the message in the OnValueChanged function causes a freeze? - app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle); } diff --git a/src/displayapp/screens/settings/SettingBluetooth.h b/src/displayapp/screens/settings/SettingBluetooth.h index 1e3f9b81..0cf014f5 100644 --- a/src/displayapp/screens/settings/SettingBluetooth.h +++ b/src/displayapp/screens/settings/SettingBluetooth.h @@ -20,6 +20,7 @@ namespace Pinetime { private: DisplayApp* app; + Pinetime::Controllers::Settings& settings; CheckboxList checkboxList; }; } From 9a5f516c427f329bbc161f794bae18908fcd33c5 Mon Sep 17 00:00:00 2001 From: Victor Kareh Date: Mon, 18 Mar 2024 12:35:22 -0400 Subject: [PATCH 42/67] WatchFaceDigital: Remove unused variables --- src/displayapp/screens/WatchFaceDigital.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 78232c1e..7bb713cb 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -43,10 +43,6 @@ namespace Pinetime { uint8_t displayedHour = -1; uint8_t displayedMinute = -1; - Utility::DirtyValue batteryPercentRemaining {}; - Utility::DirtyValue powerPresent {}; - Utility::DirtyValue bleState {}; - Utility::DirtyValue bleRadioEnabled {}; Utility::DirtyValue> currentDateTime {}; Utility::DirtyValue stepCount {}; Utility::DirtyValue heartbeat {}; From 57e625d4dcb94c4d26a3a65e6738322f172b705b Mon Sep 17 00:00:00 2001 From: BloodStainedCrow Date: Sat, 23 Mar 2024 10:45:45 +0100 Subject: [PATCH 43/67] Unify docker devcontainer with dockerfile used for CI (#1587) * Only use one Dockerfile and build.sh script for both docker and devcontainer * Remove all now unneccessary tasks and scripts * Update to clang-format-14 * Move devcontainer.json into root folder * Fix conditional statements in Dockerfile * Move .devcontainer/README into doc/usingDevcontainers * Remove obsolete VSCode Task * Change standard compiler path to the correct compiler * Set GDB Path for debugging * Hide broken buttons from CMake Extension * Refactor .devcontainer * Remove unneccessary postBuildCommand * Add devcontainer dependencies to all docker images * Add Devcontainer Debug launch config * Add an additional c_cpp_properties config as a fallback for devcontainer * Remove obsolete Docker Argument * Fix wrong C/Cpp versions * Fix silent fail of gdb, add libncurses5 --- .devcontainer.json | 32 +++++++ .devcontainer/Dockerfile | 66 -------------- .devcontainer/build.sh | 87 ------------------- .devcontainer/build_app.sh | 2 - .devcontainer/create_build_openocd.sh | 3 - .devcontainer/devcontainer.json | 38 -------- .devcontainer/make_build_dir.sh | 2 - .vscode/c_cpp_properties.json | 22 ++++- .vscode/cmake-kits.json | 6 ++ .vscode/launch.json | 45 +++++++--- .vscode/settings.json | 15 +++- .vscode/tasks.json | 22 ----- doc/buildWithVScode.md | 2 +- .../README.md => doc/usingDevcontainers.md | 0 docker/Dockerfile | 10 +++ 15 files changed, 115 insertions(+), 237 deletions(-) create mode 100644 .devcontainer.json delete mode 100644 .devcontainer/Dockerfile delete mode 100644 .devcontainer/build.sh delete mode 100644 .devcontainer/build_app.sh delete mode 100644 .devcontainer/create_build_openocd.sh delete mode 100644 .devcontainer/devcontainer.json delete mode 100644 .devcontainer/make_build_dir.sh create mode 100644 .vscode/cmake-kits.json rename .devcontainer/README.md => doc/usingDevcontainers.md (100%) diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 00000000..95a27dac --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,32 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.154.2/containers/cpp +{ + "build": { + "dockerfile": "docker/Dockerfile" + }, + "customizations": { + "vscode": { + "settings": { + // Set *default* container specific settings.json values on container create. + "terminal.integrated.profiles.linux": { + "bash": { + "path": "/bin/bash" + } + }, + "terminal.integrated.defaultProfile.linux": "bash", + "editor.formatOnSave": true, + // FIXME: This and the Dockerfile might get out of sync + "clang-format.executable": "clang-format-14" + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools", + "marus25.cortex-debug", + "notskm.clang-tidy", + "mjohns.clang-format" + ] + } + }, + "remoteUser": "infinitime" +} \ No newline at end of file diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index e4ad5c4f..00000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,66 +0,0 @@ -FROM ubuntu:latest - -ARG DEBIAN_FRONTEND=noninteractive -RUN apt-get update -qq \ - && apt-get install -y \ -# x86_64 / generic packages - bash \ - build-essential \ - cmake \ - git \ - make \ - python3 \ - python3-pip \ - python3-pil \ - tar \ - unzip \ - wget \ - curl \ - dos2unix \ - clang-format-12 \ - clang-tidy \ - locales \ - libncurses5 \ -# aarch64 packages - libffi-dev \ - libssl-dev \ - python3-dev \ - rustc \ - && rm -rf /var/cache/apt/* /var/lib/apt/lists/*; - -#SET LOCALE -RUN locale-gen en_US.UTF-8 -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN pip3 install adafruit-nrfutil -# required for McuBoot -RUN pip3 install setuptools_rust - -WORKDIR /opt/ -# build.sh knows how to compile but it problimatic on Win10 -COPY build.sh . -RUN chmod +x build.sh -# create_build_openocd.sh uses cmake to crate to build directory -COPY create_build_openocd.sh . -RUN chmod +x create_build_openocd.sh -# Lets get each in a separate docker layer for better downloads -# GCC -# RUN bash -c "source /opt/build.sh; GetGcc;" -RUN wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2 -O - | tar -xj -C /opt -# NrfSdk -# RUN bash -c "source /opt/build.sh; GetNrfSdk;" -RUN wget -q "https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip" -O /tmp/nRF5_SDK_15.3.0_59ac345 -RUN unzip -q /tmp/nRF5_SDK_15.3.0_59ac345 -d /opt -RUN rm /tmp/nRF5_SDK_15.3.0_59ac345 -# McuBoot -# RUN bash -c "source /opt/build.sh; GetMcuBoot;" -RUN git clone https://github.com/mcu-tools/mcuboot.git -RUN pip3 install -r ./mcuboot/scripts/requirements.txt - -RUN adduser infinitime - -ENV NRF5_SDK_PATH /opt/nRF5_SDK_15.3.0_59ac345 -ENV ARM_NONE_EABI_TOOLCHAIN_PATH /opt/gcc-arm-none-eabi-9-2020-q2-update -ENV SOURCES_DIR /workspaces/InfiniTime diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh deleted file mode 100644 index b4f080dd..00000000 --- a/.devcontainer/build.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash -(return 0 2>/dev/null) && SOURCED="true" || SOURCED="false" -export LC_ALL=C.UTF-8 -export LANG=C.UTF-8 -set -x -set -e - -# Default locations if the var isn't already set -export TOOLS_DIR="${TOOLS_DIR:=/opt}" -export SOURCES_DIR="${SOURCES_DIR:=/sources}" -export BUILD_DIR="${BUILD_DIR:=$SOURCES_DIR/build}" -export OUTPUT_DIR="${OUTPUT_DIR:=$BUILD_DIR/output}" - -export BUILD_TYPE=${BUILD_TYPE:=Release} -export GCC_ARM_VER=${GCC_ARM_VER:="gcc-arm-none-eabi-9-2020-q2-update"} -export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"} - -MACHINE="$(uname -m)" -[[ "$MACHINE" == "arm64" ]] && MACHINE="aarch64" - -main() { - local target="$1" - - mkdir -p "$TOOLS_DIR" - - [[ ! -d "$TOOLS_DIR/$GCC_ARM_VER" ]] && GetGcc - [[ ! -d "$TOOLS_DIR/$NRF_SDK_VER" ]] && GetNrfSdk - [[ ! -d "$TOOLS_DIR/mcuboot" ]] && GetMcuBoot - - mkdir -p "$BUILD_DIR" - - CmakeGenerate - CmakeBuild $target - BUILD_RESULT=$? - if [ "$DISABLE_POSTBUILD" != "true" -a "$BUILD_RESULT" == 0 ]; then - source "$BUILD_DIR/post_build.sh" - fi - # assuming post_build.sh will never fail on a successful build - return $BUILD_RESULT -} - -GetGcc() { - GCC_SRC="$GCC_ARM_VER-$MACHINE-linux.tar.bz" - wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/$GCC_SRC -O - | tar -xj -C $TOOLS_DIR/ -} - -GetMcuBoot() { - git clone https://github.com/mcu-tools/mcuboot.git "$TOOLS_DIR/mcuboot" - pip3 install -r "$TOOLS_DIR/mcuboot/scripts/requirements.txt" -} - -GetNrfSdk() { - wget -q "https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/$NRF_SDK_VER.zip" -O /tmp/$NRF_SDK_VER - unzip -q /tmp/$NRF_SDK_VER -d "$TOOLS_DIR/" - rm /tmp/$NRF_SDK_VER -} - -CmakeGenerate() { - # We can swap the CD and trailing SOURCES_DIR for -B and -S respectively - # once we go to newer CMake (Ubuntu 18.10 gives us CMake 3.10) - cd "$BUILD_DIR" - - cmake -G "Unix Makefiles" \ - -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ - -DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_VER" \ - -DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \ - "$SOURCES_DIR" - cmake -L -N . -} - -CmakeBuild() { - local target="$1" - [[ -n "$target" ]] && target="--target $target" - if cmake --build "$BUILD_DIR" --config $BUILD_TYPE $target -- -j$(nproc) - then return 0; else return 1; - fi -} - -if [[ $SOURCED == "false" ]]; then - # It is important to return exit code of main - # To be future-proof, this is handled explicitely - main "$@" - BUILD_RESULT=$? - exit $BUILD_RESULT -else - echo "Sourced!" -fi diff --git a/.devcontainer/build_app.sh b/.devcontainer/build_app.sh deleted file mode 100644 index 0f578cc6..00000000 --- a/.devcontainer/build_app.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -cmake --build /workspaces/Pinetime/build --config Release -- -j6 pinetime-app \ No newline at end of file diff --git a/.devcontainer/create_build_openocd.sh b/.devcontainer/create_build_openocd.sh deleted file mode 100644 index c5bff5c8..00000000 --- a/.devcontainer/create_build_openocd.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -rm -rf build/ -cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Release -DUSE_OPENOCD=1 -DARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-9-2020-q2-update -DNRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345 -S . -Bbuild \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 1bb315f7..00000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,38 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: -// https://github.com/microsoft/vscode-dev-containers/tree/v0.154.2/containers/cpp -{ - // "name": "Pinetime", - // "image": "feabhas/pinetime-dev" - "build": { - "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-10, debian-9, ubuntu-20.04, ubuntu-18.04 - // "args": { "VARIANT": "ubuntu-20.04" } - }, - "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], - - // Set *default* container specific settings.json values on container create. - "settings": { - "terminal.integrated.shell.linux": "/bin/bash", - "editor.formatOnSave": true, - "clang-format.executable": "clang-format-12" - }, - - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-vscode.cpptools", - "ms-vscode.cmake-tools", - "marus25.cortex-debug", - "notskm.clang-tidy", - "mjohns.clang-format" - ], - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "bash /opt/create_build_openocd.sh", - - // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. - // "remoteUser": "vscode" - "remoteUser": "infinitime" -} diff --git a/.devcontainer/make_build_dir.sh b/.devcontainer/make_build_dir.sh deleted file mode 100644 index 76240037..00000000 --- a/.devcontainer/make_build_dir.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Release -DUSE_OPENOCD=1 -DARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-9-2020-q2-update -DNRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345 ${SOURCES_DIR} diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 392f4151..c5f88a82 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,4 +1,9 @@ { + "env": { + // TODO: This is a duplication of the configuration set in /docker/build.sh! + "TOOLS_DIR": "/opt", + "GCC_ARM_PATH": "gcc-arm-none-eabi-10.3-2021.10" + }, "configurations": [ { "name": "nrfCC", @@ -14,7 +19,22 @@ "intelliSenseMode": "linux-gcc-arm", "configurationProvider": "ms-vscode.cpp-tools", "compileCommands": "${workspaceFolder}/build/compile_commands.json" + }, + { + "name": "nrfCC Devcontainer", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/src/**", + "${workspaceFolder}/src" + ], + "defines": [], + "compilerPath": "${TOOLS_DIR}/${GCC_ARM_PATH}/bin/arm-none-eabi-gcc", + "cStandard": "c99", + "cppStandard": "c++20", + "intelliSenseMode": "linux-gcc-arm", + "configurationProvider": "ms-vscode.cpp-tools", + "compileCommands": "${workspaceFolder}/build/compile_commands.json" } ], "version": 4 -} \ No newline at end of file +} diff --git a/.vscode/cmake-kits.json b/.vscode/cmake-kits.json new file mode 100644 index 00000000..95bb600b --- /dev/null +++ b/.vscode/cmake-kits.json @@ -0,0 +1,6 @@ +[ + { + "name": "InfiniTime Compiler", + "environmentSetupScript": "${workspaceFolder}/docker/build.sh" + } +] diff --git a/.vscode/launch.json b/.vscode/launch.json index a50270d2..7d3f17a1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,20 +1,18 @@ - { +{ "version": "0.1.0", "configurations": [ { "name": "Debug - Openocd docker Remote", - "type":"cortex-debug", - "cortex-debug.armToolchainPath":"${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin", + "type": "cortex-debug", "cwd": "${workspaceRoot}", "executable": "${command:cmake.launchTargetPath}", "request": "launch", "servertype": "external", - // This may need to be arm-none-eabi-gdb depending on your system - "gdbPath" : "${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin/arm-none-eabi-gdb", + "gdbPath": "${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin/arm-none-eabi-gdb", // Connect to an already running OpenOCD instance "gdbTarget": "host.docker.internal:3333", "svdFile": "${workspaceRoot}/nrf52.svd", - "runToMain": true, + "runToEntryPoint": "main", // Work around for stopping at main on restart "postRestartCommands": [ "break main", @@ -23,18 +21,16 @@ }, { "name": "Debug - Openocd Local", - "type":"cortex-debug", - "cortex-debug.armToolchainPath":"${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin", + "type": "cortex-debug", "cwd": "${workspaceRoot}", "executable": "${command:cmake.launchTargetPath}", "request": "launch", "servertype": "openocd", - // This may need to be arm-none-eabi-gdb depending on your system - "gdbPath" : "${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin/arm-none-eabi-gdb", + "gdbPath": "${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin/arm-none-eabi-gdb", // Connect to an already running OpenOCD instance "gdbTarget": "localhost:3333", "svdFile": "${workspaceRoot}/nrf52.svd", - "runToMain": true, + "runToEntryPoint": "main", // Work around for stopping at main on restart "postRestartCommands": [ "break main", @@ -51,6 +47,11 @@ "showDevDebugOutput": false, "servertype": "openocd", "runToMain": true, + // Work around for stopping at main on restart + "postRestartCommands": [ + "break main", + "continue" + ], // Only use armToolchainPath if your arm-none-eabi-gdb is not in your path (some GCC packages does not contain arm-none-eabi-gdb) "armToolchainPath": "${workspaceRoot}/../gcc-arm-none-eabi-10.3-2021.10/bin", "svdFile": "${workspaceRoot}/nrf52.svd", @@ -58,7 +59,25 @@ "interface/stlink.cfg", "target/nrf52.cfg" ], - } - + }, + { + "name": "Debug - Openocd Devcontainer", + "type": "cortex-debug", + "cwd": "${workspaceRoot}", + "executable": "${command:cmake.launchTargetPath}", + "request": "launch", + "servertype": "external", + // FIXME: This is hardcoded. I have no idea how to use the values set in build.sh here + "gdbPath": "/opt/gcc-arm-none-eabi-10.3-2021.10/bin/arm-none-eabi-gdb", + // Connect to an already running OpenOCD instance + "gdbTarget": "host.docker.internal:3333", + "svdFile": "${workspaceRoot}/nrf52.svd", + "runToEntryPoint": "main", + // Work around for stopping at main on restart + "postRestartCommands": [ + "break main", + "continue" + ] + }, ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index f1cc3a81..a7b04eea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,9 +1,20 @@ { "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", "cmake.configureArgs": [ - "-DARM_NONE_EABI_TOOLCHAIN_PATH=${env:ARM_NONE_EABI_TOOLCHAIN_PATH}", - "-DNRF5_SDK_PATH=${env:NRF5_SDK_PATH}", + "-DARM_NONE_EABI_TOOLCHAIN_PATH=${env:TOOLS_DIR}/${env:GCC_ARM_PATH}", + "-DNRF5_SDK_PATH=${env:TOOLS_DIR}/${env:NRF_SDK_VER}", ], + "cmake.statusbar.advanced": { + "launch": { + "visibility": "hidden" + }, + "launchTarget": { + "visibility": "hidden" + }, + "debug": { + "visibility": "hidden" + } + }, "cmake.generator": "Unix Makefiles", "clang-tidy.buildPath": "build/compile_commands.json", "files.associations": { diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 17f51f5e..06a08bfc 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,20 +1,6 @@ { "version": "2.0.0", "tasks": [ - { - "label": "create openocd build", - "type": "shell", - "command": "/opt/create_build_openocd.sh", - "group": { - "kind": "build", - "isDefault": true - }, - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "problemMatcher": [] - }, { "label": "update submodules", "type": "shell", @@ -31,14 +17,6 @@ "panel": "shared" }, "problemMatcher": [] - }, - { - "label": "BuildInit", - "dependsOn": [ - "update submodules", - "create openocd build" - ], - "problemMatcher": [] } ] } \ No newline at end of file diff --git a/doc/buildWithVScode.md b/doc/buildWithVScode.md index 9d0a5bdf..5f872482 100644 --- a/doc/buildWithVScode.md +++ b/doc/buildWithVScode.md @@ -32,7 +32,7 @@ The .devcontainer folder contains the configuration and scripts for using a Dock Using the [Remote-Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension is recommended. It will handle configuring the Docker virtual machine and setting everything up. -More documentation is available in the [readme in .devcontainer](../.devcontainer/README.md) +More documentation is available in the [readme in .devcontainer](usingDevcontainers.md) ### DevContainer on Ubuntu diff --git a/.devcontainer/README.md b/doc/usingDevcontainers.md similarity index 100% rename from .devcontainer/README.md rename to doc/usingDevcontainers.md diff --git a/docker/Dockerfile b/docker/Dockerfile index 22bf7bd7..bb5d5f65 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -37,6 +37,13 @@ RUN apt-get update -qq \ libpangocairo-1.0-0 \ && rm -rf /var/cache/apt/* /var/lib/apt/lists/*; +# Add the necessary apt-gets for the devcontainer +RUN apt-get update -qq \ + && apt-get install -y \ + clang-format-14 \ + clang-tidy \ + libncurses5 + # Git needed for PROJECT_GIT_COMMIT_HASH variable setting RUN pip3 install adafruit-nrfutil @@ -55,5 +62,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 + ENV SOURCES_DIR /sources CMD ["/opt/build.sh"] From 6b5235c3013bf8ecbd1568669f48efce3508e8c0 Mon Sep 17 00:00:00 2001 From: John Crawford <61567332+KaffeinatedKat@users.noreply.github.com> Date: Fri, 12 Apr 2024 06:50:33 -0600 Subject: [PATCH 44/67] fix: heartrate app displays --- instead of 000 (#1887) --- src/displayapp/screens/HeartRate.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/displayapp/screens/HeartRate.cpp b/src/displayapp/screens/HeartRate.cpp index f611fa26..9677be3b 100644 --- a/src/displayapp/screens/HeartRate.cpp +++ b/src/displayapp/screens/HeartRate.cpp @@ -41,7 +41,7 @@ HeartRate::HeartRate(Controllers::HeartRateController& heartRateController, Syst lv_obj_set_style_local_text_color(label_hr, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); } - lv_label_set_text_static(label_hr, "000"); + lv_label_set_text_static(label_hr, "---"); lv_obj_align(label_hr, nullptr, LV_ALIGN_CENTER, 0, -40); label_bpm = lv_label_create(lv_scr_act(), nullptr); @@ -82,10 +82,14 @@ void HeartRate::Refresh() { case Controllers::HeartRateController::States::NoTouch: case Controllers::HeartRateController::States::NotEnoughData: // case Controllers::HeartRateController::States::Stopped: - lv_label_set_text_static(label_hr, "000"); + lv_label_set_text_static(label_hr, "---"); break; default: - lv_label_set_text_fmt(label_hr, "%03d", heartRateController.HeartRate()); + if (heartRateController.HeartRate() == 0) { + lv_label_set_text_static(label_hr, "---"); + } else { + lv_label_set_text_fmt(label_hr, "%03d", heartRateController.HeartRate()); + } } lv_label_set_text_static(label_status, ToString(state)); From 079e676baf70a943d31317afde47b759ca69ca2d Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Sun, 11 Feb 2024 00:44:06 +0000 Subject: [PATCH 45/67] SPI transaction hooks --- src/drivers/Spi.cpp | 4 ++-- src/drivers/Spi.h | 2 +- src/drivers/SpiMaster.cpp | 16 ++++++++++++-- src/drivers/SpiMaster.h | 3 ++- src/drivers/SpiNorFlash.cpp | 2 +- src/drivers/St7789.cpp | 42 +++++++++++++++++++++++-------------- src/drivers/St7789.h | 8 +++---- src/main.cpp | 2 +- src/recoveryLoader.cpp | 2 +- 9 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp index c85b90c1..e0b716fa 100644 --- a/src/drivers/Spi.cpp +++ b/src/drivers/Spi.cpp @@ -9,8 +9,8 @@ Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : spiMaster {spiMaster}, pinCsn { nrf_gpio_pin_set(pinCsn); } -bool Spi::Write(const uint8_t* data, size_t size) { - return spiMaster.Write(pinCsn, data, size); +bool Spi::Write(const uint8_t* data, size_t size, void (*TransactionHook)(bool)) { + return spiMaster.Write(pinCsn, data, size, TransactionHook); } bool Spi::Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) { diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h index 9b6a30f4..55eef05c 100644 --- a/src/drivers/Spi.h +++ b/src/drivers/Spi.h @@ -14,7 +14,7 @@ namespace Pinetime { Spi& operator=(Spi&&) = delete; bool Init(); - bool Write(const uint8_t* data, size_t size); + bool Write(const uint8_t* data, size_t size, void (*TransactionHook)(bool)); bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); void Sleep(); diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 3446d639..4c2bc940 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -143,6 +143,9 @@ void SpiMaster::OnEndEvent() { } nrf_gpio_pin_set(this->pinCsn); + if (this->TransactionHook != nullptr) { + this->TransactionHook(false); + } currentBufferAddr = 0; BaseType_t xHigherPriorityTaskWoken2 = pdFALSE; xSemaphoreGiveFromISR(mutex, &xHigherPriorityTaskWoken2); @@ -173,13 +176,14 @@ void SpiMaster::PrepareRx(const uint32_t bufferAddress, const size_t size) { spiBaseAddress->EVENTS_END = 0; } -bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size) { +bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, void (*TransactionHook)(bool)) { if (data == nullptr) return false; auto ok = xSemaphoreTake(mutex, portMAX_DELAY); ASSERT(ok == true); taskToNotify = xTaskGetCurrentTaskHandle(); + this->TransactionHook = TransactionHook; this->pinCsn = pinCsn; if (size == 1) { @@ -188,6 +192,9 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size) { DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); } + if (this->TransactionHook != nullptr) { + this->TransactionHook(true); + } nrf_gpio_pin_clear(this->pinCsn); currentBufferAddr = (uint32_t) data; @@ -203,6 +210,9 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size) { while (spiBaseAddress->EVENTS_END == 0) ; nrf_gpio_pin_set(this->pinCsn); + if (this->TransactionHook != nullptr) { + this->TransactionHook(false); + } currentBufferAddr = 0; DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); @@ -217,7 +227,7 @@ bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data xSemaphoreTake(mutex, portMAX_DELAY); taskToNotify = nullptr; - + this->TransactionHook = nullptr; this->pinCsn = pinCsn; DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); spiBaseAddress->INTENCLR = (1 << 6); @@ -267,6 +277,8 @@ bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmd taskToNotify = nullptr; + this->TransactionHook = nullptr; + this->pinCsn = pinCsn; DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); spiBaseAddress->INTENCLR = (1 << 6); diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 8b698c57..9014061e 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -31,7 +31,7 @@ namespace Pinetime { SpiMaster& operator=(SpiMaster&&) = delete; bool Init(); - bool Write(uint8_t pinCsn, const uint8_t* data, size_t size); + bool Write(uint8_t pinCsn, const uint8_t* data, size_t size, void (*TransactionHook)(bool)); bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); @@ -50,6 +50,7 @@ namespace Pinetime { NRF_SPIM_Type* spiBaseAddress; uint8_t pinCsn; + void (*TransactionHook)(bool); SpiMaster::SpiModule spi; SpiMaster::Parameters params; diff --git a/src/drivers/SpiNorFlash.cpp b/src/drivers/SpiNorFlash.cpp index 28f82fe6..56a8aabd 100644 --- a/src/drivers/SpiNorFlash.cpp +++ b/src/drivers/SpiNorFlash.cpp @@ -22,7 +22,7 @@ void SpiNorFlash::Uninit() { void SpiNorFlash::Sleep() { auto cmd = static_cast(Commands::DeepPowerDown); - spi.Write(&cmd, sizeof(uint8_t)); + spi.Write(&cmd, sizeof(uint8_t), nullptr); NRF_LOG_INFO("[SpiNorFlash] Sleep") } diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index e583aac8..6824acd8 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -3,16 +3,17 @@ #include #include #include "drivers/Spi.h" +#include "drivers/PinMap.h" using namespace Pinetime::Drivers; -St7789::St7789(Spi& spi, uint8_t pinDataCommand, uint8_t pinReset) : spi {spi}, pinDataCommand {pinDataCommand}, pinReset {pinReset} { +St7789::St7789(Spi& spi) : spi {spi} { } void St7789::Init() { - nrf_gpio_cfg_output(pinDataCommand); - nrf_gpio_cfg_output(pinReset); - nrf_gpio_pin_set(pinReset); + nrf_gpio_cfg_output(PinMap::LcdDataCommand); + nrf_gpio_cfg_output(PinMap::LcdReset); + nrf_gpio_pin_set(PinMap::LcdReset); HardwareReset(); SoftwareReset(); SleepOut(); @@ -29,18 +30,28 @@ void St7789::Init() { DisplayOn(); } +void St7789::EnableDataMode(bool isStart) { + if (isStart) { + nrf_gpio_pin_set(PinMap::LcdDataCommand); + } +} + +void St7789::EnableCommandMode(bool isStart) { + if (isStart) { + nrf_gpio_pin_clear(PinMap::LcdDataCommand); + } +} + void St7789::WriteCommand(uint8_t cmd) { - nrf_gpio_pin_clear(pinDataCommand); - WriteSpi(&cmd, 1); + WriteSpi(&cmd, 1, EnableCommandMode); } void St7789::WriteData(uint8_t data) { - nrf_gpio_pin_set(pinDataCommand); - WriteSpi(&data, 1); + WriteSpi(&data, 1, EnableDataMode); } -void St7789::WriteSpi(const uint8_t* data, size_t size) { - spi.Write(data, size); +void St7789::WriteSpi(const uint8_t* data, size_t size, void (*TransactionHook)(bool)) { + spi.Write(data, size, TransactionHook); } void St7789::SoftwareReset() { @@ -152,24 +163,23 @@ void St7789::Uninit() { void St7789::DrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t* data, size_t size) { SetAddrWindow(x, y, x + width - 1, y + height - 1); - nrf_gpio_pin_set(pinDataCommand); - WriteSpi(data, size); + WriteSpi(data, size, EnableDataMode); } void St7789::HardwareReset() { - nrf_gpio_pin_clear(pinReset); + nrf_gpio_pin_clear(PinMap::LcdReset); nrf_delay_ms(10); - nrf_gpio_pin_set(pinReset); + nrf_gpio_pin_set(PinMap::LcdReset); } void St7789::Sleep() { SleepIn(); - nrf_gpio_cfg_default(pinDataCommand); + nrf_gpio_cfg_default(PinMap::LcdDataCommand); NRF_LOG_INFO("[LCD] Sleep"); } void St7789::Wakeup() { - nrf_gpio_cfg_output(pinDataCommand); + nrf_gpio_cfg_output(PinMap::LcdDataCommand); SleepOut(); VerticalScrollStartAddress(verticalScrollingStartAddress); DisplayOn(); diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index b00bee03..185c44a0 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -8,7 +8,7 @@ namespace Pinetime { class St7789 { public: - explicit St7789(Spi& spi, uint8_t pinDataCommand, uint8_t pinReset); + explicit St7789(Spi& spi); St7789(const St7789&) = delete; St7789& operator=(const St7789&) = delete; St7789(St7789&&) = delete; @@ -26,8 +26,6 @@ namespace Pinetime { private: Spi& spi; - uint8_t pinDataCommand; - uint8_t pinReset; uint8_t verticalScrollingStartAddress = 0; void HardwareReset(); @@ -45,7 +43,9 @@ namespace Pinetime { void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); void SetVdv(); void WriteCommand(uint8_t cmd); - void WriteSpi(const uint8_t* data, size_t size); + void WriteSpi(const uint8_t* data, size_t size, void (*TransactionHook)(bool)); + static void EnableDataMode(bool isStart); + static void EnableCommandMode(bool isStart); enum class Commands : uint8_t { SoftwareReset = 0x01, diff --git a/src/main.cpp b/src/main.cpp index ee6a6d3d..723c2e63 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,7 +68,7 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0, Pinetime::PinMap::SpiMiso}}; Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn}; -Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand, Pinetime::PinMap::LcdReset}; +Pinetime::Drivers::St7789 lcd {lcdSpi}; Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn}; Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index a0b4d784..56cb965f 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -45,7 +45,7 @@ Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn}; Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn}; -Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand, Pinetime::PinMap::LcdReset}; +Pinetime::Drivers::St7789 lcd {lcdSpi}; Pinetime::Controllers::BrightnessController brightnessController; From ee925200c38ef9f04f976ebaf70b17d2898fcec5 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Sun, 11 Feb 2024 14:35:11 +0000 Subject: [PATCH 46/67] Remove task to notify --- src/FreeRTOSConfig.h | 1 + src/displayapp/DisplayApp.cpp | 3 --- src/displayapp/DisplayAppRecovery.cpp | 5 ----- src/displayapp/LittleVgl.cpp | 5 ----- src/drivers/SpiMaster.cpp | 16 +++------------- src/drivers/SpiMaster.h | 1 - src/recoveryLoader.cpp | 2 -- 7 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index cf18f418..67c33a34 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -75,6 +75,7 @@ #define configUSE_TIME_SLICING 0 #define configUSE_NEWLIB_REENTRANT 0 #define configENABLE_BACKWARD_COMPATIBILITY 1 +#define configUSE_TASK_NOTIFICATIONS 0 /* Hook function related definitions. */ #define configUSE_IDLE_HOOK 0 diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 9c7d87b2..d9b2e9b3 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -142,9 +142,6 @@ void DisplayApp::Process(void* instance) { NRF_LOG_INFO("displayapp task started!"); app->InitHw(); - // Send a dummy notification to unlock the lvgl display driver for the first iteration - xTaskNotifyGive(xTaskGetCurrentTaskHandle()); - while (true) { app->Refresh(); } diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index 002ee3bd..28892723 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -38,9 +38,6 @@ void DisplayApp::Process(void* instance) { auto* app = static_cast(instance); NRF_LOG_INFO("displayapp task started!"); - // Send a dummy notification to unlock the lvgl display driver for the first iteration - xTaskNotifyGive(xTaskGetCurrentTaskHandle()); - app->InitHw(); while (true) { app->Refresh(); @@ -94,7 +91,6 @@ void DisplayApp::DisplayLogo(uint16_t color) { Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb), color, colorBlack); for (int i = 0; i < displayWidth; i++) { rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel); - ulTaskNotifyTake(pdTRUE, 500); lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast(displayBuffer), displayWidth * bytesPerPixel); } } @@ -103,7 +99,6 @@ void DisplayApp::DisplayOtaProgress(uint8_t percent, uint16_t color) { const uint8_t barHeight = 20; std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color); for (int i = 0; i < barHeight; i++) { - ulTaskNotifyTake(pdTRUE, 500); uint16_t barWidth = std::min(static_cast(percent) * 2.4f, static_cast(displayWidth)); lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast(displayBuffer), barWidth * bytesPerPixel); } diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp index 89893cf7..c70a0856 100644 --- a/src/displayapp/LittleVgl.cpp +++ b/src/displayapp/LittleVgl.cpp @@ -152,10 +152,6 @@ void LittleVgl::SetFullRefresh(FullRefreshDirections direction) { void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) { uint16_t y1, y2, width, height = 0; - ulTaskNotifyTake(pdTRUE, 200); - // Notification is still needed (even if there is a mutex on SPI) because of the DataCommand pin - // which cannot be set/clear during a transfer. - if ((scrollDirection == LittleVgl::FullRefreshDirections::Down) && (area->y2 == visibleNbLines - 1)) { writeOffset = ((writeOffset + totalNbLines) - visibleNbLines) % totalNbLines; } else if ((scrollDirection == FullRefreshDirections::Up) && (area->y1 == 0)) { @@ -219,7 +215,6 @@ void LittleVgl::FlushDisplay(const lv_area_t* area, lv_color_t* color_p) { if (height > 0) { lcd.DrawBuffer(area->x1, y1, width, height, reinterpret_cast(color_p), width * height * 2); - ulTaskNotifyTake(pdTRUE, 100); } uint16_t pixOffset = width * height; diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 4c2bc940..f878c7d5 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -136,20 +136,14 @@ void SpiMaster::OnEndEvent() { spiBaseAddress->TASKS_START = 1; } else { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - if (taskToNotify != nullptr) { - vTaskNotifyGiveFromISR(taskToNotify, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); - } - nrf_gpio_pin_set(this->pinCsn); if (this->TransactionHook != nullptr) { this->TransactionHook(false); } currentBufferAddr = 0; - BaseType_t xHigherPriorityTaskWoken2 = pdFALSE; - xSemaphoreGiveFromISR(mutex, &xHigherPriorityTaskWoken2); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken | xHigherPriorityTaskWoken2); + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xSemaphoreGiveFromISR(mutex, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } @@ -181,7 +175,6 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, void (*T return false; auto ok = xSemaphoreTake(mutex, portMAX_DELAY); ASSERT(ok == true); - taskToNotify = xTaskGetCurrentTaskHandle(); this->TransactionHook = TransactionHook; this->pinCsn = pinCsn; @@ -226,7 +219,6 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, void (*T bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) { xSemaphoreTake(mutex, portMAX_DELAY); - taskToNotify = nullptr; this->TransactionHook = nullptr; this->pinCsn = pinCsn; DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); @@ -275,8 +267,6 @@ void SpiMaster::Wakeup() { bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize) { xSemaphoreTake(mutex, portMAX_DELAY); - taskToNotify = nullptr; - this->TransactionHook = nullptr; this->pinCsn = pinCsn; diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 9014061e..131965e1 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -57,7 +57,6 @@ namespace Pinetime { volatile uint32_t currentBufferAddr = 0; volatile size_t currentBufferSize = 0; - volatile TaskHandle_t taskToNotify; SemaphoreHandle_t mutex = nullptr; }; } diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index 56cb965f..55f85123 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -121,7 +121,6 @@ void DisplayLogo() { Pinetime::Tools::RleDecoder rleDecoder(infinitime_nb, sizeof(infinitime_nb)); for (int i = 0; i < displayWidth; i++) { rleDecoder.DecodeNext(displayBuffer, displayWidth * bytesPerPixel); - ulTaskNotifyTake(pdTRUE, 500); lcd.DrawBuffer(0, i, displayWidth, 1, reinterpret_cast(displayBuffer), displayWidth * bytesPerPixel); } } @@ -130,7 +129,6 @@ void DisplayProgressBar(uint8_t percent, uint16_t color) { static constexpr uint8_t barHeight = 20; std::fill(displayBuffer, displayBuffer + (displayWidth * bytesPerPixel), color); for (int i = 0; i < barHeight; i++) { - ulTaskNotifyTake(pdTRUE, 500); uint16_t barWidth = std::min(static_cast(percent) * 2.4f, static_cast(displayWidth)); lcd.DrawBuffer(0, displayWidth - barHeight + i, barWidth, 1, reinterpret_cast(displayBuffer), barWidth * bytesPerPixel); } From 869bec8f88f72560847ea780ee8342eeb0bc215c Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Fri, 9 Feb 2024 00:11:22 +0000 Subject: [PATCH 47/67] Refactor display WriteToRam --- src/drivers/St7789.cpp | 7 +++---- src/drivers/St7789.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index 6824acd8..78ad3a66 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -131,12 +131,11 @@ void St7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { WriteData(y0 & 0xff); WriteData(y1 >> 8); WriteData(y1 & 0xff); - - WriteToRam(); } -void St7789::WriteToRam() { +void St7789::WriteToRam(const uint8_t* data, size_t size) { WriteCommand(static_cast(Commands::WriteToRam)); + WriteSpi(data, size, EnableDataMode); } void St7789::SetVdv() { @@ -163,7 +162,7 @@ void St7789::Uninit() { void St7789::DrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t* data, size_t size) { SetAddrWindow(x, y, x + width - 1, y + height - 1); - WriteSpi(data, size, EnableDataMode); + WriteToRam(data, size); } void St7789::HardwareReset() { diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 185c44a0..339776ae 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -36,7 +36,7 @@ namespace Pinetime { void MemoryDataAccessControl(); void DisplayInversionOn(); void NormalModeOn(); - void WriteToRam(); + void WriteToRam(const uint8_t* data, size_t size); void DisplayOn(); void DisplayOff(); From 940cd3459f95073e60c61b37519486f569aac840 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Mon, 1 Apr 2024 17:14:33 +0100 Subject: [PATCH 48/67] Use functional abstraction for hooks --- src/drivers/Spi.cpp | 2 +- src/drivers/Spi.h | 3 ++- src/drivers/SpiMaster.cpp | 2 +- src/drivers/SpiMaster.h | 5 +++-- src/drivers/St7789.cpp | 41 ++++++++++++++++++++++----------------- src/drivers/St7789.h | 11 +++++++---- src/main.cpp | 2 +- src/recoveryLoader.cpp | 2 +- 8 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp index e0b716fa..df018775 100644 --- a/src/drivers/Spi.cpp +++ b/src/drivers/Spi.cpp @@ -9,7 +9,7 @@ Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : spiMaster {spiMaster}, pinCsn { nrf_gpio_pin_set(pinCsn); } -bool Spi::Write(const uint8_t* data, size_t size, void (*TransactionHook)(bool)) { +bool Spi::Write(const uint8_t* data, size_t size, std::function TransactionHook) { return spiMaster.Write(pinCsn, data, size, TransactionHook); } diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h index 55eef05c..4f48fafe 100644 --- a/src/drivers/Spi.h +++ b/src/drivers/Spi.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "drivers/SpiMaster.h" namespace Pinetime { @@ -14,7 +15,7 @@ namespace Pinetime { Spi& operator=(Spi&&) = delete; bool Init(); - bool Write(const uint8_t* data, size_t size, void (*TransactionHook)(bool)); + bool Write(const uint8_t* data, size_t size, std::function TransactionHook); bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); void Sleep(); diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index f878c7d5..5bfbf7b4 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -170,7 +170,7 @@ void SpiMaster::PrepareRx(const uint32_t bufferAddress, const size_t size) { spiBaseAddress->EVENTS_END = 0; } -bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, void (*TransactionHook)(bool)) { +bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, std::function TransactionHook) { if (data == nullptr) return false; auto ok = xSemaphoreTake(mutex, portMAX_DELAY); diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 131965e1..21980f4f 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include @@ -31,7 +32,7 @@ namespace Pinetime { SpiMaster& operator=(SpiMaster&&) = delete; bool Init(); - bool Write(uint8_t pinCsn, const uint8_t* data, size_t size, void (*TransactionHook)(bool)); + bool Write(uint8_t pinCsn, const uint8_t* data, size_t size, std::function TransactionHook); bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); @@ -50,7 +51,7 @@ namespace Pinetime { NRF_SPIM_Type* spiBaseAddress; uint8_t pinCsn; - void (*TransactionHook)(bool); + std::function TransactionHook; SpiMaster::SpiModule spi; SpiMaster::Parameters params; diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index 78ad3a66..6e5d13b1 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -3,17 +3,16 @@ #include #include #include "drivers/Spi.h" -#include "drivers/PinMap.h" using namespace Pinetime::Drivers; -St7789::St7789(Spi& spi) : spi {spi} { +St7789::St7789(Spi& spi, uint8_t pinDataCommand, uint8_t pinReset) : spi {spi}, pinDataCommand {pinDataCommand}, pinReset {pinReset} { } void St7789::Init() { - nrf_gpio_cfg_output(PinMap::LcdDataCommand); - nrf_gpio_cfg_output(PinMap::LcdReset); - nrf_gpio_pin_set(PinMap::LcdReset); + nrf_gpio_cfg_output(pinDataCommand); + nrf_gpio_cfg_output(pinReset); + nrf_gpio_pin_set(pinReset); HardwareReset(); SoftwareReset(); SleepOut(); @@ -32,25 +31,29 @@ void St7789::Init() { void St7789::EnableDataMode(bool isStart) { if (isStart) { - nrf_gpio_pin_set(PinMap::LcdDataCommand); + nrf_gpio_pin_set(pinDataCommand); } } void St7789::EnableCommandMode(bool isStart) { if (isStart) { - nrf_gpio_pin_clear(PinMap::LcdDataCommand); + nrf_gpio_pin_clear(pinDataCommand); } } -void St7789::WriteCommand(uint8_t cmd) { - WriteSpi(&cmd, 1, EnableCommandMode); -} - void St7789::WriteData(uint8_t data) { - WriteSpi(&data, 1, EnableDataMode); + WriteSpi(&data, 1, [this](bool isStart) { + EnableDataMode(isStart); + }); } -void St7789::WriteSpi(const uint8_t* data, size_t size, void (*TransactionHook)(bool)) { +void St7789::WriteCommand(uint8_t cmd) { + WriteSpi(&cmd, 1, [this](bool isStart) { + EnableCommandMode(isStart); + }); +} + +void St7789::WriteSpi(const uint8_t* data, size_t size, std::function TransactionHook) { spi.Write(data, size, TransactionHook); } @@ -135,7 +138,9 @@ void St7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { void St7789::WriteToRam(const uint8_t* data, size_t size) { WriteCommand(static_cast(Commands::WriteToRam)); - WriteSpi(data, size, EnableDataMode); + WriteSpi(data, size, [this](bool isStart) { + EnableDataMode(isStart); + }); } void St7789::SetVdv() { @@ -166,19 +171,19 @@ void St7789::DrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, } void St7789::HardwareReset() { - nrf_gpio_pin_clear(PinMap::LcdReset); + nrf_gpio_pin_clear(pinReset); nrf_delay_ms(10); - nrf_gpio_pin_set(PinMap::LcdReset); + nrf_gpio_pin_set(pinReset); } void St7789::Sleep() { SleepIn(); - nrf_gpio_cfg_default(PinMap::LcdDataCommand); + nrf_gpio_cfg_default(pinDataCommand); NRF_LOG_INFO("[LCD] Sleep"); } void St7789::Wakeup() { - nrf_gpio_cfg_output(PinMap::LcdDataCommand); + nrf_gpio_cfg_output(pinDataCommand); SleepOut(); VerticalScrollStartAddress(verticalScrollingStartAddress); DisplayOn(); diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 339776ae..0c73f77e 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include namespace Pinetime { namespace Drivers { @@ -8,7 +9,7 @@ namespace Pinetime { class St7789 { public: - explicit St7789(Spi& spi); + explicit St7789(Spi& spi, uint8_t pinDataCommand, uint8_t pinReset); St7789(const St7789&) = delete; St7789& operator=(const St7789&) = delete; St7789(St7789&&) = delete; @@ -26,6 +27,8 @@ namespace Pinetime { private: Spi& spi; + uint8_t pinDataCommand; + uint8_t pinReset; uint8_t verticalScrollingStartAddress = 0; void HardwareReset(); @@ -43,9 +46,9 @@ namespace Pinetime { void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); void SetVdv(); void WriteCommand(uint8_t cmd); - void WriteSpi(const uint8_t* data, size_t size, void (*TransactionHook)(bool)); - static void EnableDataMode(bool isStart); - static void EnableCommandMode(bool isStart); + void WriteSpi(const uint8_t* data, size_t size, std::function TransactionHook); + void EnableDataMode(bool isStart); + void EnableCommandMode(bool isStart); enum class Commands : uint8_t { SoftwareReset = 0x01, diff --git a/src/main.cpp b/src/main.cpp index 723c2e63..ee6a6d3d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,7 +68,7 @@ Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0, Pinetime::PinMap::SpiMiso}}; Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn}; -Pinetime::Drivers::St7789 lcd {lcdSpi}; +Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand, Pinetime::PinMap::LcdReset}; Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn}; Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index 55f85123..fc9ab76c 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -45,7 +45,7 @@ Pinetime::Drivers::Spi flashSpi {spi, Pinetime::PinMap::SpiFlashCsn}; Pinetime::Drivers::SpiNorFlash spiNorFlash {flashSpi}; Pinetime::Drivers::Spi lcdSpi {spi, Pinetime::PinMap::SpiLcdCsn}; -Pinetime::Drivers::St7789 lcd {lcdSpi}; +Pinetime::Drivers::St7789 lcd {lcdSpi, Pinetime::PinMap::LcdDataCommand, Pinetime::PinMap::LcdReset}; Pinetime::Controllers::BrightnessController brightnessController; From 9a7ba405e1384510f92f68e75b4bb54218f637c3 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:14:45 +0100 Subject: [PATCH 49/67] Refactor lambdas --- src/drivers/St7789.cpp | 38 ++++++++++++++++++-------------------- src/drivers/St7789.h | 4 ++-- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index 6e5d13b1..e42592e6 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -29,27 +29,27 @@ void St7789::Init() { DisplayOn(); } -void St7789::EnableDataMode(bool isStart) { - if (isStart) { - nrf_gpio_pin_set(pinDataCommand); - } -} - -void St7789::EnableCommandMode(bool isStart) { - if (isStart) { - nrf_gpio_pin_clear(pinDataCommand); - } -} - void St7789::WriteData(uint8_t data) { - WriteSpi(&data, 1, [this](bool isStart) { - EnableDataMode(isStart); + WriteData(&data, 1); +} + +void St7789::WriteData(const uint8_t* data, size_t size) { + WriteSpi(data, size, [pinDataCommand = pinDataCommand](bool isStart) { + if (isStart) { + nrf_gpio_pin_set(pinDataCommand); + } }); } -void St7789::WriteCommand(uint8_t cmd) { - WriteSpi(&cmd, 1, [this](bool isStart) { - EnableCommandMode(isStart); +void St7789::WriteCommand(uint8_t data) { + WriteCommand(&data, 1); +} + +void St7789::WriteCommand(const uint8_t* data, size_t size) { + WriteSpi(data, size, [pinDataCommand = pinDataCommand](bool isStart) { + if (isStart) { + nrf_gpio_pin_clear(pinDataCommand); + } }); } @@ -138,9 +138,7 @@ void St7789::SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { void St7789::WriteToRam(const uint8_t* data, size_t size) { WriteCommand(static_cast(Commands::WriteToRam)); - WriteSpi(data, size, [this](bool isStart) { - EnableDataMode(isStart); - }); + WriteData(data, size); } void St7789::SetVdv() { diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 0c73f77e..5eb60cfd 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -46,9 +46,8 @@ namespace Pinetime { void SetAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); void SetVdv(); void WriteCommand(uint8_t cmd); + void WriteCommand(const uint8_t* data, size_t size); void WriteSpi(const uint8_t* data, size_t size, std::function TransactionHook); - void EnableDataMode(bool isStart); - void EnableCommandMode(bool isStart); enum class Commands : uint8_t { SoftwareReset = 0x01, @@ -68,6 +67,7 @@ namespace Pinetime { VdvSet = 0xc4, }; void WriteData(uint8_t data); + void WriteData(const uint8_t* data, size_t size); void ColumnAddressSet(); static constexpr uint16_t Width = 240; From 24e6a2f8abab219868cb2eb6d02b3d83504c223c Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Thu, 11 Apr 2024 00:03:36 +0100 Subject: [PATCH 50/67] Avoid storing lambda --- src/drivers/Spi.cpp | 4 ++-- src/drivers/Spi.h | 2 +- src/drivers/SpiMaster.cpp | 16 +++------------- src/drivers/SpiMaster.h | 3 +-- src/drivers/St7789.cpp | 16 ++++++---------- src/drivers/St7789.h | 2 +- 6 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp index df018775..a03ea3c0 100644 --- a/src/drivers/Spi.cpp +++ b/src/drivers/Spi.cpp @@ -9,8 +9,8 @@ Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : spiMaster {spiMaster}, pinCsn { nrf_gpio_pin_set(pinCsn); } -bool Spi::Write(const uint8_t* data, size_t size, std::function TransactionHook) { - return spiMaster.Write(pinCsn, data, size, TransactionHook); +bool Spi::Write(const uint8_t* data, size_t size, const std::function& transactionHook) { + return spiMaster.Write(pinCsn, data, size, transactionHook); } bool Spi::Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) { diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h index 4f48fafe..e30620cc 100644 --- a/src/drivers/Spi.h +++ b/src/drivers/Spi.h @@ -15,7 +15,7 @@ namespace Pinetime { Spi& operator=(Spi&&) = delete; bool Init(); - bool Write(const uint8_t* data, size_t size, std::function TransactionHook); + bool Write(const uint8_t* data, size_t size, const std::function& transactionHook); bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); void Sleep(); diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 5bfbf7b4..eec62cb7 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -137,9 +137,6 @@ void SpiMaster::OnEndEvent() { spiBaseAddress->TASKS_START = 1; } else { nrf_gpio_pin_set(this->pinCsn); - if (this->TransactionHook != nullptr) { - this->TransactionHook(false); - } currentBufferAddr = 0; BaseType_t xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(mutex, &xHigherPriorityTaskWoken); @@ -170,13 +167,12 @@ void SpiMaster::PrepareRx(const uint32_t bufferAddress, const size_t size) { spiBaseAddress->EVENTS_END = 0; } -bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, std::function TransactionHook) { +bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, const std::function& transactionHook) { if (data == nullptr) return false; auto ok = xSemaphoreTake(mutex, portMAX_DELAY); ASSERT(ok == true); - this->TransactionHook = TransactionHook; this->pinCsn = pinCsn; if (size == 1) { @@ -185,8 +181,8 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, std::fun DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); } - if (this->TransactionHook != nullptr) { - this->TransactionHook(true); + if (transactionHook != nullptr) { + transactionHook(); } nrf_gpio_pin_clear(this->pinCsn); @@ -203,9 +199,6 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, std::fun while (spiBaseAddress->EVENTS_END == 0) ; nrf_gpio_pin_set(this->pinCsn); - if (this->TransactionHook != nullptr) { - this->TransactionHook(false); - } currentBufferAddr = 0; DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); @@ -219,7 +212,6 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, std::fun bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) { xSemaphoreTake(mutex, portMAX_DELAY); - this->TransactionHook = nullptr; this->pinCsn = pinCsn; DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); spiBaseAddress->INTENCLR = (1 << 6); @@ -267,8 +259,6 @@ void SpiMaster::Wakeup() { bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize) { xSemaphoreTake(mutex, portMAX_DELAY); - this->TransactionHook = nullptr; - this->pinCsn = pinCsn; DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); spiBaseAddress->INTENCLR = (1 << 6); diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 21980f4f..2f39a1b2 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -32,7 +32,7 @@ namespace Pinetime { SpiMaster& operator=(SpiMaster&&) = delete; bool Init(); - bool Write(uint8_t pinCsn, const uint8_t* data, size_t size, std::function TransactionHook); + bool Write(uint8_t pinCsn, const uint8_t* data, size_t size, const std::function& transactionHook); bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); @@ -51,7 +51,6 @@ namespace Pinetime { NRF_SPIM_Type* spiBaseAddress; uint8_t pinCsn; - std::function TransactionHook; SpiMaster::SpiModule spi; SpiMaster::Parameters params; diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index e42592e6..e933c374 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -34,10 +34,8 @@ void St7789::WriteData(uint8_t data) { } void St7789::WriteData(const uint8_t* data, size_t size) { - WriteSpi(data, size, [pinDataCommand = pinDataCommand](bool isStart) { - if (isStart) { - nrf_gpio_pin_set(pinDataCommand); - } + WriteSpi(data, size, [pinDataCommand = pinDataCommand]() { + nrf_gpio_pin_set(pinDataCommand); }); } @@ -46,15 +44,13 @@ void St7789::WriteCommand(uint8_t data) { } void St7789::WriteCommand(const uint8_t* data, size_t size) { - WriteSpi(data, size, [pinDataCommand = pinDataCommand](bool isStart) { - if (isStart) { - nrf_gpio_pin_clear(pinDataCommand); - } + WriteSpi(data, size, [pinDataCommand = pinDataCommand]() { + nrf_gpio_pin_clear(pinDataCommand); }); } -void St7789::WriteSpi(const uint8_t* data, size_t size, std::function TransactionHook) { - spi.Write(data, size, TransactionHook); +void St7789::WriteSpi(const uint8_t* data, size_t size, const std::function& transactionHook) { + spi.Write(data, size, transactionHook); } void St7789::SoftwareReset() { diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 5eb60cfd..f49ed511 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -47,7 +47,7 @@ namespace Pinetime { void SetVdv(); void WriteCommand(uint8_t cmd); void WriteCommand(const uint8_t* data, size_t size); - void WriteSpi(const uint8_t* data, size_t size, std::function TransactionHook); + void WriteSpi(const uint8_t* data, size_t size, const std::function& transactionHook); enum class Commands : uint8_t { SoftwareReset = 0x01, From 7a9211587aa17b23b9ff5121abc4f4eca63996d8 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:54:07 +0100 Subject: [PATCH 51/67] Rename to pre-transaction hook --- src/drivers/Spi.cpp | 4 ++-- src/drivers/Spi.h | 2 +- src/drivers/SpiMaster.cpp | 6 +++--- src/drivers/SpiMaster.h | 2 +- src/drivers/St7789.cpp | 4 ++-- src/drivers/St7789.h | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/drivers/Spi.cpp b/src/drivers/Spi.cpp index a03ea3c0..a95a7eae 100644 --- a/src/drivers/Spi.cpp +++ b/src/drivers/Spi.cpp @@ -9,8 +9,8 @@ Spi::Spi(SpiMaster& spiMaster, uint8_t pinCsn) : spiMaster {spiMaster}, pinCsn { nrf_gpio_pin_set(pinCsn); } -bool Spi::Write(const uint8_t* data, size_t size, const std::function& transactionHook) { - return spiMaster.Write(pinCsn, data, size, transactionHook); +bool Spi::Write(const uint8_t* data, size_t size, const std::function& preTransactionHook) { + return spiMaster.Write(pinCsn, data, size, preTransactionHook); } bool Spi::Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize) { diff --git a/src/drivers/Spi.h b/src/drivers/Spi.h index e30620cc..0c5edf08 100644 --- a/src/drivers/Spi.h +++ b/src/drivers/Spi.h @@ -15,7 +15,7 @@ namespace Pinetime { Spi& operator=(Spi&&) = delete; bool Init(); - bool Write(const uint8_t* data, size_t size, const std::function& transactionHook); + bool Write(const uint8_t* data, size_t size, const std::function& preTransactionHook); bool Read(uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); void Sleep(); diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index eec62cb7..690a3226 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -167,7 +167,7 @@ void SpiMaster::PrepareRx(const uint32_t bufferAddress, const size_t size) { spiBaseAddress->EVENTS_END = 0; } -bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, const std::function& transactionHook) { +bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, const std::function& preTransactionHook) { if (data == nullptr) return false; auto ok = xSemaphoreTake(mutex, portMAX_DELAY); @@ -181,8 +181,8 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, const st DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); } - if (transactionHook != nullptr) { - transactionHook(); + if (preTransactionHook != nullptr) { + preTransactionHook(); } nrf_gpio_pin_clear(this->pinCsn); diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 2f39a1b2..af38e87b 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -32,7 +32,7 @@ namespace Pinetime { SpiMaster& operator=(SpiMaster&&) = delete; bool Init(); - bool Write(uint8_t pinCsn, const uint8_t* data, size_t size, const std::function& transactionHook); + bool Write(uint8_t pinCsn, const uint8_t* data, size_t size, const std::function& preTransactionHook); bool Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data, size_t dataSize); bool WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmdSize, const uint8_t* data, size_t dataSize); diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index e933c374..d1747c23 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -49,8 +49,8 @@ void St7789::WriteCommand(const uint8_t* data, size_t size) { }); } -void St7789::WriteSpi(const uint8_t* data, size_t size, const std::function& transactionHook) { - spi.Write(data, size, transactionHook); +void St7789::WriteSpi(const uint8_t* data, size_t size, const std::function& preTransactionHook) { + spi.Write(data, size, preTransactionHook); } void St7789::SoftwareReset() { diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index f49ed511..715bd1bd 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -47,7 +47,7 @@ namespace Pinetime { void SetVdv(); void WriteCommand(uint8_t cmd); void WriteCommand(const uint8_t* data, size_t size); - void WriteSpi(const uint8_t* data, size_t size, const std::function& transactionHook); + void WriteSpi(const uint8_t* data, size_t size, const std::function& preTransactionHook); enum class Commands : uint8_t { SoftwareReset = 0x01, From 7e460d3c8072cbddf98172be9e94ede8e6613de5 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Fri, 27 Oct 2023 00:26:57 +0100 Subject: [PATCH 52/67] Use FreeRTOS delay instead of spinning the CPU --- src/drivers/St7789.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index d1747c23..82cefc43 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -1,6 +1,5 @@ #include "drivers/St7789.h" #include -#include #include #include "drivers/Spi.h" @@ -55,7 +54,7 @@ void St7789::WriteSpi(const uint8_t* data, size_t size, const std::function(Commands::SoftwareReset)); - nrf_delay_ms(150); + vTaskDelay(pdMS_TO_TICKS(150)); } void St7789::SleepOut() { @@ -69,7 +68,7 @@ void St7789::SleepIn() { void St7789::ColMod() { WriteCommand(static_cast(Commands::ColMod)); WriteData(0x55); - nrf_delay_ms(10); + vTaskDelay(pdMS_TO_TICKS(10)); } void St7789::MemoryDataAccessControl() { @@ -106,12 +105,12 @@ void St7789::RowAddressSet() { void St7789::DisplayInversionOn() { WriteCommand(static_cast(Commands::DisplayInversionOn)); - nrf_delay_ms(10); + vTaskDelay(pdMS_TO_TICKS(10)); } void St7789::NormalModeOn() { WriteCommand(static_cast(Commands::NormalModeOn)); - nrf_delay_ms(10); + vTaskDelay(pdMS_TO_TICKS(10)); } void St7789::DisplayOn() { @@ -146,7 +145,7 @@ void St7789::SetVdv() { void St7789::DisplayOff() { WriteCommand(static_cast(Commands::DisplayOff)); - nrf_delay_ms(500); + vTaskDelay(pdMS_TO_TICKS(500)); } void St7789::VerticalScrollStartAddress(uint16_t line) { @@ -166,7 +165,7 @@ void St7789::DrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, void St7789::HardwareReset() { nrf_gpio_pin_clear(pinReset); - nrf_delay_ms(10); + vTaskDelay(pdMS_TO_TICKS(10)); nrf_gpio_pin_set(pinReset); } From 7b1110187e92c739f85fbfdcf80f4547f1283a33 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Tue, 30 Jan 2024 23:29:16 +0000 Subject: [PATCH 53/67] Apply display driver datasheet delays --- src/drivers/St7789.cpp | 47 ++++++++++++++++++++++++++++++++++-------- src/drivers/St7789.h | 7 +++++++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index 82cefc43..f1917a77 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -1,7 +1,4 @@ #include "drivers/St7789.h" -#include -#include -#include "drivers/Spi.h" using namespace Pinetime::Drivers; @@ -53,22 +50,52 @@ void St7789::WriteSpi(const uint8_t* data, size_t size, const std::function(Commands::SoftwareReset)); - vTaskDelay(pdMS_TO_TICKS(150)); + // If sleep in: must wait 120ms before sleep out can sent (see driver datasheet) + // Unconditionally wait as software reset doesn't need to be performant + sleepIn = true; + lastSleepExit = xTaskGetTickCount(); + vTaskDelay(pdMS_TO_TICKS(125)); } void St7789::SleepOut() { + if (!sleepIn) { + return; + } WriteCommand(static_cast(Commands::SleepOut)); + // Wait 5ms for clocks to stabilise + // pdMS rounds down => 6 used here + vTaskDelay(pdMS_TO_TICKS(6)); + // Cannot send sleep in or software reset for 120ms + lastSleepExit = xTaskGetTickCount(); + sleepIn = false; +} + +void St7789::EnsureSleepOutPostDelay() { + TickType_t delta = xTaskGetTickCount() - lastSleepExit; + // Due to timer wraparound, there is a chance of delaying when not necessary + // It is very low (pdMS_TO_TICKS(125)/2^32) and waiting an extra 125ms isn't too bad + if (delta < pdMS_TO_TICKS(125)) { + vTaskDelay(pdMS_TO_TICKS(125) - delta); + } } void St7789::SleepIn() { + if (sleepIn) { + return; + } + EnsureSleepOutPostDelay(); WriteCommand(static_cast(Commands::SleepIn)); + // Wait 5ms for clocks to stabilise + // pdMS rounds down => 6 used here + vTaskDelay(pdMS_TO_TICKS(6)); + sleepIn = true; } void St7789::ColMod() { WriteCommand(static_cast(Commands::ColMod)); WriteData(0x55); - vTaskDelay(pdMS_TO_TICKS(10)); } void St7789::MemoryDataAccessControl() { @@ -105,12 +132,10 @@ void St7789::RowAddressSet() { void St7789::DisplayInversionOn() { WriteCommand(static_cast(Commands::DisplayInversionOn)); - vTaskDelay(pdMS_TO_TICKS(10)); } void St7789::NormalModeOn() { WriteCommand(static_cast(Commands::NormalModeOn)); - vTaskDelay(pdMS_TO_TICKS(10)); } void St7789::DisplayOn() { @@ -145,7 +170,6 @@ void St7789::SetVdv() { void St7789::DisplayOff() { WriteCommand(static_cast(Commands::DisplayOff)); - vTaskDelay(pdMS_TO_TICKS(500)); } void St7789::VerticalScrollStartAddress(uint16_t line) { @@ -165,8 +189,13 @@ void St7789::DrawBuffer(uint16_t x, uint16_t y, uint16_t width, uint16_t height, void St7789::HardwareReset() { nrf_gpio_pin_clear(pinReset); - vTaskDelay(pdMS_TO_TICKS(10)); + vTaskDelay(pdMS_TO_TICKS(1)); nrf_gpio_pin_set(pinReset); + // If hardware reset started while sleep out, reset time may be up to 120ms + // Unconditionally wait as hardware reset doesn't need to be performant + sleepIn = true; + lastSleepExit = xTaskGetTickCount(); + vTaskDelay(pdMS_TO_TICKS(125)); } void St7789::Sleep() { diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 715bd1bd..fcb6f944 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -3,6 +3,10 @@ #include #include +#include +#include +#include "drivers/Spi.h" + namespace Pinetime { namespace Drivers { class Spi; @@ -30,10 +34,13 @@ namespace Pinetime { uint8_t pinDataCommand; uint8_t pinReset; uint8_t verticalScrollingStartAddress = 0; + bool sleepIn; + TickType_t lastSleepExit; void HardwareReset(); void SoftwareReset(); void SleepOut(); + void EnsureSleepOutPostDelay(); void SleepIn(); void ColMod(); void MemoryDataAccessControl(); From 47c104643db6818fd92a1afb9a4ca3d64e95facd Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Mon, 25 Mar 2024 23:05:01 +0000 Subject: [PATCH 54/67] Move includes back --- src/drivers/St7789.cpp | 3 +++ src/drivers/St7789.h | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index f1917a77..c81f3b58 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -1,4 +1,7 @@ #include "drivers/St7789.h" +#include +#include +#include "drivers/Spi.h" using namespace Pinetime::Drivers; diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index fcb6f944..45d4b56d 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -3,9 +3,7 @@ #include #include -#include -#include -#include "drivers/Spi.h" +#include namespace Pinetime { namespace Drivers { From 06c69353156559aa786e8116f2527e8de3ee2d38 Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Fri, 29 Mar 2024 16:29:07 +0000 Subject: [PATCH 55/67] Include task header (Fixes sim) --- src/drivers/St7789.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/drivers/St7789.cpp b/src/drivers/St7789.cpp index c81f3b58..12e95a41 100644 --- a/src/drivers/St7789.cpp +++ b/src/drivers/St7789.cpp @@ -2,6 +2,7 @@ #include #include #include "drivers/Spi.h" +#include "task.h" using namespace Pinetime::Drivers; From 0dcfb2edb7ac071aa0a22c01609122d577d4c05d Mon Sep 17 00:00:00 2001 From: mark9064 <30447455+mark9064@users.noreply.github.com> Date: Wed, 24 Jan 2024 23:30:48 +0000 Subject: [PATCH 56/67] Fix erratum 58 workaround --- src/drivers/SpiMaster.cpp | 61 ++++++++++++++++++++++++--------------- src/drivers/SpiMaster.h | 8 +++-- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 690a3226..19422ef3 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -94,32 +94,45 @@ bool SpiMaster::Init() { return true; } -void SpiMaster::SetupWorkaroundForFtpan58(NRF_SPIM_Type* spim, uint32_t ppi_channel, uint32_t gpiote_channel) { - // Create an event when SCK toggles. - NRF_GPIOTE->CONFIG[gpiote_channel] = (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos) | (spim->PSEL.SCK << GPIOTE_CONFIG_PSEL_Pos) | - (GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos); +void SpiMaster::SetupWorkaroundForErratum58() { + nrfx_gpiote_pin_t pin = spiBaseAddress->PSEL.SCK; + nrfx_gpiote_in_config_t gpioteCfg = {.sense = NRF_GPIOTE_POLARITY_TOGGLE, + .pull = NRF_GPIO_PIN_NOPULL, + .is_watcher = false, + .hi_accuracy = true, + .skip_gpio_setup = true}; + if (!workaroundActive) { + // Create an event when SCK toggles. + APP_ERROR_CHECK(nrfx_gpiote_in_init(pin, &gpioteCfg, NULL)); + nrfx_gpiote_in_event_enable(pin, false); + + // Stop the spim instance when SCK toggles. + nrf_ppi_channel_endpoint_setup(workaroundPpi, nrfx_gpiote_in_event_addr_get(pin), spiBaseAddress->TASKS_STOP); + nrf_ppi_channel_enable(workaroundPpi); + } - // Stop the spim instance when SCK toggles. - NRF_PPI->CH[ppi_channel].EEP = (uint32_t) &NRF_GPIOTE->EVENTS_IN[gpiote_channel]; - NRF_PPI->CH[ppi_channel].TEP = (uint32_t) &spim->TASKS_STOP; - NRF_PPI->CHENSET = 1U << ppi_channel; spiBaseAddress->EVENTS_END = 0; // Disable IRQ - spim->INTENCLR = (1 << 6); - spim->INTENCLR = (1 << 1); - spim->INTENCLR = (1 << 19); + spiBaseAddress->INTENCLR = (1 << 6); + spiBaseAddress->INTENCLR = (1 << 1); + spiBaseAddress->INTENCLR = (1 << 19); + workaroundActive = true; } -void SpiMaster::DisableWorkaroundForFtpan58(NRF_SPIM_Type* spim, uint32_t ppi_channel, uint32_t gpiote_channel) { - NRF_GPIOTE->CONFIG[gpiote_channel] = 0; - NRF_PPI->CH[ppi_channel].EEP = 0; - NRF_PPI->CH[ppi_channel].TEP = 0; - NRF_PPI->CHENSET = ppi_channel; +void SpiMaster::DisableWorkaroundForErratum58() { + nrfx_gpiote_pin_t pin = spiBaseAddress->PSEL.SCK; + if (workaroundActive) { + nrfx_gpiote_in_uninit(pin); + nrf_ppi_channel_disable(workaroundPpi); + } spiBaseAddress->EVENTS_END = 0; - spim->INTENSET = (1 << 6); - spim->INTENSET = (1 << 1); - spim->INTENSET = (1 << 19); + + // Enable IRQ + spiBaseAddress->INTENSET = (1 << 6); + spiBaseAddress->INTENSET = (1 << 1); + spiBaseAddress->INTENSET = (1 << 19); + workaroundActive = false; } void SpiMaster::OnEndEvent() { @@ -176,9 +189,9 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, const st this->pinCsn = pinCsn; if (size == 1) { - SetupWorkaroundForFtpan58(spiBaseAddress, 0, 0); + SetupWorkaroundForErratum58(); } else { - DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); + DisableWorkaroundForErratum58(); } if (preTransactionHook != nullptr) { @@ -201,7 +214,7 @@ bool SpiMaster::Write(uint8_t pinCsn, const uint8_t* data, size_t size, const st nrf_gpio_pin_set(this->pinCsn); currentBufferAddr = 0; - DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); + DisableWorkaroundForErratum58(); xSemaphoreGive(mutex); } @@ -213,7 +226,7 @@ bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data xSemaphoreTake(mutex, portMAX_DELAY); this->pinCsn = pinCsn; - DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); + DisableWorkaroundForErratum58(); spiBaseAddress->INTENCLR = (1 << 6); spiBaseAddress->INTENCLR = (1 << 1); spiBaseAddress->INTENCLR = (1 << 19); @@ -260,7 +273,7 @@ bool SpiMaster::WriteCmdAndBuffer(uint8_t pinCsn, const uint8_t* cmd, size_t cmd xSemaphoreTake(mutex, portMAX_DELAY); this->pinCsn = pinCsn; - DisableWorkaroundForFtpan58(spiBaseAddress, 0, 0); + DisableWorkaroundForErratum58(); spiBaseAddress->INTENCLR = (1 << 6); spiBaseAddress->INTENCLR = (1 << 1); spiBaseAddress->INTENCLR = (1 << 19); diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index af38e87b..be6e5351 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -6,6 +6,8 @@ #include #include #include +#include "nrfx_gpiote.h" +#include "nrf_ppi.h" namespace Pinetime { namespace Drivers { @@ -44,8 +46,8 @@ namespace Pinetime { void Wakeup(); private: - void SetupWorkaroundForFtpan58(NRF_SPIM_Type* spim, uint32_t ppi_channel, uint32_t gpiote_channel); - void DisableWorkaroundForFtpan58(NRF_SPIM_Type* spim, uint32_t ppi_channel, uint32_t gpiote_channel); + void SetupWorkaroundForErratum58(); + void DisableWorkaroundForErratum58(); void PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size); void PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size); @@ -58,6 +60,8 @@ namespace Pinetime { volatile uint32_t currentBufferAddr = 0; volatile size_t currentBufferSize = 0; SemaphoreHandle_t mutex = nullptr; + static constexpr nrf_ppi_channel_t workaroundPpi = NRF_PPI_CHANNEL0; + bool workaroundActive = false; }; } } From 0c87bc27b21f343a815eed3d7b5817e3b24d2d1d Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Sun, 2 Jun 2024 00:43:25 +0000 Subject: [PATCH 57/67] Move motorController.Init call to DisplayApp::Start --- 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 d9b2e9b3..3fd34b3a 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -125,6 +125,7 @@ void DisplayApp::Start(System::BootErrors error) { bootError = error; lvgl.Init(); + motorController.Init(); if (error == System::BootErrors::TouchController) { LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None); @@ -150,7 +151,6 @@ void DisplayApp::Process(void* instance) { void DisplayApp::InitHw() { brightnessController.Init(); ApplyBrightness(); - motorController.Init(); lcd.Init(); } From 9e406c70f95c2db93bbf84965c210ee274da1dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Mart=C3=ADnez?= Date: Sun, 12 May 2024 22:05:30 +0200 Subject: [PATCH 58/67] Remove unnecessary BMA421 reads --- src/drivers/Bma421.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/drivers/Bma421.cpp b/src/drivers/Bma421.cpp index aff62b8d..74d47d06 100644 --- a/src/drivers/Bma421.cpp +++ b/src/drivers/Bma421.cpp @@ -126,13 +126,6 @@ Bma421::Values Bma421::Process() { uint32_t steps = 0; bma423_step_counter_output(&steps, &bma); - int32_t temperature; - bma4_get_temperature(&temperature, BMA4_DEG, &bma); - temperature = temperature / 1000; - - uint8_t activity = 0; - bma423_activity_output(&activity, &bma); - // X and Y axis are swapped because of the way the sensor is mounted in the PineTime return {steps, data.y, data.x, data.z}; } From 4b854a5d09544b7ad62e29a2b925d67877dffe50 Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Fri, 7 Jun 2024 16:46:06 -0700 Subject: [PATCH 59/67] WIP fuzzy --- shell.nix | 54 +++++++ src/CMakeLists.txt | 1 + src/components/settings/Settings.h | 2 +- src/displayapp/UserApps.h | 1 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/screens/WatchFaceFuzzy.cpp | 182 ++++++++++++++++++++++ src/displayapp/screens/WatchFaceFuzzy.h | 105 +++++++++++++ 7 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 shell.nix create mode 100644 src/displayapp/screens/WatchFaceFuzzy.cpp create mode 100644 src/displayapp/screens/WatchFaceFuzzy.h diff --git a/shell.nix b/shell.nix new file mode 100644 index 00000000..45b92c8c --- /dev/null +++ b/shell.nix @@ -0,0 +1,54 @@ +{ pkgs ? import {} }: + +with pkgs; let + py4McuBoot = python3.withPackages (ps: with ps; [ + cbor + intelhex + click + cryptography + pillow + ]); + lv_img_convWrapper = pkgs.writeScriptBin "lv_img_conv" '' + npm install lv_img_conv + nodejs node_modules/lv_img_conv/lv_img_conv.js + ''; + buildInfinitime = pkgs.writeScriptBin "build-infinitime" '' + mkdir build + cd build + cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=$ARM_NONE_EABI_TOOLCHAIN_PATH \ + -DNRF5_SDK_PATH=$NRF5_SDK_PATH \ + -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ + -DBUILD_DFU=$BUILD_DFU \ + -DBUILD_RESOURCES=$BUILD_RESOURCES \ + -DTARGET_DEVICE=$TARGET_DEVICE \ + -DENABLE_WATCHFACES="WatchFace::Analog,WatchFace::Digital,WatchFace::Fuzzy" \ + .. + + cd .. + cmake --build build -j6 + ''; +in mkShell { + packages = [ + gcc-arm-embedded-10 + nrf5-sdk + cmake + nodePackages.lv_font_conv + lv_img_convWrapper + # lv_img_conv + nodejs + py4McuBoot + clang-tools + SDL2 + libpng + adafruit-nrfutil + buildInfinitime + # watchmate # wish this worked -- use flatpak run io.gitlab.azymohliad.WatchMate + ]; + + ARM_NONE_EABI_TOOLCHAIN_PATH="${gcc-arm-embedded-10}"; + NRF5_SDK_PATH="${nrf5-sdk}/share/nRF5_SDK"; + CMAKE_BUILD_TYPE="Release"; + BUILD_DFU=1; + BUILD_RESOURCES=1; + TARGET_DEVICE="PINETIME"; +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd8ece62..fd489879 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -426,6 +426,7 @@ list(APPEND SOURCE_FILES displayapp/screens/WatchFaceTerminal.cpp displayapp/screens/WatchFacePineTimeStyle.cpp displayapp/screens/WatchFaceCasioStyleG7710.cpp + displayapp/screens/WatchFaceFuzzy.cpp ## diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 06312077..e3be5256 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -9,7 +9,7 @@ namespace Pinetime { namespace Controllers { class Settings { public: - enum class ClockType : uint8_t { H24, H12 }; + enum class ClockType : uint8_t { H24, H12, FUZZY }; enum class WeatherFormat : uint8_t { Metric, Imperial }; enum class Notification : uint8_t { On, Off, Sleep }; enum class ChimesOption : uint8_t { None, Hours, HalfHours }; diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index 67bbfa7d..d5a176d9 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -9,6 +9,7 @@ #include "displayapp/screens/Tile.h" #include "displayapp/screens/ApplicationList.h" #include "displayapp/screens/WatchFaceDigital.h" +#include "displayapp/screens/WatchFaceFuzzy.h" #include "displayapp/screens/WatchFaceAnalog.h" #include "displayapp/screens/WatchFaceCasioStyleG7710.h" #include "displayapp/screens/WatchFaceInfineat.h" diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 2104a267..7d809712 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -50,6 +50,7 @@ namespace Pinetime { Analog, PineTimeStyle, Terminal, + Fuzzy, Infineat, CasioStyleG7710, }; diff --git a/src/displayapp/screens/WatchFaceFuzzy.cpp b/src/displayapp/screens/WatchFaceFuzzy.cpp new file mode 100644 index 00000000..92913bbd --- /dev/null +++ b/src/displayapp/screens/WatchFaceFuzzy.cpp @@ -0,0 +1,182 @@ +#include "displayapp/screens/WatchFaceFuzzy.h" + +#include +#include +#include "displayapp/screens/NotificationIcon.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/screens/WeatherSymbols.h" +#include "components/battery/BatteryController.h" +#include "components/ble/BleController.h" +#include "components/ble/NotificationManager.h" +#include "components/heartrate/HeartRateController.h" +#include "components/motion/MotionController.h" +#include "components/ble/SimpleWeatherService.h" +#include "components/settings/Settings.h" + +using namespace Pinetime::Applications::Screens; + +WatchFaceFuzzy::WatchFaceFuzzy(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weatherService) + : currentDateTime {{}}, + dateTimeController {dateTimeController}, + notificationManager {notificationManager}, + settingsController {settingsController}, + heartRateController {heartRateController}, + motionController {motionController}, + weatherService {weatherService}, + statusIcons(batteryController, bleController) { + + statusIcons.Create(); + + notificationIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); + lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + weatherIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); + lv_label_set_text(weatherIcon, ""); + lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 50); + lv_obj_set_auto_realign(weatherIcon, true); + + temperature = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + lv_label_set_text(temperature, ""); + lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 50); + + label_date = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); + lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + + label_time = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); + + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); + + heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + + heartbeatValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(heartbeatValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_label_set_text_static(heartbeatValue, ""); + lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0); + + stepValue = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); + lv_label_set_text_static(stepValue, "0"); + lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + + stepIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(stepIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x00FFE7)); + lv_label_set_text_static(stepIcon, Symbols::shoe); + lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); +} + +WatchFaceFuzzy::~WatchFaceFuzzy() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceFuzzy::Refresh() { + statusIcons.Update(); + + notificationState = notificationManager.AreNewNotificationsAvailable(); + if (notificationState.IsUpdated()) { + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); + } + + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + + if (currentDateTime.IsUpdated()) { + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); + + printTimeWords(hour, minute); + } + + heartbeat = heartRateController.HeartRate(); + heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped; + if (heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) { + if (heartbeatRunning.Get()) { + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0xCE1B1B)); + lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get()); + } else { + lv_obj_set_style_local_text_color(heartbeatIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x1B1B1B)); + lv_label_set_text_static(heartbeatValue, ""); + } + + lv_obj_realign(heartbeatIcon); + lv_obj_realign(heartbeatValue); + } + + stepCount = motionController.NbSteps(); + if (stepCount.IsUpdated()) { + lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get()); + lv_obj_realign(stepValue); + lv_obj_realign(stepIcon); + } + + currentWeather = weatherService.Current(); + if (currentWeather.IsUpdated()) { + auto optCurrentWeather = currentWeather.Get(); + if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature; + char tempUnit = 'C'; + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); + tempUnit = 'F'; + } + temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); + lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); + } else { + lv_label_set_text_static(temperature, ""); + lv_label_set_text(weatherIcon, ""); + } + lv_obj_realign(temperature); + lv_obj_realign(weatherIcon); + } +} + +char const* WatchFaceFuzzy::mods[] = {"", "five", "ten", "quarter", "twenty", "twenty five", "half"}; +char const* WatchFaceFuzzy::nums[] = {"twelve", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve"}; + +void WatchFaceFuzzy::printTimeWords(int h, int m) { + const char* mod; + + if (m <= 30) { + mod = mods[m / 5]; + } else { + mod = mods[(60-m) / 5]; + } + h = (h % 12); + + if (m >= 57) { + sprintf(timeStr, "#ffffff nearly %s#\n#808080 o' clock#", nums[(h+1) % 12]); + } + else if (m == 0 || m <= 4) { + sprintf(timeStr, "#ffffff %s#\n#808080 o' clock#", nums[h]); + } + + else if (m <= 32) { + sprintf(timeStr, "#ffffff %s#\n#808080 past# #FFFFFF %s#", mod, nums[h]); + } + + else if (m > 32) { + sprintf(timeStr, "#ffffff %s#\n#808080 to# #FFFFFF %s#", mod, nums[(h+1) % 12]); + } + + lv_label_set_text(label_time, timeStr); +} diff --git a/src/displayapp/screens/WatchFaceFuzzy.h b/src/displayapp/screens/WatchFaceFuzzy.h new file mode 100644 index 00000000..a7ae5c94 --- /dev/null +++ b/src/displayapp/screens/WatchFaceFuzzy.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" +#include "components/ble/SimpleWeatherService.h" +#include "components/ble/BleController.h" +#include "displayapp/widgets/StatusIcons.h" +#include "utility/DirtyValue.h" +#include "displayapp/apps/Apps.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class HeartRateController; + class MotionController; + } + + namespace Applications { + namespace Screens { + + class WatchFaceFuzzy : public Screen { + public: + WatchFaceFuzzy(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weather); + ~WatchFaceFuzzy() override; + + void Refresh() override; + + private: + uint8_t displayedHour = -1; + uint8_t displayedMinute = -1; + + Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue stepCount {}; + Utility::DirtyValue heartbeat {}; + Utility::DirtyValue heartbeatRunning {}; + Utility::DirtyValue notificationState {}; + Utility::DirtyValue> currentWeather {}; + + Utility::DirtyValue> currentDate; + + lv_obj_t* label_time; + lv_obj_t* label_time_ampm; + lv_obj_t* label_date; + lv_obj_t* heartbeatIcon; + lv_obj_t* heartbeatValue; + lv_obj_t* stepIcon; + lv_obj_t* stepValue; + lv_obj_t* notificationIcon; + lv_obj_t* weatherIcon; + lv_obj_t* temperature; + + Controllers::DateTime& dateTimeController; + Controllers::NotificationManager& notificationManager; + Controllers::Settings& settingsController; + Controllers::HeartRateController& heartRateController; + Controllers::MotionController& motionController; + Controllers::SimpleWeatherService& weatherService; + + lv_task_t* taskRefresh; + Widgets::StatusIcons statusIcons; + + + static char const *nums[]; + static char const *mods[]; + char timeStr[64]; + void printTimeWords(int hour, int minute); + }; + } + + template <> + struct WatchFaceTraits { + static constexpr WatchFace watchFace = WatchFace::Fuzzy; + static constexpr const char* name = "Fuzzy face"; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::WatchFaceFuzzy(controllers.dateTimeController, + controllers.batteryController, + controllers.bleController, + controllers.notificationManager, + controllers.settingsController, + controllers.heartRateController, + controllers.motionController, + *controllers.weatherController); + }; + + static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { + return true; + } + }; + } +} From bb743689e1e96ff52501c4e34d23f80815c87db9 Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Sun, 9 Jun 2024 00:11:00 -0700 Subject: [PATCH 60/67] vulf-ify me captain --- src/displayapp/screens/WatchFaceFuzzy.cpp | 21 ++++++++++++++++++--- src/libs/sunset | 1 + 2 files changed, 19 insertions(+), 3 deletions(-) create mode 160000 src/libs/sunset diff --git a/src/displayapp/screens/WatchFaceFuzzy.cpp b/src/displayapp/screens/WatchFaceFuzzy.cpp index 92913bbd..3d70bd17 100644 --- a/src/displayapp/screens/WatchFaceFuzzy.cpp +++ b/src/displayapp/screens/WatchFaceFuzzy.cpp @@ -56,9 +56,9 @@ WatchFaceFuzzy::WatchFaceFuzzy(Controllers::DateTime& dateTimeController, lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); label_time = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_recolor(label_time, true); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); heartbeatIcon = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(heartbeatIcon, Symbols::heartBeat); @@ -104,6 +104,19 @@ void WatchFaceFuzzy::Refresh() { uint8_t minute = dateTimeController.Minutes(); printTimeWords(hour, minute); + + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + if (currentDate.IsUpdated()) { + uint16_t year = dateTimeController.Year(); + uint8_t day = dateTimeController.Day(); + lv_label_set_text_fmt(label_date, + "%s %d %s %d", + dateTimeController.DayOfWeekShortToString(), + day, + dateTimeController.MonthShortToString(), + year); + lv_obj_realign(label_date); + } } heartbeat = heartRateController.HeartRate(); @@ -178,5 +191,7 @@ void WatchFaceFuzzy::printTimeWords(int h, int m) { sprintf(timeStr, "#ffffff %s#\n#808080 to# #FFFFFF %s#", mod, nums[(h+1) % 12]); } + printf("%s\n", timeStr); lv_label_set_text(label_time, timeStr); + lv_obj_realign(label_time); } diff --git a/src/libs/sunset b/src/libs/sunset new file mode 160000 index 00000000..4b08734e --- /dev/null +++ b/src/libs/sunset @@ -0,0 +1 @@ +Subproject commit 4b08734eb8856154d7226bfdced91a571fb6a64b From 83cae9b5bca2fbe54f3b0d4e4f4e04f1caf07aee Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Sun, 9 Jun 2024 20:26:43 -0700 Subject: [PATCH 61/67] wip sundial w/ copied analog watchface --- .gitmodules | 3 + shell.nix | 8 +- src/CMakeLists.txt | 44 +++--- src/displayapp/UserApps.h | 13 +- src/displayapp/apps/Apps.h.in | 1 + src/displayapp/apps/CMakeLists.txt | 15 +- src/displayapp/screens/WatchFaceSundial.cpp | 149 ++++++++++++++++++++ src/displayapp/screens/WatchFaceSundial.h | 99 +++++++++++++ 8 files changed, 280 insertions(+), 52 deletions(-) create mode 100644 src/displayapp/screens/WatchFaceSundial.cpp create mode 100644 src/displayapp/screens/WatchFaceSundial.h diff --git a/.gitmodules b/.gitmodules index 7a4e307b..e629301e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "src/libs/arduinoFFT"] path = src/libs/arduinoFFT url = https://github.com/kosme/arduinoFFT.git +[submodule "src/libs/sunset"] + path = src/libs/sunset + url = https://github.com/buelowp/sunset.git diff --git a/shell.nix b/shell.nix index 45b92c8c..2cd26898 100644 --- a/shell.nix +++ b/shell.nix @@ -13,18 +13,14 @@ with pkgs; let nodejs node_modules/lv_img_conv/lv_img_conv.js ''; buildInfinitime = pkgs.writeScriptBin "build-infinitime" '' - mkdir build - cd build + mkdir -p build/ cmake -DARM_NONE_EABI_TOOLCHAIN_PATH=$ARM_NONE_EABI_TOOLCHAIN_PATH \ -DNRF5_SDK_PATH=$NRF5_SDK_PATH \ -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ -DBUILD_DFU=$BUILD_DFU \ -DBUILD_RESOURCES=$BUILD_RESOURCES \ -DTARGET_DEVICE=$TARGET_DEVICE \ - -DENABLE_WATCHFACES="WatchFace::Analog,WatchFace::Digital,WatchFace::Fuzzy" \ - .. - - cd .. + -S . -B build cmake --build build -j6 ''; in mkShell { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fd489879..5922bca7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -174,6 +174,11 @@ set(LITTLEFS_SRC libs/littlefs/lfs.c ) +set(SUNSET_SRC + libs/sunset/src/sunset.h + libs/sunset/src/sunset.cpp + ) + set(LVGL_SRC libs/lv_conf.h libs/lvgl/lvgl.h @@ -366,8 +371,6 @@ list(APPEND SOURCE_FILES displayapp/DisplayApp.cpp displayapp/screens/Screen.cpp displayapp/screens/Tile.cpp - displayapp/screens/InfiniPaint.cpp - displayapp/screens/Paddle.cpp displayapp/screens/StopWatch.cpp displayapp/screens/BatteryIcon.cpp displayapp/screens/BleIcon.cpp @@ -376,14 +379,9 @@ list(APPEND SOURCE_FILES displayapp/screens/Label.cpp displayapp/screens/FirmwareUpdate.cpp displayapp/screens/Music.cpp - displayapp/screens/Navigation.cpp - displayapp/screens/Metronome.cpp - displayapp/screens/Motion.cpp - displayapp/screens/Weather.cpp displayapp/screens/FirmwareValidation.cpp displayapp/screens/ApplicationList.cpp displayapp/screens/Notifications.cpp - displayapp/screens/Twos.cpp displayapp/screens/HeartRate.cpp displayapp/screens/FlashLight.cpp displayapp/screens/List.cpp @@ -420,13 +418,9 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingBluetooth.cpp ## Watch faces - displayapp/screens/WatchFaceAnalog.cpp displayapp/screens/WatchFaceDigital.cpp - displayapp/screens/WatchFaceInfineat.cpp - displayapp/screens/WatchFaceTerminal.cpp - displayapp/screens/WatchFacePineTimeStyle.cpp - displayapp/screens/WatchFaceCasioStyleG7710.cpp displayapp/screens/WatchFaceFuzzy.cpp + displayapp/screens/WatchFaceSundial.cpp ## @@ -591,9 +585,7 @@ set(INCLUDE_FILES displayapp/TouchEvents.h displayapp/screens/Screen.h displayapp/screens/Tile.h - displayapp/screens/InfiniPaint.h displayapp/screens/StopWatch.h - displayapp/screens/Paddle.h displayapp/screens/BatteryIcon.h displayapp/screens/BleIcon.h displayapp/screens/NotificationIcon.h @@ -607,11 +599,7 @@ set(INCLUDE_FILES displayapp/Apps.h displayapp/screens/Notifications.h displayapp/screens/HeartRate.h - displayapp/screens/Metronome.h - displayapp/screens/Motion.h displayapp/screens/Timer.h - displayapp/screens/Dice.h - displayapp/screens/Alarm.h displayapp/Colors.h displayapp/widgets/Counter.h displayapp/widgets/PageIndicator.h @@ -900,13 +888,25 @@ target_compile_options(littlefs PRIVATE $<$: ${ASM_FLAGS}> ) +# SUNSET_SRC +add_library(sunset STATIC ${SUNSET_SRC}) +target_include_directories(sunset SYSTEM PUBLIC . ../) +target_include_directories(sunset SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) +target_compile_options(sunset PRIVATE + ${COMMON_FLAGS} + $<$: ${DEBUG_FLAGS}> + $<$: ${RELEASE_FLAGS}> + $<$: ${CXX_FLAGS}> + $<$: ${ASM_FLAGS}> + ) + # Build autonomous binary (without support for bootloader) set(EXECUTABLE_NAME "pinetime-app") set(EXECUTABLE_FILE_NAME ${EXECUTABLE_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}) set(NRF5_LINKER_SCRIPT "${CMAKE_SOURCE_DIR}/gcc_nrf52.ld") add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES}) set_target_properties(${EXECUTABLE_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_FILE_NAME}) -target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_NAME} nimble nrf-sdk lvgl littlefs sunset infinitime_fonts infinitime_apps) target_compile_options(${EXECUTABLE_NAME} PUBLIC ${COMMON_FLAGS} ${WARNING_FLAGS} @@ -940,7 +940,7 @@ set(IMAGE_MCUBOOT_FILE_NAME_BIN ${EXECUTABLE_MCUBOOT_NAME}-image-${pinetime_VERS set(DFU_MCUBOOT_FILE_NAME ${EXECUTABLE_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip) set(NRF5_LINKER_SCRIPT_MCUBOOT "${CMAKE_SOURCE_DIR}/gcc_nrf52-mcuboot.ld") add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES}) -target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs sunset infinitime_fonts infinitime_apps) set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_FILE_NAME}) target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC ${COMMON_FLAGS} @@ -982,7 +982,7 @@ endif() set(EXECUTABLE_RECOVERY_NAME "pinetime-recovery") set(EXECUTABLE_RECOVERY_FILE_NAME ${EXECUTABLE_RECOVERY_NAME}-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}) add_executable(${EXECUTABLE_RECOVERY_NAME} ${RECOVERY_SOURCE_FILES}) -target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs sunset infinitime_fonts infinitime_apps) set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_FILE_NAME}) target_compile_definitions(${EXECUTABLE_RECOVERY_NAME} PUBLIC "PINETIME_IS_RECOVERY") target_compile_options(${EXECUTABLE_RECOVERY_NAME} PUBLIC @@ -1014,7 +1014,7 @@ set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-image-$ set(IMAGE_RECOVERY_MCUBOOT_FILE_NAME_HEX ${IMAGE_RECOVERY_MCUBOOT_FILE_NAME}.hex) set(DFU_RECOVERY_MCUBOOT_FILE_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_NAME}-dfu-${pinetime_VERSION_MAJOR}.${pinetime_VERSION_MINOR}.${pinetime_VERSION_PATCH}.zip) add_executable(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} ${RECOVERY_SOURCE_FILES}) -target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs infinitime_fonts infinitime_apps) +target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlefs sunset infinitime_fonts infinitime_apps) set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERY_MCUBOOT_FILE_NAME}) target_compile_definitions(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC "PINETIME_IS_RECOVERY") target_compile_options(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PUBLIC diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index d5a176d9..a786a8b3 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -2,19 +2,10 @@ #include "displayapp/apps/Apps.h" #include "Controllers.h" -#include "displayapp/screens/Alarm.h" -#include "displayapp/screens/Dice.h" -#include "displayapp/screens/Timer.h" -#include "displayapp/screens/Twos.h" -#include "displayapp/screens/Tile.h" #include "displayapp/screens/ApplicationList.h" -#include "displayapp/screens/WatchFaceDigital.h" #include "displayapp/screens/WatchFaceFuzzy.h" -#include "displayapp/screens/WatchFaceAnalog.h" -#include "displayapp/screens/WatchFaceCasioStyleG7710.h" -#include "displayapp/screens/WatchFaceInfineat.h" -#include "displayapp/screens/WatchFacePineTimeStyle.h" -#include "displayapp/screens/WatchFaceTerminal.h" +#include "displayapp/screens/WatchFaceSundial.h" +#include "displayapp/screens/WatchFaceDigital.h" namespace Pinetime { namespace Applications { diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 7d809712..6201da6b 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -51,6 +51,7 @@ namespace Pinetime { PineTimeStyle, Terminal, Fuzzy, + Sundial, Infineat, CasioStyleG7710, }; diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt index d7858760..17906ff0 100644 --- a/src/displayapp/apps/CMakeLists.txt +++ b/src/displayapp/apps/CMakeLists.txt @@ -2,19 +2,11 @@ if(DEFINED ENABLE_USERAPPS) set(USERAPP_TYPES ${ENABLE_USERAPPS} CACHE STRING "List of user apps to build into the firmware") else () set(DEFAULT_USER_APP_TYPES "Apps::StopWatch") - set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Alarm") 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::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::Motion") set(USERAPP_TYPES "${DEFAULT_USER_APP_TYPES}" CACHE STRING "List of user apps to build into the firmware") endif () @@ -22,11 +14,8 @@ 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::PineTimeStyle") - set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Terminal") - set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Infineat") - set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::CasioStyleG7710") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Fuzzy") + set(DEFAULT_WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}, WatchFace::Sundial") set(WATCHFACE_TYPES "${DEFAULT_WATCHFACE_TYPES}" CACHE STRING "List of watch faces to build into the firmware") endif() diff --git a/src/displayapp/screens/WatchFaceSundial.cpp b/src/displayapp/screens/WatchFaceSundial.cpp new file mode 100644 index 00000000..b99204b0 --- /dev/null +++ b/src/displayapp/screens/WatchFaceSundial.cpp @@ -0,0 +1,149 @@ +#include "displayapp/screens/WatchFaceSundial.h" + +#include +#include +// #include +#include "displayapp/screens/NotificationIcon.h" +#include "displayapp/screens/Symbols.h" +#include "displayapp/screens/WeatherSymbols.h" +#include "components/battery/BatteryController.h" +#include "components/ble/BleController.h" +#include "components/ble/NotificationManager.h" +#include "components/heartrate/HeartRateController.h" +#include "components/motion/MotionController.h" +#include "components/ble/SimpleWeatherService.h" +#include "components/settings/Settings.h" +#include "sunset/src/sunset.h" + +using namespace Pinetime::Applications::Screens; + +// namespace { +// int16_t HourLength = 70; +// constexpr int16_t MinuteLength = 90; +// constexpr int16_t SecondLength = 110; +// constexpr int16_t SunDialVerticalOffset = 40; + +// // sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor +// const auto LV_TRIG_SCALE = _lv_trigo_sin(90); +// const lv_color_t DARK_GRAY = lv_color_make(48, 48, 48); +// const lv_color_t DARK_ORANGE = lv_color_make(48, 26, 0); + +// int16_t Cosine(int16_t angle) { +// return _lv_trigo_sin(angle + 90); +// } + +// int16_t Sine(int16_t angle) { +// return _lv_trigo_sin(angle); +// } + +// int16_t CoordinateXRelocate(int16_t x) { +// return (x + LV_HOR_RES / 2); +// } + +// int16_t CoordinateYRelocate(int16_t y) { +// return std::abs(y - LV_HOR_RES / 2); +// } + +// lv_point_t CoordinateRelocate(int16_t radius, int16_t angle) { +// return lv_point_t {.x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), +// .y = CoordinateYRelocate(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE)}; +// } + +// int16_t CoordinateYRelocateSundial(int16_t y) { +// return std::abs(y - SunDialVerticalOffset); +// } + +// lv_point_t CoordinateRelocateSundial(int16_t radius, int16_t angle) { +// return lv_point_t {.x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), +// .y = CoordinateYRelocateSundial(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE)}; +// } + +// } + +WatchFaceSundial::WatchFaceSundial(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weatherService) + : currentDateTime {{}}, + dateTimeController {dateTimeController}, + notificationManager {notificationManager}, + settingsController {settingsController}, + heartRateController {heartRateController}, + motionController {motionController}, + weatherService {weatherService}, + statusIcons(batteryController, bleController) { + + statusIcons.Create(); + + weatherIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); + lv_label_set_text(weatherIcon, ""); + lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 50); + lv_obj_set_auto_realign(weatherIcon, true); + + temperature = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + lv_label_set_text(temperature, ""); + lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 50); + + label_date = lv_label_create(lv_scr_act(), nullptr); + lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); + lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + + label_time = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_label_set_recolor(label_time, true); + lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); + + taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + Refresh(); +} + +WatchFaceSundial::~WatchFaceSundial() { + lv_task_del(taskRefresh); + lv_obj_clean(lv_scr_act()); +} + +void WatchFaceSundial::Refresh() { + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + if (currentDateTime.IsUpdated()) { + currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + if (currentDate.IsUpdated()) { + uint16_t year = dateTimeController.Year(); + uint8_t day = dateTimeController.Day(); + lv_label_set_text_fmt(label_date, + "%s %d %s %d", + dateTimeController.DayOfWeekShortToString(), + day, + dateTimeController.MonthShortToString(), + year); + lv_obj_realign(label_date); + } + } + + currentWeather = weatherService.Current(); + if (currentWeather.IsUpdated()) { + auto optCurrentWeather = currentWeather.Get(); + if (optCurrentWeather) { + int16_t temp = optCurrentWeather->temperature; + char tempUnit = 'C'; + if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { + temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); + tempUnit = 'F'; + } + temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); + lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); + lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); + } else { + lv_label_set_text_static(temperature, ""); + lv_label_set_text(weatherIcon, ""); + } + lv_obj_realign(temperature); + lv_obj_realign(weatherIcon); + } +} diff --git a/src/displayapp/screens/WatchFaceSundial.h b/src/displayapp/screens/WatchFaceSundial.h new file mode 100644 index 00000000..9c02fdfe --- /dev/null +++ b/src/displayapp/screens/WatchFaceSundial.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include +#include +#include "displayapp/screens/Screen.h" +#include "components/datetime/DateTimeController.h" +#include "components/ble/SimpleWeatherService.h" +#include "components/ble/BleController.h" +#include "displayapp/widgets/StatusIcons.h" +#include "utility/DirtyValue.h" +#include "displayapp/apps/Apps.h" + +namespace Pinetime { + namespace Controllers { + class Settings; + class Battery; + class Ble; + class NotificationManager; + class HeartRateController; + class MotionController; + } + + namespace Applications { + namespace Screens { + + class WatchFaceSundial : public Screen { + public: + WatchFaceSundial(Controllers::DateTime& dateTimeController, + const Controllers::Battery& batteryController, + const Controllers::Ble& bleController, + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weather); + ~WatchFaceSundial() override; + + void Refresh() override; + + private: + uint8_t displayedHour = -1; + uint8_t displayedMinute = -1; + + Utility::DirtyValue> currentDateTime {}; + Utility::DirtyValue stepCount {}; + Utility::DirtyValue heartbeat {}; + Utility::DirtyValue heartbeatRunning {}; + Utility::DirtyValue notificationState {}; + Utility::DirtyValue> currentWeather {}; + + Utility::DirtyValue> currentDate; + + lv_obj_t* label_time; + lv_obj_t* label_time_ampm; + lv_obj_t* label_date; + lv_obj_t* heartbeatIcon; + lv_obj_t* heartbeatValue; + lv_obj_t* stepIcon; + lv_obj_t* stepValue; + lv_obj_t* notificationIcon; + lv_obj_t* weatherIcon; + lv_obj_t* temperature; + + Controllers::DateTime& dateTimeController; + Controllers::NotificationManager& notificationManager; + Controllers::Settings& settingsController; + Controllers::HeartRateController& heartRateController; + Controllers::MotionController& motionController; + Controllers::SimpleWeatherService& weatherService; + + lv_task_t* taskRefresh; + Widgets::StatusIcons statusIcons; + }; + } + + template <> + struct WatchFaceTraits { + static constexpr WatchFace watchFace = WatchFace::Sundial; + static constexpr const char* name = "Sundial face"; + + static Screens::Screen* Create(AppControllers& controllers) { + return new Screens::WatchFaceSundial(controllers.dateTimeController, + controllers.batteryController, + controllers.bleController, + controllers.notificationManager, + controllers.settingsController, + controllers.heartRateController, + controllers.motionController, + *controllers.weatherController); + }; + + static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { + return true; + } + }; + } +} From 8cf38a34697baf6803c2661357504a6ba1eb8a9f Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Sun, 9 Jun 2024 20:28:35 -0700 Subject: [PATCH 62/67] remove unused open sans light --- src/displayapp/fonts/CMakeLists.txt | 2 +- src/displayapp/fonts/fonts.json | 19 ++++--------------- .../screens/settings/SettingWatchFace.h | 4 ++-- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/displayapp/fonts/CMakeLists.txt b/src/displayapp/fonts/CMakeLists.txt index 22627efc..0baecf4a 100644 --- a/src/displayapp/fonts/CMakeLists.txt +++ b/src/displayapp/fonts/CMakeLists.txt @@ -1,6 +1,6 @@ set(FONTS jetbrains_mono_42 jetbrains_mono_76 jetbrains_mono_bold_20 jetbrains_mono_extrabold_compressed lv_font_sys_48 - open_sans_light fontawesome_weathericons) + fontawesome_weathericons) find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin") message(STATUS "Using ${LV_FONT_CONV} to generate font files") diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 41c383c0..1a07d8cf 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -2,8 +2,8 @@ "jetbrains_mono_bold_20": { "sources": [ { - "file": "JetBrainsMono-Bold.ttf", - "range": "0x20-0x7e, 0x410-0x44f, 0xB0" + "file": "Vulf_Mono-Italic.woff", + "range": "0x20-0x7e, 0xB0" }, { "file": "FontAwesome5-Solid+Brands+Regular.woff", @@ -11,13 +11,12 @@ } ], "bpp": 1, - "size": 20, - "patches": ["jetbrains_mono_bold_20.c_zero.patch", "jetbrains_mono_bold_20.c_M.patch"] + "size": 20 }, "jetbrains_mono_42": { "sources": [ { - "file": "JetBrainsMono-Regular.ttf", + "file": "Vulf Mono Light Italic.ttf", "range": "0x25, 0x2b, 0x2d, 0x2e, 0x30-0x3a, 0x43, 0x46, 0x4b-0x4d, 0x66, 0x69, 0x6b, 0x6d, 0x74, 0xb0" } ], @@ -44,16 +43,6 @@ "bpp": 1, "size": 80 }, - "open_sans_light": { - "sources": [ - { - "file": "open_sans_light.ttf", - "symbols": "0123456789" - } - ], - "bpp": 1, - "size": 150 - }, "lv_font_sys_48": { "sources": [ { diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index 4c75b0ab..2dee4b82 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -9,8 +9,8 @@ #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/CheckboxList.h" -#include "displayapp/screens/WatchFaceInfineat.h" -#include "displayapp/screens/WatchFaceCasioStyleG7710.h" +// #include "displayapp/screens/WatchFaceInfineat.h" +// #include "displayapp/screens/WatchFaceCasioStyleG7710.h" namespace Pinetime { From 9520b2ec9b1a0696be765a8539fd5cb2bf708630 Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Sun, 9 Jun 2024 20:28:52 -0700 Subject: [PATCH 63/67] remove unused controllers from fuzzy --- src/displayapp/screens/WatchFaceFuzzy.cpp | 22 +++++++--------------- src/displayapp/screens/WatchFaceFuzzy.h | 17 +++++------------ 2 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/displayapp/screens/WatchFaceFuzzy.cpp b/src/displayapp/screens/WatchFaceFuzzy.cpp index 3d70bd17..834da064 100644 --- a/src/displayapp/screens/WatchFaceFuzzy.cpp +++ b/src/displayapp/screens/WatchFaceFuzzy.cpp @@ -5,8 +5,6 @@ #include "displayapp/screens/NotificationIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/WeatherSymbols.h" -#include "components/battery/BatteryController.h" -#include "components/ble/BleController.h" #include "components/ble/NotificationManager.h" #include "components/heartrate/HeartRateController.h" #include "components/motion/MotionController.h" @@ -16,23 +14,19 @@ using namespace Pinetime::Applications::Screens; WatchFaceFuzzy::WatchFaceFuzzy(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, - Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Controllers::SimpleWeatherService& weatherService) + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weatherService) : currentDateTime {{}}, dateTimeController {dateTimeController}, notificationManager {notificationManager}, settingsController {settingsController}, heartRateController {heartRateController}, motionController {motionController}, - weatherService {weatherService}, - statusIcons(batteryController, bleController) { - - statusIcons.Create(); + weatherService {weatherService} +{ notificationIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); @@ -90,8 +84,6 @@ WatchFaceFuzzy::~WatchFaceFuzzy() { } void WatchFaceFuzzy::Refresh() { - statusIcons.Update(); - notificationState = notificationManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); diff --git a/src/displayapp/screens/WatchFaceFuzzy.h b/src/displayapp/screens/WatchFaceFuzzy.h index a7ae5c94..4c409e8b 100644 --- a/src/displayapp/screens/WatchFaceFuzzy.h +++ b/src/displayapp/screens/WatchFaceFuzzy.h @@ -28,13 +28,11 @@ namespace Pinetime { class WatchFaceFuzzy : public Screen { public: WatchFaceFuzzy(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, - Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Controllers::SimpleWeatherService& weather); + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController, + Controllers::HeartRateController& heartRateController, + Controllers::MotionController& motionController, + Controllers::SimpleWeatherService& weather); ~WatchFaceFuzzy() override; void Refresh() override; @@ -53,7 +51,6 @@ namespace Pinetime { Utility::DirtyValue> currentDate; lv_obj_t* label_time; - lv_obj_t* label_time_ampm; lv_obj_t* label_date; lv_obj_t* heartbeatIcon; lv_obj_t* heartbeatValue; @@ -71,8 +68,6 @@ namespace Pinetime { Controllers::SimpleWeatherService& weatherService; lv_task_t* taskRefresh; - Widgets::StatusIcons statusIcons; - static char const *nums[]; static char const *mods[]; @@ -88,8 +83,6 @@ namespace Pinetime { static Screens::Screen* Create(AppControllers& controllers) { return new Screens::WatchFaceFuzzy(controllers.dateTimeController, - controllers.batteryController, - controllers.bleController, controllers.notificationManager, controllers.settingsController, controllers.heartRateController, From c20db14c43051c6042002926993fda9023a337ec Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Sun, 9 Jun 2024 20:48:06 -0700 Subject: [PATCH 64/67] how much heap can one smartwatch need, michael, 40kb? --- src/FreeRTOSConfig.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h index 67c33a34..cdb248b9 100644 --- a/src/FreeRTOSConfig.h +++ b/src/FreeRTOSConfig.h @@ -62,7 +62,8 @@ #define configTICK_RATE_HZ 1024 #define configMAX_PRIORITIES (3) #define configMINIMAL_STACK_SIZE (120) -#define configTOTAL_HEAP_SIZE (1024 * 40) +// how much heap can one smartwatch need, michael, 40kb? +#define configTOTAL_HEAP_SIZE (1024 * 39) #define configMAX_TASK_NAME_LEN (4) #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 From 41518cc5294a3dc73364ae655de16b816e57040a Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Mon, 10 Jun 2024 20:19:06 -0700 Subject: [PATCH 65/67] add larger font for fuzzy face --- src/displayapp/UserApps.h | 12 +++++++++++- src/displayapp/fonts/CMakeLists.txt | 4 ++-- src/displayapp/fonts/fonts.json | 24 +++++++++++++++++++++++ src/displayapp/screens/WatchFaceFuzzy.cpp | 2 +- src/displayapp/screens/WatchFaceFuzzy.h | 2 ++ 5 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h index a786a8b3..1788e8dc 100644 --- a/src/displayapp/UserApps.h +++ b/src/displayapp/UserApps.h @@ -2,10 +2,20 @@ #include "displayapp/apps/Apps.h" #include "Controllers.h" +#include "displayapp/screens/Alarm.h" +#include "displayapp/screens/Dice.h" +#include "displayapp/screens/Timer.h" +#include "displayapp/screens/Twos.h" +#include "displayapp/screens/Tile.h" #include "displayapp/screens/ApplicationList.h" +#include "displayapp/screens/WatchFaceDigital.h" +#include "displayapp/screens/WatchFaceAnalog.h" +#include "displayapp/screens/WatchFaceCasioStyleG7710.h" +#include "displayapp/screens/WatchFaceInfineat.h" +#include "displayapp/screens/WatchFacePineTimeStyle.h" +#include "displayapp/screens/WatchFaceTerminal.h" #include "displayapp/screens/WatchFaceFuzzy.h" #include "displayapp/screens/WatchFaceSundial.h" -#include "displayapp/screens/WatchFaceDigital.h" namespace Pinetime { namespace Applications { diff --git a/src/displayapp/fonts/CMakeLists.txt b/src/displayapp/fonts/CMakeLists.txt index 0baecf4a..228c2e52 100644 --- a/src/displayapp/fonts/CMakeLists.txt +++ b/src/displayapp/fonts/CMakeLists.txt @@ -1,6 +1,6 @@ -set(FONTS jetbrains_mono_42 jetbrains_mono_76 jetbrains_mono_bold_20 +set(FONTS jetbrains_mono_42 jetbrains_mono_76 jetbrains_mono_bold_20 jetbrains_mono_bold_24 jetbrains_mono_extrabold_compressed lv_font_sys_48 - fontawesome_weathericons) + open_sans_light fontawesome_weathericons) find_program(LV_FONT_CONV "lv_font_conv" NO_CACHE REQUIRED HINTS "${CMAKE_SOURCE_DIR}/node_modules/.bin") message(STATUS "Using ${LV_FONT_CONV} to generate font files") diff --git a/src/displayapp/fonts/fonts.json b/src/displayapp/fonts/fonts.json index 1a07d8cf..f87e57dd 100644 --- a/src/displayapp/fonts/fonts.json +++ b/src/displayapp/fonts/fonts.json @@ -13,6 +13,20 @@ "bpp": 1, "size": 20 }, + "jetbrains_mono_bold_24": { + "sources": [ + { + "file": "Vulf_Mono-Italic.woff", + "range": "0x20-0x7e, 0xB0" + }, + { + "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" + } + ], + "bpp": 1, + "size": 26 + }, "jetbrains_mono_42": { "sources": [ { @@ -43,6 +57,16 @@ "bpp": 1, "size": 80 }, + "open_sans_light": { + "sources": [ + { + "file": "open_sans_light.ttf", + "symbols": "0123456789" + } + ], + "bpp": 1, + "size": 150 + }, "lv_font_sys_48": { "sources": [ { diff --git a/src/displayapp/screens/WatchFaceFuzzy.cpp b/src/displayapp/screens/WatchFaceFuzzy.cpp index 834da064..ff75de80 100644 --- a/src/displayapp/screens/WatchFaceFuzzy.cpp +++ b/src/displayapp/screens/WatchFaceFuzzy.cpp @@ -50,7 +50,7 @@ WatchFaceFuzzy::WatchFaceFuzzy(Controllers::DateTime& dateTimeController, lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); label_time = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); + lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_24); lv_label_set_recolor(label_time, true); lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); diff --git a/src/displayapp/screens/WatchFaceFuzzy.h b/src/displayapp/screens/WatchFaceFuzzy.h index 4c409e8b..1d30fbad 100644 --- a/src/displayapp/screens/WatchFaceFuzzy.h +++ b/src/displayapp/screens/WatchFaceFuzzy.h @@ -12,6 +12,8 @@ #include "utility/DirtyValue.h" #include "displayapp/apps/Apps.h" +extern lv_font_t jetbrains_mono_bold_24; + namespace Pinetime { namespace Controllers { class Settings; From f6a558854425aaf14bd70b829d198e1a0eedca51 Mon Sep 17 00:00:00 2001 From: Ryan Rix Date: Mon, 10 Jun 2024 20:19:43 -0700 Subject: [PATCH 66/67] add location setting and integrate more sundial code from willb --- .gitignore | 2 + src/CMakeLists.txt | 1 + .../datetime/DateTimeController.cpp | 2 +- src/components/settings/Settings.h | 23 ++ src/displayapp/DisplayApp.cpp | 4 + src/displayapp/apps/Apps.h.in | 1 + src/displayapp/screens/WatchFaceSundial.cpp | 285 ++++++++++++------ src/displayapp/screens/WatchFaceSundial.h | 96 +++--- .../screens/settings/SettingLocation.cpp | 69 +++++ .../screens/settings/SettingLocation.h | 31 ++ src/displayapp/screens/settings/Settings.h | 1 + src/displayapp/widgets/Counter.h | 11 + 12 files changed, 394 insertions(+), 132 deletions(-) create mode 100644 src/displayapp/screens/settings/SettingLocation.cpp create mode 100644 src/displayapp/screens/settings/SettingLocation.h diff --git a/.gitignore b/.gitignore index 81e49ae0..b61095df 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ src/arm-none-eabi # clangd .cache/ + +nRF5_SDK/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5922bca7..3bdd6549 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -416,6 +416,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingChimes.cpp displayapp/screens/settings/SettingShakeThreshold.cpp displayapp/screens/settings/SettingBluetooth.cpp + displayapp/screens/settings/SettingLocation.cpp ## Watch faces displayapp/screens/WatchFaceDigital.cpp diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index f0ccb5e5..5335a398 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -129,7 +129,7 @@ std::string DateTime::FormattedTime() { auto hour = Hours(); auto minute = Minutes(); // Return time as a string in 12- or 24-hour format - char buff[9]; + char buff[11]; if (settingsController.GetClockType() == ClockType::H12) { uint8_t hour12; const char* amPmStr; diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index e3be5256..f76be9ff 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -50,6 +50,12 @@ namespace Pinetime { int colorIndex = 0; }; + struct Location { + int16_t latitude; + int16_t longitude; + int8_t tzOffset; + }; + Settings(Pinetime::Controllers::FS& fs); Settings(const Settings&) = delete; @@ -275,6 +281,21 @@ namespace Pinetime { return settings.stepsGoal; }; + void SetLocation(Location loc) { + if ( + loc.latitude != settings.location.latitude || + loc.longitude != settings.location.longitude || + loc.tzOffset != settings.location.tzOffset + ) { + settingsChanged = true; + } + settings.location = loc; + }; + + Location GetLocation() const { + return settings.location; + }; + void SetBleRadioEnabled(bool enabled) { bleRadioEnabled = enabled; }; @@ -308,6 +329,8 @@ namespace Pinetime { uint16_t shakeWakeThreshold = 150; Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; + + Location location = {(int16_t)-123,(int16_t)44,(int8_t)-8}; }; SettingsData settings; diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 3fd34b3a..8b8378ab 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -49,6 +49,7 @@ #include "displayapp/screens/settings/SettingChimes.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" +#include "displayapp/screens/settings/SettingLocation.h" #include "libs/lv_conf.h" #include "UserApps.h" @@ -515,6 +516,9 @@ void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections directio case Apps::SettingSetDateTime: currentScreen = std::make_unique(this, dateTimeController, settingsController); break; + case Apps::SettingLocation: + currentScreen = std::make_unique(settingsController); + break; case Apps::SettingChimes: currentScreen = std::make_unique(settingsController); break; diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in index 6201da6b..a1421af8 100644 --- a/src/displayapp/apps/Apps.h.in +++ b/src/displayapp/apps/Apps.h.in @@ -39,6 +39,7 @@ namespace Pinetime { SettingWakeUp, SettingSteps, SettingSetDateTime, + SettingLocation, SettingChimes, SettingShakeThreshold, SettingBluetooth, diff --git a/src/displayapp/screens/WatchFaceSundial.cpp b/src/displayapp/screens/WatchFaceSundial.cpp index b99204b0..1999cc78 100644 --- a/src/displayapp/screens/WatchFaceSundial.cpp +++ b/src/displayapp/screens/WatchFaceSundial.cpp @@ -6,6 +6,7 @@ #include "displayapp/screens/NotificationIcon.h" #include "displayapp/screens/Symbols.h" #include "displayapp/screens/WeatherSymbols.h" +#include "displayapp/InfiniTimeTheme.h" #include "components/battery/BatteryController.h" #include "components/ble/BleController.h" #include "components/ble/NotificationManager.h" @@ -17,95 +18,153 @@ using namespace Pinetime::Applications::Screens; -// namespace { -// int16_t HourLength = 70; -// constexpr int16_t MinuteLength = 90; -// constexpr int16_t SecondLength = 110; -// constexpr int16_t SunDialVerticalOffset = 40; +namespace { + int16_t HourLength = 70; + constexpr int16_t MinuteLength = 90; + constexpr int16_t SecondLength = 110; + constexpr int16_t SunDialVerticalOffset = 40; -// // sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor -// const auto LV_TRIG_SCALE = _lv_trigo_sin(90); -// const lv_color_t DARK_GRAY = lv_color_make(48, 48, 48); -// const lv_color_t DARK_ORANGE = lv_color_make(48, 26, 0); + // sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor + const auto LV_TRIG_SCALE = _lv_trigo_sin(90); + const lv_color_t DARK_GRAY = lv_color_make(48, 48, 48); + const lv_color_t DARK_ORANGE = lv_color_make(48, 26, 0); -// int16_t Cosine(int16_t angle) { -// return _lv_trigo_sin(angle + 90); -// } + int16_t Cosine(int16_t angle) { + return _lv_trigo_sin(angle + 90); + } -// int16_t Sine(int16_t angle) { -// return _lv_trigo_sin(angle); -// } + int16_t Sine(int16_t angle) { + return _lv_trigo_sin(angle); + } -// int16_t CoordinateXRelocate(int16_t x) { -// return (x + LV_HOR_RES / 2); -// } + int16_t CoordinateXRelocate(int16_t x) { + return (x + LV_HOR_RES / 2); + } -// int16_t CoordinateYRelocate(int16_t y) { -// return std::abs(y - LV_HOR_RES / 2); -// } -// lv_point_t CoordinateRelocate(int16_t radius, int16_t angle) { -// return lv_point_t {.x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), -// .y = CoordinateYRelocate(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE)}; -// } + int16_t CoordinateYRelocateSundial(int16_t y) { + return std::abs(y - SunDialVerticalOffset); + } -// int16_t CoordinateYRelocateSundial(int16_t y) { -// return std::abs(y - SunDialVerticalOffset); -// } + lv_point_t CoordinateRelocateSundial(int16_t radius, int16_t angle) { + return lv_point_t {.x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), + .y = CoordinateYRelocateSundial(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE)}; + } -// lv_point_t CoordinateRelocateSundial(int16_t radius, int16_t angle) { -// return lv_point_t {.x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), -// .y = CoordinateYRelocateSundial(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE)}; -// } - -// } +} WatchFaceSundial::WatchFaceSundial(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Controllers::SimpleWeatherService& weatherService) + Controllers::Settings& settingsController) : currentDateTime {{}}, dateTimeController {dateTimeController}, notificationManager {notificationManager}, - settingsController {settingsController}, - heartRateController {heartRateController}, - motionController {motionController}, - weatherService {weatherService}, - statusIcons(batteryController, bleController) { + settingsController {settingsController} +{ + // minor_scales = lv_linemeter_create(lv_scr_act(), nullptr); + // lv_linemeter_set_scale(minor_scales, 300, 51); + // lv_linemeter_set_angle_offset(minor_scales, 180); + // lv_obj_set_size(minor_scales, 240, 240); + // lv_obj_align(minor_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + // lv_obj_set_style_local_bg_opa(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + // lv_obj_set_style_local_scale_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + // lv_obj_set_style_local_scale_end_line_width(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 1); + // lv_obj_set_style_local_scale_end_color(minor_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); - statusIcons.Create(); + // major_scales = lv_linemeter_create(lv_scr_act(), nullptr); + // lv_linemeter_set_scale(major_scales, 300, 11); + // lv_linemeter_set_angle_offset(major_scales, 180); + // lv_obj_set_size(major_scales, 240, 240); + // lv_obj_align(major_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + // lv_obj_set_style_local_bg_opa(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + // lv_obj_set_style_local_scale_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 6); + // lv_obj_set_style_local_scale_end_line_width(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + // lv_obj_set_style_local_scale_end_color(major_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - weatherIcon = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - lv_obj_set_style_local_text_font(weatherIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &fontawesome_weathericons); - lv_label_set_text(weatherIcon, ""); - lv_obj_align(weatherIcon, nullptr, LV_ALIGN_IN_TOP_MID, -20, 50); - lv_obj_set_auto_realign(weatherIcon, true); + // large_scales = lv_linemeter_create(lv_scr_act(), nullptr); + // lv_linemeter_set_scale(large_scales, 180, 3); + // lv_linemeter_set_angle_offset(large_scales, 180); + // lv_obj_set_size(large_scales, 240, 240); + // lv_obj_align(large_scales, nullptr, LV_ALIGN_CENTER, 0, 0); + // lv_obj_set_style_local_bg_opa(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + // lv_obj_set_style_local_scale_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 20); + // lv_obj_set_style_local_scale_end_line_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); + // lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); - temperature = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_color(temperature, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - lv_label_set_text(temperature, ""); - lv_obj_align(temperature, nullptr, LV_ALIGN_IN_TOP_MID, 20, 50); + // twelve = lv_label_create(lv_scr_act(), nullptr); + // lv_label_set_align(twelve, LV_LABEL_ALIGN_CENTER); + // lv_label_set_text_static(twelve, "12"); + // lv_obj_set_pos(twelve, 110, 10); + // lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); - label_date = lv_label_create(lv_scr_act(), nullptr); - lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); - lv_obj_set_style_local_text_color(label_date, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); + one = lv_label_create(lv_scr_act(), NULL); + lv_label_set_align(one, LV_LABEL_ALIGN_LEFT); + lv_label_set_text(one, "I"); + lv_obj_align(one, NULL, LV_ALIGN_IN_TOP_LEFT, 20, SunDialVerticalOffset-20); + lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); - label_time = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(label_time, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - lv_label_set_recolor(label_time, true); - lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, 0); + notificationIcon = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(notificationIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_LIME); + lv_label_set_text_static(notificationIcon, NotificationIcon::GetIcon(false)); + lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 0); + + // Date - Day / Week day + label_date_day = lv_label_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_ORANGE); + lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), dateTimeController.Day()); + lv_label_set_align(label_date_day, LV_LABEL_ALIGN_CENTER); + lv_obj_align(label_date_day, nullptr, LV_ALIGN_CENTER, 50, 0); + + minute_body = lv_line_create(lv_scr_act(), nullptr); + minute_body_trace = lv_line_create(lv_scr_act(), nullptr); + hour_body = lv_line_create(lv_scr_act(), nullptr); + hour_body_trace = lv_line_create(lv_scr_act(), nullptr); + second_body = lv_line_create(lv_scr_act(), nullptr); + + lv_style_init(&second_line_style); + lv_style_set_line_width(&second_line_style, LV_STATE_DEFAULT, 3); + lv_style_set_line_color(&second_line_style, LV_STATE_DEFAULT, LV_COLOR_RED); + lv_style_set_line_rounded(&second_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(second_body, LV_LINE_PART_MAIN, &second_line_style); + + lv_style_init(&minute_line_style); + lv_style_set_line_width(&minute_line_style, LV_STATE_DEFAULT, 7); + lv_style_set_line_color(&minute_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_rounded(&minute_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(minute_body, LV_LINE_PART_MAIN, &minute_line_style); + + lv_style_init(&minute_line_style_trace); + lv_style_set_line_width(&minute_line_style_trace, LV_STATE_DEFAULT, 3); + lv_style_set_line_color(&minute_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_rounded(&minute_line_style_trace, LV_STATE_DEFAULT, false); + lv_obj_add_style(minute_body_trace, LV_LINE_PART_MAIN, &minute_line_style_trace); + + lv_style_init(&hour_line_style); + lv_style_set_line_width(&hour_line_style, LV_STATE_DEFAULT, 7); + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_rounded(&hour_line_style, LV_STATE_DEFAULT, true); + lv_obj_add_style(hour_body, LV_LINE_PART_MAIN, &hour_line_style); + + lv_style_init(&hour_line_style_trace); + lv_style_set_line_width(&hour_line_style_trace, LV_STATE_DEFAULT, 3); + lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_rounded(&hour_line_style_trace, LV_STATE_DEFAULT, false); + lv_obj_add_style(hour_body_trace, LV_LINE_PART_MAIN, &hour_line_style_trace); taskRefresh = lv_task_create(RefreshTaskCallback, LV_DISP_DEF_REFR_PERIOD, LV_TASK_PRIO_MID, this); + UpdateClock(); Refresh(); } WatchFaceSundial::~WatchFaceSundial() { lv_task_del(taskRefresh); + + lv_style_reset(&hour_line_style); + lv_style_reset(&hour_line_style_trace); + lv_style_reset(&minute_line_style); + lv_style_reset(&minute_line_style_trace); + lv_style_reset(&second_line_style); + lv_obj_clean(lv_scr_act()); } @@ -113,37 +172,85 @@ void WatchFaceSundial::Refresh() { currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); if (currentDateTime.IsUpdated()) { currentDateTime = std::chrono::time_point_cast(dateTimeController.CurrentDateTime()); + UpdateClock(); if (currentDate.IsUpdated()) { - uint16_t year = dateTimeController.Year(); - uint8_t day = dateTimeController.Day(); - lv_label_set_text_fmt(label_date, - "%s %d %s %d", - dateTimeController.DayOfWeekShortToString(), - day, - dateTimeController.MonthShortToString(), - year); - lv_obj_realign(label_date); + char const* MonthsString[] = {"--", "IANUARIUS","FEBRUARIUS","MARTIUS","APRILIS","MARTIUSIUNIUS","QUINTILIS","SEXTILIS","SEPTEMBER","OCTOBER","NOVEMBER","DECEMBER"}; + char const* DaysString[] = {"--", "LUNAE", "MARTIS", "MERCURII", "IOVIS", "VENERIS", "SATURNI", "SOLIS"}; + char const* RomanNumeralsString[] = {"--", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"}; + lv_label_set_text_fmt(label_date_day, "%s\n%s %s", + DaysString[static_cast(dateTimeController.DayOfWeek())], + RomanNumeralsString[static_cast(dateTimeController.Day())], + MonthsString[static_cast(dateTimeController.Month())]); + lv_obj_align(label_date_day, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, -20); } } + +} - currentWeather = weatherService.Current(); - if (currentWeather.IsUpdated()) { - auto optCurrentWeather = currentWeather.Get(); - if (optCurrentWeather) { - int16_t temp = optCurrentWeather->temperature; - char tempUnit = 'C'; - if (settingsController.GetWeatherFormat() == Controllers::Settings::WeatherFormat::Imperial) { - temp = Controllers::SimpleWeatherService::CelsiusToFahrenheit(temp); - tempUnit = 'F'; +void WatchFaceSundial::UpdateClock() { + uint8_t hour = dateTimeController.Hours(); + uint8_t minute = dateTimeController.Minutes(); + + if (sHour != hour || sMinute != minute) { + // sun.setPosition(settings.lat.toFloat(), settings.lon.toFloat(), settings.gmtOffset / 3600); + sun.setPosition((float)location.latitude, (float)location.longitude, location.tzOffset); + + //from minutes past midnight + sun.setCurrentDate(dateTimeController.Year(), static_cast(dateTimeController.Month())+1, dateTimeController.Day()); + sun.setTZOffset(location.tzOffset); + + minutesSunrise = sun.calcSunrise(); //360; + minutesSunset = sun.calcSunset(); //1080; + minutesDaytime = (minutesSunset - minutesSunrise); + minutesNighttime = (1440 - minutesDaytime); + + minutesBeforeSunset = minutesSunset - (hour * 60 + minute); // i.e.zero degrees + HourLength = 90; // sundial hand length + + int16_t hourAngle; + + if(minutesBeforeSunset > 0 && minutesBeforeSunset < minutesDaytime) { // day (after sunrise) + hourAngle = 180.0 * minutesBeforeSunset / minutesDaytime + 90; + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); + lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + } else { // night (before sunrise or after sunset) + lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, DARK_GRAY); + lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, DARK_GRAY); + lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_ORANGE); + lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); + + if(minutesBeforeSunset > minutesDaytime) { // before sunrise + hourAngle = 180.0 * (minutesBeforeSunset - minutesDaytime) / minutesNighttime + 90; + } else { // after sunset + hourAngle = 180 + 180.0 * minutesBeforeSunset / minutesNighttime + 90; } - temp = temp / 100 + (temp % 100 >= 50 ? 1 : 0); - lv_label_set_text_fmt(temperature, "%d°%c", temp, tempUnit); - lv_label_set_text(weatherIcon, Symbols::GetSymbol(optCurrentWeather->iconId)); - } else { - lv_label_set_text_static(temperature, ""); - lv_label_set_text(weatherIcon, ""); } - lv_obj_realign(temperature); - lv_obj_realign(weatherIcon); + /*NRF_LOG_INFO("a: %d, la: %f, lo: %f, ri: %d, se: %d, be: %d", + hourAngle, + (float)location.latitude, + (float)location.longitude, + minutesSunrise, + minutesSunset, + minutesBeforeSunset);*/ + + sHour = hour; + sMinute = minute; + + printf("<: %d %d @%d/%d+/-%d\n", hour, minute, location.latitude, location.longitude, location.tzOffset); + printf("@: %d %d:%d %d:%d\n", + minutesBeforeSunset, + minutesSunrise/60, minutesSunrise % 60, + minutesSunset/60, minutesSunset % 60); + + hour_point_trace[0] = CoordinateRelocateSundial(HourLength*.75, hourAngle); + hour_point_trace[1] = CoordinateRelocateSundial(HourLength, hourAngle); + + hour_point[0] = CoordinateRelocateSundial(0, hourAngle); + hour_point[1] = CoordinateRelocateSundial(HourLength*.75, hourAngle); + + lv_line_set_points(hour_body, hour_point, 2); + lv_line_set_points(hour_body_trace, hour_point_trace, 2); } } diff --git a/src/displayapp/screens/WatchFaceSundial.h b/src/displayapp/screens/WatchFaceSundial.h index 9c02fdfe..b5721585 100644 --- a/src/displayapp/screens/WatchFaceSundial.h +++ b/src/displayapp/screens/WatchFaceSundial.h @@ -6,11 +6,12 @@ #include #include "displayapp/screens/Screen.h" #include "components/datetime/DateTimeController.h" -#include "components/ble/SimpleWeatherService.h" +#include "components/battery/BatteryController.h" #include "components/ble/BleController.h" -#include "displayapp/widgets/StatusIcons.h" +#include "components/ble/NotificationManager.h" +#include "displayapp/screens/BatteryIcon.h" #include "utility/DirtyValue.h" -#include "displayapp/apps/Apps.h" +#include "sunset/src/sunset.h" namespace Pinetime { namespace Controllers { @@ -18,8 +19,6 @@ namespace Pinetime { class Battery; class Ble; class NotificationManager; - class HeartRateController; - class MotionController; } namespace Applications { @@ -28,50 +27,68 @@ namespace Pinetime { class WatchFaceSundial : public Screen { public: WatchFaceSundial(Controllers::DateTime& dateTimeController, - const Controllers::Battery& batteryController, - const Controllers::Ble& bleController, - Controllers::NotificationManager& notificationManager, - Controllers::Settings& settingsController, - Controllers::HeartRateController& heartRateController, - Controllers::MotionController& motionController, - Controllers::SimpleWeatherService& weather); + Controllers::NotificationManager& notificationManager, + Controllers::Settings& settingsController); + ~WatchFaceSundial() override; void Refresh() override; private: - uint8_t displayedHour = -1; - uint8_t displayedMinute = -1; + uint8_t sHour, sMinute, sSecond; - Utility::DirtyValue> currentDateTime {}; - Utility::DirtyValue stepCount {}; - Utility::DirtyValue heartbeat {}; - Utility::DirtyValue heartbeatRunning {}; - Utility::DirtyValue notificationState {}; - Utility::DirtyValue> currentWeather {}; + Utility::DirtyValue batteryPercentRemaining {0}; + Utility::DirtyValue isCharging {}; + Utility::DirtyValue bleState {}; + Utility::DirtyValue> currentDateTime; + Utility::DirtyValue notificationState {false}; + using days = std::chrono::duration>; // TODO: days is standard in c++20 + Utility::DirtyValue> currentDate; - Utility::DirtyValue> currentDate; + lv_obj_t* major_scales; + lv_obj_t* one; + lv_obj_t* twelve; - lv_obj_t* label_time; - lv_obj_t* label_time_ampm; - lv_obj_t* label_date; - lv_obj_t* heartbeatIcon; - lv_obj_t* heartbeatValue; - lv_obj_t* stepIcon; - lv_obj_t* stepValue; + lv_obj_t* hour_body; + lv_obj_t* hour_body_trace; + lv_obj_t* minute_body; + lv_obj_t* minute_body_trace; + lv_obj_t* second_body; + + lv_point_t hour_point[2]; + lv_point_t hour_point_trace[2]; + lv_point_t minute_point[2]; + lv_point_t minute_point_trace[2]; + lv_point_t second_point[2]; + + lv_style_t hour_line_style; + lv_style_t hour_line_style_trace; + lv_style_t minute_line_style; + lv_style_t minute_line_style_trace; + lv_style_t second_line_style; + + lv_obj_t* label_date_day; + lv_obj_t* plugIcon; lv_obj_t* notificationIcon; - lv_obj_t* weatherIcon; - lv_obj_t* temperature; + lv_obj_t* bleIcon; - Controllers::DateTime& dateTimeController; + Controllers::Settings::Location location; + SunSet sun; + int16_t minutesSunrise; + int16_t minutesSunset; + int16_t minutesDaytime; + int16_t minutesNighttime; + int16_t minutesBeforeSunset; + + const Controllers::DateTime& dateTimeController; Controllers::NotificationManager& notificationManager; Controllers::Settings& settingsController; - Controllers::HeartRateController& heartRateController; - Controllers::MotionController& motionController; - Controllers::SimpleWeatherService& weatherService; + + void drawWatchFaceModeNight(); + void UpdateClock(); + void SetBatteryIcon(); lv_task_t* taskRefresh; - Widgets::StatusIcons statusIcons; }; } @@ -82,13 +99,8 @@ namespace Pinetime { static Screens::Screen* Create(AppControllers& controllers) { return new Screens::WatchFaceSundial(controllers.dateTimeController, - controllers.batteryController, - controllers.bleController, - controllers.notificationManager, - controllers.settingsController, - controllers.heartRateController, - controllers.motionController, - *controllers.weatherController); + controllers.notificationManager, + controllers.settingsController); }; static bool IsAvailable(Pinetime::Controllers::FS& /*filesystem*/) { diff --git a/src/displayapp/screens/settings/SettingLocation.cpp b/src/displayapp/screens/settings/SettingLocation.cpp new file mode 100644 index 00000000..4de374b5 --- /dev/null +++ b/src/displayapp/screens/settings/SettingLocation.cpp @@ -0,0 +1,69 @@ +#include "displayapp/screens/settings/SettingLocation.h" +#include +#include +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/Symbols.h" +#include "components/settings/Settings.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Screens; + +namespace { + constexpr int16_t POS_Y_TEXT = 25; + + void ValueChangedHandler(void* userData) { + auto* screen = static_cast(userData); + screen->UpdateScreen(); + } +} + +SettingLocation::SettingLocation(Pinetime::Controllers::Settings& settingsController) + : settingsController {settingsController} { + + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_text_static(title, "Set location\n(lat/long/tz)"); + lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); + lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 15, 15); + + 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_ORANGE); + lv_label_set_text_static(icon, Symbols::map); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + + Controllers::Settings::Location loc = settingsController.GetLocation(); + + latCounter.Create(); + latCounter.SetWidth(80); + latCounter.SetValue(loc.latitude); + lv_obj_align(latCounter.GetObject(), nullptr, LV_ALIGN_CENTER, -90, POS_Y_TEXT); + latCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + longCounter.Create(); + longCounter.SetWidth(110); + longCounter.SetValue(loc.longitude); + lv_obj_align(longCounter.GetObject(), nullptr, LV_ALIGN_CENTER, -5, POS_Y_TEXT); + longCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + tzCounter.Create(); + tzCounter.SetWidth(60); + tzCounter.SetValue(loc.tzOffset); + lv_obj_align(tzCounter.GetObject(), nullptr, LV_ALIGN_CENTER, 75, POS_Y_TEXT); + tzCounter.SetValueChangedEventCallback(this, ValueChangedHandler); + + UpdateScreen(); +} + +SettingLocation::~SettingLocation() { + lv_obj_clean(lv_scr_act()); + settingsController.SaveSettings(); +} + +void SettingLocation::UpdateScreen() { + Controllers::Settings::Location loc = { + latitude: (int16_t)latCounter.GetValue(), + longitude: (int16_t)longCounter.GetValue(), + tzOffset: (int8_t)tzCounter.GetValue(), + }; + settingsController.SetLocation(loc); +} diff --git a/src/displayapp/screens/settings/SettingLocation.h b/src/displayapp/screens/settings/SettingLocation.h new file mode 100644 index 00000000..9596d12f --- /dev/null +++ b/src/displayapp/screens/settings/SettingLocation.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include "components/datetime/DateTimeController.h" +#include "components/settings/Settings.h" +#include "displayapp/widgets/Counter.h" +#include "displayapp/screens/Screen.h" +#include "displayapp/widgets/DotIndicator.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingLocation : public Screen { + public: + SettingLocation(Pinetime::Controllers::Settings& settingsController); + ~SettingLocation() override; + + void UpdateScreen(); + + private: + Controllers::Settings& settingsController; + + Widgets::Counter latCounter = Widgets::Counter(-90, 90, jetbrains_mono_42); + Widgets::Counter longCounter = Widgets::Counter(-180, 180, jetbrains_mono_42); + Widgets::Counter tzCounter = Widgets::Counter(-12, 12, jetbrains_mono_42); + }; + } + } +} diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index a21b4ccd..4e131938 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -39,6 +39,7 @@ namespace Pinetime { {Symbols::shoe, "Steps", Apps::SettingSteps}, {Symbols::clock, "Date&Time", Apps::SettingSetDateTime}, + {Symbols::map, "Location", Apps::SettingLocation}, {Symbols::cloudSunRain, "Weather", Apps::SettingWeatherFormat}, {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, diff --git a/src/displayapp/widgets/Counter.h b/src/displayapp/widgets/Counter.h index 825860b8..2deb3a99 100644 --- a/src/displayapp/widgets/Counter.h +++ b/src/displayapp/widgets/Counter.h @@ -18,6 +18,15 @@ namespace Pinetime { void EnableMonthMode(); void SetMax(int newMax); void SetValueChangedEventCallback(void* userData, void (*handler)(void* userData)); + void SetWidth(uint8_t width) { + lv_obj_set_size(counterContainer, width, containerHeight); + lv_obj_set_size(upBtn, width, btnHeight); + lv_obj_set_size(downBtn, width, btnHeight); + linePoints[0] = {0, 0}; + linePoints[1] = {width, 0}; + lv_line_set_points(upperLine, linePoints, 2); + lv_line_set_points(lowerLine, linePoints, 2); + } int GetValue() const { return value; @@ -42,6 +51,8 @@ namespace Pinetime { int max; int value; const int leadingZeroCount; + uint8_t containerHeight; + static constexpr uint8_t btnHeight = 50; bool twelveHourMode = false; bool monthMode = false; lv_font_t& font; From 49c801b82768346fe34906dbc43639feebcfdaf9 Mon Sep 17 00:00:00 2001 From: Will Bradley Date: Tue, 11 Jun 2024 21:27:26 -0700 Subject: [PATCH 67/67] Fix location counter width, font, and lat/lng bugs --- src/components/settings/Settings.h | 2 +- src/displayapp/screens/WatchFaceSundial.cpp | 19 +++++++++++-------- .../screens/settings/SettingLocation.cpp | 13 +++++++------ .../screens/settings/SettingLocation.h | 6 +++--- src/displayapp/widgets/Counter.h | 9 --------- 5 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index f76be9ff..96b8f0d0 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -330,7 +330,7 @@ namespace Pinetime { Controllers::BrightnessController::Levels brightLevel = Controllers::BrightnessController::Levels::Medium; - Location location = {(int16_t)-123,(int16_t)44,(int8_t)-8}; + Location location = {(int16_t)44,(int16_t)-123,(int8_t)-8}; }; SettingsData settings; diff --git a/src/displayapp/screens/WatchFaceSundial.cpp b/src/displayapp/screens/WatchFaceSundial.cpp index 1999cc78..7bac1ff9 100644 --- a/src/displayapp/screens/WatchFaceSundial.cpp +++ b/src/displayapp/screens/WatchFaceSundial.cpp @@ -91,11 +91,11 @@ WatchFaceSundial::WatchFaceSundial(Controllers::DateTime& dateTimeController, // lv_obj_set_style_local_scale_end_line_width(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, 4); // lv_obj_set_style_local_scale_end_color(large_scales, LV_LINEMETER_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); - // twelve = lv_label_create(lv_scr_act(), nullptr); - // lv_label_set_align(twelve, LV_LABEL_ALIGN_CENTER); - // lv_label_set_text_static(twelve, "12"); - // lv_obj_set_pos(twelve, 110, 10); - // lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); + twelve = lv_label_create(lv_scr_act(), nullptr); + lv_label_set_align(twelve, LV_LABEL_ALIGN_RIGHT); + lv_label_set_text_static(twelve, "XII"); + lv_obj_align(twelve, NULL, LV_ALIGN_IN_TOP_RIGHT, -20, SunDialVerticalOffset-20); + lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); one = lv_label_create(lv_scr_act(), NULL); lv_label_set_align(one, LV_LABEL_ALIGN_LEFT); @@ -190,6 +190,7 @@ void WatchFaceSundial::Refresh() { void WatchFaceSundial::UpdateClock() { uint8_t hour = dateTimeController.Hours(); uint8_t minute = dateTimeController.Minutes(); + location = settingsController.GetLocation(); if (sHour != hour || sMinute != minute) { // sun.setPosition(settings.lat.toFloat(), settings.lon.toFloat(), settings.gmtOffset / 3600); @@ -215,11 +216,13 @@ void WatchFaceSundial::UpdateClock() { lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_ORANGE); lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); } else { // night (before sunrise or after sunset) lv_style_set_line_color(&hour_line_style, LV_STATE_DEFAULT, DARK_GRAY); lv_style_set_line_color(&hour_line_style_trace, LV_STATE_DEFAULT, DARK_GRAY); lv_obj_set_style_local_text_color(label_date_day, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_ORANGE); lv_obj_set_style_local_text_color(one, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); + lv_obj_set_style_local_text_color(twelve, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, DARK_GRAY); if(minutesBeforeSunset > minutesDaytime) { // before sunrise hourAngle = 180.0 * (minutesBeforeSunset - minutesDaytime) / minutesNighttime + 90; @@ -238,11 +241,11 @@ void WatchFaceSundial::UpdateClock() { sHour = hour; sMinute = minute; - printf("<: %d %d @%d/%d+/-%d\n", hour, minute, location.latitude, location.longitude, location.tzOffset); - printf("@: %d %d:%d %d:%d\n", + printf("H%d:%d lat%f lng%f z%d\n", hour, minute, (float)location.latitude, (float)location.longitude, location.tzOffset); + printf("%d before sunset, sunrise at %d:%d sunset at %d:%d angle %d\n", minutesBeforeSunset, minutesSunrise/60, minutesSunrise % 60, - minutesSunset/60, minutesSunset % 60); + minutesSunset/60, minutesSunset % 60, hourAngle); hour_point_trace[0] = CoordinateRelocateSundial(HourLength*.75, hourAngle); hour_point_trace[1] = CoordinateRelocateSundial(HourLength, hourAngle); diff --git a/src/displayapp/screens/settings/SettingLocation.cpp b/src/displayapp/screens/settings/SettingLocation.cpp index 4de374b5..45909fac 100644 --- a/src/displayapp/screens/settings/SettingLocation.cpp +++ b/src/displayapp/screens/settings/SettingLocation.cpp @@ -9,6 +9,9 @@ using namespace Pinetime::Applications::Screens; namespace { + constexpr int16_t POS_X_LAT = -80; + constexpr int16_t POS_X_LONG = 0; + constexpr int16_t POS_X_TZ = 80; constexpr int16_t POS_Y_TEXT = 25; void ValueChangedHandler(void* userData) { @@ -27,6 +30,7 @@ SettingLocation::SettingLocation(Pinetime::Controllers::Settings& settingsContro 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_ORANGE); + lv_label_set_text_static(icon, Symbols::map); lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); @@ -34,21 +38,18 @@ SettingLocation::SettingLocation(Pinetime::Controllers::Settings& settingsContro Controllers::Settings::Location loc = settingsController.GetLocation(); latCounter.Create(); - latCounter.SetWidth(80); latCounter.SetValue(loc.latitude); - lv_obj_align(latCounter.GetObject(), nullptr, LV_ALIGN_CENTER, -90, POS_Y_TEXT); + lv_obj_align(latCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_LAT, POS_Y_TEXT); latCounter.SetValueChangedEventCallback(this, ValueChangedHandler); longCounter.Create(); - longCounter.SetWidth(110); longCounter.SetValue(loc.longitude); - lv_obj_align(longCounter.GetObject(), nullptr, LV_ALIGN_CENTER, -5, POS_Y_TEXT); + lv_obj_align(longCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_LONG, POS_Y_TEXT); longCounter.SetValueChangedEventCallback(this, ValueChangedHandler); tzCounter.Create(); - tzCounter.SetWidth(60); tzCounter.SetValue(loc.tzOffset); - lv_obj_align(tzCounter.GetObject(), nullptr, LV_ALIGN_CENTER, 75, POS_Y_TEXT); + lv_obj_align(tzCounter.GetObject(), nullptr, LV_ALIGN_CENTER, POS_X_TZ, POS_Y_TEXT); tzCounter.SetValueChangedEventCallback(this, ValueChangedHandler); UpdateScreen(); diff --git a/src/displayapp/screens/settings/SettingLocation.h b/src/displayapp/screens/settings/SettingLocation.h index 9596d12f..9d977ac5 100644 --- a/src/displayapp/screens/settings/SettingLocation.h +++ b/src/displayapp/screens/settings/SettingLocation.h @@ -22,9 +22,9 @@ namespace Pinetime { private: Controllers::Settings& settingsController; - Widgets::Counter latCounter = Widgets::Counter(-90, 90, jetbrains_mono_42); - Widgets::Counter longCounter = Widgets::Counter(-180, 180, jetbrains_mono_42); - Widgets::Counter tzCounter = Widgets::Counter(-12, 12, jetbrains_mono_42); + Widgets::Counter latCounter = Widgets::Counter(-90, 90, jetbrains_mono_bold_20); + Widgets::Counter longCounter = Widgets::Counter(-180, 180, jetbrains_mono_bold_20); + Widgets::Counter tzCounter = Widgets::Counter(-12, 12, jetbrains_mono_bold_20); }; } } diff --git a/src/displayapp/widgets/Counter.h b/src/displayapp/widgets/Counter.h index 2deb3a99..f075869b 100644 --- a/src/displayapp/widgets/Counter.h +++ b/src/displayapp/widgets/Counter.h @@ -18,15 +18,6 @@ namespace Pinetime { void EnableMonthMode(); void SetMax(int newMax); void SetValueChangedEventCallback(void* userData, void (*handler)(void* userData)); - void SetWidth(uint8_t width) { - lv_obj_set_size(counterContainer, width, containerHeight); - lv_obj_set_size(upBtn, width, btnHeight); - lv_obj_set_size(downBtn, width, btnHeight); - linePoints[0] = {0, 0}; - linePoints[1] = {width, 0}; - lv_line_set_points(upperLine, linePoints, 2); - lv_line_set_points(lowerLine, linePoints, 2); - } int GetValue() const { return value;