diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..1dd68f24 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,65 @@ +FROM ubuntu:latest + +ARG DEBIAN_FRONTEND=noninteractive +RUN apt-get update -qq \ + && apt-get install -y \ +# x86_64 / generic packages + bash \ + build-essential \ + cmake \ + git \ + make \ + python3 \ + python3-pip \ + tar \ + unzip \ + wget \ + curl \ + dos2unix \ + clang-format-12 \ + clang-tidy \ + locales \ + libncurses5 \ +# aarch64 packages + libffi-dev \ + libssl-dev \ + python3-dev \ + rustc \ + && rm -rf /var/cache/apt/* /var/lib/apt/lists/*; + +#SET LOCALE +RUN locale-gen en_US.UTF-8 +ENV LANG en_US.UTF-8 +ENV LANGUAGE en_US:en +ENV LC_ALL en_US.UTF-8 + +RUN pip3 install adafruit-nrfutil +# required for McuBoot +RUN pip3 install setuptools_rust + +WORKDIR /opt/ +# build.sh knows how to compile but it problimatic on Win10 +COPY build.sh . +RUN chmod +x build.sh +# create_build_openocd.sh uses cmake to crate to build directory +COPY create_build_openocd.sh . +RUN chmod +x create_build_openocd.sh +# Lets get each in a separate docker layer for better downloads +# GCC +# RUN bash -c "source /opt/build.sh; GetGcc;" +RUN wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/gcc-arm-none-eabi-9-2020-q2-update-x86_64-linux.tar.bz2 -O - | tar -xj -C /opt +# NrfSdk +# RUN bash -c "source /opt/build.sh; GetNrfSdk;" +RUN wget -q "https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/nRF5_SDK_15.3.0_59ac345.zip" -O /tmp/nRF5_SDK_15.3.0_59ac345 +RUN unzip -q /tmp/nRF5_SDK_15.3.0_59ac345 -d /opt +RUN rm /tmp/nRF5_SDK_15.3.0_59ac345 +# McuBoot +# RUN bash -c "source /opt/build.sh; GetMcuBoot;" +RUN git clone https://github.com/JuulLabs-OSS/mcuboot.git +RUN pip3 install -r ./mcuboot/scripts/requirements.txt + +RUN adduser infinitime + +ENV NRF5_SDK_PATH /opt/nRF5_SDK_15.3.0_59ac345 +ENV ARM_NONE_EABI_TOOLCHAIN_PATH /opt/gcc-arm-none-eabi-9-2020-q2-update +ENV SOURCES_DIR /workspaces/InfiniTime diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 00000000..1932a9d4 --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,60 @@ +# VS Code Dev Container +This is a docker-based interactive development environment using VS Code and Docker Dev Containers removing the need to install any tools locally* + + + +## Requirements + +- VS Code + - [Remote - Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension +- Docker +- OpenOCD - For debugging + +## Using + +### Code editing, and building. + +1. Clone InfiniTime and update submodules +2. Launch VS Code +3. Open InfiniTime directory, +4. Allow VS Code to open folder with devcontainer. + +After this the environment will be built if you do not currently have a container setup, it will install all the necessary tools and extra VSCode extensions. + +In order to build InfiniTime we need to run the initial submodule init and CMake commands. + +#### Manually + + You can use the VS Code terminal to run the CMake commands as outlined in the [build instructions](blob/develop/doc/buildAndProgram.md) + +#### Script + +The dev environment comes with some scripts to make this easier, They are located in /opt/. + +There are also VS Code tasks provided should you desire to use those. + +The task "update submodules" will update the git submodules + + + +### Build + +You can use the build.sh script located in /opt/ + +CMake is also configured and controls for the CMake plugin are available in VS Code + + + +### Debugging + +Docker on windows does not support passing USB devices to the underlying WSL2 subsystem, To get around this we use OpenOCD in server mode running on the host. + +`openocd -f -f ` + +This will launch OpenOCD in server mode and attach it to the MCU. + +The default launch.json file expects OpenOCD to be listening on port 3333, edit if needed + + +## Current Issues +Currently WSL2 Has some real performance issues with IO on a windows host. Accessing files on the virtualized filesystem is much faster. Using VS Codes "clone in container" feature of the Remote - Containers will get around this. After the container is built you will need to update the submodules and follow the build instructions like normal \ No newline at end of file diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh new file mode 100644 index 00000000..8f0d0fa9 --- /dev/null +++ b/.devcontainer/build.sh @@ -0,0 +1,78 @@ +#!/bin/bash +(return 0 2>/dev/null) && SOURCED="true" || SOURCED="false" +export LC_ALL=C.UTF-8 +export LANG=C.UTF-8 +set -x +set -e + +# Default locations if the var isn't already set +export TOOLS_DIR="${TOOLS_DIR:=/opt}" +export SOURCES_DIR="${SOURCES_DIR:=/sources}" +export BUILD_DIR="${BUILD_DIR:=$SOURCES_DIR/build}" +export OUTPUT_DIR="${OUTPUT_DIR:=$BUILD_DIR/output}" + +export BUILD_TYPE=${BUILD_TYPE:=Release} +export GCC_ARM_VER=${GCC_ARM_VER:="gcc-arm-none-eabi-9-2020-q2-update"} +export NRF_SDK_VER=${NRF_SDK_VER:="nRF5_SDK_15.3.0_59ac345"} + +MACHINE="$(uname -m)" +[[ "$MACHINE" == "arm64" ]] && MACHINE="aarch64" + +main() { + local target="$1" + + mkdir -p "$TOOLS_DIR" + + [[ ! -d "$TOOLS_DIR/$GCC_ARM_VER" ]] && GetGcc + [[ ! -d "$TOOLS_DIR/$NRF_SDK_VER" ]] && GetNrfSdk + [[ ! -d "$TOOLS_DIR/mcuboot" ]] && GetMcuBoot + + mkdir -p "$BUILD_DIR" + + CmakeGenerate + CmakeBuild $target + BUILD_RESULT=$? + if [ "$DISABLE_POSTBUILD" != "true" -a "$BUILD_RESULT" == 0 ]; then + source "$BUILD_DIR/post_build.sh" + fi +} + +GetGcc() { + GCC_SRC="$GCC_ARM_VER-$MACHINE-linux.tar.bz" + wget -q https://developer.arm.com/-/media/Files/downloads/gnu-rm/9-2020q2/$GCC_SRC -O - | tar -xj -C $TOOLS_DIR/ +} + +GetMcuBoot() { + git clone https://github.com/JuulLabs-OSS/mcuboot.git "$TOOLS_DIR/mcuboot" + pip3 install -r "$TOOLS_DIR/mcuboot/scripts/requirements.txt" +} + +GetNrfSdk() { + wget -q "https://developer.nordicsemi.com/nRF5_SDK/nRF5_SDK_v15.x.x/$NRF_SDK_VER.zip" -O /tmp/$NRF_SDK_VER + unzip -q /tmp/$NRF_SDK_VER -d "$TOOLS_DIR/" + rm /tmp/$NRF_SDK_VER +} + +CmakeGenerate() { + # We can swap the CD and trailing SOURCES_DIR for -B and -S respectively + # once we go to newer CMake (Ubuntu 18.10 gives us CMake 3.10) + cd "$BUILD_DIR" + + cmake -G "Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ + -DUSE_OPENOCD=1 \ + -DARM_NONE_EABI_TOOLCHAIN_PATH="$TOOLS_DIR/$GCC_ARM_VER" \ + -DNRF5_SDK_PATH="$TOOLS_DIR/$NRF_SDK_VER" \ + "$SOURCES_DIR" + cmake -L -N . +} + +CmakeBuild() { + local target="$1" + [[ -n "$target" ]] && target="--target $target" + if cmake --build "$BUILD_DIR" --config $BUILD_TYPE $target -- -j$(nproc) + then return 0; else return 1; + fi +} + +[[ $SOURCED == "false" ]] && main "$@" || echo "Sourced!" \ No newline at end of file diff --git a/.devcontainer/build_app.sh b/.devcontainer/build_app.sh new file mode 100644 index 00000000..0f578cc6 --- /dev/null +++ b/.devcontainer/build_app.sh @@ -0,0 +1,2 @@ +#!/bin/bash +cmake --build /workspaces/Pinetime/build --config Release -- -j6 pinetime-app \ No newline at end of file diff --git a/.devcontainer/create_build_openocd.sh b/.devcontainer/create_build_openocd.sh new file mode 100644 index 00000000..c5bff5c8 --- /dev/null +++ b/.devcontainer/create_build_openocd.sh @@ -0,0 +1,3 @@ +#!/bin/bash +rm -rf build/ +cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Release -DUSE_OPENOCD=1 -DARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-9-2020-q2-update -DNRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345 -S . -Bbuild \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..778fe9cb --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,36 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.154.2/containers/cpp +{ + // "name": "Pinetime", + // "image": "feabhas/pinetime-dev" + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Debian / Ubuntu OS version: debian-10, debian-9, ubuntu-20.04, ubuntu-18.04 + // "args": { "VARIANT": "ubuntu-20.04" } + }, + "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined"], + + // Set *default* container specific settings.json values on container create. + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-vscode.cpptools", + "ms-vscode.cmake-tools", + "marus25.cortex-debug", + "notskm.clang-tidy", + "mjohns.clang-format" + ], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "bash /opt/create_build_openocd.sh", + + // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "vscode" + "remoteUser": "infinitime" +} \ No newline at end of file diff --git a/.devcontainer/make_build_dir.sh b/.devcontainer/make_build_dir.sh new file mode 100644 index 00000000..76240037 --- /dev/null +++ b/.devcontainer/make_build_dir.sh @@ -0,0 +1,2 @@ +#!/bin/bash +cmake -G 'Unix Makefiles' -DCMAKE_BUILD_TYPE=Release -DUSE_OPENOCD=1 -DARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-9-2020-q2-update -DNRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345 ${SOURCES_DIR} diff --git a/.gitignore b/.gitignore index 2f9ac181..6de76a9e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ # CMake cmake-build-* -cmake-* +cmake-*/ CMakeFiles **/CMakeCache.txt cmake_install.cmake diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..f8da48d5 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,20 @@ +{ + "configurations": [ + { + "name": "nrfCC", + "includePath": [ + "${workspaceFolder}/**", + "${workspaceFolder}/src/**", + "${workspaceFolder}/src" + ], + "defines": [], + "compilerPath": "${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin/arm-none-eabi-gcc", + "cStandard": "c11", + "cppStandard": "c++14", + "intelliSenseMode": "linux-gcc-arm", + "configurationProvider": "ms-vscode.cpp-tools", + "compileCommands": "${workspaceFolder}/build/compile_commands.json" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/cmake-variants.json b/.vscode/cmake-variants.json new file mode 100644 index 00000000..9c95a631 --- /dev/null +++ b/.vscode/cmake-variants.json @@ -0,0 +1,62 @@ +{ + "buildType": { + "default": "release", + "choices": { + "debug": { + "short": "Debug", + "long": "Emit debug information without performing optimizations", + "buildType": "Debug" + }, + "release": { + "short": "Release", + "long": "Perform optimizations", + "buildType": "Release" + } + } + }, + "programmer":{ + "default": "OpenOCD", + "choices":{ + "OpenOCD":{ + "short":"OpenOCD", + "long": "Use OpenOCD", + "settings":{ + "USE_OPENOCD":1 + } + }, + "JLink":{ + "short":"JLink", + "long": "Use JLink", + "settings":{ + "USE_JLINK":1 + } + }, + "GDB":{ + "short":"GDB", + "long": "Use GDB", + "settings":{ + "USE_GDB_CLIENT":1 + } + } + } + }, + "DFU": { + "default": "no", + "choices": { + "no": { + "short": "No DFU", + "long": "Do not build DFU", + "settings": { + "BUILD_DFU":"0" + } + }, + "yes": { + "short": "Build DFU", + "long": "Build DFU", + "settings": { + "BUILD_DFU":"1" + } + } + } + } +} \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..1cc05268 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["ms-vscode.cpptools","ms-vscode.cmake-tools","marus25.cortex-debug"] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..7cf3acd1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,46 @@ + { + "version": "0.1.0", + "configurations": [ + { + "name": "Debug - Openocd docker Remote", + "type":"cortex-debug", + "cortex-debug.armToolchainPath":"${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin", + "cwd": "${workspaceRoot}", + "executable": "${command:cmake.launchTargetPath}", + "request": "launch", + "servertype": "external", + // This may need to be arm-none-eabi-gdb depending on your system + "gdbPath" : "${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin/arm-none-eabi-gdb", + // Connect to an already running OpenOCD instance + "gdbTarget": "host.docker.internal:3333", + "svdFile": "${workspaceRoot}/nrf52.svd", + "runToMain": true, + // Work around for stopping at main on restart + "postRestartCommands": [ + "break main", + "continue" + ] + }, + { + "name": "Debug - Openocd Local", + "type":"cortex-debug", + "cortex-debug.armToolchainPath":"${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin", + "cwd": "${workspaceRoot}", + "executable": "${command:cmake.launchTargetPath}", + "request": "launch", + "servertype": "openocd", + // This may need to be arm-none-eabi-gdb depending on your system + "gdbPath" : "${env:ARM_NONE_EABI_TOOLCHAIN_PATH}/bin/arm-none-eabi-gdb", + // Connect to an already running OpenOCD instance + "gdbTarget": "localhost:3333", + "svdFile": "${workspaceRoot}/nrf52.svd", + "runToMain": true, + // Work around for stopping at main on restart + "postRestartCommands": [ + "break main", + "continue" + ] + } + + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 05b11756..8f0e63f4 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,59 +1,9 @@ { - "files.associations": { - "chrono": "cpp", - "list": "cpp", - "array": "cpp", - "atomic": "cpp", - "bit": "cpp", - "*.tcc": "cpp", - "cctype": "cpp", - "charconv": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "condition_variable": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "deque": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "functional": "cpp", - "iterator": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "netfwd": "cpp", - "numeric": "cpp", - "optional": "cpp", - "random": "cpp", - "ratio": "cpp", - "string": "cpp", - "string_view": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "utility": "cpp", - "fstream": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "thread": "cpp", - "cinttypes": "cpp", - "typeinfo": "cpp" - } -} \ No newline at end of file + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", + "cmake.configureArgs": [ + "-DARM_NONE_EABI_TOOLCHAIN_PATH=${env:ARM_NONE_EABI_TOOLCHAIN_PATH}", + "-DNRF5_SDK_PATH=${env:NRF5_SDK_PATH}", + ], + "cmake.generator": "Unix Makefiles", + "clang-tidy.buildPath": "build/compile_commands.json" +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..17f51f5e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,44 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "create openocd build", + "type": "shell", + "command": "/opt/create_build_openocd.sh", + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "update submodules", + "type": "shell", + "command": "git submodule update --init", + "options": { + "cwd": "${workspaceFolder}" + }, + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + }, + { + "label": "BuildInit", + "dependsOn": [ + "update submodules", + "create openocd build" + ], + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index d9de4002..6549ece9 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ As of now, here is the list of achievements of this project: - [Build the project](doc/buildAndProgram.md) - [Flash the firmware using OpenOCD and STLinkV2](doc/openOCD.md) - [Build the project with Docker](doc/buildWithDocker.md) + - [Build the project with VSCode](doc/buildWithVScode.md) - [Bootloader, OTA and DFU](./bootloader/README.md) - [Stub using NRF52-DK](./doc/PinetimeStubWithNrf52DK.md) - Logging with JLink RTT. diff --git a/doc/buildWithVScode.md b/doc/buildWithVScode.md new file mode 100644 index 00000000..c1df17b7 --- /dev/null +++ b/doc/buildWithVScode.md @@ -0,0 +1,42 @@ +# Build and Develop the project using VS Code + +The .VS Code folder contains configuration files for developing InfiniTime with VS Code. Effort was made to have these rely on Environment variables instead of hardcoded paths. + +## Environment Setup + +To support as many setups as possible the VS Code configuration files expect there to be certain environment variables to be set. + + Variable | Description | Example +----------|-------------|-------- +**ARM_NONE_EABI_TOOLCHAIN_PATH**|path to the toolchain directory|`export ARM_NONE_EABI_TOOLCHAIN_PATH=/opt/gcc-arm-none-eabi-9-2020-q2-update` +**NRF5_SDK_PATH**|path to the NRF52 SDK|`export NRF5_SDK_PATH=/opt/nRF5_SDK_15.3.0_59ac345` + +## VS Code Extensions + +We leverage a few VS Code extensions for ease of development. + +#### Required Extensions + +- [C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) - C/C++ IntelliSense, debugging, and code browsing. +- [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) - Extended CMake support in Visual Studio Code + +#### Optional Extensions + +[Cortex-Debug](https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug) - ARM Cortex-M GDB Debugger support for VS Code + +Cortex-Debug is only required for interactive debugging using VS Codes built in GDB support. + + + +## VS Code/Docker DevContainer + +The .devcontainer folder contains the configuration and scripts for using a Docker dev container for building InfiniTime + +Using the [Remote-Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension is recommended. It will handle configuring the Docker virtual machine and setting everything up. + +More documentation is available in the [readme in .devcontainer](.devcontainer/readme.md) + + + + + diff --git a/src/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index fa476ea3..f8a64ecd 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -23,7 +23,6 @@ void Battery::Update() { return; } // Non blocking read - samples = 0; isReading = true; SaadcInit(); @@ -40,9 +39,9 @@ void Battery::SaadcInit() { nrf_saadc_channel_config_t adcChannelConfig = {.resistor_p = NRF_SAADC_RESISTOR_DISABLED, .resistor_n = NRF_SAADC_RESISTOR_DISABLED, - .gain = NRF_SAADC_GAIN1_5, + .gain = NRF_SAADC_GAIN1_4, .reference = NRF_SAADC_REFERENCE_INTERNAL, - .acq_time = NRF_SAADC_ACQTIME_3US, + .acq_time = NRF_SAADC_ACQTIME_40US, .mode = NRF_SAADC_MODE_SINGLE_ENDED, .burst = NRF_SAADC_BURST_ENABLED, .pin_p = batteryVoltageAdcInput, @@ -60,22 +59,21 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const* p_event) { APP_ERROR_CHECK(nrfx_saadc_buffer_convert(&saadc_value, 1)); // A hardware voltage divider divides the battery voltage by 2 - // ADC gain is 1/5 - // thus adc_voltage = battery_voltage / 2 * gain = battery_voltage / 10 - // reference_voltage is 0.6V + // ADC gain is 1/4 + // thus adc_voltage = battery_voltage / 2 * gain = battery_voltage / 8 + // reference_voltage is 600mV // p_event->data.done.p_buffer[0] = (adc_voltage / reference_voltage) * 1024 - voltage = p_event->data.done.p_buffer[0] * 6000 / 1024; - percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min); - percentRemaining = std::max(percentRemaining, 0); - percentRemaining = std::min(percentRemaining, 100); - percentRemainingBuffer.Insert(percentRemaining); + voltage = p_event->data.done.p_buffer[0] * (8 * 600) / 1024; - samples++; - if (samples > percentRemainingSamples) { - nrfx_saadc_uninit(); - isReading = false; + if (voltage > battery_max) { + percentRemaining = 100; + } else if (voltage < battery_min) { + percentRemaining = 0; } else { - nrfx_saadc_sample(); + percentRemaining = (voltage - battery_min) * 100 / (battery_max - battery_min); } + + nrfx_saadc_uninit(); + isReading = false; } } diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 1333ad0e..6f09b737 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -7,38 +7,6 @@ namespace Pinetime { namespace Controllers { - /** A simple circular buffer that can be used to average - out the sensor values. The total capacity of the CircBuffer - is given as the template parameter N. - */ - template class CircBuffer { - public: - CircBuffer() : arr {}, sz {}, cap {N}, head {} { - } - /** - insert member function overwrites the next data to the current - HEAD and moves the HEAD to the newly inserted value. - */ - void Insert(const uint8_t num) { - head %= cap; - arr[head++] = num; - if (sz != cap) { - sz++; - } - } - - uint8_t GetAverage() const { - int sum = std::accumulate(arr.begin(), arr.end(), 0); - return static_cast(sum / sz); - } - - private: - std::array arr; /**< internal array used to store the values*/ - uint8_t sz; /**< The current size of the array.*/ - uint8_t cap; /**< Total capacity of the CircBuffer.*/ - uint8_t head; /**< The current head of the CircBuffer*/ - }; - class Battery { public: Battery(); @@ -47,10 +15,7 @@ namespace Pinetime { void Update(); uint8_t PercentRemaining() const { - auto avg = percentRemainingBuffer.GetAverage(); - avg = std::min(avg, static_cast(100)); - avg = std::max(avg, static_cast(0)); - return avg; + return percentRemaining; } uint16_t Voltage() const { @@ -69,14 +34,11 @@ namespace Pinetime { static Battery* instance; nrf_saadc_value_t saadc_value; - static constexpr uint8_t percentRemainingSamples = 5; - CircBuffer percentRemainingBuffer {}; - static constexpr uint32_t chargingPin = 12; static constexpr uint32_t powerPresentPin = 19; static constexpr nrf_saadc_input_t batteryVoltageAdcInput = NRF_SAADC_INPUT_AIN7; uint16_t voltage = 0; - int percentRemaining = -1; + uint8_t percentRemaining = 0; bool isCharging = false; bool isPowerPresent = false; @@ -87,7 +49,6 @@ namespace Pinetime { static void AdcCallbackStatic(nrfx_saadc_evt_t const* event); bool isReading = false; - uint8_t samples = 0; }; } } diff --git a/src/components/datetime/DateTimeController.cpp b/src/components/datetime/DateTimeController.cpp index 28a70abc..d6aa83c8 100644 --- a/src/components/datetime/DateTimeController.cpp +++ b/src/components/datetime/DateTimeController.cpp @@ -55,9 +55,9 @@ void DateTime::UpdateTime(uint32_t systickCounter) { auto time = date::make_time(currentDateTime - dp); auto yearMonthDay = date::year_month_day(dp); - year = (int) yearMonthDay.year(); - month = static_cast((unsigned) yearMonthDay.month()); - day = (unsigned) yearMonthDay.day(); + year = static_cast(yearMonthDay.year()); + month = static_cast(static_cast(yearMonthDay.month())); + day = static_cast(yearMonthDay.day()); dayOfWeek = static_cast(date::weekday(yearMonthDay).iso_encoding()); hour = time.hours().count(); @@ -75,31 +75,31 @@ void DateTime::UpdateTime(uint32_t systickCounter) { } const char* DateTime::MonthShortToString() { - return DateTime::MonthsString[(uint8_t) month]; + return DateTime::MonthsString[static_cast(month)]; } const char* DateTime::MonthShortToStringLow() { - return DateTime::MonthsStringLow[(uint8_t) month]; + return DateTime::MonthsStringLow[static_cast(month)]; } const char* DateTime::MonthsToStringLow() { - return DateTime::MonthsLow[(uint8_t) month]; + return DateTime::MonthsLow[static_cast(month)]; } const char* DateTime::DayOfWeekToString() { - return DateTime::DaysString[(uint8_t) dayOfWeek]; + return DateTime::DaysString[static_cast(dayOfWeek)]; } const char* DateTime::DayOfWeekShortToString() { - return DateTime::DaysStringShort[(uint8_t) dayOfWeek]; + return DateTime::DaysStringShort[static_cast(dayOfWeek)]; } const char* DateTime::DayOfWeekToStringLow() { - return DateTime::DaysStringLow[(uint8_t) dayOfWeek]; + return DateTime::DaysStringLow[static_cast(dayOfWeek)]; } const char* DateTime::DayOfWeekShortToStringLow() { - return DateTime::DaysStringShortLow[(uint8_t) dayOfWeek]; + return DateTime::DaysStringShortLow[static_cast(dayOfWeek)]; } void DateTime::Register(Pinetime::System::SystemTask* systemTask) { diff --git a/src/displayapp/screens/BatteryIcon.cpp b/src/displayapp/screens/BatteryIcon.cpp index bb6626a5..c67bcb23 100644 --- a/src/displayapp/screens/BatteryIcon.cpp +++ b/src/displayapp/screens/BatteryIcon.cpp @@ -5,13 +5,13 @@ using namespace Pinetime::Applications::Screens; const char* BatteryIcon::GetBatteryIcon(uint8_t batteryPercent) { - if (batteryPercent > 90) + if (batteryPercent > 87) return Symbols::batteryFull; - if (batteryPercent > 75) + if (batteryPercent > 62) return Symbols::batteryThreeQuarter; - if (batteryPercent > 50) + if (batteryPercent > 37) return Symbols::batteryHalf; - if (batteryPercent > 25) + if (batteryPercent > 12) return Symbols::batteryOneQuarter; return Symbols::batteryEmpty; } diff --git a/src/displayapp/screens/Clock.cpp b/src/displayapp/screens/Clock.cpp index e0684976..86afee0c 100644 --- a/src/displayapp/screens/Clock.cpp +++ b/src/displayapp/screens/Clock.cpp @@ -2,11 +2,6 @@ #include #include -#include -#include "BatteryIcon.h" -#include "BleIcon.h" -#include "NotificationIcon.h" -#include "Symbols.h" #include "components/battery/BatteryController.h" #include "components/motion/MotionController.h" #include "components/ble/BleController.h" @@ -88,17 +83,4 @@ std::unique_ptr Clock::PineTimeStyleScreen() { notificatioManager, settingsController, motionController); -} - -/* -// Examples for more watch faces -std::unique_ptr Clock::WatchFaceMinimalScreen() { - return std::make_unique(app, dateTimeController, batteryController, bleController, notificatioManager, -settingsController); -} - -std::unique_ptr Clock::WatchFaceCustomScreen() { - return std::make_unique(app, dateTimeController, batteryController, bleController, notificatioManager, -settingsController); -} -*/ \ No newline at end of file +} \ No newline at end of file diff --git a/src/displayapp/screens/Clock.h b/src/displayapp/screens/Clock.h index a48feea1..7968cced 100644 --- a/src/displayapp/screens/Clock.h +++ b/src/displayapp/screens/Clock.h @@ -9,9 +9,6 @@ #include "components/datetime/DateTimeController.h" namespace Pinetime { - namespace Drivers { - class BMA421; - } namespace Controllers { class Settings; class Battery; @@ -51,10 +48,6 @@ namespace Pinetime { std::unique_ptr WatchFaceDigitalScreen(); std::unique_ptr WatchFaceAnalogScreen(); std::unique_ptr PineTimeStyleScreen(); - - // Examples for more watch faces - // std::unique_ptr WatchFaceMinimalScreen(); - // std::unique_ptr WatchFaceCustomScreen(); }; } } diff --git a/src/displayapp/screens/PineTimeStyle.cpp b/src/displayapp/screens/PineTimeStyle.cpp index 337ceba9..04128b21 100644 --- a/src/displayapp/screens/PineTimeStyle.cpp +++ b/src/displayapp/screens/PineTimeStyle.cpp @@ -218,26 +218,17 @@ bool PineTimeStyle::Refresh() { bleState = bleController.IsConnected(); if (bleState.IsUpdated()) { - if (bleState.Get() == true) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(true)); - lv_obj_realign(bleIcon); - } else { - lv_label_set_text(bleIcon, BleIcon::GetIcon(false)); - } + lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); + lv_obj_realign(bleIcon); } notificationState = notificatioManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { - if (notificationState.Get() == true) { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true)); - lv_obj_realign(notificationIcon); - } else { - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); - } + lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); + lv_obj_realign(notificationIcon); } currentDateTime = dateTimeController.CurrentDateTime(); - if (currentDateTime.IsUpdated()) { auto newDateTime = currentDateTime.Get(); @@ -245,9 +236,9 @@ bool PineTimeStyle::Refresh() { auto time = date::make_time(newDateTime - dp); auto yearMonthDay = date::year_month_day(dp); - auto year = (int) yearMonthDay.year(); - auto month = static_cast((unsigned) yearMonthDay.month()); - auto day = (unsigned) yearMonthDay.day(); + auto year = static_cast(yearMonthDay.year()); + auto month = static_cast(static_cast(yearMonthDay.month())); + auto day = static_cast(yearMonthDay.day()); auto dayOfWeek = static_cast(date::weekday(yearMonthDay).iso_encoding()); int hour = time.hours().count(); @@ -258,9 +249,8 @@ bool PineTimeStyle::Refresh() { char hoursChar[3]; char ampmChar[5]; - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - sprintf(hoursChar, "%02d", hour); + sprintf(hoursChar, "%02d", hour); } else { if (hour == 0 && hour != 12) { hour = 12; @@ -277,41 +267,26 @@ bool PineTimeStyle::Refresh() { sprintf(hoursChar, "%02d", hour); } - if (hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] || + if (hoursChar[0] != displayedChar[0] or hoursChar[1] != displayedChar[1] or minutesChar[0] != displayedChar[2] or minutesChar[1] != displayedChar[3]) { displayedChar[0] = hoursChar[0]; displayedChar[1] = hoursChar[1]; displayedChar[2] = minutesChar[0]; displayedChar[3] = minutesChar[1]; - char hourStr[3]; - char minStr[3]; - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { lv_label_set_text(timeAMPM, ampmChar); } - // Display the time as 2 pairs of digits - sprintf(hourStr, "%c%c", hoursChar[0], hoursChar[1]); - lv_label_set_text(timeDD1, hourStr); - - sprintf(minStr, "%c%c", minutesChar[0], minutesChar[1]); - lv_label_set_text(timeDD2, minStr); + lv_label_set_text_fmt(timeDD1, "%s", hoursChar); + lv_label_set_text_fmt(timeDD2, "%s", minutesChar); } if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { - char dayOfWeekStr[4]; - char dayStr[3]; - char monthStr[4]; - - sprintf(dayOfWeekStr, "%s", dateTimeController.DayOfWeekShortToString()); - sprintf(dayStr, "%d", day); - sprintf(monthStr, "%s", dateTimeController.MonthShortToString()); - - lv_label_set_text(dateDayOfWeek, dayOfWeekStr); - lv_label_set_text(dateDay, dayStr); + lv_label_set_text_fmt(dateDayOfWeek, "%s", dateTimeController.DayOfWeekShortToString()); + lv_label_set_text_fmt(dateDay, "%d", day); lv_obj_realign(dateDay); - lv_label_set_text(dateMonth, monthStr); + lv_label_set_text_fmt(dateMonth, "%s", dateTimeController.MonthShortToString()); currentYear = year; currentMonth = month; diff --git a/src/displayapp/screens/PineTimeStyle.h b/src/displayapp/screens/PineTimeStyle.h index 71b8b654..948f9929 100644 --- a/src/displayapp/screens/PineTimeStyle.h +++ b/src/displayapp/screens/PineTimeStyle.h @@ -32,8 +32,6 @@ namespace Pinetime { bool Refresh() override; - void OnObjectEvent(lv_obj_t* pObj, lv_event_t i); - private: char displayedChar[5]; @@ -67,9 +65,6 @@ namespace Pinetime { lv_obj_t* calendarBar2; lv_obj_t* calendarCrossBar1; lv_obj_t* calendarCrossBar2; - lv_obj_t* heartbeatIcon; - lv_obj_t* heartbeatValue; - lv_obj_t* heartbeatBpm; lv_obj_t* notificationIcon; lv_obj_t* stepGauge; lv_color_t needle_colors[1]; diff --git a/src/displayapp/screens/WatchFaceAnalog.cpp b/src/displayapp/screens/WatchFaceAnalog.cpp index f1889379..621929b8 100644 --- a/src/displayapp/screens/WatchFaceAnalog.cpp +++ b/src/displayapp/screens/WatchFaceAnalog.cpp @@ -10,38 +10,37 @@ LV_IMG_DECLARE(bg_clock); using namespace Pinetime::Applications::Screens; namespace { - -constexpr auto HOUR_LENGTH = 70; -constexpr auto MINUTE_LENGTH = 90; -constexpr auto SECOND_LENGTH = 110; +constexpr int16_t HourLength = 70; +constexpr int16_t MinuteLength = 90; +constexpr int16_t SecondLength = 110; // sin(90) = 1 so the value of _lv_trigo_sin(90) is the scaling factor const auto LV_TRIG_SCALE = _lv_trigo_sin(90); -int16_t cosine(int16_t angle) { +int16_t Cosine(int16_t angle) { return _lv_trigo_sin(angle + 90); } -int16_t sine(int16_t angle) { +int16_t Sine(int16_t angle) { return _lv_trigo_sin(angle); } -int16_t coordinate_x_relocate(int16_t x) { +int16_t CoordinateXRelocate(int16_t x) { return (x + LV_HOR_RES / 2); } -int16_t coordinate_y_relocate(int16_t y) { +int16_t CoordinateYRelocate(int16_t y) { return std::abs(y - LV_HOR_RES / 2); } -lv_point_t coordinate_relocate(int16_t radius, int16_t angle) { +lv_point_t CoordinateRelocate(int16_t radius, int16_t angle) { return lv_point_t{ - .x = coordinate_x_relocate(radius * static_cast(sine(angle)) / LV_TRIG_SCALE), - .y = coordinate_y_relocate(radius * static_cast(cosine(angle)) / LV_TRIG_SCALE) + .x = CoordinateXRelocate(radius * static_cast(Sine(angle)) / LV_TRIG_SCALE), + .y = CoordinateYRelocate(radius * static_cast(Cosine(angle)) / LV_TRIG_SCALE) }; } -} // namespace +} WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, Controllers::DateTime& dateTimeController, @@ -123,7 +122,6 @@ WatchFaceAnalog::WatchFaceAnalog(Pinetime::Applications::DisplayApp* app, } WatchFaceAnalog::~WatchFaceAnalog() { - lv_style_reset(&hour_line_style); lv_style_reset(&hour_line_style_trace); lv_style_reset(&minute_line_style); @@ -134,18 +132,17 @@ WatchFaceAnalog::~WatchFaceAnalog() { } void WatchFaceAnalog::UpdateClock() { - hour = dateTimeController.Hours(); minute = dateTimeController.Minutes(); second = dateTimeController.Seconds(); if (sMinute != minute) { auto const angle = minute * 6; - minute_point[0] = coordinate_relocate(30, angle); - minute_point[1] = coordinate_relocate(MINUTE_LENGTH, angle); + minute_point[0] = CoordinateRelocate(30, angle); + minute_point[1] = CoordinateRelocate(MinuteLength, angle); - minute_point_trace[0] = coordinate_relocate(5, angle); - minute_point_trace[1] = coordinate_relocate(31, angle); + minute_point_trace[0] = CoordinateRelocate(5, angle); + minute_point_trace[1] = CoordinateRelocate(31, angle); lv_line_set_points(minute_body, minute_point, 2); lv_line_set_points(minute_body_trace, minute_point_trace, 2); @@ -156,11 +153,11 @@ void WatchFaceAnalog::UpdateClock() { sMinute = minute; auto const angle = (hour * 30 + minute / 2); - hour_point[0] = coordinate_relocate(30, angle); - hour_point[1] = coordinate_relocate(HOUR_LENGTH, angle); + hour_point[0] = CoordinateRelocate(30, angle); + hour_point[1] = CoordinateRelocate(HourLength, angle); - hour_point_trace[0] = coordinate_relocate(5, angle); - hour_point_trace[1] = coordinate_relocate(31, angle); + hour_point_trace[0] = CoordinateRelocate(5, angle); + hour_point_trace[1] = CoordinateRelocate(31, angle); lv_line_set_points(hour_body, hour_point, 2); lv_line_set_points(hour_body_trace, hour_point_trace, 2); @@ -170,8 +167,8 @@ void WatchFaceAnalog::UpdateClock() { sSecond = second; auto const angle = second * 6; - second_point[0] = coordinate_relocate(-20, angle); - second_point[1] = coordinate_relocate(SECOND_LENGTH, angle); + second_point[0] = CoordinateRelocate(-20, angle); + second_point[1] = CoordinateRelocate(SecondLength, angle); lv_line_set_points(second_body, second_point, 2); } } @@ -186,16 +183,12 @@ bool WatchFaceAnalog::Refresh() { notificationState = notificationManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { - if (notificationState.Get() == true) - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true)); - else - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); + lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); } currentDateTime = dateTimeController.CurrentDateTime(); if (currentDateTime.IsUpdated()) { - month = dateTimeController.Month(); day = dateTimeController.Day(); dayOfWeek = dateTimeController.DayOfWeek(); @@ -203,7 +196,6 @@ bool WatchFaceAnalog::Refresh() { UpdateClock(); if ((month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { - lv_label_set_text_fmt(label_date_day, "%s\n%02i", dateTimeController.DayOfWeekShortToString(), day); currentMonth = month; diff --git a/src/displayapp/screens/WatchFaceAnalog.h b/src/displayapp/screens/WatchFaceAnalog.h index ac7f0ac5..5d8c6a24 100644 --- a/src/displayapp/screens/WatchFaceAnalog.h +++ b/src/displayapp/screens/WatchFaceAnalog.h @@ -58,14 +58,12 @@ namespace Pinetime { lv_obj_t* minute_body_trace; lv_obj_t* second_body; - // ## lv_point_t hour_point[2]; lv_point_t hour_point_trace[2]; lv_point_t minute_point[2]; lv_point_t minute_point_trace[2]; lv_point_t second_point[2]; - // ## lv_style_t hour_line_style; lv_style_t hour_line_style_trace; lv_style_t minute_line_style; diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index f1285eaf..7a240f1f 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -12,9 +12,6 @@ #include "components/ble/NotificationManager.h" #include "components/heartrate/HeartRateController.h" #include "components/motion/MotionController.h" -#include "components/settings/Settings.h" -#include "../DisplayApp.h" - using namespace Pinetime::Applications::Screens; WatchFaceDigital::WatchFaceDigital(DisplayApp* app, @@ -36,12 +33,6 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app, motionController {motionController} { settingsController.SetClockFace(0); - displayedChar[0] = 0; - displayedChar[1] = 0; - displayedChar[2] = 0; - displayedChar[3] = 0; - displayedChar[4] = 0; - batteryIcon = lv_label_create(lv_scr_act(), nullptr); lv_label_set_text(batteryIcon, Symbols::batteryFull); lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 2); @@ -56,7 +47,7 @@ WatchFaceDigital::WatchFaceDigital(DisplayApp* app, lv_label_set_text(bleIcon, Symbols::bluetooth); lv_obj_align(bleIcon, batteryPlug, LV_ALIGN_OUT_LEFT_MID, -5, 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_hex(0x00FF00)); lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); lv_obj_align(notificationIcon, nullptr, LV_ALIGN_IN_TOP_LEFT, 10, 0); @@ -111,17 +102,13 @@ bool WatchFaceDigital::Refresh() { if (batteryPercentRemaining.IsUpdated()) { auto batteryPercent = batteryPercentRemaining.Get(); lv_label_set_text(batteryIcon, BatteryIcon::GetBatteryIcon(batteryPercent)); - auto isCharging = batteryController.IsCharging() || batteryController.IsPowerPresent(); + auto isCharging = batteryController.IsCharging() or batteryController.IsPowerPresent(); lv_label_set_text(batteryPlug, BatteryIcon::GetPlugIcon(isCharging)); } bleState = bleController.IsConnected(); if (bleState.IsUpdated()) { - if (bleState.Get() == true) { - lv_label_set_text(bleIcon, BleIcon::GetIcon(true)); - } else { - lv_label_set_text(bleIcon, BleIcon::GetIcon(false)); - } + lv_label_set_text(bleIcon, BleIcon::GetIcon(bleState.Get())); } lv_obj_align(batteryIcon, lv_scr_act(), LV_ALIGN_IN_TOP_RIGHT, -5, 5); lv_obj_align(batteryPlug, batteryIcon, LV_ALIGN_OUT_LEFT_MID, -5, 0); @@ -129,10 +116,7 @@ bool WatchFaceDigital::Refresh() { notificationState = notificatioManager.AreNewNotificationsAvailable(); if (notificationState.IsUpdated()) { - if (notificationState.Get() == true) - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(true)); - else - lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(false)); + lv_label_set_text(notificationIcon, NotificationIcon::GetIcon(notificationState.Get())); } currentDateTime = dateTimeController.CurrentDateTime(); @@ -144,9 +128,9 @@ bool WatchFaceDigital::Refresh() { auto time = date::make_time(newDateTime - dp); auto yearMonthDay = date::year_month_day(dp); - auto year = (int) yearMonthDay.year(); - auto month = static_cast((unsigned) yearMonthDay.month()); - auto day = (unsigned) yearMonthDay.day(); + auto year = static_cast(yearMonthDay.year()); + auto month = static_cast(static_cast(yearMonthDay.month())); + auto day = static_cast(yearMonthDay.day()); auto dayOfWeek = static_cast(date::weekday(yearMonthDay).iso_encoding()); int hour = time.hours().count(); @@ -175,15 +159,13 @@ bool WatchFaceDigital::Refresh() { sprintf(hoursChar, "%02d", hour); } - if (hoursChar[0] != displayedChar[0] || hoursChar[1] != displayedChar[1] || minutesChar[0] != displayedChar[2] || - minutesChar[1] != displayedChar[3]) { + if ((hoursChar[0] != displayedChar[0]) or (hoursChar[1] != displayedChar[1]) or (minutesChar[0] != displayedChar[2]) or + (minutesChar[1] != displayedChar[3])) { displayedChar[0] = hoursChar[0]; displayedChar[1] = hoursChar[1]; displayedChar[2] = minutesChar[0]; displayedChar[3] = minutesChar[1]; - char timeStr[6]; - if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { lv_label_set_text(label_time_ampm, ampmChar); if (hoursChar[0] == '0') { @@ -191,8 +173,7 @@ bool WatchFaceDigital::Refresh() { } } - sprintf(timeStr, "%c%c:%c%c", hoursChar[0], hoursChar[1], minutesChar[0], minutesChar[1]); - lv_label_set_text(label_time, timeStr); + lv_label_set_text_fmt(label_time, "%s:%s", hoursChar, minutesChar); if (settingsController.GetClockType() == Controllers::Settings::ClockType::H12) { lv_obj_align(label_time, lv_scr_act(), LV_ALIGN_IN_RIGHT_MID, 0, 0); @@ -202,13 +183,11 @@ bool WatchFaceDigital::Refresh() { } if ((year != currentYear) || (month != currentMonth) || (dayOfWeek != currentDayOfWeek) || (day != currentDay)) { - char dateStr[22]; if (settingsController.GetClockType() == Controllers::Settings::ClockType::H24) { - sprintf(dateStr, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year); + lv_label_set_text_fmt(label_date, "%s %d %s %d", dateTimeController.DayOfWeekShortToString(), day, dateTimeController.MonthShortToString(), year); } else { - sprintf(dateStr, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year); + lv_label_set_text_fmt(label_date, "%s %s %d %d", dateTimeController.DayOfWeekShortToString(), dateTimeController.MonthShortToString(), day, year); } - lv_label_set_text(label_date, dateStr); lv_obj_align(label_date, lv_scr_act(), LV_ALIGN_CENTER, 0, 60); currentYear = year; diff --git a/src/displayapp/screens/WatchFaceDigital.h b/src/displayapp/screens/WatchFaceDigital.h index 76c8d3dc..6a6e1ac6 100644 --- a/src/displayapp/screens/WatchFaceDigital.h +++ b/src/displayapp/screens/WatchFaceDigital.h @@ -35,10 +35,8 @@ namespace Pinetime { bool Refresh() override; - void OnObjectEvent(lv_obj_t* pObj, lv_event_t i); - private: - char displayedChar[5]; + char displayedChar[5] {}; uint16_t currentYear = 1970; Pinetime::Controllers::DateTime::Months currentMonth = Pinetime::Controllers::DateTime::Months::Unknown; @@ -63,7 +61,6 @@ namespace Pinetime { lv_obj_t* batteryPlug; lv_obj_t* heartbeatIcon; lv_obj_t* heartbeatValue; - lv_obj_t* heartbeatBpm; lv_obj_t* stepIcon; lv_obj_t* stepValue; lv_obj_t* notificationIcon;