diff options
158 files changed, 1675 insertions, 1299 deletions
diff --git a/.clang-format b/.clang-format index dec58189..b5c102d5 100644 --- a/.clang-format +++ b/.clang-format @@ -59,6 +59,8 @@ Cpp11BracedListStyle: true DeriveLineEnding: false DerivePointerAlignment: false DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock ExperimentalAutoDetectBinPacking: true FixNamespaceComments: false ForEachMacros: @@ -78,6 +80,7 @@ IncludeCategories: SortPriority: 0 IncludeIsMainRegex: '(Test)?$' IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false IndentCaseLabels: true IndentGotoLabels: true IndentPPDirectives: BeforeHash @@ -92,6 +95,7 @@ MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: All +PackConstructorInitializers: NextLine PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 @@ -101,13 +105,16 @@ PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 60 PointerAlignment: Left +ReferenceAlignment: Pointer ReflowComments: true +SeparateDefinitionBlocks: Always SortIncludes: false SortUsingDeclarations: true SpaceAfterCStyleCast: true SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false SpaceBeforeCpp11BracedList: true SpaceBeforeCtorInitializerColon: true SpaceBeforeInheritanceColon: true @@ -123,7 +130,7 @@ SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false SpaceBeforeSquareBrackets: false -# Needs new Clang: SpaceAroundPointerQualifiers: After +SpaceAroundPointerQualifiers: Default Standard: Latest StatementMacros: - Q_UNUSED diff --git a/.clang-tidy b/.clang-tidy index 88ca6c54..f1ddc572 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,14 +1,15 @@ -Checks: '*, - -altera-unroll-loops, - -llvmlibc-callee-namespace, - -llvmlibc-implementation-in-namespace, - -llvmlibc-restrict-system-libc-headers, - -llvm-header-guard, - -llvm-namespace-comment, - -google-build-using-namespace, - -google-runtime-int, - -google-readability-namespace-comments, - -fuchsia-statically-constructed-objects, +Checks: 'bugprone-*, + cert-*, + cppcoreguidelines-*, + hicpp-*, + misc-*, + modernize-*, + performance-*, + portability-*, + readability-*, + fuchsia-trailing-return, + -cert-err58-cpp, + -cert-err60-cpp, -cppcoreguidelines-prefer-member-initializer, -cppcoreguidelines-pro-bounds-array-to-pointer-decay, -cppcoreguidelines-pro-bounds-constant-array-index, @@ -20,10 +21,6 @@ Checks: '*, -cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-avoid-c-arrays, -cppcoreguidelines-special-member-functions, - -readability-magic-numbers, - -readability-uppercase-literal-suffix, - -modernize-use-trailing-return-type, - -modernize-avoid-c-arrays, -hicpp-avoid-c-arrays, -hicpp-uppercase-literal-suffix, -hicpp-vararg, @@ -31,8 +28,10 @@ Checks: '*, -hicpp-no-array-decay, -hicpp-signed-bitwise, -hicpp-special-member-functions, - -cert-err58-cpp, - -cert-err60-cpp' + -modernize-use-trailing-return-type, + -modernize-avoid-c-arrays, + -readability-magic-numbers, + -readability-uppercase-literal-suffix' CheckOptions: - key: readability-function-cognitive-complexity.Threshold value: 100 diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh index 3d8aecbf..b4f080dd 100644 --- a/.devcontainer/build.sh +++ b/.devcontainer/build.sh @@ -35,6 +35,8 @@ main() { 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() { @@ -74,4 +76,12 @@ CmakeBuild() { fi } -[[ $SOURCED == "false" ]] && main "$@" || echo "Sourced!"
\ No newline at end of file +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/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml index 6e9f6606..4c85742a 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yaml +++ b/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -1,15 +1,11 @@ name: Bug Report -description: File a bug report +description: Something is broken labels: ["bug"] body: - - type: markdown - attributes: - value: | - **Thanks for taking the time to fill out this bug report!** - *Please, before opening a bug report, check if similar issues already exist. In that case, use those issues to provide your feedback instead.* - type: checkboxes attributes: label: Verification + description: Before submitting a bug report, check if similar issues already exist and use those issues to provide your feedback instead. options: - label: I searched for similar bug reports and found none was relevant. required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e5a555fd..5db3c45e 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: true contact_links: + - name: Feature request + url: https://github.com/InfiniTimeOrg/InfiniTime/discussions/categories/ideas + about: Request a feature or share your ideas - name: PineTime community chat (Matrix) url: https://app.element.io/#/room/#pinetime:matrix.org about: Please ask questions about PineTime here. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yaml b/.github/ISSUE_TEMPLATE/feature-request.yaml deleted file mode 100644 index a35bbfed..00000000 --- a/.github/ISSUE_TEMPLATE/feature-request.yaml +++ /dev/null @@ -1,41 +0,0 @@ -name: Feature Request -description: File a feature request -labels: ["feature request"] -body: - - type: markdown - attributes: - value: | - **Thanks for taking the time to fill out this feature request!** - *Please, before opening a feature request, check if similar issues already exist. In that case, use those issues to provide your feedback instead.* - - type: checkboxes - attributes: - label: Verification - options: - - label: I searched for similar feature request and found none was relevant. - required: true - - type: markdown - attributes: - value: | - **Note:** keep in mind that, while InfiniTime is usable, it is still under heavy development and as such it is continuously evolving. - Some features you want to see implemented might not be compatible with the current state of the project, or might not even be suitable to include *in the firmware* of the watch. - - type: input - id: desc-brief - attributes: - label: Pitch us your idea! - description: A one-line elevator pitch of the feature you'd like to see implemented. - placeholder: "Ex. My dog wants InfiniTime on its smart collar." - validations: - required: true - - type: textarea - id: desc-long - attributes: - label: Description - description: | - Give us a detailed description of the feature you are proposing. Mockups or a description of the possible use cases are highly appreciated. - Tell us why this should be included in the firmware. - placeholder: "Ex. Here is a drawing of my dog wearing an InfiniTime collar and smiling." - - type: markdown - id: companion-app - attributes: - value: | - If this requires features missing from other software (for example a companion app), please take care of opening any relevant feature request over there as well. diff --git a/.github/ISSUE_TEMPLATE/issue-report.yaml b/.github/ISSUE_TEMPLATE/issue-report.yaml new file mode 100644 index 00000000..f46499aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue-report.yaml @@ -0,0 +1,31 @@ +name: Issue report +description: Something's not good enough +body: +- type: checkboxes + attributes: + label: Verification + description: Before submitting an issue, check if similar issues already exist and use those issues to provide your feedback instead. + options: + - label: I searched for similar issues and found none was relevant. + required: true +- type: textarea + attributes: + label: Introduce the issue + description: Explain why it is an issue if necessary. + validations: + required: true +- type: textarea + attributes: + label: Preferred solution + description: You can suggest a solution to the issue here. + placeholder: Optional +- type: input + attributes: + label: Version + description: | + What [version of the firmware](https://github.com/JF002/InfiniTime/blob/develop/doc/gettingStarted/gettingStarted-1.0.md#how-to-check-the-version-of-infinitime-and-the-bootloader) are you running? + If you are running an older version, please consider [updating to the latest firmware](https://github.com/JF002/InfiniTime/blob/develop/doc/gettingStarted/gettingStarted-1.0.md#how-to-update-your-pinetime). + If you are running directly from git, specify the branch or the commit hash directly. + placeholder: Ex. v1.6.0 or develop or fc922b60 + validations: + required: false diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8d45fe08..7af81515 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -14,7 +14,7 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 env: USERNAME: infinitime steps: diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 23f71a94..32451a0b 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -23,7 +23,7 @@ jobs: - name: Install clang-format run: | sudo apt-get update - sudo apt-get -y install clang-format-12 + sudo apt-get -y install clang-format-14 - name: Check formatting run: tests/test-format.sh @@ -55,7 +55,7 @@ jobs: - name: Install clang-tidy run: | apt-get update - apt-get -y install clang-tidy-12 + apt-get -y install clang-tidy-14 - name: Prepare environment shell: bash env: diff --git a/.github/workflows/getSize.sh b/.github/workflows/getSize.sh new file mode 100755 index 00000000..52a86132 --- /dev/null +++ b/.github/workflows/getSize.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# Requires environment variables from docker/build.sh + +set -e + +SIZE_BIN="$TOOLS_DIR/$GCC_ARM_PATH/bin/arm-none-eabi-size" +[ ! -x "$SIZE_BIN" ] && exit 1 + +[ -z "$1" ] && exit 1 +SIZE_OUTPUT=$($SIZE_BIN "$1" | tail -n1) + +TEXT_SIZE=$(echo "$SIZE_OUTPUT" | cut -f 1 |tr -d '[:blank:]') +DATA_SIZE=$(echo "$SIZE_OUTPUT" | cut -f 2 |tr -d '[:blank:]') +BSS_SIZE=$(echo "$SIZE_OUTPUT" | cut -f 3 |tr -d '[:blank:]') + +echo "text_size=$TEXT_SIZE" +echo "data_size=$DATA_SIZE" +echo "bss_size=$BSS_SIZE" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 35d5ed1c..cdef2d03 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,28 +13,32 @@ on: - 'doc/**' - '**.md' - jobs: build-firmware: runs-on: ubuntu-latest container: image: infinitime/infinitime-build + outputs: + text_size: ${{ steps.output-sizes.outputs.text_size }} + data_size: ${{ steps.output-sizes.outputs.data_size }} + bss_size: ${{ steps.output-sizes.outputs.bss_size }} + env: + # InfiniTime sources are downloaded to the current directory. + # Override SOURCES_DIR in build.sh + SOURCES_DIR: . steps: - # This workaround fixes the error "unsafe repository (REPO is owned by someone else)". - # See https://github.com/actions/checkout/issues/760 and https://github.com/actions/checkout/issues/766 - # The fix in "actions/checkout@v2" was not sufficient as the build process also uses git (to get the current - # commit hash, for example). - - name: Workaround permission issues - run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Checkout source files - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive - name: Build shell: bash - env: - SOURCES_DIR: . run: /opt/build.sh all + - name: Output build size + id: output-sizes + run: | + . /opt/build.sh + .github/workflows/getSize.sh "$BUILD_DIR"/src/pinetime-app-*.out >> $GITHUB_OUTPUT # Unzip the package because Upload Artifact will zip up the files - name: Unzip DFU package run: unzip ./build/output/pinetime-mcuboot-app-dfu-*.zip -d ./build/output/pinetime-mcuboot-app-dfu @@ -55,22 +59,23 @@ jobs: path: ./build/output/infinitime-resources-*.zip build-simulator: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - - name: Install cmake - uses: lukka/get-cmake@v3.18.3 - - name: Install SDL2 development package run: | sudo apt-get update sudo apt-get -y install libsdl2-dev + - name: Install Ninja + run: | + sudo apt-get -y install ninja-build + - name: Install lv_font_conv run: npm i -g lv_font_conv@1.5.2 - name: Checkout source files - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive @@ -93,3 +98,111 @@ jobs: with: name: infinisim-${{ github.head_ref }} path: build_lv_sim/infinisim + + get-base-ref-size: + if: github.event_name == 'pull_request' + runs-on: ubuntu-22.04 + container: + image: infinitime/infinitime-build + outputs: + text_size: ${{ steps.output-sizes.outputs.text_size }} + data_size: ${{ steps.output-sizes.outputs.data_size }} + bss_size: ${{ steps.output-sizes.outputs.bss_size }} + env: + # InfiniTime sources are downloaded to the current directory. + # Override SOURCES_DIR in build.sh + SOURCES_DIR: . + steps: + - name: Checkout current base branch files + uses: actions/checkout@v3 + with: + ref: ${{ github.base_ref }} + submodules: recursive + + - name: Get base branch SHA + id: get-base-sha + run: | + # Fix for "detected dubious ownership in repository at '/__w/InfiniTime/InfiniTime'" + git config --global --add safe.directory /__w/InfiniTime/InfiniTime + echo base_sha=$(git rev-parse HEAD) >> $GITHUB_OUTPUT + + - name: Cache build + id: cache-build + uses: actions/cache@v3 + with: + path: ./build + key: build-files-${{ steps.get-base-sha.outputs.base_sha }} + + - if: ${{ steps.cache-build.outputs.cache-hit != 'true' }} + name: Build + shell: bash + # Only pinetime-app target is needed, but post_build.sh fails + run: /opt/build.sh all + + - name: Output build size + id: output-sizes + run: | + . /opt/build.sh + .github/workflows/getSize.sh "$BUILD_DIR"/src/pinetime-app-*.out >> $GITHUB_OUTPUT + + compare-build-size: + if: github.event_name == 'pull_request' + needs: [build-firmware, get-base-ref-size] + runs-on: ubuntu-latest + steps: + - name: Compare build size + id: output-sizes-diff + run: | + TEXT_SIZE=${{ needs.build-firmware.outputs.text_size }} + DATA_SIZE=${{ needs.build-firmware.outputs.data_size }} + BSS_SIZE=${{ needs.build-firmware.outputs.bss_size }} + + echo "text_size=$TEXT_SIZE" + echo "data_size=$DATA_SIZE" + echo "bss_size=$BSS_SIZE" + + echo "text_size=$TEXT_SIZE" >> $GITHUB_OUTPUT + echo "data_size=$DATA_SIZE" >> $GITHUB_OUTPUT + echo "bss_size=$BSS_SIZE" >> $GITHUB_OUTPUT + + TEXT_SIZE_BASE=${{ needs.get-base-ref-size.outputs.text_size }} + DATA_SIZE_BASE=${{ needs.get-base-ref-size.outputs.data_size }} + BSS_SIZE_BASE=${{ needs.get-base-ref-size.outputs.bss_size }} + + TEXT_SIZE_DIFF=$((TEXT_SIZE - TEXT_SIZE_BASE)) + DATA_SIZE_DIFF=$((DATA_SIZE - DATA_SIZE_BASE)) + BSS_SIZE_DIFF=$((BSS_SIZE - BSS_SIZE_BASE)) + + echo "text_diff=$TEXT_SIZE_DIFF" + echo "data_diff=$DATA_SIZE_DIFF" + echo "bss_diff=$BSS_SIZE_DIFF" + + echo "text_diff=$TEXT_SIZE_DIFF" >> $GITHUB_OUTPUT + echo "data_diff=$DATA_SIZE_DIFF" >> $GITHUB_OUTPUT + echo "bss_diff=$BSS_SIZE_DIFF" >> $GITHUB_OUTPUT + + - name: Find Comment + # Due to a security concern, comments can only be created in the context of branches in the repo. + # PRs from forks can't get the comment. + if: github.event.pull_request.head.repo.full_name == github.repository + uses: peter-evans/find-comment@v2 + id: build-size-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: Build size and comparison to + + - name: Create or update comment + if: github.event.pull_request.head.repo.full_name == github.repository + uses: peter-evans/create-or-update-comment@v2 + with: + comment-id: ${{ steps.build-size-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + Build size and comparison to ${{ github.base_ref }}: + | Section | Size | Difference | + | ------- | ---- | ---------- | + | text | ${{ needs.build-firmware.outputs.text_size }}B | ${{ steps.output-sizes-diff.outputs.text_diff }}B | + | data | ${{ needs.build-firmware.outputs.data_size }}B | ${{ steps.output-sizes-diff.outputs.data_diff }}B | + | bss | ${{ needs.build-firmware.outputs.bss_size }}B | ${{ steps.output-sizes-diff.outputs.bss_diff }}B | + edit-mode: replace diff --git a/CMakeLists.txt b/CMakeLists.txt index adb1754b..62c1637b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,10 +24,6 @@ if (NOT NRF5_SDK_PATH) message(FATAL_ERROR "The path to the NRF52 SDK must be specified on the command line (add -DNRF5_SDK_PATH=<path>") endif () -if(DEFINED USE_DEBUG_PINS AND USE_DEBUG_PINS) - add_definitions(-DUSE_DEBUG_PINS) -endif() - if(BUILD_DFU) set(BUILD_DFU true) endif() @@ -59,11 +55,6 @@ message(" * Toolchain : " ${ARM_NONE_EABI_TOOLCHAIN_PATH}) message(" * GitRef(S) : " ${PROJECT_GIT_COMMIT_HASH}) message(" * NRF52 SDK : " ${NRF5_SDK_PATH}) message(" * Target device : " ${TARGET_DEVICE}) -if(USE_DEBUG_PINS) - message(" * Debug pins : Enabled") -else() - message(" * Debug pins : Disabled") -endif() if(BUILD_DFU) message(" * Build DFU (using adafruit-nrfutil) : Enabled") else() @@ -20,6 +20,8 @@ Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/p - [InfiniLink](https://github.com/InfiniTimeOrg/InfiniLink) (iOS) **[Looking for a new maintainer]** - [ITD](https://gitea.arsenm.dev/Arsen6331/itd) (Linux) +***Note** : We removed mentions to NRFConnect as this app is closed source and recent versions do not work anymore with InfiniTime (the last version known to work is 4.24.3). If you used NRFConnect in the past, we recommend you switch to [Gadgetbridge](https://gadgetbridge.org/).* + ## Development - [InfiniTime Vision](doc/InfiniTimeVision.md) @@ -29,9 +31,6 @@ Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/p - [Tips on designing an app UI](doc/ui_guidelines.md) - [Bootloader, OTA and DFU](bootloader/README.md) - [External resources](doc/ExternalResources.md) -- [Versioning](doc/versioning.md) -- [Project branches](doc/branches.md) -- [Files included in the release notes](doc/filesInReleaseNotes.md) ### Contributing @@ -58,6 +57,13 @@ Fast open-source firmware for the [PineTime smartwatch](https://www.pine64.org/p - [Memory analysis](doc/MemoryAnalysis.md) +### Project management + +- [Maintainer's guide](doc/maintainer-guide.md) +- [Versioning](doc/versioning.md) +- [Project branches](doc/branches.md) +- [Files included in the release notes](doc/filesInReleaseNotes.md) + ## Licenses This project is released under the GNU General Public License version 3 or, at your option, any later version. @@ -71,7 +77,7 @@ It integrates the following projects: ## Credits -I’m not working alone on this project. First, many people create PR for this projects. Then, there is the whole #pinetime community : a lot of people all around the world who are hacking, searching, experimenting and programming the Pinetime. We exchange our ideas, experiments and code in the chat rooms and forums. +I’m not working alone on this project. First, many people create PR for this project. Then, there is the whole #pinetime community : a lot of people all around the world who are hacking, searching, experimenting and programming the Pinetime. We exchange our ideas, experiments and code in the chat rooms and forums. Here are some people I would like to highlight: diff --git a/doc/buildWithDocker.md b/doc/buildWithDocker.md index 20bf85d4..c0d425e5 100644 --- a/doc/buildWithDocker.md +++ b/doc/buildWithDocker.md @@ -1,6 +1,6 @@ # Build the project using Docker -A [Docker image (Dockerfile)](../docker) containing all the build environment is available for X86_64 and AMD64 architectures. +A [Docker image (Dockerfile)](../docker) containing all the build environment is available for X86_64 and ARM64 architectures. These images make the build of the firmware and the generation of the DFU file for OTA quite easy, as well as preventing clashes with any other toolchains or development environments you may have installed. Based on Ubuntu 22.04 with the following build dependencies: diff --git a/doc/code/Apps.md b/doc/code/Apps.md index ad0f0403..cb7cd518 100644 --- a/doc/code/Apps.md +++ b/doc/code/Apps.md @@ -95,7 +95,7 @@ in the compilation by adding it to [CMakeLists.txt](/CMakeLists.txt). The next step to making it launchable 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)). Name this entry after your app. Add `#include "displayapp/screens/MyApp.h"` to the file [displayapp/DisplayApp.cpp](/src/displayapp/DisplayApp.cpp). -Now, go to the function `DisplayApp::LoadApp` and add another case to the switch statement. +Now, go to the function `DisplayApp::LoadScreen` and add another case to the switch statement. The case will be the id you gave your app earlier. If your app needs any additional arguments, this is the place to pass them. diff --git a/doc/contribute.md b/doc/contribute.md index f4e241a1..29d20916 100644 --- a/doc/contribute.md +++ b/doc/contribute.md @@ -1,11 +1,20 @@ # How to contribute? -- [Report bugs](https://github.com/InfiniTimeOrg/InfiniTime/issues/new?assignees=&labels=bug&template=bug-report.yaml) -- Write and improve documentation - - Documentation might be incomplete, or not clear enough, and it is always possible to improve it with better wording, pictures, videos,... - - As the documentation is part of the source code, you can submit changes to the documentation by creating a pull request (see below) -- Fix bugs, add functionalities and improve the code - - See *How to create a pull request* below +Here are things you can do to help. + +- [Report bugs or issues](https://github.com/InfiniTimeOrg/InfiniTime/issues/new/choose) +- [Write and improve documentation](#documentation) +- [Fix bugs, add functionalities and improve the code](#how-to-create-a-pull-request) +- Participate in the discussions within issues and PRs. Your feedback is appreciated! +- Review pull requests. Follow the instructions [here](maintainer-guide.md#reviewing-prs) + +## Documentation + +Documentation might be incomplete, +or not clear enough, +and it is always possible to improve it with better wording, pictures, videos,... +As the documentation is part of the source code, +you can submit changes to the documentation by creating a [pull request](#how-to-create-a-pull-request) ## How to create a pull request? diff --git a/doc/gettingStarted/gettingStarted-1.0.md b/doc/gettingStarted/gettingStarted-1.0.md index 989629df..5c607444 100644 --- a/doc/gettingStarted/gettingStarted-1.0.md +++ b/doc/gettingStarted/gettingStarted-1.0.md @@ -1,6 +1,6 @@ # Getting started with InfiniTime -On April 22 2021, InfiniTime and Pine64 [announced the release of InfiniTime 1.0.0](https://www.pine64.org/2021/04/22/its-time-infinitime-1-0/) and the availability of PineTime smartwatches as an *enthusiast grade end-user product*. This page aims to guide you with your first step with your new PineTime. +On April 22, 2021, InfiniTime and Pine64 [announced the release of InfiniTime 1.0.0](https://www.pine64.org/2021/04/22/its-time-infinitime-1-0/) and the availability of PineTime smartwatches as an *enthusiast grade end-user product*. This page aims to guide you with your first step with your new PineTime. It is highly recommended to update the firmware to the latest version when you receive your watch and when a new InfiniTime version is released. More information on updating the firmware [here](/doc/gettingStarted/updating-software.md). @@ -28,15 +28,15 @@ This is what the default digital watch face looks like. You can change watch fac The indicator on the top left is visible if you have unread notifications -On the top right there are status icons +On the top right, there are status icons - The battery icon shows roughly how much charge is remaining - The Bluetooth icon is visible when the watch is connected to a companion app - A plug icon is shown when the watch is plugged into a charger. -On the bottom left you can see your heart rate if you have the measurement enabled in the heart rate app. +On the bottom left, you can see your heart rate if you have the measurement enabled in the heart rate app. -On the bottom right you can see how many steps you have taken today. +On the bottom right, you can see how many steps you have taken today. ### Navigation in the menu diff --git a/doc/maintainer-guide.md b/doc/maintainer-guide.md new file mode 100644 index 00000000..ba95eb83 --- /dev/null +++ b/doc/maintainer-guide.md @@ -0,0 +1,45 @@ +# Reviewing PRs + +Approving a PR means that the reviewer has deemed the PR ready to be merged. + +There are two steps to reviewing PRs. + +- Review the feature: + + - Consider if the feature aligns with the [InfiniTime vision](InfiniTimeVision.md) + - Discuss alternative ideas or implementations + +- Review the code: + + - Check the quality of the code and make sure it conforms to the [coding conventions](coding-convention.md) + - Consider the maintainability of the code + - Test the code with at least InfiniSim or a PineTime + +# Merging PRs + +Two approvals from core developers is usually required to merge a PR. +Exceptions include urgent fixes +and small maintenance PRs by core developers, +that don't affect the apparent behaviour of the watch in any way. + +All but the simulator check must be passed before merging a PR. + +PRs are either rebase or squash merged, +depending on whether the commits satisfy the following requirements: + +### Commits + +- Commits that fix mistakes from previous commits must be squashed before merging a PR. +- The title and description of the commit must sufficiently explain the changes in the commit. + +If these requirements are not met, +the PR must be squash merged, +and the merger must write a satisfactory description. + +# Stale PRs + +Work-in-Progress PRs shall be marked as draft. + +Draft PRs with no activity by the author for 3 months may be closed as stale. + +PRs with changes requested, but no activity by the author for 3 months may be closed as stale. diff --git a/docker/build.sh b/docker/build.sh index 07e0d17e..3a467b9f 100755 --- a/docker/build.sh +++ b/docker/build.sh @@ -20,7 +20,7 @@ export GCC_ARM_VER=${GCC_ARM_VER:="10.3-2021.10"} export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"} MACHINE="$(uname -m)" -[[ "$MACHINE" == "arm64" ]] && MACHINE="aarch64" +[ "$MACHINE" = "arm64" ] && MACHINE="aarch64" export GCC_ARM_PATH="gcc-arm-none-eabi-$GCC_ARM_VER" @@ -29,9 +29,9 @@ main() { mkdir -p "$TOOLS_DIR" - [[ ! -d "$TOOLS_DIR/$GCC_ARM_PATH" ]] && GetGcc - [[ ! -d "$TOOLS_DIR/$NRF_SDK_VER" ]] && GetNrfSdk - [[ ! -d "$TOOLS_DIR/mcuboot" ]] && GetMcuBoot + [ ! -d "$TOOLS_DIR/$GCC_ARM_PATH" ] && GetGcc + [ ! -d "$TOOLS_DIR/$NRF_SDK_VER" ] && GetNrfSdk + [ ! -d "$TOOLS_DIR/mcuboot" ] && GetMcuBoot mkdir -p "$BUILD_DIR" @@ -41,6 +41,8 @@ main() { 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() { @@ -71,10 +73,18 @@ CmakeGenerate() { 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 + [ -n "$target" ] && target="--target $target" + cmake --build "$BUILD_DIR" --config $BUILD_TYPE $target -- -j$(nproc) + BUILD_RESULT=$? + return $BUILD_RESULT } -[[ $SOURCED == "false" ]] && main "$@" || echo "Sourced!" +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/src/CMakeLists.txt b/src/CMakeLists.txt index ce365dd1..95846a9b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -407,6 +407,7 @@ list(APPEND SOURCE_FILES displayapp/Colors.cpp displayapp/widgets/Counter.cpp displayapp/widgets/PageIndicator.cpp + displayapp/widgets/DotIndicator.cpp displayapp/widgets/StatusIcons.cpp ## Settings @@ -417,6 +418,7 @@ list(APPEND SOURCE_FILES displayapp/screens/settings/SettingWakeUp.cpp displayapp/screens/settings/SettingDisplay.cpp displayapp/screens/settings/SettingSteps.cpp + displayapp/screens/settings/SettingSetDateTime.cpp displayapp/screens/settings/SettingSetDate.cpp displayapp/screens/settings/SettingSetTime.cpp displayapp/screens/settings/SettingChimes.cpp @@ -440,7 +442,6 @@ list(APPEND SOURCE_FILES drivers/SpiMaster.cpp drivers/Spi.cpp drivers/Watchdog.cpp - drivers/DebugPins.cpp drivers/InternalFlash.cpp drivers/Hrs3300.cpp drivers/Bma421.cpp @@ -507,7 +508,6 @@ list(APPEND RECOVERY_SOURCE_FILES drivers/SpiMaster.cpp drivers/Spi.cpp drivers/Watchdog.cpp - drivers/DebugPins.cpp drivers/InternalFlash.cpp drivers/Hrs3300.cpp drivers/Bma421.cpp @@ -616,13 +616,13 @@ set(INCLUDE_FILES displayapp/Colors.h displayapp/widgets/Counter.h displayapp/widgets/PageIndicator.h + displayapp/widgets/DotIndicator.h displayapp/widgets/StatusIcons.h drivers/St7789.h drivers/SpiNorFlash.h drivers/SpiMaster.h drivers/Spi.h drivers/Watchdog.h - drivers/DebugPins.h drivers/InternalFlash.h drivers/Hrs3300.h drivers/PinMap.h @@ -686,6 +686,8 @@ include_directories( ${CMAKE_BINARY_DIR}/src # include generated files like Version.h . ../ +) +include_directories(SYSTEM libs/ FreeRTOS/ libs/date/include @@ -778,7 +780,12 @@ link_directories( ) -set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -ftree-vrp -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -g3 -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin --short-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -Wreturn-type -Werror=return-type -fstack-usage -fno-exceptions -fno-non-call-exceptions) +set(COMMON_FLAGS -MP -MD -mthumb -mabi=aapcs -ftree-vrp -ffunction-sections -fdata-sections -fno-strict-aliasing -fno-builtin -fshort-enums -mcpu=cortex-m4 -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fstack-usage -fno-exceptions -fno-non-call-exceptions) +set(WARNING_FLAGS -Wall -Wextra -Warray-bounds=2 -Wformat=2 -Wformat-overflow=2 -Wformat-truncation=2 -Wformat-nonliteral -Wno-missing-field-initializers -Wno-unknown-pragmas -Wno-expansion-to-defined -Wreturn-type -Werror=return-type) +set(DEBUG_FLAGS -Og -g3) +set(RELEASE_FLAGS -Os) +set(CXX_FLAGS -fno-rtti) +set(ASM_FLAGS -x assembler-with-cpp) add_definitions(-DCONFIG_GPIO_AS_PINRESET) add_definitions(-DNIMBLE_CFG_CONTROLLER) add_definitions(-DOS_CPUTIME_FREQ) @@ -843,11 +850,11 @@ endif() add_subdirectory(displayapp/fonts) target_compile_options(infinitime_fonts PUBLIC - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # NRF SDK @@ -855,11 +862,12 @@ add_library(nrf-sdk STATIC ${SDK_SOURCE_FILES}) target_include_directories(nrf-sdk SYSTEM PUBLIC . ../) target_include_directories(nrf-sdk SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) target_compile_options(nrf-sdk PRIVATE - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -Og -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-expansion-to-defined -O3 -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> + -O3 ) # NimBLE @@ -867,11 +875,11 @@ add_library(nimble STATIC ${NIMBLE_SRC} ${TINYCRYPT_SRC}) target_include_directories(nimble SYSTEM PUBLIC . ../) target_include_directories(nimble SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) target_compile_options(nimble PRIVATE - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -Wno-unused-but-set-variable -Wno-maybe-uninitialized> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -Wno-unused-but-set-variable -Wno-maybe-uninitialized -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # lvgl @@ -879,11 +887,11 @@ add_library(lvgl STATIC ${LVGL_SRC}) target_include_directories(lvgl SYSTEM PUBLIC . ../) target_include_directories(lvgl SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) target_compile_options(lvgl PRIVATE - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # QCBOR @@ -900,9 +908,11 @@ target_compile_definitions(QCBOR PUBLIC QCBOR_DISABLE_UNCOMMON_TAGS) target_compile_definitions(QCBOR PUBLIC USEFULBUF_CONFIG_LITTLE_ENDIAN) set_target_properties(QCBOR PROPERTIES LINKER_LANGUAGE C) target_compile_options(QCBOR PRIVATE - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -O0 -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -O3> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> + -O3 ) # LITTLEFS_SRC @@ -910,11 +920,11 @@ add_library(littlefs STATIC ${LITTLEFS_SRC}) target_include_directories(littlefs SYSTEM PUBLIC . ../) target_include_directories(littlefs SYSTEM PUBLIC ${INCLUDES_FROM_LIBS}) target_compile_options(littlefs PRIVATE - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-unused-function -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-unused-function -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wno-unused-function -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wno-unused-function -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) # Build autonomous binary (without support for bootloader) @@ -925,11 +935,12 @@ 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 QCBOR infinitime_fonts) target_compile_options(${EXECUTABLE_NAME} PUBLIC - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Wextra -Wformat -Wno-missing-field-initializers -Wno-unused-parameter -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_NAME} PROPERTIES @@ -959,11 +970,12 @@ add_executable(${EXECUTABLE_MCUBOOT_NAME} ${SOURCE_FILES}) target_link_libraries(${EXECUTABLE_MCUBOOT_NAME} nimble nrf-sdk lvgl littlefs QCBOR infinitime_fonts) set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_FILE_NAME}) target_compile_options(${EXECUTABLE_MCUBOOT_NAME} PUBLIC - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_MCUBOOT_NAME} PROPERTIES @@ -1001,11 +1013,12 @@ target_link_libraries(${EXECUTABLE_RECOVERY_NAME} nimble nrf-sdk littlefs QCBOR 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 - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_RECOVERY_NAME} PROPERTIES @@ -1032,11 +1045,12 @@ target_link_libraries(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} nimble nrf-sdk littlef 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 - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) set_target_properties(${EXECUTABLE_RECOVERY_MCUBOOT_NAME} PROPERTIES @@ -1070,11 +1084,12 @@ add_executable(${EXECUTABLE_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE_FILES}) target_link_libraries(${EXECUTABLE_RECOVERYLOADER_NAME} nrf-sdk QCBOR infinitime_fonts) set_target_properties(${EXECUTABLE_RECOVERYLOADER_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_RECOVERYLOADER_FILE_NAME}) target_compile_options(${EXECUTABLE_RECOVERYLOADER_NAME} PUBLIC - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) target_include_directories(${EXECUTABLE_RECOVERYLOADER_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src> @@ -1104,11 +1119,12 @@ add_executable(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} ${RECOVERYLOADER_SOURCE target_link_libraries(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} nrf-sdk QCBOR infinitime_fonts) set_target_properties(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PROPERTIES OUTPUT_NAME ${EXECUTABLE_MCUBOOT_RECOVERYLOADER_FILE_NAME}) target_compile_options(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PUBLIC - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3> - $<$<AND:$<COMPILE_LANGUAGE:C>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:DEBUG>>: ${COMMON_FLAGS} -Og -g3 -fno-rtti> - $<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CONFIG:RELEASE>>: ${COMMON_FLAGS} -Os -fno-rtti> - $<$<COMPILE_LANGUAGE:ASM>: -MP -MD -x assembler-with-cpp> + ${COMMON_FLAGS} + ${WARNING_FLAGS} + $<$<CONFIG:DEBUG>: ${DEBUG_FLAGS}> + $<$<CONFIG:RELEASE>: ${RELEASE_FLAGS}> + $<$<COMPILE_LANGUAGE:CXX>: ${CXX_FLAGS}> + $<$<COMPILE_LANGUAGE:ASM>: ${ASM_FLAGS}> ) target_include_directories(${EXECUTABLE_MCUBOOT_RECOVERYLOADER_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/src> diff --git a/src/StaticStack.h b/src/StaticStack.h new file mode 100644 index 00000000..64886604 --- /dev/null +++ b/src/StaticStack.h @@ -0,0 +1,38 @@ +#include <array> +#include <cstddef> + +template <typename T, size_t N> class StaticStack { +public: + T Pop(); + void Push(T element); + void Reset(); + T Top(); + +private: + std::array<T, N> elementArray; + // Number of elements in stack, points to the next empty slot + size_t stackPointer = 0; +}; + +// Returns random data when popping from empty array. +template <typename T, size_t N> T StaticStack<T, N>::Pop() { + if (stackPointer > 0) { + stackPointer--; + } + return elementArray[stackPointer]; +} + +template <typename T, size_t N> void StaticStack<T, N>::Push(T element) { + if (stackPointer < elementArray.size()) { + elementArray[stackPointer] = element; + stackPointer++; + } +} + +template <typename T, size_t N> void StaticStack<T, N>::Reset() { + stackPointer = 0; +} + +template <typename T, size_t N> T StaticStack<T, N>::Top() { + return elementArray[stackPointer - 1]; +} diff --git a/src/components/alarm/AlarmController.cpp b/src/components/alarm/AlarmController.cpp index d97e1cff..88f65d9a 100644 --- a/src/components/alarm/AlarmController.cpp +++ b/src/components/alarm/AlarmController.cpp @@ -28,7 +28,7 @@ AlarmController::AlarmController(Controllers::DateTime& dateTimeController) : da namespace { void SetOffAlarm(TimerHandle_t xTimer) { - auto controller = static_cast<Pinetime::Controllers::AlarmController*>(pvTimerGetTimerID(xTimer)); + auto* controller = static_cast<Pinetime::Controllers::AlarmController*>(pvTimerGetTimerID(xTimer)); controller->SetOffAlarmNow(); } } diff --git a/src/components/alarm/AlarmController.h b/src/components/alarm/AlarmController.h index 91f60f5a..8ac0de9a 100644 --- a/src/components/alarm/AlarmController.h +++ b/src/components/alarm/AlarmController.h @@ -26,6 +26,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class AlarmController { public: @@ -40,18 +41,23 @@ namespace Pinetime { void StopAlerting(); enum class AlarmState { Not_Set, Set, Alerting }; enum class RecurType { None, Daily, Weekdays }; + uint8_t Hours() const { return hours; } + uint8_t Minutes() const { return minutes; } + AlarmState State() const { return state; } + RecurType Recurrence() const { return recurrence; } + void SetRecurrence(RecurType recurType) { recurrence = recurType; } diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index 300d0978..4d860490 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -1,4 +1,5 @@ #include "components/battery/BatteryController.h" +#include "components/utility/LinearApproximation.h" #include "drivers/PinMap.h" #include <hal/nrf_gpio.h> #include <nrfx_saadc.h> @@ -15,8 +16,8 @@ Battery::Battery() { } void Battery::ReadPowerState() { - isCharging = !nrf_gpio_pin_read(PinMap::Charging); - isPowerPresent = !nrf_gpio_pin_read(PinMap::PowerPresent); + isCharging = (nrf_gpio_pin_read(PinMap::Charging) == 0); + isPowerPresent = (nrf_gpio_pin_read(PinMap::PowerPresent) == 0); if (isPowerPresent && !isCharging) { isFull = true; @@ -60,8 +61,8 @@ void Battery::SaadcInit() { } void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { - const uint16_t battery_max = 4180; // maximum voltage of battery ( max charging voltage is 4.21 ) - const uint16_t battery_min = 3200; // minimum voltage of battery before shutdown ( depends on the battery ) + static const Utility::LinearApproximation<uint16_t, uint8_t, 6> approx { + {{{3500, 0}, {3616, 3}, {3723, 22}, {3776, 48}, {3979, 79}, {4180, 100}}}}; if (p_event->type == NRFX_SAADC_EVT_DONE) { @@ -74,19 +75,26 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { // p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024 voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024; - uint8_t newPercent; - if (isFull) { - newPercent = 100; - } else if (voltage < battery_min) { - newPercent = 0; - } else { - newPercent = std::min((voltage - battery_min) * 100 / (battery_max - battery_min), isCharging ? 99 : 100); + uint8_t newPercent = 100; + if (!isFull) { + // max. voltage while charging is higher than when discharging + newPercent = std::min(approx.GetValue(voltage), isCharging ? uint8_t {99} : uint8_t {100}); + } + + if (isPowerPresent) { + batteryLowNotified = false; } if ((isPowerPresent && newPercent > percentRemaining) || (!isPowerPresent && newPercent < percentRemaining) || firstMeasurement) { firstMeasurement = false; percentRemaining = newPercent; systemTask->PushMessage(System::Messages::BatteryPercentageUpdated); + + // warn about low battery when not charging and below threshold + if (BatteryIsLow() && !isPowerPresent && !batteryLowNotified) { + systemTask->PushMessage(System::Messages::LowBattery); + batteryLowNotified = true; + } } nrfx_saadc_uninit(); diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 5a7394c4..b47b77cc 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -18,6 +18,10 @@ namespace Pinetime { return percentRemaining; } + bool BatteryIsLow() const { + return percentRemaining <= lowBatteryThreshold; + } + uint16_t Voltage() const { return voltage; } @@ -39,6 +43,7 @@ namespace Pinetime { static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7; uint16_t voltage = 0; uint8_t percentRemaining = 0; + bool batteryLowNotified = false; bool isFull = false; bool isCharging = false; @@ -50,6 +55,8 @@ namespace Pinetime { void SaadcEventHandler(nrfx_saadc_evt_t const* p_event); static void AdcCallbackStatic(nrfx_saadc_evt_t const* event); + static constexpr uint8_t lowBatteryThreshold {15}; + bool isReading = false; Pinetime::System::SystemTask* systemTask = nullptr; diff --git a/src/components/ble/AlertNotificationClient.cpp b/src/components/ble/AlertNotificationClient.cpp index 095fdef6..e3bc9242 100644 --- a/src/components/ble/AlertNotificationClient.cpp +++ b/src/components/ble/AlertNotificationClient.cpp @@ -35,9 +35,9 @@ namespace { return client->OnDescriptorDiscoveryEventCallback(conn_handle, error, chr_val_handle, dsc); } - int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* attr, void* arg) { + int NewAlertSubcribeCallback(uint16_t conn_handle, const struct ble_gatt_error* error, struct ble_gatt_attr* /*attr*/, void* arg) { auto client = static_cast<AlertNotificationClient*>(arg); - return client->OnNewAlertSubcribe(conn_handle, error, attr); + return client->OnNewAlertSubcribe(conn_handle, error); } } @@ -107,7 +107,7 @@ int AlertNotificationClient::OnCharacteristicsDiscoveryEvent(uint16_t connection return 0; } -int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute) { +int AlertNotificationClient::OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error) { if (error->status == 0) { NRF_LOG_INFO("ANS New alert subscribe OK"); } else { diff --git a/src/components/ble/AlertNotificationClient.h b/src/components/ble/AlertNotificationClient.h index 2d6a3873..b038f0d8 100644 --- a/src/components/ble/AlertNotificationClient.h +++ b/src/components/ble/AlertNotificationClient.h @@ -25,7 +25,7 @@ namespace Pinetime { bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service); int OnCharacteristicsDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); - int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error, ble_gatt_attr* attribute); + int OnNewAlertSubcribe(uint16_t connectionHandle, const ble_gatt_error* error); int OnDescriptorDiscoveryEventCallback(uint16_t connectionHandle, const ble_gatt_error* error, uint16_t characteristicValueHandle, diff --git a/src/components/ble/AlertNotificationService.cpp b/src/components/ble/AlertNotificationService.cpp index 04819122..d9f28698 100644 --- a/src/components/ble/AlertNotificationService.cpp +++ b/src/components/ble/AlertNotificationService.cpp @@ -11,9 +11,9 @@ constexpr ble_uuid16_t AlertNotificationService::ansUuid; constexpr ble_uuid16_t AlertNotificationService::ansCharUuid; constexpr ble_uuid128_t AlertNotificationService::notificationEventUuid; -int AlertNotificationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int AlertNotificationCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto anService = static_cast<AlertNotificationService*>(arg); - return anService->OnAlert(conn_handle, attr_handle, ctxt); + return anService->OnAlert(ctxt); } void AlertNotificationService::Init() { @@ -44,7 +44,7 @@ AlertNotificationService::AlertNotificationService(System::SystemTask& systemTas notificationManager {notificationManager} { } -int AlertNotificationService::OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int AlertNotificationService::OnAlert(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { constexpr size_t stringTerminatorSize = 1; // end of string '\0' constexpr size_t headerSize = 3; diff --git a/src/components/ble/AlertNotificationService.h b/src/components/ble/AlertNotificationService.h index 5c7d428c..4b3c6385 100644 --- a/src/components/ble/AlertNotificationService.h +++ b/src/components/ble/AlertNotificationService.h @@ -16,6 +16,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NotificationManager; @@ -24,7 +25,7 @@ namespace Pinetime { AlertNotificationService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager); void Init(); - int OnAlert(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnAlert(struct ble_gatt_access_ctxt* ctxt); void AcceptIncomingCall(); void RejectIncomingCall(); diff --git a/src/components/ble/BatteryInformationService.cpp b/src/components/ble/BatteryInformationService.cpp index 9a3f86f5..db7c8566 100644 --- a/src/components/ble/BatteryInformationService.cpp +++ b/src/components/ble/BatteryInformationService.cpp @@ -7,9 +7,9 @@ using namespace Pinetime::Controllers; constexpr ble_uuid16_t BatteryInformationService::batteryInformationServiceUuid; constexpr ble_uuid16_t BatteryInformationService::batteryLevelUuid; -int BatteryInformationServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int BatteryInformationServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* batteryInformationService = static_cast<BatteryInformationService*>(arg); - return batteryInformationService->OnBatteryServiceRequested(conn_handle, attr_handle, ctxt); + return batteryInformationService->OnBatteryServiceRequested(attr_handle, ctxt); } BatteryInformationService::BatteryInformationService(Controllers::Battery& batteryController) @@ -38,9 +38,7 @@ void BatteryInformationService::Init() { ASSERT(res == 0); } -int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHandle, - uint16_t attributeHandle, - ble_gatt_access_ctxt* context) { +int BatteryInformationService::OnBatteryServiceRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == batteryLevelHandle) { NRF_LOG_INFO("BATTERY : handle = %d", batteryLevelHandle); uint8_t batteryValue = batteryController.PercentRemaining(); @@ -49,6 +47,7 @@ int BatteryInformationService::OnBatteryServiceRequested(uint16_t connectionHand } return 0; } + void BatteryInformationService::NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level) { auto* om = ble_hs_mbuf_from_flat(&level, 1); ble_gattc_notify_custom(connectionHandle, batteryLevelHandle, om); diff --git a/src/components/ble/BatteryInformationService.h b/src/components/ble/BatteryInformationService.h index c6fc52e4..7f0a89ad 100644 --- a/src/components/ble/BatteryInformationService.h +++ b/src/components/ble/BatteryInformationService.h @@ -9,14 +9,16 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class Battery; + class BatteryInformationService { public: BatteryInformationService(Controllers::Battery& batteryController); void Init(); - int OnBatteryServiceRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnBatteryServiceRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void NotifyBatteryLevel(uint16_t connectionHandle, uint8_t level); private: diff --git a/src/components/ble/BleController.h b/src/components/ble/BleController.h index 675ede2d..de0a1bc2 100644 --- a/src/components/ble/BleController.h +++ b/src/components/ble/BleController.h @@ -24,6 +24,7 @@ namespace Pinetime { void StopFirmwareUpdate(); void FirmwareUpdateTotalBytes(uint32_t totalBytes); void FirmwareUpdateCurrentBytes(uint32_t currentBytes); + void State(FirmwareUpdateStates state) { firmwareUpdateState = state; } @@ -31,12 +32,15 @@ namespace Pinetime { bool IsFirmwareUpdating() const { return isFirmwareUpdating; } + uint32_t FirmwareUpdateTotalBytes() const { return firmwareUpdateTotalBytes; } + uint32_t FirmwareUpdateCurrentBytes() const { return firmwareUpdateCurrentBytes; } + FirmwareUpdateStates State() const { return firmwareUpdateState; } @@ -44,15 +48,19 @@ namespace Pinetime { void Address(BleAddress&& addr) { address = addr; } + const BleAddress& Address() const { return address; } + void AddressType(AddressTypes t) { addressType = t; } + void SetPairingKey(uint32_t k) { pairingKey = k; } + uint32_t GetPairingKey() const { return pairingKey; } diff --git a/src/components/ble/CurrentTimeClient.cpp b/src/components/ble/CurrentTimeClient.cpp index 53e98cb6..e535ae83 100644 --- a/src/components/ble/CurrentTimeClient.cpp +++ b/src/components/ble/CurrentTimeClient.cpp @@ -85,21 +85,11 @@ int CurrentTimeClient::OnCurrentTimeReadResult(uint16_t conn_handle, const ble_g // TODO check that attribute->handle equals the handle discovered in OnCharacteristicDiscoveryEvent CtsData result; os_mbuf_copydata(attribute->om, 0, sizeof(CtsData), &result); - NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", - result.year, - result.month, - result.dayofmonth, - result.hour, - result.minute, - result.second); - dateTimeController.SetTime(result.year, - result.month, - result.dayofmonth, - 0, - result.hour, - result.minute, - result.second, - nrf_rtc_counter_get(portNRF_RTC_REG)); + uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO; + + NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second); + dateTimeController + .SetTime(year, result.month, result.dayofmonth, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG)); } else { NRF_LOG_INFO("Error retrieving current time: %d", error->status); } diff --git a/src/components/ble/CurrentTimeClient.h b/src/components/ble/CurrentTimeClient.h index 9e48be79..0a3a8735 100644 --- a/src/components/ble/CurrentTimeClient.h +++ b/src/components/ble/CurrentTimeClient.h @@ -19,24 +19,29 @@ namespace Pinetime { bool OnDiscoveryEvent(uint16_t connectionHandle, const ble_gatt_error* error, const ble_gatt_svc* service); int OnCharacteristicDiscoveryEvent(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_chr* characteristic); int OnCurrentTimeReadResult(uint16_t conn_handle, const ble_gatt_error* error, const ble_gatt_attr* attribute); + static constexpr const ble_uuid16_t* Uuid() { return &CurrentTimeClient::ctsServiceUuid; } + static constexpr const ble_uuid16_t* CurrentTimeCharacteristicUuid() { return &CurrentTimeClient::currentTimeCharacteristicUuid; } + void Discover(uint16_t connectionHandle, std::function<void(uint16_t)> lambda) override; private: typedef struct __attribute__((packed)) { - uint16_t year; + uint8_t year_LSO; // explicit byte ordering to be independent of machine order + uint8_t year_MSO; // BLE GATT is little endian uint8_t month; uint8_t dayofmonth; uint8_t hour; uint8_t minute; uint8_t second; - uint8_t millis; - uint8_t reason; + uint8_t dayofweek; + uint8_t fractions256; // currently ignored + uint8_t reason; // currently ignored, not that any host would set it anyway } CtsData; static constexpr uint16_t ctsServiceId {0x1805}; @@ -55,4 +60,4 @@ namespace Pinetime { std::function<void(uint16_t)> onServiceDiscovered; }; } -}
\ No newline at end of file +} diff --git a/src/components/ble/CurrentTimeService.cpp b/src/components/ble/CurrentTimeService.cpp index 8430d1bc..856bc63a 100644 --- a/src/components/ble/CurrentTimeService.cpp +++ b/src/components/ble/CurrentTimeService.cpp @@ -5,11 +5,23 @@ using namespace Pinetime::Controllers; constexpr ble_uuid16_t CurrentTimeService::ctsUuid; -constexpr ble_uuid16_t CurrentTimeService::ctChrUuid; +constexpr ble_uuid16_t CurrentTimeService::ctsCtChrUuid; +constexpr ble_uuid16_t CurrentTimeService::ctsLtChrUuid; -int CTSCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int CTSCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto cts = static_cast<CurrentTimeService*>(arg); - return cts->OnTimeAccessed(conn_handle, attr_handle, ctxt); + + return cts->OnCurrentTimeServiceAccessed(ctxt); +} + +int CurrentTimeService::OnCurrentTimeServiceAccessed(struct ble_gatt_access_ctxt* ctxt) { + switch (ble_uuid_u16(ctxt->chr->uuid)) { + case ctsCurrentTimeCharId: + return OnCurrentTimeAccessed(ctxt); + case ctsLocalTimeCharId: + return OnLocalTimeAccessed(ctxt); + } + return -1; // Unknown characteristic } void CurrentTimeService::Init() { @@ -18,45 +30,69 @@ void CurrentTimeService::Init() { ASSERT(res == 0); res = ble_gatts_add_svcs(serviceDefinition); + ASSERT(res == 0); } -int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int CurrentTimeService::OnCurrentTimeAccessed(struct ble_gatt_access_ctxt* ctxt) { NRF_LOG_INFO("Setting time..."); if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - CtsData result; - os_mbuf_copydata(ctxt->om, 0, sizeof(CtsData), &result); + CtsCurrentTimeData result; + int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsCurrentTimeData), &result); + if (res < 0) { + NRF_LOG_ERROR("Error reading BLE Data writing to CTS Current Time (too little data)") + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + uint16_t year = ((uint16_t) result.year_MSO << 8) + result.year_LSO; - NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", - result.year, - result.month, - result.dayofmonth, - result.hour, - result.minute, - result.second); + NRF_LOG_INFO("Received data: %d-%d-%d %d:%d:%d", year, result.month, result.dayofmonth, result.hour, result.minute, result.second); - m_dateTimeController.SetTime(result.year, - result.month, - result.dayofmonth, - 0, - result.hour, - result.minute, - result.second, - nrf_rtc_counter_get(portNRF_RTC_REG)); + m_dateTimeController + .SetTime(year, result.month, result.dayofmonth, result.hour, result.minute, result.second, nrf_rtc_counter_get(portNRF_RTC_REG)); } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - CtsData currentDateTime; - currentDateTime.year = m_dateTimeController.Year(); + CtsCurrentTimeData currentDateTime; + currentDateTime.year_LSO = m_dateTimeController.Year() & 0xff; + currentDateTime.year_MSO = (m_dateTimeController.Year() >> 8) & 0xff; currentDateTime.month = static_cast<u_int8_t>(m_dateTimeController.Month()); currentDateTime.dayofmonth = m_dateTimeController.Day(); currentDateTime.hour = m_dateTimeController.Hours(); currentDateTime.minute = m_dateTimeController.Minutes(); currentDateTime.second = m_dateTimeController.Seconds(); - currentDateTime.millis = 0; + currentDateTime.fractions256 = 0; - int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsData)); + int res = os_mbuf_append(ctxt->om, ¤tDateTime, sizeof(CtsCurrentTimeData)); + return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + + return 0; +} + +int CurrentTimeService::OnLocalTimeAccessed(struct ble_gatt_access_ctxt* ctxt) { + NRF_LOG_INFO("Setting timezone..."); + + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + CtsLocalTimeData result; + int res = os_mbuf_copydata(ctxt->om, 0, sizeof(CtsLocalTimeData), &result); + + if (res < 0) { + NRF_LOG_ERROR("Error reading BLE Data writing to CTS Local Time (too little data)") + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + NRF_LOG_INFO("Received data: %d %d", result.timezone, result.dst); + + m_dateTimeController.SetTimeZone(result.timezone, result.dst); + + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + CtsLocalTimeData currentTimezone; + currentTimezone.timezone = m_dateTimeController.TzOffset(); + currentTimezone.dst = m_dateTimeController.DstOffset(); + + int res = os_mbuf_append(ctxt->om, ¤tTimezone, sizeof(currentTimezone)); return (res == 0) ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; } @@ -64,12 +100,19 @@ int CurrentTimeService::OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handl } CurrentTimeService::CurrentTimeService(DateTime& dateTimeController) - : characteristicDefinition {{.uuid = &ctChrUuid.u, + : characteristicDefinition { + + {.uuid = &ctsLtChrUuid.u, .access_cb = CTSCallback, + .arg = this, + .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, + {.uuid = &ctsCtChrUuid.u, + .access_cb = CTSCallback, .arg = this, .flags = BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_READ}, - {0}}, + + {0}}, serviceDefinition { {/* Device Information Service */ .type = BLE_GATT_SVC_TYPE_PRIMARY, diff --git a/src/components/ble/CurrentTimeService.h b/src/components/ble/CurrentTimeService.h index ca87d970..bec75a2b 100644 --- a/src/components/ble/CurrentTimeService.h +++ b/src/components/ble/CurrentTimeService.h @@ -16,29 +16,40 @@ namespace Pinetime { CurrentTimeService(DateTime& dateTimeController); void Init(); - int OnTimeAccessed(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCurrentTimeServiceAccessed(struct ble_gatt_access_ctxt* ctxt); + int OnCurrentTimeAccessed(struct ble_gatt_access_ctxt* ctxt); + int OnLocalTimeAccessed(struct ble_gatt_access_ctxt* ctxt); private: static constexpr uint16_t ctsId {0x1805}; - static constexpr uint16_t ctsCharId {0x2a2b}; + static constexpr uint16_t ctsCurrentTimeCharId {0x2a2b}; + static constexpr uint16_t ctsLocalTimeCharId {0x2a0f}; static constexpr ble_uuid16_t ctsUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsId}; - static constexpr ble_uuid16_t ctChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCharId}; + static constexpr ble_uuid16_t ctsCtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsCurrentTimeCharId}; + static constexpr ble_uuid16_t ctsLtChrUuid {.u {.type = BLE_UUID_TYPE_16}, .value = ctsLocalTimeCharId}; - struct ble_gatt_chr_def characteristicDefinition[2]; + struct ble_gatt_chr_def characteristicDefinition[3]; struct ble_gatt_svc_def serviceDefinition[2]; typedef struct __attribute__((packed)) { - uint16_t year; + uint8_t year_LSO; // BLE GATT is little endian + uint8_t year_MSO; uint8_t month; uint8_t dayofmonth; uint8_t hour; uint8_t minute; uint8_t second; - uint8_t millis; - uint8_t reason; - } CtsData; + uint8_t dayofweek; + uint8_t fractions256; // currently ignored + uint8_t reason; // currently ignored, not that any host would set it anyway + } CtsCurrentTimeData; + + typedef struct __attribute__((packed)) { + int8_t timezone; + int8_t dst; + } CtsLocalTimeData; DateTime& m_dateTimeController; }; diff --git a/src/components/ble/DeviceInformationService.cpp b/src/components/ble/DeviceInformationService.cpp index 0f47c90f..f0d1b5a7 100644 --- a/src/components/ble/DeviceInformationService.cpp +++ b/src/components/ble/DeviceInformationService.cpp @@ -10,9 +10,9 @@ constexpr ble_uuid16_t DeviceInformationService::deviceInfoUuid; constexpr ble_uuid16_t DeviceInformationService::hwRevisionUuid; constexpr ble_uuid16_t DeviceInformationService::swRevisionUuid; -int DeviceInformationCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { +int DeviceInformationCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto deviceInformationService = static_cast<DeviceInformationService*>(arg); - return deviceInformationService->OnDeviceInfoRequested(conn_handle, attr_handle, ctxt); + return deviceInformationService->OnDeviceInfoRequested(ctxt); } void DeviceInformationService::Init() { @@ -24,7 +24,7 @@ void DeviceInformationService::Init() { ASSERT(res == 0); } -int DeviceInformationService::OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int DeviceInformationService::OnDeviceInfoRequested(struct ble_gatt_access_ctxt* ctxt) { const char* str; switch (ble_uuid_u16(ctxt->chr->uuid)) { diff --git a/src/components/ble/DeviceInformationService.h b/src/components/ble/DeviceInformationService.h index a269afb4..c4babd1b 100644 --- a/src/components/ble/DeviceInformationService.h +++ b/src/components/ble/DeviceInformationService.h @@ -14,7 +14,7 @@ namespace Pinetime { DeviceInformationService(); void Init(); - int OnDeviceInfoRequested(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnDeviceInfoRequested(struct ble_gatt_access_ctxt* ctxt); private: static constexpr uint16_t deviceInfoId {0x180a}; @@ -50,4 +50,4 @@ namespace Pinetime { struct ble_gatt_svc_def serviceDefinition[2]; }; } -}
\ No newline at end of file +} diff --git a/src/components/ble/DfuService.h b/src/components/ble/DfuService.h index 4708a4a6..b56911b9 100644 --- a/src/components/ble/DfuService.h +++ b/src/components/ble/DfuService.h @@ -13,9 +13,11 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Drivers { class SpiNorFlash; } + namespace Controllers { class Ble; @@ -46,10 +48,12 @@ namespace Pinetime { void OnNotificationTimer(); void Reset(); }; + class DfuImage { public: DfuImage(Pinetime::Drivers::SpiNorFlash& spiNorFlash) : spiNorFlash {spiNorFlash} { } + void Init(size_t chunkSize, size_t totalSize, uint16_t expectedCrc); void Erase(); void Append(uint8_t* data, size_t size); diff --git a/src/components/ble/FSService.h b/src/components/ble/FSService.h index 828925a8..b2299623 100644 --- a/src/components/ble/FSService.h +++ b/src/components/ble/FSService.h @@ -11,8 +11,10 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class Ble; + class FSService { public: FSService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::FS& fs); @@ -71,6 +73,7 @@ namespace Pinetime { FSState state; char filepath[maxpathlen]; // TODO ..ugh fixed filepath len int fileSize; + using ReadHeader = struct __attribute__((packed)) { commands command; uint8_t padding; @@ -89,6 +92,7 @@ namespace Pinetime { uint32_t chunklen; uint8_t chunk[]; }; + using ReadPacing = struct __attribute__((packed)) { commands command; uint8_t status; @@ -124,6 +128,7 @@ namespace Pinetime { uint32_t dataSize; uint8_t data[]; }; + using ListDirHeader = struct __attribute__((packed)) { commands command; uint8_t padding; @@ -171,6 +176,7 @@ namespace Pinetime { commands command; uint8_t status; }; + using MoveHeader = struct __attribute__((packed)) { commands command; uint8_t padding; diff --git a/src/components/ble/HeartRateService.cpp b/src/components/ble/HeartRateService.cpp index d49a02c8..c522e67e 100644 --- a/src/components/ble/HeartRateService.cpp +++ b/src/components/ble/HeartRateService.cpp @@ -9,9 +9,9 @@ constexpr ble_uuid16_t HeartRateService::heartRateServiceUuid; constexpr ble_uuid16_t HeartRateService::heartRateMeasurementUuid; namespace { - int HeartRateServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int HeartRateServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* heartRateService = static_cast<HeartRateService*>(arg); - return heartRateService->OnHeartRateRequested(conn_handle, attr_handle, ctxt); + return heartRateService->OnHeartRateRequested(attr_handle, ctxt); } } @@ -45,7 +45,7 @@ void HeartRateService::Init() { ASSERT(res == 0); } -int HeartRateService::OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int HeartRateService::OnHeartRateRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == heartRateMeasurementHandle) { NRF_LOG_INFO("HEARTRATE : handle = %d", heartRateMeasurementHandle); uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value @@ -60,7 +60,7 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) { if (!heartRateMeasurementNotificationEnable) return; - uint8_t buffer[2] = {0, heartRateController.HeartRate()}; // [0] = flags, [1] = hr value + uint8_t buffer[2] = {0, heartRateValue}; // [0] = flags, [1] = hr value auto* om = ble_hs_mbuf_from_flat(buffer, 2); uint16_t connectionHandle = system.nimble().connHandle(); @@ -72,12 +72,12 @@ void HeartRateService::OnNewHeartRateValue(uint8_t heartRateValue) { ble_gattc_notify_custom(connectionHandle, heartRateMeasurementHandle, om); } -void HeartRateService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void HeartRateService::SubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == heartRateMeasurementHandle) heartRateMeasurementNotificationEnable = true; } -void HeartRateService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void HeartRateService::UnsubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == heartRateMeasurementHandle) heartRateMeasurementNotificationEnable = false; -}
\ No newline at end of file +} diff --git a/src/components/ble/HeartRateService.h b/src/components/ble/HeartRateService.h index 4e4a5a42..003bdbd1 100644 --- a/src/components/ble/HeartRateService.h +++ b/src/components/ble/HeartRateService.h @@ -10,17 +10,19 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class HeartRateController; + class HeartRateService { public: HeartRateService(Pinetime::System::SystemTask& system, Controllers::HeartRateController& heartRateController); void Init(); - int OnHeartRateRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnHeartRateRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnNewHeartRateValue(uint8_t hearRateValue); - void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); - void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); + void SubscribeNotification(uint16_t attributeHandle); + void UnsubscribeNotification(uint16_t attributeHandle); private: Pinetime::System::SystemTask& system; diff --git a/src/components/ble/ImmediateAlertService.cpp b/src/components/ble/ImmediateAlertService.cpp index c80b3783..b9de615a 100644 --- a/src/components/ble/ImmediateAlertService.cpp +++ b/src/components/ble/ImmediateAlertService.cpp @@ -9,9 +9,9 @@ constexpr ble_uuid16_t ImmediateAlertService::immediateAlertServiceUuid; constexpr ble_uuid16_t ImmediateAlertService::alertLevelUuid; namespace { - int AlertLevelCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int AlertLevelCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* immediateAlertService = static_cast<ImmediateAlertService*>(arg); - return immediateAlertService->OnAlertLevelChanged(conn_handle, attr_handle, ctxt); + return immediateAlertService->OnAlertLevelChanged(attr_handle, ctxt); } const char* ToString(ImmediateAlertService::Levels level) { @@ -56,7 +56,7 @@ void ImmediateAlertService::Init() { ASSERT(res == 0); } -int ImmediateAlertService::OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int ImmediateAlertService::OnAlertLevelChanged(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == alertLevelHandle) { if (context->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { auto alertLevel = static_cast<Levels>(context->om->om_data[0]); diff --git a/src/components/ble/ImmediateAlertService.h b/src/components/ble/ImmediateAlertService.h index 1f778acd..47a05439 100644 --- a/src/components/ble/ImmediateAlertService.h +++ b/src/components/ble/ImmediateAlertService.h @@ -9,15 +9,17 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NotificationManager; + class ImmediateAlertService { public: enum class Levels : uint8_t { NoAlert = 0, MildAlert = 1, HighAlert = 2 }; ImmediateAlertService(Pinetime::System::SystemTask& systemTask, Pinetime::Controllers::NotificationManager& notificationManager); void Init(); - int OnAlertLevelChanged(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnAlertLevelChanged(uint16_t attributeHandle, ble_gatt_access_ctxt* context); private: Pinetime::System::SystemTask& systemTask; diff --git a/src/components/ble/MotionService.cpp b/src/components/ble/MotionService.cpp index 121ad3b0..604f22d5 100644 --- a/src/components/ble/MotionService.cpp +++ b/src/components/ble/MotionService.cpp @@ -21,9 +21,9 @@ namespace { constexpr ble_uuid128_t stepCountCharUuid {CharUuid(0x01, 0x00)}; constexpr ble_uuid128_t motionValuesCharUuid {CharUuid(0x02, 0x00)}; - int MotionServiceCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { + int MotionServiceCallback(uint16_t /*conn_handle*/, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { auto* motionService = static_cast<MotionService*>(arg); - return motionService->OnStepCountRequested(conn_handle, attr_handle, ctxt); + return motionService->OnStepCountRequested(attr_handle, ctxt); } } @@ -59,7 +59,7 @@ void MotionService::Init() { ASSERT(res == 0); } -int MotionService::OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context) { +int MotionService::OnStepCountRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context) { if (attributeHandle == stepCountHandle) { NRF_LOG_INFO("Motion-stepcount : handle = %d", stepCountHandle); uint32_t buffer = motionController.NbSteps(); @@ -90,11 +90,12 @@ void MotionService::OnNewStepCountValue(uint32_t stepCount) { ble_gattc_notify_custom(connectionHandle, stepCountHandle, om); } + void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) { if (!motionValuesNoficationEnabled) return; - int16_t buffer[3] = {motionController.X(), motionController.Y(), motionController.Z()}; + int16_t buffer[3] = {x, y, z}; auto* om = ble_hs_mbuf_from_flat(buffer, 3 * sizeof(int16_t)); uint16_t connectionHandle = system.nimble().connHandle(); @@ -106,14 +107,14 @@ void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) { ble_gattc_notify_custom(connectionHandle, motionValuesHandle, om); } -void MotionService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void MotionService::SubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == stepCountHandle) stepCountNoficationEnabled = true; else if (attributeHandle == motionValuesHandle) motionValuesNoficationEnabled = true; } -void MotionService::UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { +void MotionService::UnsubscribeNotification(uint16_t attributeHandle) { if (attributeHandle == stepCountHandle) stepCountNoficationEnabled = false; else if (attributeHandle == motionValuesHandle) diff --git a/src/components/ble/MotionService.h b/src/components/ble/MotionService.h index 1b4ac0a3..1b172528 100644 --- a/src/components/ble/MotionService.h +++ b/src/components/ble/MotionService.h @@ -10,18 +10,20 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class MotionController; + class MotionService { public: MotionService(Pinetime::System::SystemTask& system, Controllers::MotionController& motionController); void Init(); - int OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); + int OnStepCountRequested(uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnNewStepCountValue(uint32_t stepCount); void OnNewMotionValues(int16_t x, int16_t y, int16_t z); - void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); - void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); + void SubscribeNotification(uint16_t attributeHandle); + void UnsubscribeNotification(uint16_t attributeHandle); private: Pinetime::System::SystemTask& system; diff --git a/src/components/ble/MusicService.cpp b/src/components/ble/MusicService.cpp index fc7cef01..403c957b 100644 --- a/src/components/ble/MusicService.cpp +++ b/src/components/ble/MusicService.cpp @@ -48,8 +48,8 @@ namespace { constexpr uint8_t MaxStringSize {40}; - int MusicCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - return static_cast<Pinetime::Controllers::MusicService*>(arg)->OnCommand(conn_handle, attr_handle, ctxt); + int MusicCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + return static_cast<Pinetime::Controllers::MusicService*>(arg)->OnCommand(ctxt); } } @@ -122,7 +122,7 @@ void Pinetime::Controllers::MusicService::Init() { ASSERT(res == 0); } -int Pinetime::Controllers::MusicService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int Pinetime::Controllers::MusicService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); size_t bufferSize = notifSize; diff --git a/src/components/ble/MusicService.h b/src/components/ble/MusicService.h index 047d0d26..6aebc3c5 100644 --- a/src/components/ble/MusicService.h +++ b/src/components/ble/MusicService.h @@ -30,6 +30,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class MusicService { public: @@ -37,7 +38,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); void event(char event); diff --git a/src/components/ble/NavigationService.cpp b/src/components/ble/NavigationService.cpp index 76143686..5508d08c 100644 --- a/src/components/ble/NavigationService.cpp +++ b/src/components/ble/NavigationService.cpp @@ -39,9 +39,9 @@ namespace { constexpr ble_uuid128_t navManDistCharUuid {CharUuid(0x03, 0x00)}; constexpr ble_uuid128_t navProgressCharUuid {CharUuid(0x04, 0x00)}; - int NAVCallback(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - auto navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); - return navService->OnCommand(conn_handle, attr_handle, ctxt); + int NAVCallback(uint16_t /*conn_handle*/, uint16_t /*attr_handle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + auto* navService = static_cast<Pinetime::Controllers::NavigationService*>(arg); + return navService->OnCommand(ctxt); } } // namespace @@ -81,7 +81,7 @@ void Pinetime::Controllers::NavigationService::Init() { ASSERT(res == 0); } -int Pinetime::Controllers::NavigationService::OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt) { +int Pinetime::Controllers::NavigationService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { size_t notifSize = OS_MBUF_PKTLEN(ctxt->om); diff --git a/src/components/ble/NavigationService.h b/src/components/ble/NavigationService.h index c0c77f35..1c1739ba 100644 --- a/src/components/ble/NavigationService.h +++ b/src/components/ble/NavigationService.h @@ -30,6 +30,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class NavigationService { @@ -38,7 +39,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); std::string getFlag(); diff --git a/src/components/ble/NimbleController.cpp b/src/components/ble/NimbleController.cpp index 52f4e4ce..912f5927 100644 --- a/src/components/ble/NimbleController.cpp +++ b/src/components/ble/NimbleController.cpp @@ -322,14 +322,14 @@ int NimbleController::OnGAPEvent(ble_gap_event* event) { event->subscribe.prev_indicate); if (event->subscribe.reason == BLE_GAP_SUBSCRIBE_REASON_TERM) { - heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.UnsubscribeNotification(event->subscribe.attr_handle); + motionService.UnsubscribeNotification(event->subscribe.attr_handle); } else if (event->subscribe.prev_notify == 0 && event->subscribe.cur_notify == 1) { - heartRateService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.SubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.SubscribeNotification(event->subscribe.attr_handle); + motionService.SubscribeNotification(event->subscribe.attr_handle); } else if (event->subscribe.prev_notify == 1 && event->subscribe.cur_notify == 0) { - heartRateService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); - motionService.UnsubscribeNotification(event->subscribe.conn_handle, event->subscribe.attr_handle); + heartRateService.UnsubscribeNotification(event->subscribe.attr_handle); + motionService.UnsubscribeNotification(event->subscribe.attr_handle); } break; diff --git a/src/components/ble/NimbleController.h b/src/components/ble/NimbleController.h index 000231fe..8f1dfed7 100644 --- a/src/components/ble/NimbleController.h +++ b/src/components/ble/NimbleController.h @@ -58,12 +58,15 @@ namespace Pinetime { Pinetime::Controllers::MusicService& music() { return musicService; }; + Pinetime::Controllers::NavigationService& navigation() { return navService; }; + Pinetime::Controllers::AlertNotificationService& alertService() { return anService; }; + Pinetime::Controllers::WeatherService& weather() { return weatherService; }; diff --git a/src/components/ble/NotificationManager.h b/src/components/ble/NotificationManager.h index 4c199dbf..09b5a561 100644 --- a/src/components/ble/NotificationManager.h +++ b/src/components/ble/NotificationManager.h @@ -51,9 +51,11 @@ namespace Pinetime { static constexpr size_t MaximumMessageSize() { return MessageSize; }; + bool IsEmpty() const { return size == 0; } + size_t NbNotifications() const; private: diff --git a/src/components/ble/weather/WeatherService.cpp b/src/components/ble/weather/WeatherService.cpp index 23f53b74..e606d9bf 100644 --- a/src/components/ble/weather/WeatherService.cpp +++ b/src/components/ble/weather/WeatherService.cpp @@ -20,8 +20,8 @@ #include "libs/QCBOR/inc/qcbor/qcbor.h" #include "systemtask/SystemTask.h" -int WeatherCallback(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt, void* arg) { - return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(connHandle, attrHandle, ctxt); +int WeatherCallback(uint16_t /*connHandle*/, uint16_t /*attrHandle*/, struct ble_gatt_access_ctxt* ctxt, void* arg) { + return static_cast<Pinetime::Controllers::WeatherService*>(arg)->OnCommand(ctxt); } namespace Pinetime { @@ -41,7 +41,7 @@ namespace Pinetime { ASSERT(res == 0); } - int WeatherService::OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt) { + int WeatherService::OnCommand(struct ble_gatt_access_ctxt* ctxt) { if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { const uint8_t packetLen = OS_MBUF_PKTLEN(ctxt->om); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) if (packetLen <= 0) { @@ -552,11 +552,12 @@ namespace Pinetime { int16_t WeatherService::GetTodayMinTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + uint64_t currentDayEnd = currentTimestamp + ((24 - dateTimeController.Hours()) * 60 * 60) + + ((60 - dateTimeController.Minutes()) * 60) + (60 - dateTimeController.Seconds()); + uint64_t currentDayStart = currentDayEnd - 86400; int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp >= currentDayStart && header->timestamp < currentDayEnd && reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature; @@ -575,11 +576,12 @@ namespace Pinetime { int16_t WeatherService::GetTodayMaxTemp() const { uint64_t currentTimestamp = GetCurrentUnixTimestamp(); - uint64_t currentDayEnd = currentTimestamp - ((24 - dateTimeController.Hours()) * 60 * 60) - - ((60 - dateTimeController.Minutes()) * 60) - (60 - dateTimeController.Seconds()); + uint64_t currentDayEnd = currentTimestamp + ((24 - dateTimeController.Hours()) * 60 * 60) + + ((60 - dateTimeController.Minutes()) * 60) + (60 - dateTimeController.Seconds()); + uint64_t currentDayStart = currentDayEnd - 86400; int16_t result = -32768; for (auto&& header : this->timeline) { - if (header->eventType == WeatherData::eventtype::Temperature && IsEventStillValid(header, currentTimestamp) && + if (header->eventType == WeatherData::eventtype::Temperature && header->timestamp >= currentDayStart && header->timestamp < currentDayEnd && reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature != -32768) { int16_t temperature = reinterpret_cast<const std::unique_ptr<WeatherData::Temperature>&>(header)->temperature; diff --git a/src/components/ble/weather/WeatherService.h b/src/components/ble/weather/WeatherService.h index e37417da..00650e90 100644 --- a/src/components/ble/weather/WeatherService.h +++ b/src/components/ble/weather/WeatherService.h @@ -39,6 +39,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class WeatherService { @@ -47,7 +48,7 @@ namespace Pinetime { void Init(); - int OnCommand(uint16_t connHandle, uint16_t attrHandle, struct ble_gatt_access_ctxt* ctxt); + int OnCommand(struct ble_gatt_access_ctxt* ctxt); /* * Helper functions for quick access to currently valid data diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index 4dc16329..b744fbb2 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -20,14 +20,7 @@ void DateTime::SetCurrentTime(std::chrono::time_point<std::chrono::system_clock, UpdateTime(previousSystickCounter); // Update internal state without updating the time } -void DateTime::SetTime(uint16_t year, - uint8_t month, - uint8_t day, - uint8_t dayOfWeek, - uint8_t hour, - uint8_t minute, - uint8_t second, - uint32_t systickCounter) { +void DateTime::SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter) { std::tm tm = { /* .tm_sec = */ second, /* .tm_min = */ minute, @@ -36,6 +29,7 @@ void DateTime::SetTime(uint16_t year, /* .tm_mon = */ month - 1, /* .tm_year = */ year - 1900, }; + tm.tm_isdst = -1; // Use DST value from local time zone currentDateTime = std::chrono::system_clock::from_time_t(std::mktime(&tm)); @@ -50,6 +44,11 @@ void DateTime::SetTime(uint16_t year, systemTask->PushMessage(System::Messages::OnNewTime); } +void DateTime::SetTimeZone(int8_t timezone, int8_t dst) { + tzOffset = timezone; + dstOffset = dst; +} + void DateTime::UpdateTime(uint32_t systickCounter) { // Handle systick counter overflow uint32_t systickDelta = 0; @@ -136,6 +135,7 @@ void DateTime::Register(Pinetime::System::SystemTask* systemTask) { } using ClockType = Pinetime::Controllers::Settings::ClockType; + std::string DateTime::FormattedTime() { // Return time as a string in 12- or 24-hour format char buff[9]; diff --git a/src/components/datetime/DateTimeController.h b/src/components/datetime/DateTimeController.h index 81319d15..74ccf4da 100644 --- a/src/components/datetime/DateTimeController.h +++ b/src/components/datetime/DateTimeController.h @@ -9,6 +9,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class DateTime { public: @@ -30,37 +31,85 @@ namespace Pinetime { December }; - void SetTime(uint16_t year, - uint8_t month, - uint8_t day, - uint8_t dayOfWeek, - uint8_t hour, - uint8_t minute, - uint8_t second, - uint32_t systickCounter); + void SetTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second, uint32_t systickCounter); + + /* + * setter corresponding to the BLE Set Local Time characteristic. + * + * used to update difference between utc and local time (see UtcOffset()) + * + * parameters are in quarters of an our. Following the BLE CTS specification, + * timezone is expected to be constant over DST which will be reported in + * dst field. + */ + void SetTimeZone(int8_t timezone, int8_t dst); + void UpdateTime(uint32_t systickCounter); + uint16_t Year() const { return year; } + Months Month() const { return month; } + uint8_t Day() const { return day; } + Days DayOfWeek() const { return dayOfWeek; } + uint8_t Hours() const { return hour; } + uint8_t Minutes() const { return minute; } + uint8_t Seconds() const { return second; } + /* + * returns the offset between local time and UTC in quarters of an hour + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t UtcOffset() const { + return tzOffset + dstOffset; + } + + /* + * returns the offset between the (dst independent) local time zone and UTC + * in quarters of an hour + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t TzOffset() const { + return tzOffset; + } + + /* + * returns the offset between the local time zone and local time + * in quarters of an hour + * if != 0, DST is in effect, if == 0 not. + * + * Availability of this field depends on wether the companion app + * supports the BLE CTS Local Time Characteristic. Expect it to be 0 + * if not. + */ + int8_t DstOffset() const { + return dstOffset; + } + const char* MonthShortToString() const; const char* DayOfWeekShortToString() const; static const char* MonthShortToStringLow(Months month); @@ -69,6 +118,11 @@ namespace Pinetime { std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> CurrentDateTime() const { return currentDateTime; } + + std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> UTCDateTime() const { + return currentDateTime - std::chrono::seconds((tzOffset + dstOffset) * 15 * 60); + } + std::chrono::seconds Uptime() const { return uptime; } @@ -85,6 +139,8 @@ namespace Pinetime { uint8_t hour = 0; uint8_t minute = 0; uint8_t second = 0; + int8_t tzOffset = 0; + int8_t dstOffset = 0; uint32_t previousSystickCounter = 0; std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> currentDateTime; diff --git a/src/components/fs/FS.cpp b/src/components/fs/FS.cpp index 14b05525..0bb59afa 100644 --- a/src/components/fs/FS.cpp +++ b/src/components/fs/FS.cpp @@ -89,18 +89,23 @@ int FS::DirClose(lfs_dir_t* lfs_dir) { int FS::DirRead(lfs_dir_t* dir, lfs_info* info) { return lfs_dir_read(&lfs, dir, info); } + int FS::DirRewind(lfs_dir_t* dir) { return lfs_dir_rewind(&lfs, dir); } + int FS::DirCreate(const char* path) { return lfs_mkdir(&lfs, path); } + int FS::Rename(const char* oldPath, const char* newPath) { return lfs_rename(&lfs, oldPath, newPath); } + int FS::Stat(const char* path, lfs_info* info) { return lfs_stat(&lfs, path, info); } + lfs_ssize_t FS::GetFSSize() { return lfs_fs_size(&lfs); } @@ -110,7 +115,7 @@ lfs_ssize_t FS::GetFSSize() { ----------- Interface between littlefs and SpiNorFlash ----------- */ -int FS::SectorSync(const struct lfs_config* c) { +int FS::SectorSync(const struct lfs_config* /*c*/) { return 0; } @@ -142,7 +147,7 @@ int FS::SectorRead(const struct lfs_config* c, lfs_block_t block, lfs_off_t off, */ namespace { - lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t mode) { + lv_fs_res_t lvglOpen(lv_fs_drv_t* drv, void* file_p, const char* path, lv_fs_mode_t /*mode*/) { lfs_file_t* file = static_cast<lfs_file_t*>(file_p); FS* filesys = static_cast<FS*>(drv->user_data); int res = filesys->FileOpen(file, path, LFS_O_RDONLY); @@ -195,4 +200,4 @@ void FS::LVGLFileSystemInit() { fs_drv.user_data = this; lv_fs_drv_register(&fs_drv); -}
\ No newline at end of file +} diff --git a/src/components/fs/FS.h b/src/components/fs/FS.h index 87fcdc23..9730e474 100644 --- a/src/components/fs/FS.h +++ b/src/components/fs/FS.h @@ -35,6 +35,7 @@ namespace Pinetime { static size_t getSize() { return size; } + static size_t getBlockSize() { return blockSize; } diff --git a/src/components/gfx/Gfx.h b/src/components/gfx/Gfx.h index 54c4a8b7..17c248f7 100644 --- a/src/components/gfx/Gfx.h +++ b/src/components/gfx/Gfx.h @@ -10,6 +10,7 @@ namespace Pinetime { namespace Drivers { class St7789; } + namespace Components { class Gfx : public Pinetime::Drivers::BufferProvider { public: @@ -33,9 +34,11 @@ namespace Pinetime { 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; diff --git a/src/components/heartrate/HeartRateController.h b/src/components/heartrate/HeartRateController.h index a63f1a70..f66c79f8 100644 --- a/src/components/heartrate/HeartRateController.h +++ b/src/components/heartrate/HeartRateController.h @@ -7,9 +7,11 @@ namespace Pinetime { namespace Applications { class HeartRateTask; } + namespace System { class SystemTask; } + namespace Controllers { class HeartRateController { public: @@ -21,9 +23,11 @@ namespace Pinetime { void Update(States newState, uint8_t heartRate); void SetHeartRateTask(Applications::HeartRateTask* task); + States State() const { return state; } + uint8_t HeartRate() const { return heartRate; } diff --git a/src/components/heartrate/Ppg.cpp b/src/components/heartrate/Ppg.cpp index a5d83696..900b1c22 100644 --- a/src/components/heartrate/Ppg.cpp +++ b/src/components/heartrate/Ppg.cpp @@ -29,8 +29,9 @@ namespace { auto z1 = CompareShift(d, mn - 1, size); for (int i = mn; i < mx + 1; i++) { auto z = CompareShift(d, i, size); - if (z2 > z1 && z1 < z) + if (z2 > z1 && z1 < z) { return i; + } z2 = z1; z1 = z; } @@ -52,41 +53,48 @@ int8_t Ppg::Preprocess(float spl) { auto spl_int = static_cast<int8_t>(spl); - if (dataIndex < 200) + if (dataIndex < 200) { data[dataIndex++] = spl_int; + } return spl_int; } -float Ppg::HeartRate() { - if (dataIndex < 200) +int Ppg::HeartRate() { + if (dataIndex < 200) { return 0; + } NRF_LOG_INFO("PREPROCESS, offset = %d", offset); auto hr = ProcessHeartRate(); dataIndex = 0; return hr; } -float Ppg::ProcessHeartRate() { - auto t0 = Trough(data.data(), dataIndex, 7, 48); - if (t0 < 0) + +int Ppg::ProcessHeartRate() { + int t0 = Trough(data.data(), dataIndex, 7, 48); + if (t0 < 0) { return 0; + } - float t1 = t0 * 2; + int t1 = t0 * 2; t1 = Trough(data.data(), dataIndex, t1 - 5, t1 + 5); - if (t1 < 0) + if (t1 < 0) { return 0; + } - float t2 = static_cast<int>(t1 * 3) / 2; + int t2 = (t1 * 3) / 2; t2 = Trough(data.data(), dataIndex, t2 - 5, t2 + 5); - if (t2 < 0) + if (t2 < 0) { return 0; + } - float t3 = static_cast<int>(t2 * 4) / 3; + int t3 = (t2 * 4) / 3; t3 = Trough(data.data(), dataIndex, t3 - 4, t3 + 4); - if (t3 < 0) - return static_cast<int>(60 * 24 * 3) / static_cast<int>(t2); + if (t3 < 0) { + return (60 * 24 * 3) / t2; + } - return static_cast<int>(60 * 24 * 4) / static_cast<int>(t3); + return (60 * 24 * 4) / t3; } void Ppg::SetOffset(uint16_t offset) { diff --git a/src/components/heartrate/Ppg.h b/src/components/heartrate/Ppg.h index 7000c871..1f709bab 100644 --- a/src/components/heartrate/Ppg.h +++ b/src/components/heartrate/Ppg.h @@ -12,9 +12,9 @@ namespace Pinetime { public: Ppg(); int8_t Preprocess(float spl); - float HeartRate(); + int HeartRate(); - void SetOffset(uint16_t i); + void SetOffset(uint16_t offset); void Reset(); private: @@ -25,7 +25,7 @@ namespace Pinetime { Ptagc agc; Biquad lpf; - float ProcessHeartRate(); + int ProcessHeartRate(); }; } } diff --git a/src/components/heartrate/Ptagc.cpp b/src/components/heartrate/Ptagc.cpp index 1c60bc23..221be460 100644 --- a/src/components/heartrate/Ptagc.cpp +++ b/src/components/heartrate/Ptagc.cpp @@ -14,13 +14,15 @@ Ptagc::Ptagc(float start, float decay, float threshold) : peak {start}, decay {d } float Ptagc::Step(float spl) { - if (std::abs(spl) > peak) + if (std::abs(spl) > peak) { peak *= boost; - else + } else { peak *= decay; + } - if ((spl > (peak * threshold)) || (spl < (peak * -threshold))) + if ((spl > (peak * threshold)) || (spl < (peak * -threshold))) { return 0.0f; + } spl = 100.0f * spl / (2.0f * peak); return spl; diff --git a/src/components/motion/MotionController.cpp b/src/components/motion/MotionController.cpp index 7dd32127..8ba46814 100644 --- a/src/components/motion/MotionController.cpp +++ b/src/components/motion/MotionController.cpp @@ -26,10 +26,9 @@ bool MotionController::Should_RaiseWake(bool isSleeping) { if (not isSleeping) { if (y <= 0) { return false; - } else { - lastYForWakeUp = 0; - return false; } + lastYForWakeUp = 0; + return false; } if (y >= 0) { @@ -62,6 +61,7 @@ bool MotionController::Should_ShakeWake(uint16_t thresh) { lastZForShake = z; return wake; } + int32_t MotionController::currentShakeSpeed() { return accumulatedspeed; } @@ -69,6 +69,7 @@ int32_t MotionController::currentShakeSpeed() { void MotionController::IsSensorOk(bool isOk) { isSensorOk = isOk; } + void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) { switch (types) { case Drivers::Bma421::DeviceTypes::BMA421: @@ -82,6 +83,7 @@ void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) { break; } } + void MotionController::SetService(Pinetime::Controllers::MotionService* service) { this->service = service; } diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h index f80b11b9..857bd45a 100644 --- a/src/components/motion/MotionController.h +++ b/src/components/motion/MotionController.h @@ -19,12 +19,15 @@ namespace Pinetime { int16_t X() const { return x; } + int16_t Y() const { return y; } + int16_t Z() const { return z; } + uint32_t NbSteps() const { return nbSteps; } @@ -32,6 +35,7 @@ namespace Pinetime { void ResetTrip() { currentTripSteps = 0; } + uint32_t GetTripSteps() const { return currentTripSteps; } @@ -40,6 +44,7 @@ namespace Pinetime { bool Should_RaiseWake(bool isSleeping); int32_t currentShakeSpeed(); void IsSensorOk(bool isOk); + bool IsSensorOk() const { return isSensorOk; } diff --git a/src/components/motor/MotorController.cpp b/src/components/motor/MotorController.cpp index db6103f4..4e392416 100644 --- a/src/components/motor/MotorController.cpp +++ b/src/components/motor/MotorController.cpp @@ -34,6 +34,6 @@ void MotorController::StopRinging() { nrf_gpio_pin_set(PinMap::Motor); } -void MotorController::StopMotor(TimerHandle_t xTimer) { +void MotorController::StopMotor(TimerHandle_t /*xTimer*/) { nrf_gpio_pin_set(PinMap::Motor); } diff --git a/src/components/settings/Settings.h b/src/components/settings/Settings.h index 93f861f3..d1e71656 100644 --- a/src/components/settings/Settings.h +++ b/src/components/settings/Settings.h @@ -45,6 +45,7 @@ namespace Pinetime { Colors ColorBG = Colors::Black; PTSGaugeStyle gaugeStyle = PTSGaugeStyle::Full; }; + struct WatchFaceInfineat { bool showSideCover = true; int colorIndex = 0; @@ -66,6 +67,7 @@ namespace Pinetime { } settings.clockFace = face; }; + uint8_t GetClockFace() const { return settings.clockFace; }; @@ -76,6 +78,7 @@ namespace Pinetime { } settings.chimesOption = chimeOption; }; + ChimesOption GetChimeOption() const { return settings.chimesOption; }; @@ -85,6 +88,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorTime = colorTime; }; + Colors GetPTSColorTime() const { return settings.PTS.ColorTime; }; @@ -94,6 +98,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorBar = colorBar; }; + Colors GetPTSColorBar() const { return settings.PTS.ColorBar; }; @@ -103,6 +108,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.ColorBG = colorBG; }; + Colors GetPTSColorBG() const { return settings.PTS.ColorBG; }; @@ -113,6 +119,7 @@ namespace Pinetime { settingsChanged = true; } }; + bool GetInfineatShowSideCover() const { return settings.watchFaceInfineat.showSideCover; }; @@ -123,6 +130,7 @@ namespace Pinetime { settingsChanged = true; } }; + int GetInfineatColorIndex() const { return settings.watchFaceInfineat.colorIndex; }; @@ -132,6 +140,7 @@ namespace Pinetime { settingsChanged = true; settings.PTS.gaugeStyle = gaugeStyle; }; + PTSGaugeStyle GetPTSGaugeStyle() const { return settings.PTS.gaugeStyle; }; @@ -147,6 +156,7 @@ namespace Pinetime { void SetSettingsMenu(uint8_t menu) { settingsMenu = menu; }; + uint8_t GetSettingsMenu() const { return settingsMenu; }; @@ -157,6 +167,7 @@ namespace Pinetime { } settings.clockType = clocktype; }; + ClockType GetClockType() const { return settings.clockType; }; @@ -167,6 +178,7 @@ namespace Pinetime { } settings.notificationStatus = status; }; + Notification GetNotificationStatus() const { return settings.notificationStatus; }; @@ -255,6 +267,7 @@ namespace Pinetime { Pinetime::Controllers::FS& fs; static constexpr uint32_t settingsVersion = 0x0004; + struct SettingsData { uint32_t version = settingsVersion; uint32_t stepsGoal = 10000; diff --git a/src/components/timer/TimerController.h b/src/components/timer/TimerController.h index 93d8afc6..20f07e82 100644 --- a/src/components/timer/TimerController.h +++ b/src/components/timer/TimerController.h @@ -7,6 +7,7 @@ namespace Pinetime { namespace System { class SystemTask; } + namespace Controllers { class TimerController { diff --git a/src/components/utility/LinearApproximation.h b/src/components/utility/LinearApproximation.h new file mode 100644 index 00000000..f7104ced --- /dev/null +++ b/src/components/utility/LinearApproximation.h @@ -0,0 +1,41 @@ +#pragma once + +#include <cstddef> +#include <array> + +namespace Pinetime { + namespace Utility { + + // based on: https://github.com/SHristov92/LinearApproximation/blob/main/Linear.h + template <typename Key, typename Value, std::size_t Size> class LinearApproximation { + using Point = struct { + Key key; + Value value; + }; + + public: + LinearApproximation(const std::array<Point, Size>&& sorted_points) : points {sorted_points} { + } + + Value GetValue(Key key) const { + if (key <= points[0].key) { + return points[0].value; + } + + for (std::size_t i = 1; i < Size; i++) { + const auto& p = points[i]; + const auto& p_prev = points[i - 1]; + + if (key < p.key) { + return p_prev.value + (key - p_prev.key) * (p.value - p_prev.value) / (p.key - p_prev.key); + } + } + + return points[Size - 1].value; + } + + private: + std::array<Point, Size> points; + }; + } +} diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h index 8aad9535..89b05d87 100644 --- a/src/displayapp/Apps.h +++ b/src/displayapp/Apps.h @@ -34,8 +34,7 @@ namespace Pinetime { SettingDisplay, SettingWakeUp, SettingSteps, - SettingSetDate, - SettingSetTime, + SettingSetDateTime, SettingChimes, SettingShakeThreshold, SettingBluetooth, diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 108e380d..725caaf4 100644 --- a/src/displayapp/DisplayApp.cpp +++ b/src/displayapp/DisplayApp.cpp @@ -43,8 +43,7 @@ #include "displayapp/screens/settings/SettingWakeUp.h" #include "displayapp/screens/settings/SettingDisplay.h" #include "displayapp/screens/settings/SettingSteps.h" -#include "displayapp/screens/settings/SettingSetDate.h" -#include "displayapp/screens/settings/SettingSetTime.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" #include "displayapp/screens/settings/SettingChimes.h" #include "displayapp/screens/settings/SettingShakeThreshold.h" #include "displayapp/screens/settings/SettingBluetooth.h" @@ -102,9 +101,9 @@ void DisplayApp::Start(System::BootErrors error) { bootError = error; if (error == System::BootErrors::TouchController) { - LoadApp(Apps::Error, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Error, DisplayApp::FullRefreshDirections::None); } else { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); } if (pdPASS != xTaskCreate(DisplayApp::Process, "displayapp", 800, this, 0, &taskHandle)) { @@ -132,7 +131,25 @@ void DisplayApp::InitHw() { void DisplayApp::Refresh() { auto LoadPreviousScreen = [this]() { - LoadApp(returnToApp, returnDirection); + FullRefreshDirections returnDirection; + switch (appStackDirections.Pop()) { + case FullRefreshDirections::Up: + returnDirection = FullRefreshDirections::Down; + break; + case FullRefreshDirections::Down: + returnDirection = FullRefreshDirections::Up; + break; + case FullRefreshDirections::LeftAnim: + returnDirection = FullRefreshDirections::RightAnim; + break; + case FullRefreshDirections::RightAnim: + returnDirection = FullRefreshDirections::LeftAnim; + break; + default: + returnDirection = FullRefreshDirections::None; + break; + } + LoadScreen(returnAppStack.Pop(), returnDirection); }; TickType_t queueTimeout; @@ -152,7 +169,7 @@ void DisplayApp::Refresh() { } Messages msg; - if (xQueueReceive(msgQueue, &msg, queueTimeout)) { + if (xQueueReceive(msgQueue, &msg, queueTimeout) == pdTRUE) { switch (msg) { case Messages::DimScreen: brightnessController.Set(Controllers::BrightnessController::Levels::Low); @@ -180,14 +197,14 @@ void DisplayApp::Refresh() { // Screens::Clock::BleConnectionStates::NotConnected); break; case Messages::NewNotification: - LoadApp(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down); break; case Messages::TimerDone: if (currentApp == Apps::Timer) { auto* timer = static_cast<Screens::Timer*>(currentScreen.get()); timer->Reset(); } else { - LoadApp(Apps::Timer, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Timer, DisplayApp::FullRefreshDirections::Up); } break; case Messages::AlarmTriggered: @@ -195,11 +212,11 @@ void DisplayApp::Refresh() { auto* alarm = static_cast<Screens::Alarm*>(currentScreen.get()); alarm->SetAlerting(); } else { - LoadApp(Apps::Alarm, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Alarm, DisplayApp::FullRefreshDirections::None); } break; case Messages::ShowPairingKey: - LoadApp(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::PassKey, DisplayApp::FullRefreshDirections::Up); break; case Messages::TouchEvent: { if (state != States::Running) { @@ -209,17 +226,30 @@ void DisplayApp::Refresh() { if (gesture == TouchEvents::None) { break; } + auto LoadDirToReturnSwipe = [](DisplayApp::FullRefreshDirections refreshDirection) { + switch (refreshDirection) { + default: + case DisplayApp::FullRefreshDirections::Up: + return TouchEvents::SwipeDown; + case DisplayApp::FullRefreshDirections::Down: + return TouchEvents::SwipeUp; + case DisplayApp::FullRefreshDirections::LeftAnim: + return TouchEvents::SwipeRight; + case DisplayApp::FullRefreshDirections::RightAnim: + return TouchEvents::SwipeLeft; + } + }; if (!currentScreen->OnTouchEvent(gesture)) { if (currentApp == Apps::Clock) { switch (gesture) { case TouchEvents::SwipeUp: - LoadApp(Apps::Launcher, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::Launcher, DisplayApp::FullRefreshDirections::Up); break; case TouchEvents::SwipeDown: - LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); break; case TouchEvents::SwipeRight: - LoadApp(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim); + LoadNewScreen(Apps::QuickSettings, DisplayApp::FullRefreshDirections::RightAnim); break; case TouchEvents::DoubleTap: PushMessageToSystemTask(System::Messages::GoToSleep); @@ -227,7 +257,7 @@ void DisplayApp::Refresh() { default: break; } - } else if (returnTouchEvent == gesture) { + } else if (gesture == LoadDirToReturnSwipe(appStackDirections.Top())) { LoadPreviousScreen(); } } else { @@ -246,26 +276,28 @@ void DisplayApp::Refresh() { case Messages::ButtonLongPressed: if (currentApp != Apps::Clock) { if (currentApp == Apps::Notifications) { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::Up); } else if (currentApp == Apps::QuickSettings) { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::LeftAnim); } else { - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::Down); } + appStackDirections.Reset(); + returnAppStack.Reset(); } break; case Messages::ButtonLongerPressed: // Create reboot app and open it instead - LoadApp(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up); + LoadNewScreen(Apps::SysInfo, DisplayApp::FullRefreshDirections::Up); break; case Messages::ButtonDoubleClicked: if (currentApp != Apps::Notifications && currentApp != Apps::NotificationsPreview) { - LoadApp(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::Notifications, DisplayApp::FullRefreshDirections::Down); } break; case Messages::BleFirmwareUpdateStarted: - LoadApp(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); + LoadNewScreen(Apps::FirmwareUpdate, DisplayApp::FullRefreshDirections::Down); break; case Messages::BleRadioEnableToggle: PushMessageToSystemTask(System::Messages::BleRadioEnableToggle); @@ -275,7 +307,7 @@ void DisplayApp::Refresh() { // What should happen here? break; case Messages::Clock: - LoadApp(Apps::Clock, DisplayApp::FullRefreshDirections::None); + LoadNewScreen(Apps::Clock, DisplayApp::FullRefreshDirections::None); break; } } @@ -285,7 +317,7 @@ void DisplayApp::Refresh() { } if (nextApp != Apps::None) { - LoadApp(nextApp, nextDirection); + LoadNewScreen(nextApp, nextDirection); nextApp = Apps::None; } } @@ -295,27 +327,28 @@ void DisplayApp::StartApp(Apps app, DisplayApp::FullRefreshDirections direction) nextDirection = direction; } -void DisplayApp::ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent) { - returnToApp = app; - returnDirection = direction; - returnTouchEvent = touchEvent; +void DisplayApp::LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction) { + // Don't add the same screen to the stack back to back. + // This is mainly to fix an issue with receiving two notifications at the same time + // and shouldn't happen otherwise. + if (app != currentApp) { + returnAppStack.Push(currentApp); + appStackDirections.Push(direction); + } + LoadScreen(app, direction); } -void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) { +void DisplayApp::LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction) { touchHandler.CancelTap(); ApplyBrightness(); currentScreen.reset(nullptr); SetFullRefresh(direction); - // default return to launcher - ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown); - switch (app) { case Apps::Launcher: currentScreen = std::make_unique<Screens::ApplicationList>(this, settingsController, batteryController, bleController, dateTimeController); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::None: case Apps::Clock: @@ -332,21 +365,17 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Error: currentScreen = std::make_unique<Screens::Error>(this, bootError); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::FirmwareValidation: currentScreen = std::make_unique<Screens::FirmwareValidation>(this, validator); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::FirmwareUpdate: currentScreen = std::make_unique<Screens::FirmwareUpdate>(this, bleController); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::PassKey: currentScreen = std::make_unique<Screens::PassKey>(this, bleController.GetPairingKey()); - ReturnApp(Apps::Clock, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::Notifications: @@ -356,7 +385,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, *systemTask, Screens::Notifications::Modes::Normal); - ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::NotificationsPreview: currentScreen = std::make_unique<Screens::Notifications>(this, @@ -365,7 +393,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, *systemTask, Screens::Notifications::Modes::Preview); - ReturnApp(Apps::Clock, FullRefreshDirections::Up, TouchEvents::SwipeUp); break; case Apps::Timer: currentScreen = std::make_unique<Screens::Timer>(this, timerController); @@ -383,55 +410,39 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) motorController, settingsController, bleController); - ReturnApp(Apps::Clock, FullRefreshDirections::LeftAnim, TouchEvents::SwipeLeft); break; case Apps::Settings: currentScreen = std::make_unique<Screens::Settings>(this, settingsController); - ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingWatchFace: currentScreen = std::make_unique<Screens::SettingWatchFace>(this, settingsController, filesystem); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingTimeFormat: currentScreen = std::make_unique<Screens::SettingTimeFormat>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingWakeUp: currentScreen = std::make_unique<Screens::SettingWakeUp>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingDisplay: currentScreen = std::make_unique<Screens::SettingDisplay>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingSteps: currentScreen = std::make_unique<Screens::SettingSteps>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; - case Apps::SettingSetDate: - currentScreen = std::make_unique<Screens::SettingSetDate>(this, dateTimeController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); - break; - case Apps::SettingSetTime: - currentScreen = std::make_unique<Screens::SettingSetTime>(this, dateTimeController, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); + case Apps::SettingSetDateTime: + currentScreen = std::make_unique<Screens::SettingSetDateTime>(this, dateTimeController, settingsController); break; case Apps::SettingChimes: currentScreen = std::make_unique<Screens::SettingChimes>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingShakeThreshold: currentScreen = std::make_unique<Screens::SettingShakeThreshold>(this, settingsController, motionController, *systemTask); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SettingBluetooth: currentScreen = std::make_unique<Screens::SettingBluetooth>(this, settingsController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::BatteryInfo: currentScreen = std::make_unique<Screens::BatteryInfo>(this, batteryController); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::SysInfo: currentScreen = std::make_unique<Screens::SystemInfo>(this, @@ -442,11 +453,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) watchdog, motionController, touchPanel); - ReturnApp(Apps::Settings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::FlashLight: currentScreen = std::make_unique<Screens::FlashLight>(this, *systemTask, brightnessController); - ReturnApp(Apps::QuickSettings, FullRefreshDirections::Down, TouchEvents::SwipeDown); break; case Apps::StopWatch: currentScreen = std::make_unique<Screens::StopWatch>(this, *systemTask); @@ -471,7 +480,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) break; case Apps::Metronome: currentScreen = std::make_unique<Screens::Metronome>(this, motorController, *systemTask); - ReturnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::None); break; case Apps::Motion: currentScreen = std::make_unique<Screens::Motion>(this, motionController); @@ -485,10 +493,9 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) void DisplayApp::PushMessage(Messages msg) { if (in_isr()) { - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(msgQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { + if (xHigherPriorityTaskWoken == pdTRUE) { portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } else { @@ -530,10 +537,10 @@ void DisplayApp::PushMessageToSystemTask(Pinetime::System::Messages message) { void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) { this->systemTask = systemTask; } + void DisplayApp::ApplyBrightness() { auto brightness = settingsController.GetBrightness(); - if(brightness != Controllers::BrightnessController::Levels::Low && - brightness != Controllers::BrightnessController::Levels::Medium && + if (brightness != Controllers::BrightnessController::Levels::Low && brightness != Controllers::BrightnessController::Levels::Medium && brightness != Controllers::BrightnessController::Levels::High) { brightness = Controllers::BrightnessController::Levels::High; } diff --git a/src/displayapp/DisplayApp.h b/src/displayapp/DisplayApp.h index 4c54e227..c1d04cc9 100644 --- a/src/displayapp/DisplayApp.h +++ b/src/displayapp/DisplayApp.h @@ -20,6 +20,8 @@ #include "displayapp/Messages.h" #include "BootErrors.h" +#include "StaticStack.h" + namespace Pinetime { namespace Drivers { @@ -27,6 +29,7 @@ namespace Pinetime { class Cst816S; class WatchdogView; } + namespace Controllers { class Settings; class Battery; @@ -41,6 +44,7 @@ namespace Pinetime { namespace System { class SystemTask; }; + namespace Applications { class DisplayApp { public: @@ -114,14 +118,18 @@ namespace Pinetime { static void Process(void* instance); void InitHw(); void Refresh(); - void ReturnApp(Apps app, DisplayApp::FullRefreshDirections direction, TouchEvents touchEvent); - void LoadApp(Apps app, DisplayApp::FullRefreshDirections direction); + void LoadNewScreen(Apps app, DisplayApp::FullRefreshDirections direction); + void LoadScreen(Apps app, DisplayApp::FullRefreshDirections direction); void PushMessageToSystemTask(Pinetime::System::Messages message); Apps nextApp = Apps::None; DisplayApp::FullRefreshDirections nextDirection; System::BootErrors bootError; void ApplyBrightness(); + + static constexpr size_t returnAppStackSize = 10; + StaticStack<Apps, returnAppStackSize> returnAppStack; + StaticStack<FullRefreshDirections, returnAppStackSize> appStackDirections; }; } } diff --git a/src/displayapp/DisplayAppRecovery.cpp b/src/displayapp/DisplayAppRecovery.cpp index e553aa87..ecc01e9b 100644 --- a/src/displayapp/DisplayAppRecovery.cpp +++ b/src/displayapp/DisplayAppRecovery.cpp @@ -11,22 +11,22 @@ using namespace Pinetime::Applications; DisplayApp::DisplayApp(Drivers::St7789& lcd, - Components::LittleVgl& lvgl, - Drivers::Cst816S& touchPanel, - Controllers::Battery& batteryController, + Components::LittleVgl& /*lvgl*/, + Drivers::Cst816S& /*touchPanel*/, + Controllers::Battery& /*batteryController*/, Controllers::Ble& bleController, - Controllers::DateTime& dateTimeController, - Drivers::WatchdogView& watchdog, - Pinetime::Controllers::NotificationManager& notificationManager, - Pinetime::Controllers::HeartRateController& heartRateController, - Controllers::Settings& settingsController, - Pinetime::Controllers::MotorController& motorController, - Pinetime::Controllers::MotionController& motionController, - Pinetime::Controllers::TimerController& timerController, - Pinetime::Controllers::AlarmController& alarmController, - Pinetime::Controllers::BrightnessController& brightnessController, - Pinetime::Controllers::TouchHandler& touchHandler, - Pinetime::Controllers::FS& filesystem) + Controllers::DateTime& /*dateTimeController*/, + Drivers::WatchdogView& /*watchdog*/, + Pinetime::Controllers::NotificationManager& /*notificationManager*/, + Pinetime::Controllers::HeartRateController& /*heartRateController*/, + Controllers::Settings& /*settingsController*/, + Pinetime::Controllers::MotorController& /*motorController*/, + Pinetime::Controllers::MotionController& /*motionController*/, + Pinetime::Controllers::TimerController& /*timerController*/, + Pinetime::Controllers::AlarmController& /*alarmController*/, + Pinetime::Controllers::BrightnessController& /*brightnessController*/, + Pinetime::Controllers::TouchHandler& /*touchHandler*/, + Pinetime::Controllers::FS& /*filesystem*/) : lcd {lcd}, bleController {bleController} { } @@ -121,5 +121,5 @@ void DisplayApp::PushMessage(Display::Messages msg) { } } -void DisplayApp::Register(Pinetime::System::SystemTask* systemTask) { +void DisplayApp::Register(Pinetime::System::SystemTask* /*systemTask*/) { } diff --git a/src/displayapp/DisplayAppRecovery.h b/src/displayapp/DisplayAppRecovery.h index 7d4f0fd0..97aaca88 100644 --- a/src/displayapp/DisplayAppRecovery.h +++ b/src/displayapp/DisplayAppRecovery.h @@ -22,6 +22,7 @@ namespace Pinetime { class Cst816S; class WatchdogView; } + namespace Controllers { class Settings; class Battery; @@ -63,9 +64,11 @@ namespace Pinetime { Pinetime::Controllers::TouchHandler& touchHandler, Pinetime::Controllers::FS& filesystem); void Start(); + void Start(Pinetime::System::BootErrors) { Start(); }; + void PushMessage(Pinetime::Applications::Display::Messages msg); void Register(Pinetime::System::SystemTask* systemTask); diff --git a/src/displayapp/DummyLittleVgl.h b/src/displayapp/DummyLittleVgl.h index 05355a97..7a8ae999 100644 --- a/src/displayapp/DummyLittleVgl.h +++ b/src/displayapp/DummyLittleVgl.h @@ -11,6 +11,7 @@ namespace Pinetime { class LittleVgl { public: enum class FullRefreshDirections { None, Up, Down }; + LittleVgl(Pinetime::Drivers::St7789& lcd, Pinetime::Drivers::Cst816S& touchPanel) { } @@ -24,13 +25,17 @@ namespace Pinetime { void FlushDisplay(const lv_area_t* area, lv_color_t* color_p) { } + bool GetTouchPadInfo(lv_indev_data_t* ptr) { return false; } + void SetFullRefresh(FullRefreshDirections direction) { } + void SetNewTapEvent(uint16_t x, uint16_t y) { } + void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) { } }; diff --git a/src/displayapp/InfiniTimeTheme.cpp b/src/displayapp/InfiniTimeTheme.cpp index 4290d87f..6795647e 100644 --- a/src/displayapp/InfiniTimeTheme.cpp +++ b/src/displayapp/InfiniTimeTheme.cpp @@ -1,4 +1,17 @@ #include "displayapp/InfiniTimeTheme.h" +#include <algorithm> + +// Replace LV_DPX with a constexpr version using a constant LV_DPI +#undef LV_DPX + +namespace { + constexpr int LV_DPX(int n) { + if (n == 0) { + return 0; + } + return std::max(((LV_DPI * n + 80) / 160), 1); /*+80 for rounding*/ + } +} static void theme_apply(lv_obj_t* obj, lv_theme_style_t name); @@ -47,7 +60,6 @@ static void basic_init() { style_init_reset(&style_box); lv_style_set_bg_opa(&style_box, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_radius(&style_box, LV_STATE_DEFAULT, 10); - lv_style_set_value_color(&style_box, LV_STATE_DEFAULT, Colors::bg); lv_style_set_value_font(&style_box, LV_STATE_DEFAULT, theme.font_normal); style_init_reset(&style_label_white); @@ -60,25 +72,12 @@ static void basic_init() { lv_style_set_bg_color(&style_btn, LV_STATE_DEFAULT, Colors::bg); lv_style_set_bg_color(&style_btn, LV_STATE_CHECKED, Colors::highlight); lv_style_set_bg_color(&style_btn, LV_STATE_DISABLED, Colors::bgDark); - lv_style_set_border_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_border_width(&style_btn, LV_STATE_DEFAULT, 0); lv_style_set_text_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_style_set_text_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); - lv_style_set_value_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_value_color(&style_btn, LV_STATE_DISABLED, LV_COLOR_GRAY); - - lv_style_set_pad_left(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_right(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_top(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_pad_bottom(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); + lv_style_set_pad_all(&style_btn, LV_STATE_DEFAULT, LV_DPX(20)); lv_style_set_pad_inner(&style_btn, LV_STATE_DEFAULT, LV_DPX(15)); - lv_style_set_outline_width(&style_btn, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_outline_opa(&style_btn, LV_STATE_DEFAULT, LV_OPA_0); - lv_style_set_outline_color(&style_btn, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_transition_time(&style_btn, LV_STATE_DEFAULT, 0); - lv_style_set_transition_delay(&style_btn, LV_STATE_DEFAULT, 0); style_init_reset(&style_icon); lv_style_set_text_color(&style_icon, LV_STATE_DEFAULT, LV_COLOR_WHITE); @@ -132,10 +131,7 @@ static void basic_init() { lv_style_set_bg_color(&style_sw_knob, LV_STATE_DEFAULT, LV_COLOR_SILVER); lv_style_set_bg_color(&style_sw_knob, LV_STATE_CHECKED, LV_COLOR_WHITE); lv_style_set_radius(&style_sw_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_bottom(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_left(&style_sw_knob, LV_STATE_DEFAULT, -4); - lv_style_set_pad_right(&style_sw_knob, LV_STATE_DEFAULT, -4); + lv_style_set_pad_all(&style_sw_knob, LV_STATE_DEFAULT, -4); style_init_reset(&style_slider_knob); lv_style_set_bg_opa(&style_slider_knob, LV_STATE_DEFAULT, LV_OPA_COVER); @@ -143,14 +139,8 @@ static void basic_init() { lv_style_set_border_color(&style_slider_knob, LV_STATE_DEFAULT, LV_COLOR_WHITE); lv_style_set_border_width(&style_slider_knob, LV_STATE_DEFAULT, 6); lv_style_set_radius(&style_slider_knob, LV_STATE_DEFAULT, LV_RADIUS_CIRCLE); - lv_style_set_pad_top(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_left(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_right(&style_slider_knob, LV_STATE_DEFAULT, 10); - lv_style_set_pad_top(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_bottom(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_left(&style_slider_knob, LV_STATE_PRESSED, 14); - lv_style_set_pad_right(&style_slider_knob, LV_STATE_PRESSED, 14); + lv_style_set_pad_all(&style_slider_knob, LV_STATE_DEFAULT, 10); + lv_style_set_pad_all(&style_slider_knob, LV_STATE_PRESSED, 14); style_init_reset(&style_arc_indic); lv_style_set_line_color(&style_arc_indic, LV_STATE_DEFAULT, Colors::lightGray); @@ -180,10 +170,7 @@ static void basic_init() { style_init_reset(&style_pad_small); lv_style_int_t pad_small_value = 10; - lv_style_set_pad_left(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_right(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_top(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); - lv_style_set_pad_bottom(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); + lv_style_set_pad_all(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); lv_style_set_pad_inner(&style_pad_small, LV_STATE_DEFAULT, pad_small_value); style_init_reset(&style_lmeter); @@ -209,20 +196,12 @@ static void basic_init() { lv_style_reset(&style_cb_bg); lv_style_set_radius(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(4)); lv_style_set_pad_inner(&style_cb_bg, LV_STATE_DEFAULT, 18); - lv_style_set_outline_color(&style_cb_bg, LV_STATE_DEFAULT, LV_COLOR_WHITE); - lv_style_set_outline_width(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(2)); - lv_style_set_outline_pad(&style_cb_bg, LV_STATE_DEFAULT, LV_DPX(20)); - lv_style_set_transition_time(&style_cb_bg, LV_STATE_DEFAULT, 0); - lv_style_set_transition_prop_6(&style_cb_bg, LV_STATE_DEFAULT, LV_STYLE_OUTLINE_OPA); lv_style_reset(&style_cb_bullet); lv_style_set_radius(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(4)); lv_style_set_pattern_image(&style_cb_bullet, LV_STATE_CHECKED, LV_SYMBOL_OK); lv_style_set_pattern_recolor(&style_cb_bullet, LV_STATE_CHECKED, LV_COLOR_WHITE); - lv_style_set_pad_left(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_right(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_top(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); - lv_style_set_pad_bottom(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); + lv_style_set_pad_all(&style_cb_bullet, LV_STATE_DEFAULT, LV_DPX(8)); } /** @@ -236,20 +215,14 @@ static void basic_init() { * @param font_title pointer to a extra large font * @return a pointer to reference this theme later */ -lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, - lv_color_t color_secondary, - uint32_t flags, - const lv_font_t* font_small, - const lv_font_t* font_normal, - const lv_font_t* font_subtitle, - const lv_font_t* font_title) { - theme.color_primary = color_primary; - theme.color_secondary = color_secondary; - theme.font_small = font_small; - theme.font_normal = font_normal; - theme.font_subtitle = font_subtitle; - theme.font_title = font_title; - theme.flags = flags; +lv_theme_t* lv_pinetime_theme_init() { + theme.color_primary = LV_COLOR_WHITE; + theme.color_secondary = LV_COLOR_GRAY; + theme.font_small = &jetbrains_mono_bold_20; + theme.font_normal = &jetbrains_mono_bold_20; + theme.font_subtitle = &jetbrains_mono_bold_20; + theme.font_title = &jetbrains_mono_bold_20; + theme.flags = 0; basic_init(); diff --git a/src/displayapp/InfiniTimeTheme.h b/src/displayapp/InfiniTimeTheme.h index 5709b007..52c339dd 100644 --- a/src/displayapp/InfiniTimeTheme.h +++ b/src/displayapp/InfiniTimeTheme.h @@ -24,10 +24,4 @@ namespace Colors { * @param font_title pointer to a extra large font * @return a pointer to reference this theme later */ -lv_theme_t* lv_pinetime_theme_init(lv_color_t color_primary, - lv_color_t color_secondary, - uint32_t flags, - const lv_font_t* font_small, - const lv_font_t* font_normal, - const lv_font_t* font_subtitle, - const lv_font_t* font_title); +lv_theme_t* lv_pinetime_theme_init(); diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp index d5f31848..e3d564a3 100644 --- a/src/displayapp/LittleVgl.cpp +++ b/src/displayapp/LittleVgl.cpp @@ -3,13 +3,17 @@ #include <FreeRTOS.h> #include <task.h> -//#include <projdefs.h> #include "drivers/Cst816s.h" #include "drivers/St7789.h" using namespace Pinetime::Components; -lv_style_t* LabelBigStyle = nullptr; +namespace { + void InitTheme() { + lv_theme_t* theme = lv_pinetime_theme_init(); + lv_theme_set_act(theme); + } +} static void disp_flush(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p) { auto* lvgl = static_cast<LittleVgl*>(disp_drv->user_data); @@ -192,16 +196,3 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) { } return false; } - -void LittleVgl::InitTheme() { - - lv_theme_t* th = lv_pinetime_theme_init(LV_COLOR_WHITE, - LV_COLOR_SILVER, - 0, - &jetbrains_mono_bold_20, - &jetbrains_mono_bold_20, - &jetbrains_mono_bold_20, - &jetbrains_mono_bold_20); - - lv_theme_set_act(th); -} diff --git a/src/displayapp/LittleVgl.h b/src/displayapp/LittleVgl.h index 45826165..7bd0198c 100644 --- a/src/displayapp/LittleVgl.h +++ b/src/displayapp/LittleVgl.h @@ -37,7 +37,6 @@ namespace Pinetime { private: void InitDisplay(); void InitTouchpad(); - void InitTheme(); Pinetime::Drivers::St7789& lcd; Pinetime::Drivers::Cst816S& touchPanel; @@ -52,9 +51,11 @@ namespace Pinetime { static constexpr uint8_t nbWriteLines = 4; static constexpr uint16_t totalNbLines = 320; static constexpr uint16_t visibleNbLines = 240; + static constexpr uint8_t MaxScrollOffset() { return LV_VER_RES_MAX - nbWriteLines; } + FullRefreshDirections scrollDirection = FullRefreshDirections::None; uint16_t writeOffset = 0; uint16_t scrollOffset = 0; diff --git a/src/displayapp/Messages.h b/src/displayapp/Messages.h index 58df4556..afa7709a 100644 --- a/src/displayapp/Messages.h +++ b/src/displayapp/Messages.h @@ -1,5 +1,6 @@ #pragma once #include <cstdint> + namespace Pinetime { namespace Applications { namespace Display { diff --git a/src/displayapp/screens/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index 9febda61..87d1f2e1 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -59,7 +59,7 @@ void BatteryInfo::Refresh() { } else if (batteryPercent == 100) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_BLUE); lv_label_set_text_static(status, "Fully charged"); - } else if (batteryPercent < 10) { + } else if (batteryController.BatteryIsLow()) { lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC, LV_STATE_DEFAULT, LV_COLOR_YELLOW); lv_label_set_text_static(status, "Battery low"); } else { diff --git a/src/displayapp/screens/CheckboxList.cpp b/src/displayapp/screens/CheckboxList.cpp index c189b075..928b2e61 100644 --- a/src/displayapp/screens/CheckboxList.cpp +++ b/src/displayapp/screens/CheckboxList.cpp @@ -28,7 +28,9 @@ CheckboxList::CheckboxList(const uint8_t screenID, // Set the background to Black lv_obj_set_style_local_bg_color(lv_scr_act(), LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - pageIndicator.Create(); + if (numScreens > 1) { + pageIndicator.Create(); + } lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); diff --git a/src/displayapp/screens/CheckboxList.h b/src/displayapp/screens/CheckboxList.h index 48125d4b..359b835e 100644 --- a/src/displayapp/screens/CheckboxList.h +++ b/src/displayapp/screens/CheckboxList.h @@ -15,6 +15,7 @@ namespace Pinetime { class CheckboxList : public Screen { public: static constexpr size_t MaxItems = 4; + struct Item { const char* name; bool enabled; diff --git a/src/displayapp/screens/FirmwareUpdate.h b/src/displayapp/screens/FirmwareUpdate.h index 5156b7ea..cc3b09b2 100644 --- a/src/displayapp/screens/FirmwareUpdate.h +++ b/src/displayapp/screens/FirmwareUpdate.h @@ -8,6 +8,7 @@ namespace Pinetime { namespace Controllers { class Ble; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/FirmwareValidation.cpp b/src/displayapp/screens/FirmwareValidation.cpp index a2314690..bda6d68d 100644 --- a/src/displayapp/screens/FirmwareValidation.cpp +++ b/src/displayapp/screens/FirmwareValidation.cpp @@ -32,16 +32,16 @@ FirmwareValidation::FirmwareValidation(Pinetime::Applications::DisplayApp* app, lv_label_set_long_mode(labelIsValidated, LV_LABEL_LONG_BREAK); lv_obj_set_width(labelIsValidated, 240); - if (validator.IsValidated()) + if (validator.IsValidated()) { lv_label_set_text_static(labelIsValidated, "You have already\n#00ff00 validated# this firmware#"); - else { + } else { lv_label_set_text_static(labelIsValidated, "Please #00ff00 Validate# this version or\n#ff0000 Reset# to rollback to the previous version."); buttonValidate = lv_btn_create(lv_scr_act(), nullptr); buttonValidate->user_data = this; lv_obj_set_size(buttonValidate, 115, 50); - lv_obj_align(buttonValidate, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_align(buttonValidate, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_obj_set_event_cb(buttonValidate, ButtonEventHandler); lv_obj_set_style_local_bg_color(buttonValidate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); diff --git a/src/displayapp/screens/HeartRate.cpp b/src/displayapp/screens/HeartRate.cpp index 305e0c4b..71bf86ca 100644 --- a/src/displayapp/screens/HeartRate.cpp +++ b/src/displayapp/screens/HeartRate.cpp @@ -64,8 +64,9 @@ HeartRate::HeartRate(Pinetime::Applications::DisplayApp* app, label_startStop = lv_label_create(btn_startStop, nullptr); UpdateStartStopButton(isHrRunning); - if (isHrRunning) + if (isHrRunning) { systemTask.PushMessage(Pinetime::System::Messages::DisableSleeping); + } taskRefresh = lv_task_create(RefreshTaskCallback, 100, LV_TASK_PRIO_MID, this); } @@ -110,8 +111,9 @@ void HeartRate::OnStartStopEvent(lv_event_t event) { } void HeartRate::UpdateStartStopButton(bool isRunning) { - if (isRunning) + if (isRunning) { lv_label_set_text_static(label_startStop, "Stop"); - else + } else { lv_label_set_text_static(label_startStop, "Start"); + } } diff --git a/src/displayapp/screens/HeartRate.h b/src/displayapp/screens/HeartRate.h index 2ad00351..d68133ad 100644 --- a/src/displayapp/screens/HeartRate.h +++ b/src/displayapp/screens/HeartRate.h @@ -11,6 +11,7 @@ namespace Pinetime { namespace Controllers { class HeartRateController; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/InfiniPaint.h b/src/displayapp/screens/InfiniPaint.h index 8c427402..a6b6eb18 100644 --- a/src/displayapp/screens/InfiniPaint.h +++ b/src/displayapp/screens/InfiniPaint.h @@ -10,6 +10,7 @@ namespace Pinetime { namespace Components { class LittleVgl; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/List.cpp b/src/displayapp/screens/List.cpp index f44825c7..3f219ea1 100644 --- a/src/displayapp/screens/List.cpp +++ b/src/displayapp/screens/List.cpp @@ -1,6 +1,7 @@ #include "displayapp/screens/List.h" #include "displayapp/DisplayApp.h" #include "displayapp/screens/Symbols.h" +#include "displayapp/InfiniTimeTheme.h" using namespace Pinetime::Applications::Screens; @@ -25,41 +26,44 @@ List::List(uint8_t screenID, pageIndicator.Create(); - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); + lv_obj_t* container = lv_cont_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 4); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + static constexpr int innerPad = 4; + lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, innerPad); + lv_obj_set_style_local_border_width(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); - lv_obj_set_pos(container1, 0, 0); - lv_obj_set_width(container1, LV_HOR_RES - 8); - lv_obj_set_height(container1, LV_VER_RES); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); - - lv_obj_t* labelBt; - lv_obj_t* labelBtIco; + lv_obj_set_pos(container, 0, 0); + lv_obj_set_width(container, LV_HOR_RES - 8); + lv_obj_set_height(container, LV_VER_RES); + lv_cont_set_layout(container, LV_LAYOUT_COLUMN_LEFT); for (int i = 0; i < MAXLISTITEMS; i++) { apps[i] = applications[i].application; if (applications[i].application != Apps::None) { - itemApps[i] = lv_btn_create(container1, nullptr); - lv_obj_set_style_local_bg_opa(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_50); - lv_obj_set_style_local_radius(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, 57); - lv_obj_set_style_local_bg_color(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_AQUA); - + static constexpr int btnHeight = (LV_HOR_RES_MAX - ((MAXLISTITEMS - 1) * innerPad)) / MAXLISTITEMS; + itemApps[i] = lv_btn_create(container, nullptr); + lv_obj_set_style_local_radius(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, btnHeight / 3); + lv_obj_set_style_local_bg_color(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, Colors::bgAlt); lv_obj_set_width(itemApps[i], LV_HOR_RES - 8); - lv_obj_set_height(itemApps[i], 57); + lv_obj_set_height(itemApps[i], btnHeight); lv_obj_set_event_cb(itemApps[i], ButtonEventHandler); - lv_btn_set_layout(itemApps[i], LV_LAYOUT_ROW_MID); + lv_btn_set_layout(itemApps[i], LV_LAYOUT_OFF); itemApps[i]->user_data = this; + lv_obj_set_style_local_clip_corner(itemApps[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, true); - labelBtIco = lv_label_create(itemApps[i], nullptr); - lv_obj_set_style_local_text_color(labelBtIco, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); - lv_label_set_text_static(labelBtIco, applications[i].icon); + lv_obj_t* icon = lv_label_create(itemApps[i], nullptr); + lv_obj_set_style_local_text_color(icon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_YELLOW); + lv_label_set_text_static(icon, applications[i].icon); + lv_label_set_long_mode(icon, LV_LABEL_LONG_CROP); + lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); + lv_obj_set_width(icon, btnHeight); + lv_obj_align(icon, nullptr, LV_ALIGN_IN_LEFT_MID, 0, 0); - labelBt = lv_label_create(itemApps[i], nullptr); - lv_label_set_text_fmt(labelBt, " %s", applications[i].name); + lv_obj_t* text = lv_label_create(itemApps[i], nullptr); + lv_label_set_text_fmt(text, "%s", applications[i].name); + lv_obj_align(text, icon, LV_ALIGN_OUT_RIGHT_MID, 0, 0); } } } diff --git a/src/displayapp/screens/Metronome.cpp b/src/displayapp/screens/Metronome.cpp index df87092b..40456ab8 100644 --- a/src/displayapp/screens/Metronome.cpp +++ b/src/displayapp/screens/Metronome.cpp @@ -146,7 +146,6 @@ void Metronome::OnEvent(lv_obj_t* obj, lv_event_t event) { bool Metronome::OnTouchEvent(TouchEvents event) { if (event == TouchEvents::SwipeDown && allowExit) { running = false; - return true; } - return false; + return true; } diff --git a/src/displayapp/screens/Motion.cpp b/src/displayapp/screens/Motion.cpp index c2dc4dac..e3689599 100644 --- a/src/displayapp/screens/Motion.cpp +++ b/src/displayapp/screens/Motion.cpp @@ -7,9 +7,9 @@ using namespace Pinetime::Applications::Screens; Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionController& motionController) : Screen(app), motionController {motionController} { - chart = lv_chart_create(lv_scr_act(), NULL); + chart = lv_chart_create(lv_scr_act(), nullptr); lv_obj_set_size(chart, 240, 240); - lv_obj_align(chart, NULL, LV_ALIGN_IN_TOP_MID, 0, 0); + lv_obj_align(chart, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); lv_chart_set_type(chart, LV_CHART_TYPE_LINE); /*Show lines and points too*/ // lv_chart_set_series_opa(chart, LV_OPA_70); /*Opacity of the data series*/ // lv_chart_set_series_width(chart, 4); /*Line width and point radious*/ @@ -28,13 +28,13 @@ Motion::Motion(Pinetime::Applications::DisplayApp* app, Controllers::MotionContr lv_chart_init_points(chart, ser3, 0); lv_chart_refresh(chart); /*Required after direct set*/ - label = lv_label_create(lv_scr_act(), NULL); + label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_fmt(label, "X #FF0000 %d# Y #00B000 %d# Z #FFFF00 %d#", 0, 0, 0); lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); - lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10); + lv_obj_align(label, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10); lv_label_set_recolor(label, true); - labelStep = lv_label_create(lv_scr_act(), NULL); + labelStep = lv_label_create(lv_scr_act(), nullptr); lv_obj_align(labelStep, chart, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); lv_label_set_text_static(labelStep, "Steps ---"); @@ -58,5 +58,5 @@ void Motion::Refresh() { motionController.X() / 0x10, motionController.Y() / 0x10, motionController.Z() / 0x10); - lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_MID, 0, 10); + lv_obj_align(label, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10); } diff --git a/src/displayapp/screens/Notifications.cpp b/src/displayapp/screens/Notifications.cpp index 90a010f5..6c68c70d 100644 --- a/src/displayapp/screens/Notifications.cpp +++ b/src/displayapp/screens/Notifications.cpp @@ -79,9 +79,12 @@ void Notifications::Refresh() { timeoutLinePoints[1].x = pos; lv_line_set_points(timeoutLine, timeoutLinePoints, 2); } - } - if (dismissingNotification) { + } else if (mode == Modes::Preview && dismissingNotification) { + running = false; + currentItem = std::make_unique<NotificationItem>(alertNotificationService, motorController); + + } else if (dismissingNotification) { dismissingNotification = false; auto notification = notificationManager.Get(currentId); if (!notification.valid) { @@ -126,12 +129,34 @@ void Notifications::OnPreviewInteraction() { } } +void Notifications::DismissToBlack() { + currentItem.reset(nullptr); + app->SetFullRefresh(DisplayApp::FullRefreshDirections::RightAnim); + // create black transition screen to let the notification dismiss to blackness + lv_obj_t* blackBox = lv_obj_create(lv_scr_act(), nullptr); + lv_obj_set_size(blackBox, LV_HOR_RES, LV_VER_RES); + lv_obj_set_style_local_bg_color(blackBox, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); + dismissingNotification = true; +} + +void Notifications::OnPreviewDismiss() { + notificationManager.Dismiss(currentId); + if (timeoutLine != nullptr) { + lv_obj_del(timeoutLine); + timeoutLine = nullptr; + } + DismissToBlack(); +} + bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { if (mode != Modes::Normal) { if (!interacted && event == TouchEvents::Tap) { interacted = true; OnPreviewInteraction(); return true; + } else if (event == Pinetime::Applications::TouchEvents::SwipeRight) { + OnPreviewDismiss(); + return true; } return false; } @@ -139,15 +164,9 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { switch (event) { case Pinetime::Applications::TouchEvents::SwipeRight: if (validDisplay) { - Controllers::NotificationManager::Notification previousNotification; auto previousMessage = notificationManager.GetPrevious(currentId); auto nextMessage = notificationManager.GetNext(currentId); - if (!previousMessage.valid) { - // dismissed last message (like 5/5), need to go one message down (like 4/4) - afterDismissNextMessageFromAbove = false; // show next message coming from below - } else { - afterDismissNextMessageFromAbove = true; // show next message coming from above - } + afterDismissNextMessageFromAbove = previousMessage.valid; notificationManager.Dismiss(currentId); if (previousMessage.valid) { currentId = previousMessage.id; @@ -156,13 +175,7 @@ bool Notifications::OnTouchEvent(Pinetime::Applications::TouchEvents event) { } else { // don't update id, won't be found be refresh and try to load latest message or no message box } - currentItem.reset(nullptr); - app->SetFullRefresh(DisplayApp::FullRefreshDirections::RightAnim); - // create black transition screen to let the notification dismiss to blackness - lv_obj_t* blackBox = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_size(blackBox, LV_HOR_RES, LV_VER_RES); - lv_obj_set_style_local_bg_color(blackBox, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - dismissingNotification = true; + DismissToBlack(); return true; } return false; @@ -270,7 +283,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, lv_obj_t* alert_count = lv_label_create(container, nullptr); lv_label_set_text_fmt(alert_count, "%i/%i", notifNr, notifNb); - lv_obj_align(alert_count, NULL, LV_ALIGN_IN_TOP_RIGHT, 0, 16); + lv_obj_align(alert_count, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 16); lv_obj_t* alert_type = lv_label_create(container, nullptr); lv_obj_set_style_local_text_color(alert_type, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::orange); @@ -288,7 +301,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, } lv_label_set_long_mode(alert_type, LV_LABEL_LONG_SROLL_CIRC); lv_obj_set_width(alert_type, 180); - lv_obj_align(alert_type, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 16); + lv_obj_align(alert_type, nullptr, LV_ALIGN_IN_TOP_LEFT, 0, 16); lv_obj_t* alert_subject = lv_label_create(subject_container, nullptr); lv_label_set_long_mode(alert_subject, LV_LABEL_LONG_BREAK); @@ -312,7 +325,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, bt_accept->user_data = this; lv_obj_set_event_cb(bt_accept, CallEventHandler); lv_obj_set_size(bt_accept, 76, 76); - lv_obj_align(bt_accept, NULL, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); + lv_obj_align(bt_accept, nullptr, LV_ALIGN_IN_BOTTOM_LEFT, 0, 0); label_accept = lv_label_create(bt_accept, nullptr); lv_label_set_text_static(label_accept, Symbols::phone); lv_obj_set_style_local_bg_color(bt_accept, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::highlight); @@ -321,7 +334,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, bt_reject->user_data = this; lv_obj_set_event_cb(bt_reject, CallEventHandler); lv_obj_set_size(bt_reject, 76, 76); - lv_obj_align(bt_reject, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, 0); + lv_obj_align(bt_reject, nullptr, LV_ALIGN_IN_BOTTOM_MID, 0, 0); label_reject = lv_label_create(bt_reject, nullptr); lv_label_set_text_static(label_reject, Symbols::phoneSlash); lv_obj_set_style_local_bg_color(bt_reject, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); @@ -330,7 +343,7 @@ Notifications::NotificationItem::NotificationItem(const char* title, bt_mute->user_data = this; lv_obj_set_event_cb(bt_mute, CallEventHandler); lv_obj_set_size(bt_mute, 76, 76); - lv_obj_align(bt_mute, NULL, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); + lv_obj_align(bt_mute, nullptr, LV_ALIGN_IN_BOTTOM_RIGHT, 0, 0); label_mute = lv_label_create(bt_mute, nullptr); lv_label_set_text_static(label_mute, Symbols::volumMute); lv_obj_set_style_local_bg_color(bt_mute, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, Colors::lightGray); diff --git a/src/displayapp/screens/Notifications.h b/src/displayapp/screens/Notifications.h index 9d843a9b..a4d2709b 100644 --- a/src/displayapp/screens/Notifications.h +++ b/src/displayapp/screens/Notifications.h @@ -13,6 +13,7 @@ namespace Pinetime { namespace Controllers { class AlertNotificationService; } + namespace Applications { namespace Screens { @@ -29,7 +30,9 @@ namespace Pinetime { void Refresh() override; bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override; + void DismissToBlack(); void OnPreviewInteraction(); + void OnPreviewDismiss(); class NotificationItem { public: @@ -43,9 +46,11 @@ namespace Pinetime { Pinetime::Controllers::AlertNotificationService& alertNotificationService, Pinetime::Controllers::MotorController& motorController); ~NotificationItem(); + bool IsRunning() const { return running; } + void OnCallButtonEvent(lv_obj_t*, lv_event_t event); private: diff --git a/src/displayapp/screens/Paddle.cpp b/src/displayapp/screens/Paddle.cpp index 1fb25085..dc973957 100644 --- a/src/displayapp/screens/Paddle.cpp +++ b/src/displayapp/screens/Paddle.cpp @@ -79,11 +79,11 @@ void Paddle::Refresh() { lv_label_set_text_fmt(points, "%04d", score); } -bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents event) { +bool Paddle::OnTouchEvent(Pinetime::Applications::TouchEvents /*event*/) { return true; } -bool Paddle::OnTouchEvent(uint16_t x, uint16_t y) { +bool Paddle::OnTouchEvent(uint16_t /*x*/, uint16_t y) { // sets the center paddle pos. (30px offset) with the the y_coordinate of the finger // but clamp it such that the paddle never clips off screen if (y < 31) { diff --git a/src/displayapp/screens/Paddle.h b/src/displayapp/screens/Paddle.h index 3a30eee6..d62550c4 100644 --- a/src/displayapp/screens/Paddle.h +++ b/src/displayapp/screens/Paddle.h @@ -8,6 +8,7 @@ namespace Pinetime { namespace Components { class LittleVgl; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/Screen.h b/src/displayapp/screens/Screen.h index e72a2368..4cf134d2 100644 --- a/src/displayapp/screens/Screen.h +++ b/src/displayapp/screens/Screen.h @@ -7,13 +7,16 @@ namespace Pinetime { namespace Applications { class DisplayApp; + namespace Screens { template <class T> class DirtyValue { public: DirtyValue() = default; // Use NSDMI + explicit DirtyValue(T const& v) : value {v} { } // Use MIL and const-lvalue-ref + bool IsUpdated() { if (this->isUpdated) { this->isUpdated = false; @@ -21,10 +24,12 @@ namespace Pinetime { } return false; } + T const& Get() { this->isUpdated = false; return value; } // never expose a non-const lvalue-ref + DirtyValue& operator=(const T& other) { if (this->value != other) { this->value = other; @@ -46,6 +51,7 @@ namespace Pinetime { public: explicit Screen(DisplayApp* app) : app {app} { } + virtual ~Screen() = default; static void RefreshTaskCallback(lv_task_t* task); @@ -61,10 +67,11 @@ namespace Pinetime { /** @return false if the event hasn't been handled by the app, true if it has been handled */ // Returning true will cancel lvgl tap - virtual bool OnTouchEvent(TouchEvents event) { + virtual bool OnTouchEvent(TouchEvents /*event*/) { return false; } - virtual bool OnTouchEvent(uint16_t x, uint16_t y) { + + virtual bool OnTouchEvent(uint16_t /*x*/, uint16_t /*y*/) { return false; } diff --git a/src/displayapp/screens/ScreenList.h b/src/displayapp/screens/ScreenList.h index ad882948..6c9a2218 100644 --- a/src/displayapp/screens/ScreenList.h +++ b/src/displayapp/screens/ScreenList.h @@ -11,6 +11,7 @@ namespace Pinetime { namespace Screens { enum class ScreenListModes { UpDown, RightLeft, LongPress }; + template <size_t N> class ScreenList : public Screen { public: ScreenList(DisplayApp* app, diff --git a/src/displayapp/screens/Steps.h b/src/displayapp/screens/Steps.h index f109e0f2..32ad40bd 100644 --- a/src/displayapp/screens/Steps.h +++ b/src/displayapp/screens/Steps.h @@ -29,7 +29,6 @@ namespace Pinetime { uint32_t currentTripSteps = 0; lv_obj_t* lSteps; - lv_obj_t* lStepsIcon; lv_obj_t* stepsArc; lv_obj_t* resetBtn; lv_obj_t* resetButtonLabel; diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index 01c35195..b5b17347 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -99,7 +99,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen1() { std::unique_ptr<Screen> SystemInfo::CreateScreen2() { auto batteryPercent = batteryController.PercentRemaining(); - auto resetReason = [this]() { + const auto* resetReason = [this]() { switch (watchdog.ResetReason()) { case Drivers::Watchdog::ResetReasons::Watchdog: return "wtdg"; @@ -182,7 +182,7 @@ std::unique_ptr<Screen> SystemInfo::CreateScreen3() { lv_obj_t* label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); - auto& bleAddr = bleController.Address(); + const auto& bleAddr = bleController.Address(); lv_label_set_text_fmt(label, "#808080 BLE MAC#\n" " %02x:%02x:%02x:%02x:%02x:%02x" diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index a60076ed..681f9c9f 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -51,8 +51,9 @@ Tile::Tile(uint8_t screenID, uint8_t btIndex = 0; for (uint8_t i = 0; i < 6; i++) { - if (i == 3) + if (i == 3) { btnmMap[btIndex++] = "\n"; + } if (applications[i].application == Apps::None) { btnmMap[btIndex] = " "; } else { @@ -66,7 +67,7 @@ Tile::Tile(uint8_t screenID, btnm1 = lv_btnmatrix_create(lv_scr_act(), nullptr); lv_btnmatrix_set_map(btnm1, btnmMap); lv_obj_set_size(btnm1, LV_HOR_RES - 16, LV_VER_RES - 60); - lv_obj_align(btnm1, NULL, LV_ALIGN_CENTER, 0, 10); + lv_obj_align(btnm1, nullptr, LV_ALIGN_CENTER, 0, 10); lv_obj_set_style_local_radius(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, 20); lv_obj_set_style_local_bg_opa(btnm1, LV_BTNMATRIX_PART_BTN, LV_STATE_DEFAULT, LV_OPA_50); @@ -102,8 +103,9 @@ void Tile::UpdateScreen() { } void Tile::OnValueChangedEvent(lv_obj_t* obj, uint32_t buttonId) { - if (obj != btnm1) + if (obj != btnm1) { return; + } app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Up); running = false; diff --git a/src/displayapp/screens/Timer.h b/src/displayapp/screens/Timer.h index a6b60a17..306281d7 100644 --- a/src/displayapp/screens/Timer.h +++ b/src/displayapp/screens/Timer.h @@ -26,7 +26,6 @@ namespace Pinetime::Applications::Screens { void UpdateMask(); Controllers::TimerController& timerController; - lv_obj_t* msecTime; lv_obj_t* btnPlayPause; lv_obj_t* txtPlayPause; @@ -40,7 +39,7 @@ namespace Pinetime::Applications::Screens { Widgets::Counter secondCounter = Widgets::Counter(0, 59, jetbrains_mono_76); bool buttonPressing = false; - int maskPosition = 0; - TickType_t pressTime; + lv_coord_t maskPosition = 0; + TickType_t pressTime = 0; }; } diff --git a/src/displayapp/screens/Twos.h b/src/displayapp/screens/Twos.h index da935724..15017581 100644 --- a/src/displayapp/screens/Twos.h +++ b/src/displayapp/screens/Twos.h @@ -9,6 +9,7 @@ namespace Pinetime { bool merged = false; unsigned int value = 0; }; + namespace Screens { class Twos : public Screen { public: diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index 5e5317ee..b36c29d3 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -61,9 +61,9 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, sMinute = 99; sSecond = 99; - lv_obj_t* bg_clock_img = lv_img_create(lv_scr_act(), NULL); + lv_obj_t* bg_clock_img = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src(bg_clock_img, &bg_clock); - lv_obj_align(bg_clock_img, NULL, LV_ALIGN_CENTER, 0, 0); + lv_obj_align(bg_clock_img, nullptr, LV_ALIGN_CENTER, 0, 0); batteryIcon.Create(lv_scr_act()); lv_obj_align(batteryIcon.GetObject(), nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); @@ -72,24 +72,24 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, lv_label_set_text_static(plugIcon, Symbols::plug); lv_obj_align(plugIcon, nullptr, LV_ALIGN_IN_TOP_RIGHT, 0, 0); - notificationIcon = lv_label_create(lv_scr_act(), NULL); + 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, NULL, LV_ALIGN_IN_TOP_LEFT, 0, 0); + 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(), NULL); + 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, Colors::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, NULL, LV_ALIGN_CENTER, 50, 0); + lv_obj_align(label_date_day, nullptr, LV_ALIGN_CENTER, 50, 0); - minute_body = lv_line_create(lv_scr_act(), NULL); - minute_body_trace = lv_line_create(lv_scr_act(), NULL); - hour_body = lv_line_create(lv_scr_act(), NULL); - hour_body_trace = lv_line_create(lv_scr_act(), NULL); - second_body = lv_line_create(lv_scr_act(), NULL); + 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); diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index 04d9e711..6e4e88a3 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -18,6 +18,7 @@ namespace Pinetime { class Ble; class NotificationManager; } + namespace Applications { namespace Screens { diff --git a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp index bdae0d42..94b6a405 100644 --- a/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp +++ b/src/displayapp/screens/WatchFaceCasioStyleG7710.cpp @@ -333,6 +333,7 @@ void WatchFaceCasioStyleG7710::Refresh() { lv_obj_realign(stepIcon); } } + bool WatchFaceCasioStyleG7710::IsAvailable(Pinetime::Controllers::FS& filesystem) { lfs_file file = {}; diff --git a/src/displayapp/screens/WatchFaceInfineat.cpp b/src/displayapp/screens/WatchFaceInfineat.cpp index bd4e4ac8..ddf3cbcc 100644 --- a/src/displayapp/screens/WatchFaceInfineat.cpp +++ b/src/displayapp/screens/WatchFaceInfineat.cpp @@ -47,125 +47,40 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, font_bebas = lv_font_load("F:/fonts/bebas.bin"); } - // Black background covering the whole screen - background = lv_obj_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_bg_color(background, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLACK); - lv_obj_set_size(background, 240, 240); - lv_obj_align(background, lv_scr_act(), LV_ALIGN_IN_TOP_LEFT, 0, 0); - // Side Cover - line0 = lv_line_create(lv_scr_act(), nullptr); - line1 = lv_line_create(lv_scr_act(), nullptr); - line2 = lv_line_create(lv_scr_act(), nullptr); - line3 = lv_line_create(lv_scr_act(), nullptr); - line4 = lv_line_create(lv_scr_act(), nullptr); - line5 = lv_line_create(lv_scr_act(), nullptr); - line6 = lv_line_create(lv_scr_act(), nullptr); - line7 = lv_line_create(lv_scr_act(), nullptr); - line8 = lv_line_create(lv_scr_act(), nullptr); - lineBattery = lv_line_create(lv_scr_act(), nullptr); - - lv_style_init(&line0Style); - lv_style_set_line_width(&line0Style, LV_STATE_DEFAULT, 18); - lv_style_set_line_color(&line0Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines])); - lv_obj_add_style(line0, LV_LINE_PART_MAIN, &line0Style); - line0Points[0] = {30, 25}; - line0Points[1] = {68, -8}; - lv_line_set_points(line0, line0Points, 2); - - lv_style_init(&line1Style); - lv_style_set_line_width(&line1Style, LV_STATE_DEFAULT, 15); - lv_style_set_line_color(&line1Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 1])); - lv_obj_add_style(line1, LV_LINE_PART_MAIN, &line1Style); - line1Points[0] = {26, 167}; - line1Points[1] = {43, 216}; - lv_line_set_points(line1, line1Points, 2); - - lv_style_init(&line2Style); - lv_style_set_line_width(&line2Style, LV_STATE_DEFAULT, 14); - lv_style_set_line_color(&line2Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 2])); - lv_obj_add_style(line2, LV_LINE_PART_MAIN, &line2Style); - line2Points[0] = {27, 40}; - line2Points[1] = {27, 196}; - lv_line_set_points(line2, line2Points, 2); - - lv_style_init(&line3Style); - lv_style_set_line_width(&line3Style, LV_STATE_DEFAULT, 22); - lv_style_set_line_color(&line3Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 3])); - lv_obj_add_style(line3, LV_LINE_PART_MAIN, &line3Style); - line3Points[0] = {12, 182}; - line3Points[1] = {65, 249}; - lv_line_set_points(line3, line3Points, 2); - - lv_style_init(&line4Style); - lv_style_set_line_width(&line4Style, LV_STATE_DEFAULT, 20); - lv_style_set_line_color(&line4Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4])); - lv_obj_add_style(line4, LV_LINE_PART_MAIN, &line4Style); - line4Points[0] = {17, 99}; - line4Points[1] = {17, 144}; - lv_line_set_points(line4, line4Points, 2); + static constexpr lv_point_t linePoints[nLines][2] = {{{30, 25}, {68, -8}}, + {{26, 167}, {43, 216}}, + {{27, 40}, {27, 196}}, + {{12, 182}, {65, 249}}, + {{17, 99}, {17, 144}}, + {{14, 81}, {40, 127}}, + {{14, 163}, {40, 118}}, + {{-20, 124}, {25, -11}}, + {{-29, 89}, {27, 254}}}; - lv_style_init(&line5Style); - lv_style_set_line_width(&line5Style, LV_STATE_DEFAULT, 18); - lv_style_set_line_color(&line5Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 5])); - lv_obj_add_style(line5, LV_LINE_PART_MAIN, &line5Style); - line5Points[0] = {14, 81}; - line5Points[1] = {40, 127}; - lv_line_set_points(line5, line5Points, 2); + static constexpr lv_style_int_t lineWidths[nLines] = {18, 15, 14, 22, 20, 18, 18, 52, 48}; - lv_style_init(&line6Style); - lv_style_set_line_width(&line6Style, LV_STATE_DEFAULT, 18); - lv_style_set_line_color(&line6Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 6])); - lv_obj_add_style(line6, LV_LINE_PART_MAIN, &line6Style); - line6Points[0] = {14, 163}; - line6Points[1] = {40, 118}; - lv_line_set_points(line6, line6Points, 2); - - lv_style_init(&line7Style); - lv_style_set_line_width(&line7Style, LV_STATE_DEFAULT, 52); - lv_style_set_line_color(&line7Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 7])); - lv_obj_add_style(line7, LV_LINE_PART_MAIN, &line7Style); - line7Points[0] = {-20, 124}; - line7Points[1] = {25, -11}; - lv_line_set_points(line7, line7Points, 2); - - lv_style_init(&line8Style); - lv_style_set_line_width(&line8Style, LV_STATE_DEFAULT, 48); - lv_style_set_line_color(&line8Style, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 8])); - lv_obj_add_style(line8, LV_LINE_PART_MAIN, &line8Style); - line8Points[0] = {-29, 89}; - line8Points[1] = {27, 254}; - lv_line_set_points(line8, line8Points, 2); + for (int i = 0; i < nLines; i++) { + lines[i] = lv_line_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_line_width(lines[i], LV_LINE_PART_MAIN, LV_STATE_DEFAULT, lineWidths[i]); + lv_obj_set_style_local_line_color(lines[i], + LV_LINE_PART_MAIN, + LV_STATE_DEFAULT, + lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + i])); + lv_line_set_points(lines[i], linePoints[i], 2); + } logoPine = lv_img_create(lv_scr_act(), nullptr); lv_img_set_src(logoPine, "F:/images/pine_small.bin"); lv_obj_set_pos(logoPine, 15, 106); - lv_style_init(&lineBatteryStyle); - lv_style_set_line_width(&lineBatteryStyle, LV_STATE_DEFAULT, 24); - lv_style_set_line_color(&lineBatteryStyle, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4])); - lv_style_set_line_opa(&lineBatteryStyle, LV_STATE_DEFAULT, 190); - lv_obj_add_style(lineBattery, LV_LINE_PART_MAIN, &lineBatteryStyle); + lineBattery = lv_line_create(lv_scr_act(), nullptr); + lv_obj_set_style_local_line_width(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 24); + lv_obj_set_style_local_line_color(lineBattery, + LV_LINE_PART_MAIN, + LV_STATE_DEFAULT, + lv_color_hex(infineatColors.orange[settingsController.GetInfineatColorIndex() * nLines + 4])); + lv_obj_set_style_local_line_opa(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, 190); lineBatteryPoints[0] = {27, 105}; lineBatteryPoints[1] = {27, 106}; lv_line_set_points(lineBattery, lineBatteryPoints, 2); @@ -182,55 +97,30 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, if (!settingsController.GetInfineatShowSideCover()) { ToggleBatteryIndicatorColor(false); - lv_obj_set_hidden(line0, true); - lv_obj_set_hidden(line1, true); - lv_obj_set_hidden(line2, true); - lv_obj_set_hidden(line3, true); - lv_obj_set_hidden(line4, true); - lv_obj_set_hidden(line5, true); - lv_obj_set_hidden(line6, true); - lv_obj_set_hidden(line7, true); - lv_obj_set_hidden(line8, true); + for (auto& line : lines) { + lv_obj_set_hidden(line, true); + } } timeContainer = lv_obj_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_opa(timeContainer, LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - if (font_bebas != nullptr) { - lv_obj_set_size(timeContainer, 185, 185); - lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, -10); - } else { - lv_obj_set_size(timeContainer, 110, 145); - lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); - } + lv_obj_set_size(timeContainer, 185, 185); + lv_obj_align(timeContainer, lv_scr_act(), LV_ALIGN_CENTER, 0, -10); labelHour = lv_label_create(lv_scr_act(), nullptr); - lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - lv_label_set_text(labelHour, "01"); - if (font_bebas != nullptr) { - lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); - lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 0); - } else { - lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 5); - } + lv_label_set_text_static(labelHour, "01"); + lv_obj_set_style_local_text_font(labelHour, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); + lv_obj_align(labelHour, timeContainer, LV_ALIGN_IN_TOP_MID, 0, 0); labelMinutes = lv_label_create(lv_scr_act(), nullptr); - if (font_bebas != nullptr) { - lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); - } else { - lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_extrabold_compressed); - } - lv_label_set_text(labelMinutes, "00"); + lv_obj_set_style_local_text_font(labelMinutes, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_bebas); + lv_label_set_text_static(labelMinutes, "00"); lv_obj_align(labelMinutes, timeContainer, LV_ALIGN_IN_BOTTOM_MID, 0, 0); labelTimeAmPm = lv_label_create(lv_scr_act(), nullptr); - if (font_teko != nullptr) { - lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - } else { - lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - } + lv_obj_set_style_local_text_font(labelTimeAmPm, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - lv_label_set_text(labelTimeAmPm, ""); + lv_label_set_text_static(labelTimeAmPm, ""); lv_obj_align(labelTimeAmPm, timeContainer, LV_ALIGN_OUT_RIGHT_TOP, 0, 15); dateContainer = lv_obj_create(lv_scr_act(), nullptr); @@ -240,32 +130,24 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, labelDate = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - if (font_teko != nullptr) { - lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - } else { - lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - } + lv_obj_set_style_local_text_font(labelDate, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); lv_obj_align(labelDate, dateContainer, LV_ALIGN_IN_TOP_MID, 0, 0); - lv_label_set_text(labelDate, "Mon 01"); + lv_label_set_text_static(labelDate, "Mon 01"); bleIcon = lv_label_create(lv_scr_act(), nullptr); lv_obj_set_style_local_text_color(bleIcon, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, lv_color_hex(0x999999)); - lv_label_set_text(bleIcon, Symbols::bluetooth); + lv_label_set_text_static(bleIcon, Symbols::bluetooth); lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 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(0x999999)); - if (font_teko != nullptr) { - lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); - } else { - lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &jetbrains_mono_bold_20); - } + lv_obj_set_style_local_text_font(stepValue, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, font_teko); lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, 10, 0); - lv_label_set_text(stepValue, "0"); + lv_label_set_text_static(stepValue, "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(0x999999)); - lv_label_set_text(stepIcon, Symbols::shoe); + lv_label_set_text_static(stepIcon, Symbols::shoe); lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0); // Setting buttons @@ -330,17 +212,6 @@ WatchFaceInfineat::WatchFaceInfineat(DisplayApp* app, WatchFaceInfineat::~WatchFaceInfineat() { lv_task_del(taskRefresh); - lv_style_reset(&line0Style); - lv_style_reset(&line1Style); - lv_style_reset(&line2Style); - lv_style_reset(&line3Style); - lv_style_reset(&line4Style); - lv_style_reset(&line5Style); - lv_style_reset(&line6Style); - lv_style_reset(&line7Style); - lv_style_reset(&line8Style); - lv_style_reset(&lineBatteryStyle); - if (font_bebas != nullptr) { lv_font_free(font_bebas); } @@ -398,15 +269,9 @@ void WatchFaceInfineat::UpdateSelected(lv_obj_t* object, lv_event_t event) { if (object == btnToggleCover) { settingsController.SetInfineatShowSideCover(!showSideCover); ToggleBatteryIndicatorColor(!showSideCover); - lv_obj_set_hidden(line0, showSideCover); - lv_obj_set_hidden(line1, showSideCover); - lv_obj_set_hidden(line2, showSideCover); - lv_obj_set_hidden(line3, showSideCover); - lv_obj_set_hidden(line4, showSideCover); - lv_obj_set_hidden(line5, showSideCover); - lv_obj_set_hidden(line6, showSideCover); - lv_obj_set_hidden(line7, showSideCover); - lv_obj_set_hidden(line8, showSideCover); + for (auto& line : lines) { + lv_obj_set_hidden(line, showSideCover); + } lv_obj_set_hidden(btnNextColor, showSideCover); lv_obj_set_hidden(btnPrevColor, showSideCover); const char* labelToggle = showSideCover ? "OFF" : "ON"; @@ -423,42 +288,12 @@ void WatchFaceInfineat::UpdateSelected(lv_obj_t* object, lv_event_t event) { settingsController.SetInfineatColorIndex(colorIndex); } if (object == btnNextColor || object == btnPrevColor) { - lv_obj_set_style_local_line_color(line0, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 0])); - lv_obj_set_style_local_line_color(line1, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 1])); - lv_obj_set_style_local_line_color(line2, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 2])); - lv_obj_set_style_local_line_color(line3, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 3])); - lv_obj_set_style_local_line_color(line4, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 4])); - lv_obj_set_style_local_line_color(line5, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 5])); - lv_obj_set_style_local_line_color(line6, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 6])); - lv_obj_set_style_local_line_color(line7, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 7])); - lv_obj_set_style_local_line_color(line8, - LV_LINE_PART_MAIN, - LV_STATE_DEFAULT, - lv_color_hex(infineatColors.orange[colorIndex * nLines + 8])); + for (int i = 0; i < nLines; i++) { + lv_obj_set_style_local_line_color(lines[i], + LV_LINE_PART_MAIN, + LV_STATE_DEFAULT, + lv_color_hex(infineatColors.orange[colorIndex * nLines + i])); + } lv_obj_set_style_local_line_color(lineBattery, LV_LINE_PART_MAIN, LV_STATE_DEFAULT, @@ -547,17 +382,13 @@ void WatchFaceInfineat::Refresh() { batteryPercentRemaining = batteryController.PercentRemaining(); isCharging = batteryController.IsCharging(); - // We store if battery and charging are updated before calling Get(), - // since Get() sets isUpdated to false. - bool isBatteryUpdated = batteryPercentRemaining.IsUpdated(); - bool isChargingUpdated = isCharging.IsUpdated(); - if (isCharging.Get()) { // Charging battery animation + if (batteryController.IsCharging()) { // Charging battery animation chargingBatteryPercent += 1; if (chargingBatteryPercent > 100) { chargingBatteryPercent = batteryPercentRemaining.Get(); } SetBatteryLevel(chargingBatteryPercent); - } else if (isChargingUpdated || isBatteryUpdated) { + } else if (isCharging.IsUpdated() || batteryPercentRemaining.IsUpdated()) { chargingBatteryPercent = batteryPercentRemaining.Get(); SetBatteryLevel(chargingBatteryPercent); } @@ -565,7 +396,7 @@ void WatchFaceInfineat::Refresh() { bleState = bleController.IsConnected(); bleRadioEnabled = bleController.IsRadioEnabled(); if (bleState.IsUpdated()) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); + lv_label_set_text_static(bleIcon, BleIcon::GetIcon(bleState.Get())); lv_obj_align(bleIcon, dateContainer, LV_ALIGN_OUT_BOTTOM_MID, 0, 3); } diff --git a/src/displayapp/screens/WatchFaceInfineat.h b/src/displayapp/screens/WatchFaceInfineat.h index 6c3c30ba..dfa0b38b 100644 --- a/src/displayapp/screens/WatchFaceInfineat.h +++ b/src/displayapp/screens/WatchFaceInfineat.h @@ -60,40 +60,9 @@ namespace Pinetime { DirtyValue<uint32_t> stepCount {}; DirtyValue<bool> notificationState {}; - lv_obj_t* background; - // Lines making up the side cover - lv_obj_t* line0; - lv_obj_t* line1; - lv_obj_t* line2; - lv_obj_t* line3; - lv_obj_t* line4; - lv_obj_t* line5; - lv_obj_t* line6; - lv_obj_t* line7; - lv_obj_t* line8; lv_obj_t* lineBattery; - lv_style_t line0Style; - lv_style_t line1Style; - lv_style_t line2Style; - lv_style_t line3Style; - lv_style_t line4Style; - lv_style_t line5Style; - lv_style_t line6Style; - lv_style_t line7Style; - lv_style_t line8Style; - lv_style_t lineBatteryStyle; - - lv_point_t line0Points[2]; - lv_point_t line1Points[2]; - lv_point_t line2Points[2]; - lv_point_t line3Points[2]; - lv_point_t line4Points[2]; - lv_point_t line5Points[2]; - lv_point_t line6Points[2]; - lv_point_t line7Points[2]; - lv_point_t line8Points[2]; lv_point_t lineBatteryPoints[2]; lv_obj_t* logoPine; @@ -118,6 +87,9 @@ namespace Pinetime { static constexpr int nLines = 9; static constexpr int nColors = 7; // must match number of colors in InfineatColors + + lv_obj_t* lines[nLines]; + struct InfineatColors { int orange[nLines] = {0xfd872b, 0xdb3316, 0x6f1000, 0xfd7a0a, 0xffffff, 0xffffff, 0xffffff, 0xe85102, 0xea1c00}; int blue[nLines] = {0xe7f8ff, 0x2232d0, 0x182a8b, 0xe7f8ff, 0xffffff, 0xffffff, 0xffffff, 0x5991ff, 0x1636ff}; diff --git a/src/displayapp/screens/WatchFacePineTimeStyle.h b/src/displayapp/screens/WatchFacePineTimeStyle.h index 3085a1ae..b2cb0736 100644 --- a/src/displayapp/screens/WatchFacePineTimeStyle.h +++ b/src/displayapp/screens/WatchFacePineTimeStyle.h @@ -5,10 +5,10 @@ #include <cstdint> #include <memory> #include "displayapp/screens/Screen.h" +#include "displayapp/screens/BatteryIcon.h" #include "displayapp/Colors.h" #include "components/datetime/DateTimeController.h" #include "components/ble/BleController.h" -#include <displayapp/screens/BatteryIcon.h> namespace Pinetime { namespace Controllers { diff --git a/src/displayapp/screens/WatchFaceTerminal.cpp b/src/displayapp/screens/WatchFaceTerminal.cpp index 92189737..d04cc517 100644 --- a/src/displayapp/screens/WatchFaceTerminal.cpp +++ b/src/displayapp/screens/WatchFaceTerminal.cpp @@ -30,8 +30,6 @@ WatchFaceTerminal::WatchFaceTerminal(DisplayApp* app, settingsController {settingsController}, heartRateController {heartRateController}, motionController {motionController} { - settingsController.SetClockFace(3); - batteryValue = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(batteryValue, true); lv_obj_align(batteryValue, lv_scr_act(), LV_ALIGN_IN_LEFT_MID, 0, -20); diff --git a/src/displayapp/screens/Weather.cpp b/src/displayapp/screens/Weather.cpp index 1d0a83bd..ff067db8 100644 --- a/src/displayapp/screens/Weather.cpp +++ b/src/displayapp/screens/Weather.cpp @@ -27,7 +27,6 @@ using namespace Pinetime::Applications::Screens; Weather::Weather(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::WeatherService& weather) : Screen(app), - dateTimeController {dateTimeController}, weatherService(weather), screens {app, 0, diff --git a/src/displayapp/screens/Weather.h b/src/displayapp/screens/Weather.h index 34f95fce..21b05bd8 100644 --- a/src/displayapp/screens/Weather.h +++ b/src/displayapp/screens/Weather.h @@ -25,7 +25,6 @@ namespace Pinetime { private: bool running = true; - Pinetime::Controllers::DateTime& dateTimeController; Controllers::WeatherService& weatherService; ScreenList<5> screens; diff --git a/src/displayapp/screens/settings/SettingBluetooth.cpp b/src/displayapp/screens/settings/SettingBluetooth.cpp index c66be3e9..fd07be88 100644 --- a/src/displayapp/screens/settings/SettingBluetooth.cpp +++ b/src/displayapp/screens/settings/SettingBluetooth.cpp @@ -9,84 +9,52 @@ using namespace Pinetime::Applications::Screens; namespace { - void OnBluetoothDisabledEvent(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingBluetooth*>(obj->user_data); - screen->OnBluetoothDisabled(obj, event); - } + struct Option { + const char* name; + bool radioEnabled; + }; - void OnBluetoothEnabledEvent(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingBluetooth*>(obj->user_data); - screen->OnBluetoothEnabled(obj, event); - } + constexpr std::array<Option, 2> options = {{ + {"Enabled", true}, + {"Disabled", false}, + }}; + + std::array<CheckboxList::Item, CheckboxList::MaxItems> CreateOptionArray() { + std::array<Pinetime::Applications::Screens::CheckboxList::Item, CheckboxList::MaxItems> optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; + }; } SettingBluetooth::SettingBluetooth(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : Screen(app), settingsController {settingsController} { - - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); - - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); - - lv_obj_set_pos(container1, 10, 60); - lv_obj_set_width(container1, LV_HOR_RES - 20); - lv_obj_set_height(container1, LV_VER_RES - 50); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); - - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Bluetooth"); - 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::bluetooth); - lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); - lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); - - cbEnabled = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbEnabled, " Enabled"); - cbEnabled->user_data = this; - lv_obj_set_event_cb(cbEnabled, OnBluetoothEnabledEvent); - SetRadioButtonStyle(cbEnabled); - - cbDisabled = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbDisabled, " Disabled"); - cbDisabled->user_data = this; - lv_obj_set_event_cb(cbDisabled, OnBluetoothDisabledEvent); - SetRadioButtonStyle(cbDisabled); - - if (settingsController.GetBleRadioEnabled()) { - lv_checkbox_set_checked(cbEnabled, true); - priorMode = true; - } else { - lv_checkbox_set_checked(cbDisabled, true); - priorMode = false; - } + : Screen(app), + checkboxList( + 0, + 1, + app, + "Bluetooth", + Symbols::bluetooth, + settingsController.GetBleRadioEnabled() ? 0 : 1, + [&settings = settingsController](uint32_t index) { + const bool priorMode = settings.GetBleRadioEnabled(); + const bool newMode = options[index].radioEnabled; + if (newMode != priorMode) { + settings.SetBleRadioEnabled(newMode); + } + }, + CreateOptionArray()) { } SettingBluetooth::~SettingBluetooth() { lv_obj_clean(lv_scr_act()); - // Do not call SaveSettings - see src/components/settings/Settings.h - if (priorMode != settingsController.GetBleRadioEnabled()) { - app->PushMessage(Pinetime::Applications::Display::Messages::BleRadioEnableToggle); - } -} - -void SettingBluetooth::OnBluetoothDisabled(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - lv_checkbox_set_checked(cbEnabled, false); - lv_checkbox_set_checked(cbDisabled, true); - settingsController.SetBleRadioEnabled(false); - } -} - -void SettingBluetooth::OnBluetoothEnabled(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - lv_checkbox_set_checked(cbEnabled, true); - lv_checkbox_set_checked(cbDisabled, false); - settingsController.SetBleRadioEnabled(true); - } + // 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 12bb459a..611a0d5c 100644 --- a/src/displayapp/screens/settings/SettingBluetooth.h +++ b/src/displayapp/screens/settings/SettingBluetooth.h @@ -6,6 +6,7 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" namespace Pinetime { @@ -17,14 +18,8 @@ namespace Pinetime { SettingBluetooth(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingBluetooth() override; - void OnBluetoothEnabled(lv_obj_t* object, lv_event_t event); - void OnBluetoothDisabled(lv_obj_t* object, lv_event_t event); - private: - Controllers::Settings& settingsController; - lv_obj_t* cbEnabled; - lv_obj_t* cbDisabled; - bool priorMode; + CheckboxList checkboxList; }; } } diff --git a/src/displayapp/screens/settings/SettingChimes.cpp b/src/displayapp/screens/settings/SettingChimes.cpp index 7f519f75..6e12fb88 100644 --- a/src/displayapp/screens/settings/SettingChimes.cpp +++ b/src/displayapp/screens/settings/SettingChimes.cpp @@ -4,70 +4,62 @@ #include "displayapp/screens/Styles.h" #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" +#include <array> using namespace Pinetime::Applications::Screens; namespace { - void event_handler(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingChimes*>(obj->user_data); - screen->UpdateSelected(obj, event); - } -} - -constexpr std::array<SettingChimes::Option, 3> SettingChimes::options; - -SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : Screen(app), settingsController {settingsController} { - - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); + struct Option { + Pinetime::Controllers::Settings::ChimesOption chimesOption; + const char* name; + }; - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + constexpr std::array<Option, 3> options = {{ + {Pinetime::Controllers::Settings::ChimesOption::None, "Off"}, + {Pinetime::Controllers::Settings::ChimesOption::Hours, "Every hour"}, + {Pinetime::Controllers::Settings::ChimesOption::HalfHours, "Every 30 mins"}, + }}; - lv_obj_set_pos(container1, 10, 60); - lv_obj_set_width(container1, LV_HOR_RES - 20); - lv_obj_set_height(container1, LV_VER_RES - 50); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); - - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Chimes"); - lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); - lv_obj_align(title, lv_scr_act(), LV_ALIGN_IN_TOP_MID, 10, 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::clock); - lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); - lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); + std::array<CheckboxList::Item, CheckboxList::MaxItems> CreateOptionArray() { + std::array<Pinetime::Applications::Screens::CheckboxList::Item, CheckboxList::MaxItems> optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; + } - for (unsigned int i = 0; i < options.size(); i++) { - cbOption[i] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbOption[i], options[i].name); - if (settingsController.GetChimeOption() == options[i].chimesOption) { - lv_checkbox_set_checked(cbOption[i], true); + uint32_t GetDefaultOption(Pinetime::Controllers::Settings::ChimesOption currentOption) { + for (size_t i = 0; i < options.size(); i++) { + if (options[i].chimesOption == currentOption) { + return i; + } } - cbOption[i]->user_data = this; - lv_obj_set_event_cb(cbOption[i], event_handler); - SetRadioButtonStyle(cbOption[i]); + return 0; } } -SettingChimes::~SettingChimes() { - lv_obj_clean(lv_scr_act()); - settingsController.SaveSettings(); +SettingChimes::SettingChimes(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) + : Screen(app), + checkboxList( + 0, + 1, + app, + "Chimes", + Symbols::clock, + GetDefaultOption(settingsController.GetChimeOption()), + [&settings = settingsController](uint32_t index) { + settings.SetChimeOption(options[index].chimesOption); + settings.SaveSettings(); + }, + CreateOptionArray()) { } -void SettingChimes::UpdateSelected(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - for (uint8_t i = 0; i < options.size(); i++) { - if (object == cbOption[i]) { - lv_checkbox_set_checked(cbOption[i], true); - settingsController.SetChimeOption(options[i].chimesOption); - } else { - lv_checkbox_set_checked(cbOption[i], false); - } - } - } +SettingChimes::~SettingChimes() { + lv_obj_clean(lv_scr_act()); } diff --git a/src/displayapp/screens/settings/SettingChimes.h b/src/displayapp/screens/settings/SettingChimes.h index e48432c6..a306e81d 100644 --- a/src/displayapp/screens/settings/SettingChimes.h +++ b/src/displayapp/screens/settings/SettingChimes.h @@ -2,9 +2,10 @@ #include <cstdint> #include <lvgl/lvgl.h> + #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" -#include <array> +#include "displayapp/screens/CheckboxList.h" namespace Pinetime { @@ -19,19 +20,7 @@ namespace Pinetime { void UpdateSelected(lv_obj_t* object, lv_event_t event); private: - struct Option { - Controllers::Settings::ChimesOption chimesOption; - const char* name; - }; - static constexpr std::array<Option, 3> options = {{ - {Controllers::Settings::ChimesOption::None, " Off"}, - {Controllers::Settings::ChimesOption::Hours, " Every hour"}, - {Controllers::Settings::ChimesOption::HalfHours, " Every 30 mins"} - }}; - - std::array<lv_obj_t*, options.size()> cbOption; - - Controllers::Settings& settingsController; + CheckboxList checkboxList; }; } } diff --git a/src/displayapp/screens/settings/SettingSetDate.cpp b/src/displayapp/screens/settings/SettingSetDate.cpp index 421aef02..c58f6fca 100644 --- a/src/displayapp/screens/settings/SettingSetDate.cpp +++ b/src/displayapp/screens/settings/SettingSetDate.cpp @@ -1,4 +1,5 @@ #include "displayapp/screens/settings/SettingSetDate.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" #include <lvgl/lvgl.h> #include <hal/nrf_rtc.h> #include <nrf_log.h> @@ -44,8 +45,11 @@ namespace { } } -SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController) - : Screen(app), dateTimeController {dateTimeController} { +SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime) + : Screen(app), dateTimeController {dateTimeController}, settingSetDateTime {settingSetDateTime} { + lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Set current date"); lv_label_set_align(title, LV_LABEL_ALIGN_CENTER); @@ -82,8 +86,6 @@ SettingSetDate::SettingSetDate(Pinetime::Applications::DisplayApp* app, Pinetime lblSetTime = lv_label_create(btnSetTime, nullptr); lv_label_set_text_static(lblSetTime, "Set"); lv_obj_set_event_cb(btnSetTime, event_handler); - lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); } SettingSetDate::~SettingSetDate() { @@ -98,18 +100,14 @@ void SettingSetDate::HandleButtonPress() { dateTimeController.SetTime(yearValue, monthValue, dayValue, - 0, dateTimeController.Hours(), dateTimeController.Minutes(), dateTimeController.Seconds(), nrf_rtc_counter_get(portNRF_RTC_REG)); - lv_btn_set_state(btnSetTime, LV_BTN_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); + settingSetDateTime.Advance(); } void SettingSetDate::CheckDay() { const int maxDay = MaximumDayOfMonth(monthCounter.GetValue(), yearCounter.GetValue()); dayCounter.SetMax(maxDay); - lv_btn_set_state(btnSetTime, LV_BTN_STATE_RELEASED); - lv_obj_set_state(lblSetTime, LV_STATE_DEFAULT); } diff --git a/src/displayapp/screens/settings/SettingSetDate.h b/src/displayapp/screens/settings/SettingSetDate.h index a0ffc683..dfb0e0d2 100644 --- a/src/displayapp/screens/settings/SettingSetDate.h +++ b/src/displayapp/screens/settings/SettingSetDate.h @@ -5,13 +5,17 @@ #include "components/datetime/DateTimeController.h" #include "displayapp/screens/Screen.h" #include "displayapp/widgets/Counter.h" +#include "displayapp/widgets/DotIndicator.h" +#include "displayapp/screens/settings/SettingSetDateTime.h" namespace Pinetime { namespace Applications { namespace Screens { class SettingSetDate : public Screen { public: - SettingSetDate(DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController); + SettingSetDate(DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime); ~SettingSetDate() override; void HandleButtonPress(); @@ -19,6 +23,7 @@ namespace Pinetime { private: Controllers::DateTime& dateTimeController; + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime; lv_obj_t* btnSetTime; lv_obj_t* lblSetTime; diff --git a/src/displayapp/screens/settings/SettingSetDateTime.cpp b/src/displayapp/screens/settings/SettingSetDateTime.cpp new file mode 100644 index 00000000..905a76ab --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetDateTime.cpp @@ -0,0 +1,54 @@ +#include "displayapp/screens/settings/SettingSetDateTime.h" +#include "displayapp/screens/settings/SettingSetDate.h" +#include "displayapp/screens/settings/SettingSetTime.h" +#include "displayapp/DisplayApp.h" +#include "displayapp/screens/ScreenList.h" +#include "components/settings/Settings.h" +#include "displayapp/widgets/DotIndicator.h" + +using namespace Pinetime::Applications::Screens; + +bool SettingSetDateTime::OnTouchEvent(Pinetime::Applications::TouchEvents event) { + return screens.OnTouchEvent(event); +} + +SettingSetDateTime::SettingSetDateTime(Pinetime::Applications::DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController) + : Screen(app), + dateTimeController {dateTimeController}, + settingsController {settingsController}, + screens {app, + 0, + {[this]() -> std::unique_ptr<Screen> { + return screenSetDate(); + }, + [this]() -> std::unique_ptr<Screen> { + return screenSetTime(); + }}, + Screens::ScreenListModes::UpDown} { +} + +std::unique_ptr<Screen> SettingSetDateTime::screenSetDate() { + Widgets::DotIndicator dotIndicator(0, 2); + dotIndicator.Create(); + return std::make_unique<Screens::SettingSetDate>(app, dateTimeController, *this); +} + +std::unique_ptr<Screen> SettingSetDateTime::screenSetTime() { + Widgets::DotIndicator dotIndicator(1, 2); + dotIndicator.Create(); + return std::make_unique<Screens::SettingSetTime>(app, dateTimeController, settingsController, *this); +} + +SettingSetDateTime::~SettingSetDateTime() { + lv_obj_clean(lv_scr_act()); +} + +void SettingSetDateTime::Advance() { + screens.OnTouchEvent(Pinetime::Applications::TouchEvents::SwipeUp); +} + +void SettingSetDateTime::Quit() { + running = false; +} diff --git a/src/displayapp/screens/settings/SettingSetDateTime.h b/src/displayapp/screens/settings/SettingSetDateTime.h new file mode 100644 index 00000000..dea283f8 --- /dev/null +++ b/src/displayapp/screens/settings/SettingSetDateTime.h @@ -0,0 +1,32 @@ +#pragma once + +#include <cstdint> +#include <lvgl/lvgl.h> +#include "displayapp/screens/Screen.h" +#include "displayapp/screens/ScreenList.h" + +namespace Pinetime { + namespace Applications { + namespace Screens { + class SettingSetDateTime : public Screen { + public: + SettingSetDateTime(DisplayApp* app, + Pinetime::Controllers::DateTime& dateTimeController, + Pinetime::Controllers::Settings& settingsController); + ~SettingSetDateTime() override; + + bool OnTouchEvent(TouchEvents event) override; + void Advance(); + void Quit(); + + private: + Controllers::DateTime& dateTimeController; + Controllers::Settings& settingsController; + + ScreenList<2> screens; + std::unique_ptr<Screen> screenSetDate(); + std::unique_ptr<Screen> screenSetTime(); + }; + } + } +} diff --git a/src/displayapp/screens/settings/SettingSetTime.cpp b/src/displayapp/screens/settings/SettingSetTime.cpp index e7d824fd..67ea7afa 100644 --- a/src/displayapp/screens/settings/SettingSetTime.cpp +++ b/src/displayapp/screens/settings/SettingSetTime.cpp @@ -18,6 +18,7 @@ namespace { screen->SetTime(); } } + void ValueChangedHandler(void* userData) { auto* screen = static_cast<SettingSetTime*>(userData); screen->UpdateScreen(); @@ -26,8 +27,9 @@ namespace { SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController) - : Screen(app), dateTimeController {dateTimeController}, settingsController {settingsController} { + Pinetime::Controllers::Settings& settingsController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime) + : Screen(app), dateTimeController {dateTimeController}, settingsController {settingsController}, settingSetDateTime {settingSetDateTime} { lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text_static(title, "Set current time"); @@ -74,8 +76,6 @@ SettingSetTime::SettingSetTime(Pinetime::Applications::DisplayApp* app, lv_obj_set_event_cb(btnSetTime, SetTimeEventHandler); UpdateScreen(); - lv_obj_set_state(btnSetTime, LV_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); } SettingSetTime::~SettingSetTime() { @@ -90,8 +90,6 @@ void SettingSetTime::UpdateScreen() { lv_label_set_text_static(lblampm, "AM"); } } - lv_obj_set_state(btnSetTime, LV_STATE_DEFAULT); - lv_obj_set_state(lblSetTime, LV_STATE_DEFAULT); } void SettingSetTime::SetTime() { @@ -101,11 +99,9 @@ void SettingSetTime::SetTime() { dateTimeController.SetTime(dateTimeController.Year(), static_cast<uint8_t>(dateTimeController.Month()), dateTimeController.Day(), - static_cast<uint8_t>(dateTimeController.DayOfWeek()), static_cast<uint8_t>(hoursValue), static_cast<uint8_t>(minutesValue), 0, nrf_rtc_counter_get(portNRF_RTC_REG)); - lv_obj_set_state(btnSetTime, LV_STATE_DISABLED); - lv_obj_set_state(lblSetTime, LV_STATE_DISABLED); + settingSetDateTime.Quit(); } diff --git a/src/displayapp/screens/settings/SettingSetTime.h b/src/displayapp/screens/settings/SettingSetTime.h index b61962c1..edd89b16 100644 --- a/src/displayapp/screens/settings/SettingSetTime.h +++ b/src/displayapp/screens/settings/SettingSetTime.h @@ -6,6 +6,8 @@ #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 { @@ -14,7 +16,8 @@ namespace Pinetime { public: SettingSetTime(DisplayApp* app, Pinetime::Controllers::DateTime& dateTimeController, - Pinetime::Controllers::Settings& settingsController); + Pinetime::Controllers::Settings& settingsController, + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime); ~SettingSetTime() override; void SetTime(); @@ -23,6 +26,7 @@ namespace Pinetime { private: Controllers::DateTime& dateTimeController; Controllers::Settings& settingsController; + Pinetime::Applications::Screens::SettingSetDateTime& settingSetDateTime; lv_obj_t* lblampm; lv_obj_t* btnSetTime; diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.cpp b/src/displayapp/screens/settings/SettingShakeThreshold.cpp index de46f7de..e7edee9a 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.cpp +++ b/src/displayapp/screens/settings/SettingShakeThreshold.cpp @@ -57,7 +57,7 @@ SettingShakeThreshold::SettingShakeThreshold(DisplayApp* app, lv_obj_set_width(calButton, 200); lv_obj_align(calButton, lv_scr_act(), LV_ALIGN_IN_BOTTOM_MID, 0, 0); lv_btn_set_checkable(calButton, true); - calLabel = lv_label_create(calButton, NULL); + calLabel = lv_label_create(calButton, nullptr); lv_label_set_text_static(calLabel, "Calibrate"); lv_arc_set_value(positionArc, settingsController.GetShakeThreshold()); @@ -102,7 +102,7 @@ void SettingShakeThreshold::Refresh() { } if (xTaskGetTickCount() - vCalTime > pdMS_TO_TICKS(7500)) { lv_btn_set_state(calButton, LV_STATE_DEFAULT); - lv_event_send(calButton, LV_EVENT_VALUE_CHANGED, NULL); + lv_event_send(calButton, LV_EVENT_VALUE_CHANGED, nullptr); } } if (motionController.currentShakeSpeed() - 300 > lv_arc_get_value(animArc)) { diff --git a/src/displayapp/screens/settings/SettingShakeThreshold.h b/src/displayapp/screens/settings/SettingShakeThreshold.h index 43319468..d0979fa6 100644 --- a/src/displayapp/screens/settings/SettingShakeThreshold.h +++ b/src/displayapp/screens/settings/SettingShakeThreshold.h @@ -6,6 +6,7 @@ #include "displayapp/screens/Screen.h" #include <components/motion/MotionController.h> #include "systemtask/SystemTask.h" + namespace Pinetime { namespace Applications { diff --git a/src/displayapp/screens/settings/SettingTimeFormat.cpp b/src/displayapp/screens/settings/SettingTimeFormat.cpp index 5502794b..824a10b2 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.cpp +++ b/src/displayapp/screens/settings/SettingTimeFormat.cpp @@ -8,76 +8,56 @@ using namespace Pinetime::Applications::Screens; namespace { - void event_handler(lv_obj_t* obj, lv_event_t event) { - auto* screen = static_cast<SettingTimeFormat*>(obj->user_data); - screen->UpdateSelected(obj, event); - } -} - -constexpr std::array<const char*, 2> SettingTimeFormat::options; - -SettingTimeFormat::SettingTimeFormat(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) - : Screen(app), settingsController {settingsController} { - - lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); - - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); + struct Option { + Pinetime::Controllers::Settings::ClockType clockType; + const char* name; + }; - lv_obj_set_pos(container1, 10, 60); - lv_obj_set_width(container1, LV_HOR_RES - 20); - lv_obj_set_height(container1, LV_VER_RES - 50); - lv_cont_set_layout(container1, LV_LAYOUT_COLUMN_LEFT); + constexpr std::array<Option, 2> options = {{ + {Pinetime::Controllers::Settings::ClockType::H12, "12-hour"}, + {Pinetime::Controllers::Settings::ClockType::H24, "24-hour"}, + }}; - lv_obj_t* title = lv_label_create(lv_scr_act(), nullptr); - lv_label_set_text_static(title, "Time format"); - 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::clock); - lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); - lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); - - for (unsigned int i = 0; i < options.size(); i++) { - cbOption[i] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text(cbOption[i], options[i]); - cbOption[i]->user_data = this; - lv_obj_set_event_cb(cbOption[i], event_handler); - SetRadioButtonStyle(cbOption[i]); + std::array<CheckboxList::Item, CheckboxList::MaxItems> CreateOptionArray() { + std::array<Pinetime::Applications::Screens::CheckboxList::Item, CheckboxList::MaxItems> optionArray; + for (size_t i = 0; i < CheckboxList::MaxItems; i++) { + if (i >= options.size()) { + optionArray[i].name = ""; + optionArray[i].enabled = false; + } else { + optionArray[i].name = options[i].name; + optionArray[i].enabled = true; + } + } + return optionArray; } - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { - lv_checkbox_set_checked(cbOption[0], true); - } else if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - lv_checkbox_set_checked(cbOption[1], true); + uint32_t GetDefaultOption(Pinetime::Controllers::Settings::ClockType currentOption) { + for (size_t i = 0; i < options.size(); i++) { + if (options[i].clockType == currentOption) { + return i; + } + } + return 0; } } -SettingTimeFormat::~SettingTimeFormat() { - lv_obj_clean(lv_scr_act()); - settingsController.SaveSettings(); +SettingTimeFormat::SettingTimeFormat(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) + : Screen(app), + checkboxList( + 0, + 1, + app, + "Time format", + Symbols::clock, + GetDefaultOption(settingsController.GetClockType()), + [&settings = settingsController](uint32_t index) { + settings.SetClockType(options[index].clockType); + settings.SaveSettings(); + }, + CreateOptionArray()) { } -void SettingTimeFormat::UpdateSelected(lv_obj_t* object, lv_event_t event) { - if (event == LV_EVENT_VALUE_CHANGED) { - for (unsigned int i = 0; i < options.size(); i++) { - if (object == cbOption[i]) { - lv_checkbox_set_checked(cbOption[i], true); - - if (i == 0) { - settingsController.SetClockType(Controllers::Settings::ClockType::H12); - }; - if (i == 1) { - settingsController.SetClockType(Controllers::Settings::ClockType::H24); - }; - - } else { - lv_checkbox_set_checked(cbOption[i], false); - } - } - } +SettingTimeFormat::~SettingTimeFormat() { + lv_obj_clean(lv_scr_act()); } diff --git a/src/displayapp/screens/settings/SettingTimeFormat.h b/src/displayapp/screens/settings/SettingTimeFormat.h index 01ca2c9b..de37f43e 100644 --- a/src/displayapp/screens/settings/SettingTimeFormat.h +++ b/src/displayapp/screens/settings/SettingTimeFormat.h @@ -6,6 +6,7 @@ #include "components/settings/Settings.h" #include "displayapp/screens/Screen.h" +#include "displayapp/screens/CheckboxList.h" namespace Pinetime { @@ -17,12 +18,8 @@ namespace Pinetime { SettingTimeFormat(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingTimeFormat() override; - void UpdateSelected(lv_obj_t* object, lv_event_t event); - private: - static constexpr std::array<const char*, 2> options = {"12-hour", "24-hour"}; - Controllers::Settings& settingsController; - lv_obj_t* cbOption[options.size()]; + CheckboxList checkboxList; }; } } diff --git a/src/displayapp/screens/settings/SettingWakeUp.cpp b/src/displayapp/screens/settings/SettingWakeUp.cpp index 59275e2f..620fe6e8 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.cpp +++ b/src/displayapp/screens/settings/SettingWakeUp.cpp @@ -4,19 +4,23 @@ #include "displayapp/screens/Screen.h" #include "displayapp/screens/Symbols.h" #include "components/settings/Settings.h" +#include "displayapp/screens/Styles.h" using namespace Pinetime::Applications::Screens; +constexpr std::array<SettingWakeUp::Option, 4> SettingWakeUp::options; + namespace { void event_handler(lv_obj_t* obj, lv_event_t event) { auto* screen = static_cast<SettingWakeUp*>(obj->user_data); - screen->UpdateSelected(obj, event); + if (event == LV_EVENT_VALUE_CHANGED) { + screen->UpdateSelected(obj); + } } } SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController) : Screen(app), settingsController {settingsController} { - ignoringEvents = false; lv_obj_t* container1 = lv_cont_create(lv_scr_act(), nullptr); lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); @@ -40,39 +44,15 @@ SettingWakeUp::SettingWakeUp(Pinetime::Applications::DisplayApp* app, Pinetime:: lv_label_set_align(icon, LV_LABEL_ALIGN_CENTER); lv_obj_align(icon, title, LV_ALIGN_OUT_LEFT_MID, -10, 0); - optionsTotal = 0; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text_static(cbOption[optionsTotal], "Single Tap"); - cbOption[optionsTotal]->user_data = this; - lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); - } - optionsTotal++; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text_static(cbOption[optionsTotal], "Double Tap"); - cbOption[optionsTotal]->user_data = this; - lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); - } - optionsTotal++; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text_static(cbOption[optionsTotal], "Raise Wrist"); - cbOption[optionsTotal]->user_data = this; - lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); - } - optionsTotal++; - cbOption[optionsTotal] = lv_checkbox_create(container1, nullptr); - lv_checkbox_set_text_static(cbOption[optionsTotal], "Shake Wake"); - cbOption[optionsTotal]->user_data = this; - lv_obj_set_event_cb(cbOption[optionsTotal], event_handler); - if (settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake)) { - lv_checkbox_set_checked(cbOption[optionsTotal], true); + for (unsigned int i = 0; i < options.size(); i++) { + cbOption[i] = lv_checkbox_create(container1, nullptr); + lv_checkbox_set_text(cbOption[i], options[i].name); + if (settingsController.isWakeUpModeOn(static_cast<Controllers::Settings::WakeUpMode>(i))) { + lv_checkbox_set_checked(cbOption[i], true); + } + cbOption[i]->user_data = this; + lv_obj_set_event_cb(cbOption[i], event_handler); } - optionsTotal++; } SettingWakeUp::~SettingWakeUp() { @@ -80,32 +60,21 @@ SettingWakeUp::~SettingWakeUp() { settingsController.SaveSettings(); } -void SettingWakeUp::UpdateSelected(lv_obj_t* object, lv_event_t event) { - using WakeUpMode = Pinetime::Controllers::Settings::WakeUpMode; - if (event == LV_EVENT_VALUE_CHANGED && !ignoringEvents) { - ignoringEvents = true; - - // Find the index of the checkbox that triggered the event - int index = 0; - for (; index < optionsTotal; ++index) { - if (cbOption[index] == object) { - break; - } - } - - // Toggle needed wakeup mode - auto mode = static_cast<WakeUpMode>(index); - auto currentState = settingsController.isWakeUpModeOn(mode); - settingsController.setWakeUpMode(mode, !currentState); - - // Update checkbox according to current wakeup modes. - // This is needed because we can have extra logic when setting or unsetting wakeup modes, - // for example, when setting SingleTap, DoubleTap is unset and vice versa. - auto modes = settingsController.getWakeUpModes(); - for (int i = 0; i < optionsTotal; ++i) { - lv_checkbox_set_checked(cbOption[i], modes[i]); +void SettingWakeUp::UpdateSelected(lv_obj_t* object) { + // Find the index of the checkbox that triggered the event + for (size_t i = 0; i < options.size(); i++) { + if (cbOption[i] == object) { + bool currentState = settingsController.isWakeUpModeOn(options[i].wakeUpMode); + settingsController.setWakeUpMode(options[i].wakeUpMode, !currentState); + break; } + } - ignoringEvents = false; + // Update checkbox according to current wakeup modes. + // This is needed because we can have extra logic when setting or unsetting wakeup modes, + // for example, when setting SingleTap, DoubleTap is unset and vice versa. + auto modes = settingsController.getWakeUpModes(); + for (size_t i = 0; i < options.size(); ++i) { + lv_checkbox_set_checked(cbOption[i], modes[i]); } } diff --git a/src/displayapp/screens/settings/SettingWakeUp.h b/src/displayapp/screens/settings/SettingWakeUp.h index cd244ae5..2a4e7509 100644 --- a/src/displayapp/screens/settings/SettingWakeUp.h +++ b/src/displayapp/screens/settings/SettingWakeUp.h @@ -1,5 +1,6 @@ #pragma once +#include <array> #include <cstdint> #include <lvgl/lvgl.h> #include "components/settings/Settings.h" @@ -15,17 +16,23 @@ namespace Pinetime { SettingWakeUp(DisplayApp* app, Pinetime::Controllers::Settings& settingsController); ~SettingWakeUp() override; - void UpdateSelected(lv_obj_t* object, lv_event_t event); + void UpdateSelected(lv_obj_t* object); private: + struct Option { + Controllers::Settings::WakeUpMode wakeUpMode; + const char* name; + }; + Controllers::Settings& settingsController; - uint8_t optionsTotal; - lv_obj_t* cbOption[5]; - // When UpdateSelected is called, it uses lv_checkbox_set_checked, - // which can cause extra events to be fired, - // which might trigger UpdateSelected again, causing a loop. - // This variable is used as a mutex to prevent that. - bool ignoringEvents; + static constexpr std::array<Option, 4> options = {{ + {Controllers::Settings::WakeUpMode::SingleTap, "Single Tap"}, + {Controllers::Settings::WakeUpMode::DoubleTap, "Double Tap"}, + {Controllers::Settings::WakeUpMode::RaiseWrist, "Raise Wrist"}, + {Controllers::Settings::WakeUpMode::Shake, "Shake Wake"}, + }}; + + lv_obj_t* cbOption[options.size()]; }; } } diff --git a/src/displayapp/screens/settings/SettingWatchFace.cpp b/src/displayapp/screens/settings/SettingWatchFace.cpp index 217f97b8..da32b5ee 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.cpp +++ b/src/displayapp/screens/settings/SettingWatchFace.cpp @@ -1,32 +1,31 @@ #include "displayapp/screens/settings/SettingWatchFace.h" #include <lvgl/lvgl.h> #include "displayapp/DisplayApp.h" -#include "displayapp/screens/CheckboxList.h" #include "displayapp/screens/Screen.h" #include "components/settings/Settings.h" -#include "displayapp/screens/WatchFaceInfineat.h" -#include "displayapp/screens/WatchFaceCasioStyleG7710.h" using namespace Pinetime::Applications::Screens; constexpr const char* SettingWatchFace::title; constexpr const char* SettingWatchFace::symbol; +auto SettingWatchFace::CreateScreenList() const { + std::array<std::function<std::unique_ptr<Screen>()>, nScreens> screens; + for (size_t i = 0; i < screens.size(); i++) { + screens[i] = [this, i]() -> std::unique_ptr<Screen> { + return CreateScreen(i); + }; + } + return screens; +} + SettingWatchFace::SettingWatchFace(Pinetime::Applications::DisplayApp* app, Pinetime::Controllers::Settings& settingsController, Pinetime::Controllers::FS& filesystem) : Screen(app), settingsController {settingsController}, filesystem {filesystem}, - screens {app, - 0, - {[this]() -> std::unique_ptr<Screen> { - return CreateScreen1(); - }, - [this]() -> std::unique_ptr<Screen> { - return CreateScreen2(); - }}, - Screens::ScreenListModes::UpDown} { + screens {app, 0, CreateScreenList(), Screens::ScreenListModes::UpDown} { } SettingWatchFace::~SettingWatchFace() { @@ -37,32 +36,15 @@ bool SettingWatchFace::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screens.OnTouchEvent(event); } -std::unique_ptr<Screen> SettingWatchFace::CreateScreen1() { - std::array<Screens::CheckboxList::Item, 4> watchfaces { - {{"Digital face", true}, {"Analog face", true}, {"PineTimeStyle", true}, {"Terminal", true}}}; - return std::make_unique<Screens::CheckboxList>( - 0, - 2, - app, - title, - symbol, - settingsController.GetClockFace(), - [&settings = settingsController](uint32_t clockFace) { - settings.SetClockFace(clockFace); - settings.SaveSettings(); - }, - watchfaces); -} +std::unique_ptr<Screen> SettingWatchFace::CreateScreen(unsigned int screenNum) const { + std::array<Screens::CheckboxList::Item, settingsPerScreen> watchfacesOnThisScreen; + for (int i = 0; i < settingsPerScreen; i++) { + watchfacesOnThisScreen[i] = watchfaces[screenNum * settingsPerScreen + i]; + } -std::unique_ptr<Screen> SettingWatchFace::CreateScreen2() { - std::array<Screens::CheckboxList::Item, 4> watchfaces { - {{"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)}, - {"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)}, - {"", false}, - {"", false}}}; return std::make_unique<Screens::CheckboxList>( - 1, - 2, + screenNum, + nScreens, app, title, symbol, @@ -71,5 +53,5 @@ std::unique_ptr<Screen> SettingWatchFace::CreateScreen2() { settings.SetClockFace(clockFace); settings.SaveSettings(); }, - watchfaces); + watchfacesOnThisScreen); } diff --git a/src/displayapp/screens/settings/SettingWatchFace.h b/src/displayapp/screens/settings/SettingWatchFace.h index 158397f8..7b8cdcdc 100644 --- a/src/displayapp/screens/settings/SettingWatchFace.h +++ b/src/displayapp/screens/settings/SettingWatchFace.h @@ -8,6 +8,9 @@ #include "components/settings/Settings.h" #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" namespace Pinetime { @@ -22,14 +25,30 @@ namespace Pinetime { bool OnTouchEvent(TouchEvents event) override; private: + auto CreateScreenList() const; + std::unique_ptr<Screen> CreateScreen(unsigned int screenNum) const; + Controllers::Settings& settingsController; Pinetime::Controllers::FS& filesystem; - ScreenList<2> screens; static constexpr const char* title = "Watch face"; static constexpr const char* symbol = Symbols::home; - std::unique_ptr<Screen> CreateScreen1(); - std::unique_ptr<Screen> CreateScreen2(); + + static constexpr int settingsPerScreen = 4; + + // Increment this when more space is needed + static constexpr int nScreens = 2; + + std::array<Screens::CheckboxList::Item, settingsPerScreen * nScreens> watchfaces { + {{"Digital face", true}, + {"Analog face", true}, + {"PineTimeStyle", true}, + {"Terminal", true}, + {"Infineat face", Applications::Screens::WatchFaceInfineat::IsAvailable(filesystem)}, + {"Casio G7710", Applications::Screens::WatchFaceCasioStyleG7710::IsAvailable(filesystem)}, + {"", false}, + {"", false}}}; + ScreenList<nScreens> screens; }; } } diff --git a/src/displayapp/screens/settings/Settings.h b/src/displayapp/screens/settings/Settings.h index a86db44f..b88c13b7 100644 --- a/src/displayapp/screens/settings/Settings.h +++ b/src/displayapp/screens/settings/Settings.h @@ -28,7 +28,7 @@ namespace Pinetime { static constexpr int entriesPerScreen = 4; // Increment this when more space is needed - static constexpr int nScreens = 4; + static constexpr int nScreens = 3; static constexpr std::array<List::Applications, entriesPerScreen * nScreens> entries {{ {Symbols::sun, "Display", Apps::SettingDisplay}, @@ -37,19 +37,20 @@ namespace Pinetime { {Symbols::home, "Watch face", Apps::SettingWatchFace}, {Symbols::shoe, "Steps", Apps::SettingSteps}, - {Symbols::clock, "Set date", Apps::SettingSetDate}, - {Symbols::clock, "Set time", Apps::SettingSetTime}, + {Symbols::clock, "Date&Time", Apps::SettingSetDateTime}, {Symbols::batteryHalf, "Battery", Apps::BatteryInfo}, - {Symbols::clock, "Chimes", Apps::SettingChimes}, + {Symbols::tachometer, "Shake Calib.", Apps::SettingShakeThreshold}, {Symbols::check, "Firmware", Apps::FirmwareValidation}, {Symbols::bluetooth, "Bluetooth", Apps::SettingBluetooth}, - {Symbols::list, "About", Apps::SysInfo}, - {Symbols::none, "None", Apps::None}, - {Symbols::none, "None", Apps::None}, - {Symbols::none, "None", Apps::None}, + + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + // {Symbols::none, "None", Apps::None}, + }}; ScreenList<nScreens> screens; }; diff --git a/src/displayapp/widgets/Counter.cpp b/src/displayapp/widgets/Counter.cpp index e95178ec..b486e372 100644 --- a/src/displayapp/widgets/Counter.cpp +++ b/src/displayapp/widgets/Counter.cpp @@ -18,6 +18,7 @@ namespace { widget->DownBtnPressed(); } } + constexpr int digitCount(int number) { int digitCount = 0; while (number > 0) { @@ -28,7 +29,7 @@ namespace { } } -Counter::Counter(int min, int max, lv_font_t& font) : min {min}, max {max}, value {min}, font {font}, leadingZeroCount {digitCount(max)} { +Counter::Counter(int min, int max, lv_font_t& font) : min {min}, max {max}, value {min}, leadingZeroCount {digitCount(max)}, font {font} { } void Counter::UpBtnPressed() { @@ -67,6 +68,7 @@ void Counter::HideControls() { lv_obj_set_hidden(lowerLine, true); lv_obj_set_style_local_bg_opa(counterContainer, LV_OBJ_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); } + void Counter::ShowControls() { lv_obj_set_hidden(upBtn, false); lv_obj_set_hidden(downBtn, false); diff --git a/src/displayapp/widgets/DotIndicator.cpp b/src/displayapp/widgets/DotIndicator.cpp new file mode 100644 index 00000000..209b43bd --- /dev/null +++ b/src/displayapp/widgets/DotIndicator.cpp @@ -0,0 +1,28 @@ +#include "displayapp/widgets/DotIndicator.h" +#include "displayapp/InfiniTimeTheme.h" + +using namespace Pinetime::Applications::Widgets; + +DotIndicator::DotIndicator(uint8_t nCurrentScreen, uint8_t nScreens) : nCurrentScreen {nCurrentScreen}, nScreens {nScreens} { +} + +void DotIndicator::Create() { + lv_obj_t* dotIndicator[nScreens]; + static constexpr uint8_t dotSize = 12; + + lv_obj_t* container = lv_cont_create(lv_scr_act(), nullptr); + lv_cont_set_layout(container, LV_LAYOUT_COLUMN_LEFT); + lv_cont_set_fit(container, LV_FIT_TIGHT); + lv_obj_set_style_local_pad_inner(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, dotSize); + lv_obj_set_style_local_bg_opa(container, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); + + for (int i = 0; i < nScreens; i++) { + dotIndicator[i] = lv_obj_create(container, nullptr); + lv_obj_set_size(dotIndicator[i], dotSize, dotSize); + lv_obj_set_style_local_bg_color(dotIndicator[i], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_GRAY); + } + + lv_obj_set_style_local_bg_color(dotIndicator[nCurrentScreen], LV_BTN_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_WHITE); + + lv_obj_align(container, nullptr, LV_ALIGN_IN_RIGHT_MID, 0, 0); +} diff --git a/src/displayapp/widgets/DotIndicator.h b/src/displayapp/widgets/DotIndicator.h new file mode 100644 index 00000000..49cdca26 --- /dev/null +++ b/src/displayapp/widgets/DotIndicator.h @@ -0,0 +1,18 @@ +#pragma once +#include <lvgl/lvgl.h> + +namespace Pinetime { + namespace Applications { + namespace Widgets { + class DotIndicator { + public: + DotIndicator(uint8_t nCurrentScreen, uint8_t nScreens); + void Create(); + + private: + uint8_t nCurrentScreen; + uint8_t nScreens; + }; + } + } +} diff --git a/src/displayapp/widgets/StatusIcons.h b/src/displayapp/widgets/StatusIcons.h index f4a30a80..7d9e3ae3 100644 --- a/src/displayapp/widgets/StatusIcons.h +++ b/src/displayapp/widgets/StatusIcons.h @@ -15,9 +15,11 @@ namespace Pinetime { StatusIcons(Controllers::Battery& batteryController, Controllers::Ble& bleController); void Align(); void Create(); + lv_obj_t* GetObject() { return container; } + void Update(); private: diff --git a/src/drivers/Bma421.cpp b/src/drivers/Bma421.cpp index 539cc8d1..84d76ab3 100644 --- a/src/drivers/Bma421.cpp +++ b/src/drivers/Bma421.cpp @@ -19,7 +19,7 @@ namespace { return 0; } - void user_delay(uint32_t period_us, void* intf_ptr) { + void user_delay(uint32_t period_us, void* /*intf_ptr*/) { nrf_delay_us(period_us); } } @@ -118,6 +118,7 @@ Bma421::Values Bma421::Process() { // 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}; } + bool Bma421::IsOk() const { return isOk; } @@ -133,6 +134,7 @@ void Bma421::SoftReset() { nrf_delay_ms(1); } } + Bma421::DeviceTypes Bma421::DeviceType() const { return deviceType; } diff --git a/src/drivers/Bma421.h b/src/drivers/Bma421.h index ac5c707f..fb832514 100644 --- a/src/drivers/Bma421.h +++ b/src/drivers/Bma421.h @@ -4,15 +4,18 @@ namespace Pinetime { namespace Drivers { class TwiMaster; + class Bma421 { public: enum class DeviceTypes : uint8_t { Unknown, BMA421, BMA425 }; + struct Values { uint32_t steps; int16_t x; int16_t y; int16_t z; }; + Bma421(TwiMaster& twiMaster, uint8_t twiAddress); Bma421(const Bma421&) = delete; Bma421& operator=(const Bma421&) = delete; diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h index 9d426c9d..c50bb733 100644 --- a/src/drivers/Cst816s.h +++ b/src/drivers/Cst816s.h @@ -16,6 +16,7 @@ namespace Pinetime { DoubleTap = 0x0B, LongPress = 0x0C }; + struct TouchInfos { uint16_t x = 0; uint16_t y = 0; @@ -38,9 +39,11 @@ namespace Pinetime { uint8_t GetChipId() const { return chipId; } + uint8_t GetVendorId() const { return vendorId; } + uint8_t GetFwVersion() const { return fwVersion; } diff --git a/src/drivers/DebugPins.cpp b/src/drivers/DebugPins.cpp index 4b2f0f16..6d24ca04 100644 --- a/src/drivers/DebugPins.cpp +++ b/src/drivers/DebugPins.cpp @@ -18,6 +18,7 @@ void debugpins_init() { nrf_gpio_cfg_output(DebugPin4); nrf_gpio_pin_clear(DebugPin4); } + void debugpins_set(debugpins_pins pin) { nrf_gpio_pin_set(static_cast<uint32_t>(pin)); } @@ -33,6 +34,7 @@ void debugpins_pulse(debugpins_pins pin) { #else void debugpins_init() { } + void debugpins_set(debugpins_pins pin) { } diff --git a/src/drivers/DebugPins.h b/src/drivers/DebugPins.h deleted file mode 100644 index b30cd222..00000000 --- a/src/drivers/DebugPins.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include <stdint.h> - -typedef enum { - DebugPin0 = 27, - DebugPin1 = 29, - DebugPin2 = 20, - DebugPin3 = 17, - DebugPin4 = 11, -} debugpins_pins; - -void debugpins_init(); -void debugpins_set(debugpins_pins pin); -void debugpins_clear(debugpins_pins pin); -void debugpins_pulse(debugpins_pins pin); - -#ifdef __cplusplus -} -#endif diff --git a/src/drivers/Hrs3300.cpp b/src/drivers/Hrs3300.cpp index ec620af2..6c47ae28 100644 --- a/src/drivers/Hrs3300.cpp +++ b/src/drivers/Hrs3300.cpp @@ -13,6 +13,7 @@ #include <nrf_log.h> using namespace Pinetime::Drivers; + /** 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 */ diff --git a/src/drivers/SpiMaster.cpp b/src/drivers/SpiMaster.cpp index 38f72fee..234884ab 100644 --- a/src/drivers/SpiMaster.cpp +++ b/src/drivers/SpiMaster.cpp @@ -163,10 +163,7 @@ void SpiMaster::PrepareTx(const volatile uint32_t bufferAddress, const volatile spiBaseAddress->EVENTS_END = 0; } -void SpiMaster::PrepareRx(const volatile uint32_t cmdAddress, - const volatile size_t cmdSize, - const volatile uint32_t bufferAddress, - const volatile size_t size) { +void SpiMaster::PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size) { spiBaseAddress->TXD.PTR = 0; spiBaseAddress->TXD.MAXCNT = 0; spiBaseAddress->TXD.LIST = 0; @@ -234,7 +231,7 @@ bool SpiMaster::Read(uint8_t pinCsn, uint8_t* cmd, size_t cmdSize, uint8_t* data while (spiBaseAddress->EVENTS_END == 0) ; - PrepareRx((uint32_t) cmd, cmdSize, (uint32_t) data, dataSize); + PrepareRx((uint32_t) data, dataSize); spiBaseAddress->TASKS_START = 1; while (spiBaseAddress->EVENTS_END == 0) diff --git a/src/drivers/SpiMaster.h b/src/drivers/SpiMaster.h index 5ea624f2..8b698c57 100644 --- a/src/drivers/SpiMaster.h +++ b/src/drivers/SpiMaster.h @@ -14,6 +14,7 @@ namespace Pinetime { enum class BitOrder : uint8_t { Msb_Lsb, Lsb_Msb }; enum class Modes : uint8_t { Mode0, Mode1, Mode2, Mode3 }; enum class Frequencies : uint8_t { Freq8Mhz }; + struct Parameters { BitOrder bitOrder; Modes mode; @@ -45,10 +46,7 @@ namespace Pinetime { 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 PrepareTx(const volatile uint32_t bufferAddress, const volatile size_t size); - void PrepareRx(const volatile uint32_t cmdAddress, - const volatile size_t cmdSize, - const volatile uint32_t bufferAddress, - const volatile size_t size); + void PrepareRx(const volatile uint32_t bufferAddress, const volatile size_t size); NRF_SPIM_Type* spiBaseAddress; uint8_t pinCsn; diff --git a/src/drivers/SpiNorFlash.h b/src/drivers/SpiNorFlash.h index ad4d0907..8a063fea 100644 --- a/src/drivers/SpiNorFlash.h +++ b/src/drivers/SpiNorFlash.h @@ -5,6 +5,7 @@ namespace Pinetime { namespace Drivers { class Spi; + class SpiNorFlash { public: explicit SpiNorFlash(Spi& spi); diff --git a/src/drivers/St7789.h b/src/drivers/St7789.h index 8c2ac093..8a1bdfca 100644 --- a/src/drivers/St7789.h +++ b/src/drivers/St7789.h @@ -5,6 +5,7 @@ namespace Pinetime { namespace Drivers { class Spi; + class St7789 { public: explicit St7789(Spi& spi, uint8_t pinDataCommand); diff --git a/src/drivers/Watchdog.h b/src/drivers/Watchdog.h index 03807d61..22aa9df6 100644 --- a/src/drivers/Watchdog.h +++ b/src/drivers/Watchdog.h @@ -9,9 +9,11 @@ namespace Pinetime { void Setup(uint8_t timeoutSeconds); void Start(); void Kick(); + ResetReasons ResetReason() const { return resetReason; } + static const char* ResetReasonToString(ResetReasons reason); private: @@ -23,6 +25,7 @@ namespace Pinetime { public: WatchdogView(const Watchdog& watchdog) : watchdog {watchdog} { } + Watchdog::ResetReasons ResetReason() const { return watchdog.ResetReason(); } diff --git a/src/heartratetask/HeartRateTask.cpp b/src/heartratetask/HeartRateTask.cpp index bc227624..50833ab2 100644 --- a/src/heartratetask/HeartRateTask.cpp +++ b/src/heartratetask/HeartRateTask.cpp @@ -6,15 +6,16 @@ using namespace Pinetime::Applications; HeartRateTask::HeartRateTask(Drivers::Hrs3300& heartRateSensor, Controllers::HeartRateController& controller) - : heartRateSensor {heartRateSensor}, controller {controller}, ppg {} { + : heartRateSensor {heartRateSensor}, controller {controller} { } void HeartRateTask::Start() { messageQueue = xQueueCreate(10, 1); controller.SetHeartRateTask(this); - if (pdPASS != xTaskCreate(HeartRateTask::Process, "Heartrate", 500, this, 0, &taskHandle)) + if (pdPASS != xTaskCreate(HeartRateTask::Process, "Heartrate", 500, this, 0, &taskHandle)) { APP_ERROR_HANDLER(NRF_ERROR_NO_MEM); + } } void HeartRateTask::Process(void* instance) { @@ -25,17 +26,19 @@ void HeartRateTask::Process(void* instance) { void HeartRateTask::Work() { int lastBpm = 0; while (true) { - Messages msg; - uint32_t delay; + auto delay = portMAX_DELAY; if (state == States::Running) { - if (measurementStarted) + if (measurementStarted) { delay = 40; - else + } else { delay = 100; - } else + } + } else { delay = portMAX_DELAY; + } - if (xQueueReceive(messageQueue, &msg, delay)) { + Messages msg; + if (xQueueReceive(messageQueue, &msg, delay) == pdTRUE) { switch (msg) { case Messages::GoToSleep: StopMeasurement(); @@ -49,15 +52,17 @@ void HeartRateTask::Work() { } break; case Messages::StartMeasurement: - if (measurementStarted) + if (measurementStarted) { break; + } lastBpm = 0; StartMeasurement(); measurementStarted = true; break; case Messages::StopMeasurement: - if (!measurementStarted) + if (!measurementStarted) { break; + } StopMeasurement(); measurementStarted = false; break; @@ -68,8 +73,9 @@ void HeartRateTask::Work() { ppg.Preprocess(static_cast<float>(heartRateSensor.ReadHrs())); auto bpm = ppg.HeartRate(); - if (lastBpm == 0 && bpm == 0) + if (lastBpm == 0 && bpm == 0) { controller.Update(Controllers::HeartRateController::States::NotEnoughData, 0); + } if (bpm != 0) { lastBpm = bpm; controller.Update(Controllers::HeartRateController::States::Running, lastBpm); @@ -79,10 +85,9 @@ void HeartRateTask::Work() { } void HeartRateTask::PushMessage(HeartRateTask::Messages msg) { - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(messageQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { + if (xHigherPriorityTaskWoken == pdTRUE) { /* Actual macro used here is port specific. */ // TODO : should I do something here? } @@ -91,7 +96,7 @@ void HeartRateTask::PushMessage(HeartRateTask::Messages msg) { void HeartRateTask::StartMeasurement() { heartRateSensor.Enable(); vTaskDelay(100); - ppg.SetOffset(static_cast<float>(heartRateSensor.ReadHrs())); + ppg.SetOffset(heartRateSensor.ReadHrs()); } void HeartRateTask::StopMeasurement() { diff --git a/src/heartratetask/HeartRateTask.h b/src/heartratetask/HeartRateTask.h index 0796dc74..5bbfb9fb 100644 --- a/src/heartratetask/HeartRateTask.h +++ b/src/heartratetask/HeartRateTask.h @@ -8,9 +8,11 @@ namespace Pinetime { namespace Drivers { class Hrs3300; } + namespace Controllers { class HeartRateController; } + namespace Applications { class HeartRateTask { public: diff --git a/src/logging/DummyLogger.h b/src/logging/DummyLogger.h index 1b050b37..53590b6f 100644 --- a/src/logging/DummyLogger.h +++ b/src/logging/DummyLogger.h @@ -7,6 +7,7 @@ namespace Pinetime { public: void Init() override { } + void Resume() override { } }; diff --git a/src/main.cpp b/src/main.cpp index ad7a07dc..b205f1e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,7 +45,6 @@ #include "drivers/Cst816s.h" #include "drivers/PinMap.h" #include "systemtask/SystemTask.h" -#include "drivers/PinMap.h" #include "touchhandler/TouchHandler.h" #include "buttonhandler/ButtonHandler.h" @@ -210,29 +209,29 @@ void SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void) { } } -static void (*radio_isr_addr)(void); -static void (*rng_isr_addr)(void); -static void (*rtc0_isr_addr)(void); +static void (*radio_isr_addr)(); +static void (*rng_isr_addr)(); +static void (*rtc0_isr_addr)(); /* Some interrupt handlers required for NimBLE radio driver */ extern "C" { void RADIO_IRQHandler(void) { - ((void (*)(void)) radio_isr_addr)(); + ((void (*)()) radio_isr_addr)(); } void RNG_IRQHandler(void) { - ((void (*)(void)) rng_isr_addr)(); + ((void (*)()) rng_isr_addr)(); } void RTC0_IRQHandler(void) { - ((void (*)(void)) rtc0_isr_addr)(); + ((void (*)()) rtc0_isr_addr)(); } void WDT_IRQHandler(void) { nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT); } -void npl_freertos_hw_set_isr(int irqn, void (*addr)(void)) { +void npl_freertos_hw_set_isr(int irqn, void (*addr)()) { switch (irqn) { case RADIO_IRQn: radio_isr_addr = addr; @@ -243,6 +242,8 @@ void npl_freertos_hw_set_isr(int irqn, void (*addr)(void)) { case RTC0_IRQn: rtc0_isr_addr = addr; break; + default: + break; } } @@ -253,7 +254,7 @@ uint32_t npl_freertos_hw_enter_critical(void) { } void npl_freertos_hw_exit_critical(uint32_t ctx) { - if (!ctx) { + if (ctx == 0) { __enable_irq(); } } @@ -265,15 +266,14 @@ struct ble_npl_eventq* nimble_port_get_dflt_eventq(void) { } void nimble_port_run(void) { - struct ble_npl_event* ev; - - while (1) { - ev = ble_npl_eventq_get(&g_eventq_dflt, BLE_NPL_TIME_FOREVER); - ble_npl_event_run(ev); + struct ble_npl_event* event; + while (true) { + event = ble_npl_eventq_get(&g_eventq_dflt, BLE_NPL_TIME_FOREVER); + ble_npl_event_run(event); } } -void BleHost(void*) { +void BleHost(void* /*unused*/) { nimble_port_run(); } @@ -285,8 +285,7 @@ void nimble_port_init(void) { ble_hs_init(); ble_store_ram_init(); - int res; - res = hal_timer_init(5, NULL); + int res = hal_timer_init(5, nullptr); ASSERT(res == 0); res = os_cputime_init(32768); ASSERT(res == 0); @@ -301,17 +300,17 @@ void nimble_port_ll_task_func(void* args) { } } -void calibrate_lf_clock_rc(nrf_drv_clock_evt_type_t event) { +void calibrate_lf_clock_rc(nrf_drv_clock_evt_type_t /*event*/) { // 16 * 0.25s = 4s calibration cycle // Not recursive, call is deferred via internal calibration timer nrf_drv_clock_calibration_start(16, calibrate_lf_clock_rc); } -int main(void) { +int main() { logger.Init(); nrf_drv_clock_init(); - nrf_drv_clock_lfclk_request(NULL); + nrf_drv_clock_lfclk_request(nullptr); // When loading the firmware via the Wasp-OS reloader-factory, which uses the used internal LF RC oscillator, // the LF clock has to be explicitly restarted because InfiniTime uses the external crystal oscillator if available. diff --git a/src/recoveryLoader.cpp b/src/recoveryLoader.cpp index 27a79d9c..d6f8d49b 100644 --- a/src/recoveryLoader.cpp +++ b/src/recoveryLoader.cpp @@ -81,7 +81,8 @@ void RefreshWatchdog() { } uint8_t displayBuffer[displayWidth * bytesPerPixel]; -void Process(void* instance) { + +void Process(void* /*instance*/) { RefreshWatchdog(); APP_GPIOTE_INIT(2); diff --git a/src/resources/fonts.json b/src/resources/fonts.json index a270e6a2..c4a63349 100644 --- a/src/resources/fonts.json +++ b/src/resources/fonts.json @@ -3,7 +3,7 @@ "sources": [ { "file": "fonts/Teko-Light.ttf", - "symbols": "0123456789:/ampMonTueWdhFriSt " + "symbols": "0123456789:/APMonTueWdhFriSat " } ], "bpp": 1, diff --git a/src/systemtask/Messages.h b/src/systemtask/Messages.h index 7a46e060..b7fee8a5 100644 --- a/src/systemtask/Messages.h +++ b/src/systemtask/Messages.h @@ -1,8 +1,9 @@ #pragma once +#include <cstdint> namespace Pinetime { namespace System { - enum class Messages { + enum class Messages : uint8_t { GoToSleep, GoToRunning, TouchWakeUp, @@ -29,6 +30,7 @@ namespace Pinetime { StopRinging, MeasureBatteryTimerExpired, BatteryPercentageUpdated, + LowBattery, StartFileTransfer, StopFileTransfer, BleRadioEnableToggle diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index ef631af7..73f573fa 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -18,6 +18,8 @@ #include "BootErrors.h" #include <memory> +#include <algorithm> +#include <cstring> using namespace Pinetime::System; @@ -30,14 +32,14 @@ namespace { void DimTimerCallback(TimerHandle_t xTimer) { NRF_LOG_INFO("DimTimerCallback"); - auto sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); + auto* sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); sysTask->OnDim(); } void IdleTimerCallback(TimerHandle_t xTimer) { NRF_LOG_INFO("IdleTimerCallback"); - auto sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); + auto* sysTask = static_cast<SystemTask*>(pvTimerGetTimerID(xTimer)); sysTask->OnIdle(); } @@ -208,10 +210,9 @@ void SystemTask::Work() { while (true) { UpdateMotion(); - uint8_t msg; - if (xQueueReceive(systemTasksMsgQueue, &msg, 100)) { - Messages message = static_cast<Messages>(msg); - switch (message) { + Messages msg; + if (xQueueReceive(systemTasksMsgQueue, &msg, 100) == pdTRUE) { + switch (msg) { case Messages::EnableSleeping: // Make sure that exiting an app doesn't enable sleeping, // if the exiting was caused by a firmware update @@ -348,7 +349,7 @@ void SystemTask::Work() { displayApp.PushMessage(Pinetime::Applications::Display::Messages::TouchEvent); break; case Messages::HandleButtonEvent: { - Controllers::ButtonActions action; + Controllers::ButtonActions action = Controllers::ButtonActions::None; if (nrf_gpio_pin_read(Pinetime::PinMap::Button) == 0) { action = buttonHandler.HandleEvent(Controllers::ButtonHandler::Events::Release); } else { @@ -425,6 +426,16 @@ void SystemTask::Work() { case Messages::BatteryPercentageUpdated: nimbleController.NotifyBatteryLevel(batteryController.PercentRemaining()); break; + case Messages::LowBattery: { + Pinetime::Controllers::NotificationManager::Notification notif; + constexpr char message[] = "Low Battery\0Charge your watch to prevent data loss.\0"; + constexpr size_t messageSize = std::min(sizeof(message), Pinetime::Controllers::NotificationManager::MaximumMessageSize()); + std::memcpy(notif.message.data(), message, messageSize); + notif.size = messageSize; + notif.category = Pinetime::Controllers::NotificationManager::Categories::SimpleAlert; + notificationManager.Push(std::move(notif)); + PushMessage(Messages::OnNewNotification); + } break; case Messages::OnPairing: if (state == SystemTaskState::Sleeping) { GoToRunning(); @@ -459,7 +470,7 @@ void SystemTask::Work() { uint32_t systick_counter = nrf_rtc_counter_get(portNRF_RTC_REG); dateTimeController.UpdateTime(systick_counter); NoInit_BackUpTime = dateTimeController.CurrentDateTime(); - if (!nrf_gpio_pin_read(PinMap::Button)) { + if (nrf_gpio_pin_read(PinMap::Button) == 0) { watchdog.Kick(); } } @@ -552,10 +563,9 @@ void SystemTask::PushMessage(System::Messages msg) { } if (in_isr()) { - BaseType_t xHigherPriorityTaskWoken; - xHigherPriorityTaskWoken = pdFALSE; + BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(systemTasksMsgQueue, &msg, &xHigherPriorityTaskWoken); - if (xHigherPriorityTaskWoken) { + if (xHigherPriorityTaskWoken == pdTRUE) { /* Actual macro used here is port specific. */ portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index d1e4a004..9c43b9b2 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -36,6 +36,7 @@ #include "systemtask/Messages.h" extern std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds> NoInit_BackUpTime; + namespace Pinetime { namespace Drivers { class Cst816S; @@ -45,11 +46,13 @@ namespace Pinetime { class TwiMaster; class Hrs3300; } + namespace Controllers { class Battery; class TouchHandler; class ButtonHandler; } + namespace System { class SystemTask { public: diff --git a/src/touchhandler/TouchHandler.h b/src/touchhandler/TouchHandler.h index 332041e5..afce2844 100644 --- a/src/touchhandler/TouchHandler.h +++ b/src/touchhandler/TouchHandler.h @@ -6,9 +6,11 @@ namespace Pinetime { namespace Components { class LittleVgl; } + namespace Drivers { class Cst816S; } + namespace Controllers { class TouchHandler { public: @@ -20,12 +22,15 @@ namespace Pinetime { bool IsTouching() const { return info.touching; } + uint8_t GetX() const { return info.x; } + uint8_t GetY() const { return info.y; } + Pinetime::Applications::TouchEvents GestureGet(); private: diff --git a/tests/test-format.sh b/tests/test-format.sh index fd3201d0..693377b9 100755 --- a/tests/test-format.sh +++ b/tests/test-format.sh @@ -20,7 +20,7 @@ do *.cpp|*.h) echo Checking "$file" PATCH="$(basename "$file").patch" - git clang-format-12 -q --style file --diff "$GITHUB_BASE_REF" "$file" > "$PATCH" + git clang-format-14 -q --style file --diff "$GITHUB_BASE_REF" "$file" > "$PATCH" if [ -s "$PATCH" ] then printf "\033[31mError:\033[0m Formatting error in %s\n" "$file" diff --git a/tests/test-tidy.sh b/tests/test-tidy.sh index f1ee5fed..522f6e2a 100755 --- a/tests/test-tidy.sh +++ b/tests/test-tidy.sh @@ -17,7 +17,7 @@ do src/libs/*|src/FreeRTOS/*) continue ;; *.cpp|*.h) echo "::group::$file" - clang-tidy-12 -p build "$file" || true + clang-tidy-14 -p build "$file" || true echo "::endgroup::" esac done |
